Hi,
So I have made a program to do fitting in some values. The chi2/ndf, I obtain from the TGrapherror is very different from the one of the TF1. The TF1 for instance can give around 2 while the TGrapherror gives 0.03… My errors are very small and non existant in some points and they are calculated correctly… but I would like to have them and fit with them, is this ok? or is it better to just do it without them? Why the chi2/ndf is so different? I have seen in other answers to fit with W. I do fit with W in TF1, but in tgrapherror, I want to fit with the tgraph rror in order to account even the small errors. Which of the 2 chi2/ndf should i report as correct?! it seems the higher value to be correct, since there are fits like these in the attached photo. Yes the errors are that small… the code with the tgrapherrors:
`std::unordered_map<PixelPosition, CalibrationFunction> calcCalibrationParams(const BiasedChargeMap& biasedCharges, TTree* data) {
std::unordered_map<PixelPosition, CalibrationFunction> calibrationParams;for (auto& [p, line] : biasedCharges) { if (line.size() < 9) { // Ensure there's enough data to perform a meaningful fit continue; } // Create TGraphErrors to hold the data points with error bars TGraphErrors graph(line.size()); for (size_t i = 0; i < line.size(); ++i) { // Use the mean charge and error directly from the ChargeAtBias structure double mean_charge = line[i].charge; double error = line[i].error; std::cout <<"qtp" << qtp << "charge = " << mean_charge << ", samples = " << line[i].samples << ", error = " << error << '\n'; // Add the point and error to the graph graph.SetPoint(i, qtps[line[i].bias], mean_charge); graph.SetPointError(i, 0, error); // x-error is 0, y-error is the calculated error } // Define the fitting function, where [2] is dynamically set to the last charge double last_charge = line[line.size() - 1].charge; std::stringstream function_def; function_def << last_charge << "*pow((1-exp(-[0]*x)),[1])"; TF1 ex("tf_name", function_def.str().c_str(), 0, 60); ex.SetParameters(1./12., 1.0); // Initial guesses for [0] and [1] // Add a synthetic point at (0,0) with a very small error to enforce the fit passing through the origin graph.SetPoint(graph.GetN(), 0, 0); graph.SetPointError(graph.GetN()-1, 0, 1e-10); // Very small error to enforce fit through (0,0) // Perform the fit graph.Fit(&ex, "W"); double chi_square_ndf = ex.GetChisquare() / ex.GetNDF(); calibrationParams[p] = { ex.GetParameter(0), ex.GetParameter(1), last_charge + 0.001f, chi_square_ndf }; // Plot the graph with error bars TCanvas* c1 = new TCanvas("c1", "Calibration Fit", 800, 800); // Create a square canvas graph.SetMarkerStyle(20); // Marker style graph.SetMarkerSize(0.5); // Marker size graph.SetMarkerColor(kBlue); // Marker color graph.Draw("AP"); // Draw points with error bars ex.Draw("same"); // Set axis ranges graph.GetXaxis()->SetLimits(0, 60); // Set x-axis limits graph.SetMinimum(0); // Set y-axis minimum graph.SetMaximum(15); // Set y-axis maximum to match the x-axis range // Add text annotations TLatex latex; latex.SetNDC(); latex.SetTextSize(0.03); std::stringstream func_text, chi_square_text; func_text << "f(qtp) = " << last_charge << " * (1 - exp(-" << ex.GetParameter(0) << " * qtp))^{" << ex.GetParameter(1) << "}"; chi_square_text << "#chi^{2}/NDF = " << chi_square_ndf; latex.DrawLatex(0.15, 0.85, func_text.str().c_str()); latex.DrawLatex(0.15, 0.80, chi_square_text.str().c_str()); // Save the plot std::stringstream save_path; save_path << "fit_plots/fit_plot_" << p.super_column_id << "_" << p.super_pixel_id << "_" << p.pixel_id << ".png"; c1->SaveAs(save_path.str().c_str()); delete c1; } return calibrationParams;
}
`
The code without:
`std::unordered_map<PixelPosition, CalibrationFunction> calcCalibrationParams(const >BiasedChargeMap& biasedCharges, TTree* data) {
std::unordered_map<PixelPosition, CalibrationFunction> calibrationParams;for (auto& [p, line] : biasedCharges) { // std::cout << '{' << p.super_column_id << ",sp" << p.super_pixel_id << ",pix" << p.pixel_id << "} -> "; // for (auto& point : line) { // std::cout << "{tp: " << point.bias << ", adc: " << point.charge << "}, "; // } // std::cout << '\n'; if (line.size() < 9) { continue; } std::stringstream function_def; function_def << line[line.size() - 1].charge; function_def << "*pow((1-exp(-[0]*x)),[1])"; auto to_string = function_def.str(); TF1 ex("tf_name", to_string.c_str()); ex.SetParameters(1./12., 1); // Create a TGraph to plot the data points and the fit TGraph graph; // Add the real data points to the graph for (std::size_t i = 0; i < line.size(); ++i) { auto& point = line[i]; graph.SetPoint(i, point.bias, point.charge); } // Add a synthetic point at (0,0) graph.SetPoint(graph.GetN(), 0, 0); std::stringstream predicate; predicate << "pixel_id == " << p.pixel_id << "&& super_column_id == " << p.super_column_id << "&& super_pixel_id == " << p.super_pixel_id; data->Fit("tf_name", "charge:qtp", predicate.str().c_str(), "W0N"); //graph.Fit(&ex, "W"); double chi_square_ndf = ex.GetChisquare() / ex.GetNDF(); calibrationParams[p] = { ex.GetParameter(0), ex.GetParameter(1), line[line.size() - 1].charge + 0.001f, chi_square_ndf }; // Plot the graph and fit TCanvas* c1 = new TCanvas("c1", "Calibration Fit", 800, 800); graph.SetMarkerStyle(20); graph.SetMarkerSize(0.5); graph.SetMarkerColor(kBlue); graph.Draw("AP"); ex.Draw("same"); // Set axis ranges graph.GetXaxis()->SetLimits(0, 60); graph.SetMinimum(0); graph.SetMaximum(15); // Add text annotations TLatex latex; latex.SetNDC(); latex.SetTextSize(0.03); std::stringstream func_text, chi_square_text; func_text << "f(qtp) = " << line[line.size() - 1].charge + 0.001f << " * (1 - exp(-" << ex.GetParameter(0) << " * qtp))^{" << ex.GetParameter(1) << "}"; chi_square_text << "#chi^{2}/NDF = " << chi_square_ndf; latex.DrawLatex(0.15, 0.85, func_text.str().c_str()); latex.DrawLatex(0.15, 0.80, chi_square_text.str().c_str()); // Save the plot std::stringstream save_path; save_path << "fit_plots/fit_plot_" << p.super_column_id << "_" << p.super_pixel_id << "_" << p.pixel_id << ".png"; c1->SaveAs(save_path.str().c_str()); } return calibrationParams;
}`
an example of my errors when they exist:
charge = 6, samples = 183, error = 0 charge = 8, samples = 183, error = 0 charge = 8, samples = 183, error = 0 charge = 10, samples = 183, error = 0 charge = 11, samples = 183, error = 0 charge = 11.456, samples = 182, error = 0.0400562 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0 charge = 12, samples = 183, error = 0
Note that the png with the appeared red line is with the TGRAPHerrors. The other is with th tf1, it doesnt seem to be able to plot the fitted function… although note that also the data appear differently while are the same! Do you know why is that?! The data are exactly the same!
Note that the code without the errors that i add above its an effort of mine to try to plot and see what i fit from the original code which is this. the following code and the code without errors abo e give the same results:
std::unordered_map<PixelPosition, CalibrationFunction> calcCalibrationParams(const BiasedChargeMap& biasedCharges, TTree* data) {
std::unordered_map<PixelPosition, CalibrationFunction> calibrationParams;
for (auto& [p, line] : biasedCharges) {
// std::cout << '{' << p.super_column_id << ",sp" << p.super_pixel_id << ",pix" << p.pixel_id << "} -> ";
// for (auto& point : line) {
// std::cout << "{tp: " << point.bias << ", adc: " << point.charge << "}, ";
// }
// std::cout << '\n';
if (line.size() < 9) {
continue;
}
std::stringstream function_def;
function_def << line[line.size() - 1].charge;
function_def << "*pow((1-exp(-[0]*x)),[1])";
auto to_string = function_def.str();
TF1 ex("tf_name", to_string.c_str());
ex.SetParameters(1./12., 1);
std::stringstream predicate;
predicate << "pixel_id == " << p.pixel_id
<< "&& super_column_id == " << p.super_column_id
<< "&& super_pixel_id == " << p.super_pixel_id;
data->Fit("tf_name", "charge:qtp", predicate.str().c_str(), "WQ0N");
double chi_square_ndf = ex.GetChisquare() / ex.GetNDF();
calibrationParams[p] = { ex.GetParameter(0), ex.GetParameter(1), line[line.size() - 1].charge + 0.001f, chi_square_ndf };
}
return calibrationParams;
}
Thank you very much for your quick answers. I have this problem for months… literally i dont know what else to do…
At last I want the fitting function to pass from (0,0). The different chi2/ndf is not due to the (0,0) point.
I am attaching you the three full code versions. As you will see I do thousands of fittings like these. The above was an example of them.
main_original_plot_effort.cpp (18.7 KB)
main_errors.cpp (17.6 KB)
main_original.cpp (16.9 KB)
Please read tips for efficient and successful posting and posting code
ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided