GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TCalibrationGraph.cxx
Go to the documentation of this file.
1#include "TCalibrationGraph.h"
2
3#include <iostream>
4#include <algorithm>
5
6#include "TMath.h"
7#include "TPad.h"
8#include "TF1.h"
9#include "TBuffer.h"
10#include "TH1F.h"
11
13{
14 if(TCalibrationGraphSet::VerboseLevel() > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
15 Int_t px = gPad->GetEventX();
16 Int_t py = gPad->GetEventY();
17 if(TCalibrationGraphSet::VerboseLevel() > EVerbosity::kBasicFlow) { std::cout << "px, py " << px << ", " << py << " on gPad " << gPad->GetName() << std::endl; }
18 if(fIsResidual) { return fParent->RemoveResidualPoint(px, py); }
19 return fParent->RemovePoint(px, py);
20}
21
22#if ROOT_VERSION_CODE < ROOT_VERSION(6, 26, 0)
23void TCalibrationGraph::Scale(const double& scale)
24{
25 Double_t* y = GetY();
26 Double_t* ey = GetEY();
27
28 for(int i = 0; i < GetN(); ++i) {
29 y[i] *= scale;
30 ey[i] *= scale;
31 }
32}
33#endif
34
36
37TCalibrationGraphSet::TCalibrationGraphSet(TGraphErrors* graph, const std::string& label)
38 : fTotalGraph(new TGraphErrors), fTotalResidualGraph(new TGraphErrors)
39{
40 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " fTotalGraph " << fTotalGraph << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
41 if(graph != nullptr) {
42 Add(graph, label);
44 }
45}
46
47TCalibrationGraphSet::TCalibrationGraphSet(std::string xAxisLabel, std::string yAxisLabel)
48 : fTotalGraph(new TGraphErrors), fTotalResidualGraph(new TGraphErrors), fXAxisLabel(std::move(xAxisLabel)), fYAxisLabel(std::move(yAxisLabel))
49{
50 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " fTotalGraph " << fTotalGraph << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
51}
52
58
59int TCalibrationGraphSet::Add(TGraphErrors* graph, const std::string& label)
60{
62 std::cout << __PRETTY_FUNCTION__ << ", fTotalGraph " << fTotalGraph << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
63 Print();
64 }
65 if(graph->GetN() == 0) {
66 std::cout << __PRETTY_FUNCTION__ << ": graph \"" << graph->GetName() << "\", label \"" << label << "\" is empty, not adding it" << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
67 return -1;
68 }
69
70 graph->GetListOfFunctions()->Clear(); // we don't want to include any fits
71
72 // get points and error bars from our calibration
73 double* x = fTotalGraph->GetX();
74 double* y = fTotalGraph->GetY();
75 double* ex = fTotalGraph->GetEX();
76 double* ey = fTotalGraph->GetEY();
77
78 // get points and error bars from graph
79 double* rhsX = graph->GetX();
80 double* rhsY = graph->GetY();
81 double* rhsEX = graph->GetEX();
82 double* rhsEY = graph->GetEY();
83
84 // create one vector with x, y, ex, ey, index of graph, and index of point that we can use to sort the data
85 // TODO: create a (private?) enum to reference to x, y, ex, ey, graph index, and point index
86 std::vector<std::tuple<double, double, double, double, size_t, size_t>> data(fTotalGraph->GetN() + graph->GetN());
87 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Filling vector of size " << data.size() << " with " << fTotalGraph->GetN() << " and " << graph->GetN() << " entries" << std::endl; }
88 for(int i = 0; i < fTotalGraph->GetN(); ++i) {
89 data[i] = std::make_tuple(x[i], y[i], ex[i], ey[i], fGraphIndex[i], fPointIndex[i]);
90 }
91 for(int i = 0; i < graph->GetN(); ++i) {
92 data[fTotalGraph->GetN() + i] = std::make_tuple(rhsX[i], rhsY[i], rhsEX[i], rhsEY[i], fGraphs.size(), i);
93 }
94
95 std::sort(data.begin(), data.end());
96
97 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "sorted vector, setting graph sizes" << std::endl; }
98
99 fTotalGraph->Set(static_cast<Int_t>(data.size()));
100 fTotalResidualGraph->Set(static_cast<Int_t>(data.size()));
101 fGraphIndex.resize(data.size());
102 fPointIndex.resize(data.size());
103
104 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Filling fTotalGraph, fGraphIndex, and fPointIndex with " << data.size() << " points" << std::endl; }
105 for(size_t i = 0; i < data.size(); ++i) {
106 fTotalGraph->SetPoint(static_cast<Int_t>(i), std::get<0>(data[i]), std::get<1>(data[i]));
107 fTotalGraph->SetPointError(static_cast<Int_t>(i), std::get<2>(data[i]), std::get<3>(data[i]));
108 fGraphIndex[i] = std::get<4>(data[i]);
109 fPointIndex[i] = std::get<5>(data[i]);
110 }
111 fMinimumX = std::get<0>(data[0]);
112 fMinimumY = std::get<1>(data[0]);
113 fMaximumX = std::get<0>(data.back());
114 fMaximumY = std::get<1>(data.back());
115 // doesn't really make sense to calculate the residual here, as we don't have a fit of all the data yet
116 fResidualSet = false;
117
118 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Adding new calibration graph and label to vectors" << std::endl; }
119 // add graph and label to our vectors
120 fGraphs.emplace_back(this, graph);
121 fResidualGraphs.emplace_back(this, 0, true);
122 fLabel.push_back(label);
123 // set initial color
124 fGraphs.back().SetLineColor(static_cast<Color_t>(fGraphs.size()));
125 fGraphs.back().SetMarkerColor(static_cast<Color_t>(fGraphs.size()));
126 fGraphs.back().SetMarkerStyle(static_cast<Style_t>(fGraphs.size()));
127 fResidualGraphs.back().SetLineColor(static_cast<Color_t>(fResidualGraphs.size()));
128 fResidualGraphs.back().SetMarkerColor(static_cast<Color_t>(fResidualGraphs.size()));
129 fResidualGraphs.back().SetMarkerStyle(static_cast<Style_t>(fResidualGraphs.size()));
130
132 std::cout << "done" << std::endl;
133 Print();
134 }
135 return static_cast<int>(fGraphs.size() - 1);
136}
137
139{
140 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " gpad " << gPad->GetName() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
141 TF1* calibration = FitFunction();
142 if(calibration != nullptr && (!fResidualSet || force)) {
144 std::cout << "calibration " << calibration << ", fResidualSet " << (fResidualSet ? "true" : "false") << ", force " << (force ? "true" : "false") << ", calibration: " << std::endl;
145 calibration->Print();
146 }
147 double* x = fTotalGraph->GetX();
148 double* y = fTotalGraph->GetY();
149 double* ex = fTotalGraph->GetEX();
150 double* ey = fTotalGraph->GetEY();
151 fTotalResidualGraph->Set(fTotalGraph->GetN());
152 for(int i = 0; i < fTotalGraph->GetN(); ++i) {
153 fTotalResidualGraph->SetPoint(i, y[i] - calibration->Eval(x[i]), y[i]);
154 fTotalResidualGraph->SetPointError(i, TMath::Sqrt(TMath::Power(ey[i], 2) + TMath::Power(ex[i] * calibration->Derivative(x[i]), 2)), ey[i]);
155 }
157 std::cout << "Done calculating total residual graph with " << fTotalResidualGraph->GetN() << " points" << std::endl;
158 }
159 for(size_t g = 0; g < fGraphs.size(); ++g) {
160 x = fGraphs[g].GetX();
161 y = fGraphs[g].GetY();
162 ex = fGraphs[g].GetEX();
163 ey = fGraphs[g].GetEY();
164 fResidualGraphs[g].Set(fGraphs[g].GetN());
165 for(int i = 0; i < fGraphs[g].GetN(); ++i) {
166 fResidualGraphs[g].SetPoint(i, y[i] - calibration->Eval(x[i]), y[i]);
167 fResidualGraphs[g].SetPointError(i, TMath::Sqrt(TMath::Power(ey[i], 2) + TMath::Power(ex[i] * calibration->Derivative(x[i]), 2)), ey[i]);
168 }
169 }
171 std::cout << "Done calculating all " << fGraphs.size() << " individual residual graphs" << std::endl;
172 }
173 fResidualSet = true;
174 auto* mother = gPad->GetMother();
175 int pad = 0;
176 while(mother->GetPad(pad) != nullptr) {
177 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "pad " << pad << " = " << std::flush << mother->GetPad(pad) << " = " << std::flush << mother->GetPad(pad)->GetName() << ": modifying, " << std::flush; }
178 mother->GetPad(pad)->Modified();
179 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "updating, " << std::flush; }
180 mother->GetPad(pad)->Update();
181 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "changing to pad, " << std::flush; }
182 mother->cd(pad);
183 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "done!" << std::endl; }
184 pad++;
185 }
186 } else {
187 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << __PRETTY_FUNCTION__ << ": didn't find calibration (" << calibration << "), or the residual was already set (" << (fResidualSet ? "true" : "false") << ") and we don't force it (" << (force ? "true" : "false") << ")" << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
188 if(calibration == nullptr) { fResidualSet = false; }
189 }
191 return fResidualSet;
192}
193
195{
196 if(fTotalGraph == nullptr) {
197 std::cerr << "Trying to set axis title to \"" << title << "\" failed because no total graph is present for this title to be applied to!" << std::endl;
198 return;
199 }
200 fTotalGraph->SetTitle(Form("%s;%s", fTotalGraph->GetTitle(), title));
201}
202
203void TCalibrationGraphSet::DrawCalibration(Option_t* opt, TLegend* legend)
204{
205 TString options = opt;
206 options.ToLower();
207 if(options.Contains("same")) {
208 options.Remove(options.Index("same"), 4);
209 opt = options.Data();
210 } else {
211 options.Append("a");
212 }
213 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing total graph with option \"" << options.Data() << "\" on gPad " << gPad->GetName() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
214 fTotalGraph->Draw(options.Data());
215
216 if(fTotalGraph->GetHistogram() != nullptr) {
217 fTotalGraph->GetHistogram()->GetXaxis()->CenterTitle();
218 fTotalGraph->GetHistogram()->GetXaxis()->SetTitle(fXAxisLabel.c_str());
219 fTotalGraph->GetHistogram()->GetYaxis()->CenterTitle();
220 fTotalGraph->GetHistogram()->GetYaxis()->SetTitle(fYAxisLabel.c_str());
221 }
222
223 for(size_t i = 0; i < fGraphs.size(); ++i) {
224 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing " << i << ". graph with option \"" << opt << "\", marker color " << fGraphs[i].GetMarkerColor() << " on gPad " << gPad->GetName() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
225 fGraphs[i].Draw(opt);
226 if(legend != nullptr) {
227 legend->AddEntry(&(fGraphs[i]), fLabel[i].c_str());
228 }
229 }
230 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing legend " << legend << " on gPad " << gPad->GetName() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
231 if(legend != nullptr) {
232 legend->Draw();
233 }
234}
235
236void TCalibrationGraphSet::DrawResidual(Option_t* opt, TLegend* legend)
237{
238 TString options = opt;
239 options.ToLower();
240 options.Append("a");
241 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing total residual graph with option \"" << options.Data() << "\" on gPad " << gPad->GetName() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
242 fTotalResidualGraph->Draw(options.Data());
243 auto* hist = fTotalResidualGraph->GetHistogram();
244 if(hist != nullptr) {
245 hist->GetXaxis()->SetLabelSize(0.06);
246 } else {
247 std::cout << "Failed to get histogram for graph:" << std::endl;
248 fTotalResidualGraph->Print();
249 }
250
251 for(size_t i = 0; i < fResidualGraphs.size(); ++i) {
252 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing " << i << ". residual graph with option \"" << opt << "\", marker color " << fResidualGraphs[i].GetMarkerColor() << " on gPad " << gPad->GetName() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
253 fResidualGraphs[i].Draw(opt);
254 if(legend != nullptr) {
255 legend->AddEntry(&(fResidualGraphs[i]), fLabel[i].c_str());
256 }
257 }
258 if(legend != nullptr) {
259 legend->Draw();
260 }
261}
262
263Int_t TCalibrationGraphSet::RemovePoint(const Int_t& px, const Int_t& py)
264{
265 /// This function calls RemovePoint on the total graph.
266
268 std::cout << __PRETTY_FUNCTION__ << ": point " << px << ", " << py << "; gPad " << gPad->GetName() << ": " << gPad->AbsPixeltoX(px) << ", " << gPad->AbsPixeltoY(py) << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
269 }
270
271 return RemovePoint(fTotalGraph, px, py);
272}
273
274Int_t TCalibrationGraphSet::RemoveResidualPoint(const Int_t& px, const Int_t& py)
275{
276 /// This function calls RemovePoint on the total graph.
277
279 std::cout << __PRETTY_FUNCTION__ << ": point " << px << ", " << py << "; gPad " << gPad->GetName() << ": " << gPad->AbsPixeltoX(px) << ", " << gPad->AbsPixeltoY(py) << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
280 }
281
282 return RemovePoint(fTotalResidualGraph, px, py);
283}
284
285Int_t TCalibrationGraphSet::RemovePoint(TGraphErrors* graph, const Int_t& px, const Int_t& py)
286{
287 /// This function is primarily a copy of TGraph::RemovePoint with some added bits to remove a point that has been selected in the residual graph from it and the corresponding point from the calibration graph and the total graphs
288
290
291 // localize point to be deleted
292 Int_t point = -2;
293 Int_t i = 0;
294 // start with a small window (in case the mouse is very close to one point)
295 double* x = graph->GetX();
296 double* y = graph->GetY();
297 for(i = 0; i < graph->GetN(); i++) {
298 Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(x[i]));
299 Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(y[i]));
300 // TODO replace 100 with member variable?
301 if(dpx * dpx + dpy * dpy < 100) {
303 std::cout << i << ": dpx = " << dpx << " = " << px << " - " << gPad->XtoAbsPixel(gPad->XtoPad(x[i])) << ", dpy = " << dpy << " = " << py << " - " << gPad->YtoAbsPixel(gPad->YtoPad(y[i])) << " this is the point we're looking for at " << x[i] << ", " << y[i] << std::endl;
304 }
305 point = i;
306 break;
307 }
309 std::cout << i << ": dpx = " << dpx << " = " << px << " - " << gPad->XtoAbsPixel(gPad->XtoPad(x[i])) << ", dpy = " << dpy << " = " << py << " - " << gPad->YtoAbsPixel(gPad->YtoPad(y[i])) << " not the point we're looking for" << std::endl;
310 }
311 }
312
313 if(point < 0) {
314 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << "Failed to find point close to " << px << ", " << py << std::endl; }
316 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
317 Print();
318 }
319 return point;
320 }
322 Print();
323 }
324
325 // now that we have the point we want to delete, remove it from the total graphs
326 fTotalGraph->RemovePoint(point);
327 if(fTotalResidualGraph->RemovePoint(point) < 0) {
328 // we failed to remove the point in the residual, so we assume it's out of whack
329 fResidualSet = false;
330 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << point << " didn't removed residual point" << std::endl; }
332 std::cout << point << " removed residual point" << std::endl;
333 }
334
335 // need to find which of the graphs we have to remove this point from -> use fGraphIndex[point]
336 // and also which point this is of the graph -> use fPointIndex[point]
337 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << point << " - " << fGraphIndex[point] << ", " << fPointIndex[point] << std::endl; }
338 if(fGraphs[fGraphIndex[point]].RemovePoint(fPointIndex[point]) == -1 || fResidualGraphs[fGraphIndex[point]].RemovePoint(fPointIndex[point]) == -1) {
339 std::cout << "point " << point << " out of range?" << std::endl;
340 }
341
342 // now we need to update the indices by removing this one, and updating all that come after it
343 auto oldGraph = fGraphIndex[point];
344 auto oldPoint = fPointIndex[point];
345 fGraphIndex.erase(fGraphIndex.begin() + point);
346 fPointIndex.erase(fPointIndex.begin() + point);
347 for(size_t p = 0; p < fGraphIndex.size(); ++p) {
348 if(fGraphIndex[p] == oldGraph && fPointIndex[p] >= oldPoint) {
349 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << fGraphIndex[p] << " == " << oldGraph << " && " << fPointIndex[p] << " >= " << oldPoint << ": decrementing index" << std::endl; }
350 --fPointIndex[p];
352 std::cout << fGraphIndex[p] << " != " << oldGraph << " || " << fPointIndex[p] << " < " << oldPoint << ": decrementing index" << std::endl;
353 }
354 }
355
356 // update the graphics
357 auto* mother = gPad->GetMother();
358 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Got mother pad " << mother->GetName() << " from pad " << gPad->GetName() << std::endl; }
359 int pad = 0;
360 while(mother->GetPad(pad) != nullptr) {
361 mother->GetPad(pad)->Modified(); // one version also used Update and cd(pad)?
362 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Modified pad " << pad << " = " << mother->GetPad(pad)->GetName() << std::endl; }
363 pad++;
364 }
366
367 // emit signal that this point has been removed
368 std::array<Longptr_t, 2> args = {static_cast<int64_t>(oldGraph), static_cast<int64_t>(oldPoint)};
369 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Emitting RemovePoint(Int_t, Int_t) with " << args[0] << ", " << args[1] << " - " << args.data() << std::endl; }
370 Emit("RemovePoint(Int_t, Int_t)", args.data());
371
372 return point;
373}
374
376{
377 /// This function removes the indicated point from the total graph.
378
380
381 // now that we have the point we want to delete, remove it from the total graphs
382 fTotalGraph->RemovePoint(point);
383 if(fTotalResidualGraph->RemovePoint(point) < 0) {
384 // we failed to remove the point in the residual, so we assume it's out of whack
385 fResidualSet = false;
386 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << point << " didn't removed residual point" << std::endl; }
388 std::cout << point << " removed residual point" << std::endl;
389 }
390
391 // need to find which of the graphs we have to remove this point from -> use fGraphIndex[point]
392 // and also which point this is of the graph -> use fPointIndex[point]
393 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Going to remove " << point << " - " << fGraphIndex[point] << ", " << fPointIndex[point] << std::endl; }
394 if(fGraphs[fGraphIndex[point]].RemovePoint(fPointIndex[point]) == -1 || fResidualGraphs[fGraphIndex[point]].RemovePoint(fPointIndex[point]) == -1) {
395 std::cout << "point " << point << " out of range?" << std::endl;
396 }
397
398 // now we need to update the indices by removing this one, and updating all that come after it
399 auto oldGraph = fGraphIndex[point];
400 auto oldPoint = fPointIndex[point];
401 fGraphIndex.erase(fGraphIndex.begin() + point);
402 fPointIndex.erase(fPointIndex.begin() + point);
403 for(size_t p = 0; p < fGraphIndex.size(); ++p) {
404 if(fGraphIndex[p] == oldGraph && fPointIndex[p] >= oldPoint) {
405 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << fGraphIndex[p] << " == " << oldGraph << " && " << fPointIndex[p] << " >= " << oldPoint << ": decrementing index" << std::endl; }
406 --fPointIndex[p];
408 std::cout << fGraphIndex[p] << " != " << oldGraph << " || " << fPointIndex[p] << " < " << oldPoint << ": decrementing index" << std::endl;
409 }
410 }
411
412 // update the graphics
413 auto* mother = gPad->GetMother();
414 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Got mother pad " << mother->GetName() << " from pad " << gPad->GetName() << std::endl; }
415 int pad = 0;
416 while(mother->GetPad(pad) != nullptr) {
417 mother->GetPad(pad)->Modified(); // one version also used Update and cd(pad)?
418 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Modified pad " << pad << " = " << mother->GetPad(pad)->GetName() << std::endl; }
419 pad++;
420 }
422
423 // emit signal that this point has been removed
424 std::array<Longptr_t, 2> args = {static_cast<int64_t>(oldGraph), static_cast<int64_t>(oldPoint)};
425 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Emitting RemovePoint(Int_t, Int_t) with " << args[0] << ", " << args[1] << " - " << args.data() << std::endl; }
426 Emit("RemovePoint(Int_t, Int_t)", args.data());
427}
428
430{
431 for(auto& graph : fGraphs) {
432 graph.Sort();
433 }
434 for(auto& graph : fResidualGraphs) {
435 // residuals plot energy vs. residual, so we want to sort by y, not x!
436 graph.Sort(&TGraph::CompareY);
437 }
438}
439
440void TCalibrationGraphSet::Scale(bool useAllPrevious)
441{
442 /// Scale all graphs to fit each other (based on the first "previous" graph found or just the first graph).
443 /// If no overlap is being found between the graph that is being scaled and the first graph (or all graphs before this one),
444 /// the current graph isn't being scaled and we continue with the next graph.
446 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
447 Print();
448 }
449 Sort();
450 for(size_t g = 1; g < fGraphs.size(); ++g) {
451 auto& graph = fGraphs[g];
452 if(graph.GetN() == 0) {
453 std::cout << "No entries in " << g << ". graph" << std::endl;
454 }
455 double* x = graph.GetX();
456 double* y = graph.GetY();
457 // loop over all other graphs before this one and use the first one with an overlap (should this be extended to use all possible ones before this one?)
458 size_t g2 = 0;
459 for(g2 = 0; (useAllPrevious ? g2 < g : g2 < 1); ++g2) {
460 double minRef = fGraphs[g2].GetX()[0];
461 double maxRef = fGraphs[g2].GetX()[fGraphs[g2].GetN() - 1];
463 std::cout << "Checking overlap between " << g2 << ". graph (" << fGraphs[g2].GetN() << ": " << minRef << " - " << maxRef << ") and " << g << ". graph (" << graph.GetN() << std::flush << ": " << x[0] << " - " << x[graph.GetN() - 1] << ")" << std::endl;
464 }
465 if(maxRef < x[0] || x[graph.GetN() - 1] < minRef) {
466 // no overlap between the two graphs, for now we just skip this one, but we could try and compare it to all the other ones?
467 std::cout << "No overlap between " << g2 << ". graph (" << fGraphs[g2].GetN() << ": " << minRef << " - " << maxRef << ") and " << g << ". graph (" << graph.GetN() << ": " << x[0] << " - " << x[graph.GetN() - 1] << ")" << std::endl;
468 continue;
469 }
470 // we have an overlap, so we calculate the scaling factor for each point and take the average (maybe should add some weight from the errors bars)
471 int count = 0;
472 double sum = 0.;
473 for(int p = 0; p < graph.GetN(); ++p) {
474 if(minRef < x[p] && x[p] < maxRef) {
475 sum += fGraphs[g2].Eval(x[p]) / y[p];
476 ++count;
477 if(fVerboseLevel > EVerbosity::kLoops) { std::cout << g << ", " << p << ": " << count << " - " << sum << ", " << fGraphs[g2].Eval(x[p]) / y[p] << std::endl; }
478 }
479 }
480 sum /= count;
481 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << g << ": scaling with " << sum << std::endl; }
482 graph.Scale(sum);
483 break;
484 }
485 if(g2 == g && fVerboseLevel > EVerbosity::kQuiet) {
486 std::cout << "No overlap(s) between 0. to " << g2 - 1 << ". graph and " << g << ". graph (" << graph.GetN() << ": " << x[0] << " - " << x[graph.GetN() - 1] << "), not scaling this one!" << std::endl;
487 }
488 }
491}
492
494{
495 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
496 if(fGraphs.empty()) {
497 std::cerr << "No graphs added yet, makes no sense to reset total graph?" << std::endl;
498 return;
499 }
500
501 size_t newSize = 0;
502 for(auto& graph : fGraphs) {
503 newSize += graph.GetN();
504 }
505 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "creating graph with " << newSize << " points" << std::endl; }
506 // create one vector with x, y, ex, ey, index of graph, and index of point that we can use to sort the data
507 std::vector<std::tuple<double, double, double, double, size_t, size_t>> data(newSize);
508 size_t counter = 0;
509 for(size_t i = 0; i < fGraphs.size(); ++i) {
510 // get points and error bars from graph
511 double* x = fGraphs[i].GetX();
512 double* y = fGraphs[i].GetY();
513 double* eX = fGraphs[i].GetEX();
514 double* eY = fGraphs[i].GetEY();
515 for(int p = 0; p < fGraphs[i].GetN(); ++p, ++counter) {
516 if(fVerboseLevel > EVerbosity::kLoops) { std::cout << "filling point " << counter << " of vector of size " << newSize << std::endl; }
517 data[counter] = std::make_tuple(x[p], y[p], eX[p], eY[p], i, p);
518 }
519 }
520
521 std::sort(data.begin(), data.end());
522
523 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "sorted vector, setting graph sizes" << std::endl; }
524
525 fTotalGraph->Set(data.size());
526 fTotalResidualGraph->Set(data.size());
527 fGraphIndex.resize(data.size());
528 fPointIndex.resize(data.size());
529
530 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Filling fTotalGraph, fGraphIndex, and fPointIndex with " << data.size() << " points" << std::endl; }
531 for(size_t i = 0; i < data.size(); ++i) {
532 fTotalGraph->SetPoint(i, std::get<0>(data[i]), std::get<1>(data[i]));
533 fTotalGraph->SetPointError(i, std::get<2>(data[i]), std::get<3>(data[i]));
534 fGraphIndex[i] = std::get<4>(data[i]);
535 fPointIndex[i] = std::get<5>(data[i]);
536 }
537 // doesn't really make sense to calculate the residual here, as we don't have a fit of all the data yet
538 fResidualSet = false;
539 // set the new minima and maxima (always assuming the first and last points are minima and maxima, respectively)
540 fMinimumX = std::get<0>(data[0]);
541 fMinimumY = std::get<1>(data[0]);
542 fMaximumX = std::get<0>(data.back());
543 fMaximumY = std::get<1>(data.back());
544}
545
546void TCalibrationGraphSet::Print(Option_t* opt) const
547{
549 std::cout << __PRETTY_FUNCTION__ << ", fTotalGraph " << fTotalGraph << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
550 }
551
552 std::cout << "TCalibrationGraphSet " << this << " - " << GetName() << ": " << fGraphs.size() << " calibration graphs, " << fResidualGraphs.size() << " residual graphs, " << fLabel.size() << " labels, ";
553 if(fTotalGraph != nullptr) {
554 std::cout << fTotalGraph->GetN() << " calibration points, and ";
555 } else {
556 std::cout << " no calibration points, and ";
557 }
558 if(fTotalResidualGraph != nullptr) {
559 std::cout << fTotalResidualGraph->GetN() << " residual points" << std::endl;
560 } else {
561 std::cout << " no residual points" << std::endl;
562 }
563 TString options = opt;
564 bool errors = options.Contains("e", TString::ECaseCompare::kIgnoreCase);
565 for(const auto& g : fGraphs) {
566 double* x = g.GetX();
567 double* y = g.GetY();
568 double* ex = g.GetEX();
569 double* ey = g.GetEY();
570 for(int p = 0; p < g.GetN(); ++p) {
571 if(errors) {
572 std::cout << p << " - " << x[p] << "(" << ex[p] << "), " << y[p] << "(" << ey[p] << "); ";
573 } else {
574 std::cout << p << " - " << x[p] << ", " << y[p] << "; ";
575 }
576 }
577 std::cout << std::endl;
578 }
579 std::cout << fGraphIndex.size() << " graph indices: ";
580 for(const auto& i : fGraphIndex) { std::cout << std::setw(3) << i << " "; }
581 std::cout << std::endl;
582 std::cout << fPointIndex.size() << " point indices: ";
583 for(const auto& i : fPointIndex) { std::cout << std::setw(3) << i << " "; }
584 std::cout << std::endl;
585 std::cout << "---- total graph ----" << std::endl;
586 double* x = fTotalGraph->GetX();
587 double* y = fTotalGraph->GetY();
588 for(int p = 0; p < fTotalGraph->GetN(); ++p) {
589 std::cout << p << " - " << x[p] << ", " << y[p] << "; ";
590 }
591 std::cout << std::endl;
592 std::cout << "---------------------" << std::endl;
593}
594
595void TCalibrationGraphSet::Clear(Option_t* option)
596{
597 fGraphs.clear();
598 fResidualGraphs.clear();
599 fLabel.clear();
600 fGraphIndex.clear();
601 fPointIndex.clear();
602 fResidualSet = false;
603 fMinimumX = 0.;
604 fMaximumX = 0.;
605 fMinimumY = 0.;
606 fMaximumY = 0.;
607 TNamed::Clear(option);
608 fTotalGraph->Set(0);
609 fTotalResidualGraph->Set(0);
610}
EVerbosity
Definition Globals.h:143
@ kQuiet
Definition Globals.h:144
@ kSubroutines
Definition Globals.h:146
@ kLoops
Definition Globals.h:147
@ kBasicFlow
Definition Globals.h:145
TH1D * hist
Definition UserFillObj.h:3
TCalibrationGraphSet * fParent
pointer to the set this graph belongs to
bool fIsResidual
flag to indicate that this graph is for residuals
Int_t RemovePoint() override
void ResetTotalGraph()
reset the total graph and add the individual ones again (used e.g. after scaling of individual graphs...
void DrawResidual(Option_t *opt="", TLegend *legend=nullptr)
std::vector< size_t > fGraphIndex
Index of the graph this point belongs to.
int GetN()
Returns GetN(), i.e. number of points of the total graph.
std::vector< size_t > fPointIndex
Index of the point within the graph this point corresponds to.
bool SetResidual(const bool &force=false)
TCalibrationGraphSet(TGraphErrors *graph=nullptr, const std::string &label="")
std::string fYAxisLabel
The label of the y-axis.
static EVerbosity fVerboseLevel
Changes verbosity.
std::vector< TCalibrationGraph > fResidualGraphs
These are the graphs used for plotting the residuals per source.
TGraphErrors * fTotalGraph
The sum of the other graphs, used for fitting.
double fMaximumX
Maximum x-value.
double fMinimumY
Minimum y-value.
void Print(Option_t *opt="") const override
double fMaximumY
Maximum y-value.
std::string fXAxisLabel
The label of the x-axis.
void Scale(bool useAllPrevious=true)
int Add(TGraphErrors *, const std::string &label)
Add new graph to set, using the label when creating legends during plotting.
void DrawCalibration(Option_t *opt="", TLegend *legend=nullptr)
TGraphErrors * fTotalResidualGraph
The sum of the residuals. Not really used apart from plotting (but overlayed with the individual grap...
bool fResidualSet
Flag to indicate if the residual has been set correctly.
void Clear(Option_t *option="") override
double fMinimumX
Minimum x-value.
Int_t RemovePoint(const Int_t &px, const Int_t &py)
void SetAxisTitle(const char *title)
Set axis title for the graph (form "x-axis title;y-axis title")
std::vector< TCalibrationGraph > fGraphs
These are the graphs used for plotting the calibration points per source.
TF1 * FitFunction()
Gets the calibration from the total graph (might be nullptr!).
Int_t RemoveResidualPoint(const Int_t &px, const Int_t &py)
static EVerbosity VerboseLevel()
std::vector< std::string > fLabel
The labels for the different graphs.