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)) {
143 double* x = fTotalGraph->GetX();
144 double* y = fTotalGraph->GetY();
145 double* ex = fTotalGraph->GetEX();
146 double* ey = fTotalGraph->GetEY();
147 fTotalResidualGraph->Set(fTotalGraph->GetN());
148 for(int i = 0; i < fTotalGraph->GetN(); ++i) {
149 fTotalResidualGraph->SetPoint(i, y[i] - calibration->Eval(x[i]), y[i]);
150 fTotalResidualGraph->SetPointError(i, TMath::Sqrt(TMath::Power(ey[i], 2) + TMath::Power(ex[i] * calibration->Derivative(x[i]), 2)), ey[i]);
151 }
152 for(size_t g = 0; g < fGraphs.size(); ++g) {
153 x = fGraphs[g].GetX();
154 y = fGraphs[g].GetY();
155 ex = fGraphs[g].GetEX();
156 ey = fGraphs[g].GetEY();
157 fResidualGraphs[g].Set(fGraphs[g].GetN());
158 for(int i = 0; i < fGraphs[g].GetN(); ++i) {
159 fResidualGraphs[g].SetPoint(i, y[i] - calibration->Eval(x[i]), y[i]);
160 fResidualGraphs[g].SetPointError(i, TMath::Sqrt(TMath::Power(ey[i], 2) + TMath::Power(ex[i] * calibration->Derivative(x[i]), 2)), ey[i]);
161 }
162 }
163 fResidualSet = true;
164 auto* mother = gPad->GetMother();
165 int pad = 0;
166 while(mother->GetPad(pad) != nullptr) {
167 mother->GetPad(pad)->Modified();
168 mother->GetPad(pad)->Update();
169 mother->cd(pad);
170 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Modified and updated pad " << pad << " = " << mother->GetPad(pad)->GetName() << std::endl; }
171 pad++;
172 }
173 } else {
174 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)
175 if(calibration == nullptr) { fResidualSet = false; }
176 }
178 return fResidualSet;
179}
180
182{
183 if(fTotalGraph == nullptr) {
184 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;
185 return;
186 }
187 fTotalGraph->SetTitle(Form("%s;%s", fTotalGraph->GetTitle(), title));
188}
189
190void TCalibrationGraphSet::DrawCalibration(Option_t* opt, TLegend* legend)
191{
192 TString options = opt;
193 options.ToLower();
194 if(options.Contains("same")) {
195 options.Remove(options.Index("same"), 4);
196 opt = options.Data();
197 } else {
198 options.Append("a");
199 }
200 fTotalGraph->Draw(options.Data());
201
202 if(fTotalGraph->GetHistogram() != nullptr) {
203 fTotalGraph->GetHistogram()->GetXaxis()->CenterTitle();
204 fTotalGraph->GetHistogram()->GetXaxis()->SetTitle(fXAxisLabel.c_str());
205 fTotalGraph->GetHistogram()->GetYaxis()->CenterTitle();
206 fTotalGraph->GetHistogram()->GetYaxis()->SetTitle(fYAxisLabel.c_str());
207 }
208
209 for(size_t i = 0; i < fGraphs.size(); ++i) {
210 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing " << i << ". graph with option \"" << opt << "\", marker color " << fGraphs[i].GetMarkerColor() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
211 fGraphs[i].Draw(opt);
212 if(legend != nullptr) {
213 legend->AddEntry(&(fGraphs[i]), fLabel[i].c_str());
214 }
215 }
216}
217
218void TCalibrationGraphSet::DrawResidual(Option_t* opt, TLegend* legend)
219{
220 TString options = opt;
221 options.ToLower();
222 options.Append("a");
223 fTotalResidualGraph->Draw(options.Data());
224 auto* hist = fTotalResidualGraph->GetHistogram();
225 if(hist != nullptr) {
226 hist->GetXaxis()->SetLabelSize(0.06);
227 } else {
228 std::cout << "Failed to get histogram for graph:" << std::endl;
229 fTotalResidualGraph->Print();
230 }
231
232 for(size_t i = 0; i < fResidualGraphs.size(); ++i) {
233 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << " drawing " << i << ". residual graph with option \"" << opt << "\", marker color " << fResidualGraphs[i].GetMarkerColor() << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
234 fResidualGraphs[i].Draw(opt);
235 if(legend != nullptr) {
236 legend->AddEntry(&(fResidualGraphs[i]), fLabel[i].c_str());
237 }
238 }
239}
240
241Int_t TCalibrationGraphSet::RemovePoint(const Int_t& px, const Int_t& py)
242{
243 /// This function is primarily a copy of TGraph::RemovePoint with some added bits to remove a point that has been selected in the calibration graph from it and the corresponding point from the residual graph and the total graphs
244
246 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)
247 Print();
248 }
249
250 // localize point to be deleted
251 Int_t ipoint = -2;
252 Int_t i = 0;
253 // start with a small window (in case the mouse is very close to one point)
254 double* x = fTotalGraph->GetX();
255 double* y = fTotalGraph->GetY();
256 for(i = 0; i < fTotalGraph->GetN(); i++) {
257 Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(x[i]));
258 Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(y[i]));
259 // TODO replace 100 with member variable?
260 if(dpx * dpx + dpy * dpy < 100) {
262 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" << std::endl;
263 }
264 ipoint = i;
265 break;
266 }
268 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;
269 }
270 }
271 if(ipoint < 0) {
272 std::cout << "Failed to find point close to " << px << ", " << py << std::endl;
274 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
275 Print();
276 }
277 return ipoint;
278 }
280 Print();
281 }
282 fTotalGraph->RemovePoint(ipoint);
283 if(fTotalResidualGraph->RemovePoint(ipoint) < 0) {
284 // we failed to remove the point in the residual, so we assume it's out of whack
285 fResidualSet = false;
286 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << ipoint << " didn't removed residual point" << std::endl; }
288 std::cout << ipoint << " removed residual point" << std::endl;
289 }
290 // need to find which of the graphs we have to remove this point from -> use fGraphIndex[ipoint]
291 // and also which point this is of the graph -> use fPointIndex[ipoint]
292 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << ipoint << " - " << fGraphIndex[ipoint] << ", " << fPointIndex[ipoint] << std::endl; }
293 if(fGraphs[fGraphIndex[ipoint]].RemovePoint(fPointIndex[ipoint]) == -1 || fResidualGraphs[fGraphIndex[ipoint]].RemovePoint(fPointIndex[ipoint]) == -1) {
294 std::cout << "point " << ipoint << " out of range?" << std::endl;
295 }
296 // and now also remove the points from the indices - also need to update all points after this point!
297 auto& oldGraph = fGraphIndex[ipoint];
298 auto& oldPoint = fPointIndex[ipoint];
299 fGraphIndex.erase(fGraphIndex.begin() + ipoint);
300 fPointIndex.erase(fPointIndex.begin() + ipoint);
301 for(size_t p = 0; p < fGraphIndex.size(); ++p) {
302 if(fGraphIndex[p] == oldGraph && fPointIndex[p] > oldPoint) {
303 --fPointIndex[p];
304 }
305 }
306 auto* mother = gPad->GetMother();
307 int pad = 0;
308 while(mother->GetPad(pad) != nullptr) {
309 mother->GetPad(pad)->Modified();
310 mother->GetPad(pad)->Update();
311 mother->cd(pad);
312 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Modified and updated pad " << pad << " = " << mother->GetPad(pad)->GetName() << std::endl; }
313 pad++;
314 }
316 std::array<Longptr_t, 2> args = {px, py};
317 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Emitting RemovePoint(Int_t, Int_t) with " << px << ", " << py << " - " << args.data() << std::endl; }
318 Emit("RemovePoint(Int_t, Int_t)", args.data());
319 return ipoint;
320}
321
322Int_t TCalibrationGraphSet::RemoveResidualPoint(const Int_t& px, const Int_t& py)
323{
324 /// 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
325
326 // localize point to be deleted
327 Int_t ipoint = -2;
328 Int_t i = 0;
329 // start with a small window (in case the mouse is very close to one point)
330 double* x = fTotalResidualGraph->GetX();
331 double* y = fTotalResidualGraph->GetY();
332 for(i = 0; i < fTotalResidualGraph->GetN(); i++) {
333 Int_t dpx = px - gPad->XtoAbsPixel(gPad->XtoPad(x[i]));
334 Int_t dpy = py - gPad->YtoAbsPixel(gPad->YtoPad(y[i]));
335 // TODO replace 100 with member variable?
336 if(dpx * dpx + dpy * dpy < 100) {
337 ipoint = i;
338 break;
339 }
340 }
341 if(ipoint < 0) {
342 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << "Failed to find point close to " << px << ", " << py << std::endl; }
344 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
345 Print();
346 }
347 return ipoint;
348 }
350 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
351 Print();
352 }
353 // no need to check if we can remove the residual point in this case
354 // need to find which of the graphs we have to remove this point from -> use fGraphIndex[ipoint]
355 // and also which point this is of the graph -> use fPointIndex[ipoint]
356 fTotalGraph->RemovePoint(ipoint);
357 fTotalResidualGraph->RemovePoint(ipoint);
358 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << ipoint << " - " << fGraphIndex[ipoint] << ", " << fPointIndex[ipoint] << std::endl; }
359 if(fGraphs[fGraphIndex[ipoint]].RemovePoint(fPointIndex[ipoint]) == -1 || fResidualGraphs[fGraphIndex[ipoint]].RemovePoint(fPointIndex[ipoint]) == -1) {
360 std::cout << "point " << ipoint << " out of range?" << std::endl;
361 }
362 // and now also remove the points from the indices - also need to update all points after this point!
363 auto& oldGraph = fGraphIndex[ipoint];
364 auto& oldPoint = fPointIndex[ipoint];
365 fGraphIndex.erase(fGraphIndex.begin() + ipoint);
366 fPointIndex.erase(fPointIndex.begin() + ipoint);
367 for(size_t p = 0; p < fGraphIndex.size(); ++p) {
368 if(fGraphIndex[p] == oldGraph && fPointIndex[p] > oldPoint) {
369 --fPointIndex[p];
370 }
371 }
372 auto* mother = gPad->GetMother();
373 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Got mother pad " << mother->GetName() << " from pad " << gPad->GetName() << std::endl; }
374 int pad = 0;
375 while(mother->GetPad(pad) != nullptr) {
376 mother->GetPad(pad)->Modified();
377 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Modified pad " << pad << " = " << mother->GetPad(pad)->GetName() << std::endl; }
378 pad++;
379 }
381 std::array<Longptr_t, 2> args = {px, py};
382 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Emitting RemoveResidualPoint(Int_t, Int_t) with " << px << ", " << py << " - " << args.data() << std::endl; }
383 Emit("RemoveResidualPoint(Int_t, Int_t)", args.data());
384 return ipoint;
385}
386
387void TCalibrationGraphSet::Scale(bool useAllPrevious)
388{
389 /// Scale all graphs to fit each other (based on the first "previous" graph found or just the first graph).
390 /// If no overlap is being found between the graph that is being scaled and the first graph (or all graphs before this one),
391 /// the current graph isn't being scaled and we continue with the next graph.
393 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
394 Print();
395 }
396 for(size_t g = 1; g < fGraphs.size(); ++g) {
397 auto& graph = fGraphs[g];
398 if(graph.GetN() == 0) {
399 std::cout << "No entries in " << g << ". graph" << std::endl;
400 }
401 graph.Sort();
402 double* x = graph.GetX();
403 double* y = graph.GetY();
404 // 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?)
405 size_t g2 = 0;
406 for(g2 = 0; (useAllPrevious ? g2 < g : g2 < 1); ++g2) {
407 double minRef = fGraphs[g2].GetX()[0];
408 double maxRef = fGraphs[g2].GetX()[fGraphs[g2].GetN() - 1];
410 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;
411 }
412 if(maxRef < x[0] || x[graph.GetN() - 1] < minRef) {
413 // 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?
414 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;
415 continue;
416 }
417 // 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)
418 int count = 0;
419 double sum = 0.;
420 for(int p = 0; p < graph.GetN(); ++p) {
421 if(minRef < x[p] && x[p] < maxRef) {
422 sum += fGraphs[g2].Eval(x[p]) / y[p];
423 ++count;
424 if(fVerboseLevel > EVerbosity::kLoops) { std::cout << g << ", " << p << ": " << count << " - " << sum << ", " << fGraphs[g2].Eval(x[p]) / y[p] << std::endl; }
425 }
426 }
427 sum /= count;
428 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << g << ": scaling with " << sum << std::endl; }
429 graph.Scale(sum);
430 break;
431 }
432 if(g2 == g && fVerboseLevel > EVerbosity::kQuiet) {
433 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;
434 }
435 }
438}
439
441{
442 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
443 if(fGraphs.empty()) {
444 std::cerr << "No graphs added yet, makes no sense to reset total graph?" << std::endl;
445 return;
446 }
447
448 size_t newSize = 0;
449 for(auto& graph : fGraphs) {
450 newSize += graph.GetN();
451 }
452 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "creating graph with " << newSize << " points" << std::endl; }
453 // create one vector with x, y, ex, ey, index of graph, and index of point that we can use to sort the data
454 std::vector<std::tuple<double, double, double, double, size_t, size_t>> data(newSize);
455 size_t counter = 0;
456 for(size_t i = 0; i < fGraphs.size(); ++i) {
457 // get points and error bars from graph
458 double* x = fGraphs[i].GetX();
459 double* y = fGraphs[i].GetY();
460 double* eX = fGraphs[i].GetEX();
461 double* eY = fGraphs[i].GetEY();
462 for(int p = 0; p < fGraphs[i].GetN(); ++p, ++counter) {
463 if(fVerboseLevel > EVerbosity::kLoops) { std::cout << "filling point " << counter << " of vector of size " << newSize << std::endl; }
464 data[counter] = std::make_tuple(x[p], y[p], eX[p], eY[p], i, p);
465 }
466 }
467
468 std::sort(data.begin(), data.end());
469
470 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "sorted vector, setting graph sizes" << std::endl; }
471
472 fTotalGraph->Set(data.size());
473 fTotalResidualGraph->Set(data.size());
474 fGraphIndex.resize(data.size());
475 fPointIndex.resize(data.size());
476
477 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Filling fTotalGraph, fGraphIndex, and fPointIndex with " << data.size() << " points" << std::endl; }
478 for(size_t i = 0; i < data.size(); ++i) {
479 fTotalGraph->SetPoint(i, std::get<0>(data[i]), std::get<1>(data[i]));
480 fTotalGraph->SetPointError(i, std::get<2>(data[i]), std::get<3>(data[i]));
481 fGraphIndex[i] = std::get<4>(data[i]);
482 fPointIndex[i] = std::get<5>(data[i]);
483 }
484 // doesn't really make sense to calculate the residual here, as we don't have a fit of all the data yet
485 fResidualSet = false;
486 // set the new minima and maxima (always assuming the first and last points are minima and maxima, respectively)
487 fMinimumX = std::get<0>(data[0]);
488 fMinimumY = std::get<1>(data[0]);
489 fMaximumX = std::get<0>(data.back());
490 fMaximumY = std::get<1>(data.back());
491}
492
493void TCalibrationGraphSet::Print(Option_t* opt) const
494{
496 std::cout << __PRETTY_FUNCTION__ << ", fTotalGraph " << fTotalGraph << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
497 }
498
499 std::cout << "TCalibrationGraphSet " << this << " - " << GetName() << ": " << fGraphs.size() << " calibration graphs, " << fResidualGraphs.size() << " residual graphs, " << fLabel.size() << " labels, ";
500 if(fTotalGraph != nullptr) {
501 std::cout << fTotalGraph->GetN() << " calibration points, and ";
502 } else {
503 std::cout << " no calibration points, and ";
504 }
505 if(fTotalResidualGraph != nullptr) {
506 std::cout << fTotalResidualGraph->GetN() << " residual points" << std::endl;
507 } else {
508 std::cout << " no residual points" << std::endl;
509 }
510 TString options = opt;
511 bool errors = options.Contains("e", TString::ECaseCompare::kIgnoreCase);
512 for(const auto& g : fGraphs) {
513 double* x = g.GetX();
514 double* y = g.GetY();
515 double* ex = g.GetEX();
516 double* ey = g.GetEY();
517 for(int p = 0; p < g.GetN(); ++p) {
518 if(errors) {
519 std::cout << p << " - " << x[p] << "(" << ex[p] << "), " << y[p] << "(" << ey[p] << "); ";
520 } else {
521 std::cout << p << " - " << x[p] << ", " << y[p] << "; ";
522 }
523 }
524 std::cout << std::endl;
525 }
526 std::cout << fGraphIndex.size() << " graph indices: ";
527 for(const auto& i : fGraphIndex) { std::cout << i << " "; }
528 std::cout << std::endl;
529 std::cout << fPointIndex.size() << " point indices: ";
530 for(const auto& i : fPointIndex) { std::cout << i << " "; }
531 std::cout << std::endl;
532 std::cout << "---- total graph ----" << std::endl;
533 double* x = fTotalGraph->GetX();
534 double* y = fTotalGraph->GetY();
535 for(int p = 0; p < fTotalGraph->GetN(); ++p) {
536 std::cout << p << " - " << x[p] << ", " << y[p] << "; ";
537 }
538 std::cout << std::endl;
539 std::cout << "---------------------" << std::endl;
540}
541
542void TCalibrationGraphSet::Clear(Option_t* option)
543{
544 fGraphs.clear();
545 fResidualGraphs.clear();
546 fLabel.clear();
547 fGraphIndex.clear();
548 fPointIndex.clear();
549 fResidualSet = false;
550 fMinimumX = 0.;
551 fMaximumX = 0.;
552 fMinimumY = 0.;
553 fMaximumY = 0.;
554 TNamed::Clear(option);
555}
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.