GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TEfficiencyCalibrator.cxx
Go to the documentation of this file.
2
3#if __cplusplus >= 201703L
4
5#include <cstdarg>
6#include <cstdio>
7#include <fcntl.h>
8
9#include "TGTableLayout.h"
10#include "TTimer.h"
11#include "TCanvas.h"
12
13#include "TGauss.h"
14#include "TABPeak.h"
15#include "TAB3Peak.h"
16#include "TRWPeak.h"
17#include "TRedirect.h"
18
19//////////////////////////////////////// TEfficiencyTab ////////////////////////////////////////
20TEfficiencyTab::TEfficiencyTab(TEfficiencyDatatypeTab* parent, TNucleus* nucleus, std::tuple<TH1*, TH1*, TH2*> hists, TGCompositeFrame* frame)
21 : fFrame(frame), fNucleus(nucleus), fParent(parent),
22 fSingles(std::get<0>(hists)), fSummingOut(std::get<1>(hists)), fSummingIn(std::get<2>(hists))
23// name *180Corr // name *Sum180Corr
24{
25 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
26 std::cout << "Assigned singles, summing out, and summing in histograms (" << fSingles->GetName() << ", " << fSummingOut->GetName() << ", " << fSummingIn->GetName() << ")" << std::endl;
27 }
28 BuildInterface();
29 {
30 TRedirect redirect("fitOutput.txt");
31 std::cout << "======================================== Finding peaks in " << fSingles->GetName() << ", " << fSummingOut->GetName() << ", and " << fSummingIn->GetName() << std::endl;
32 FindPeaks();
33 }
34}
35
36void TEfficiencyTab::BuildInterface()
37{
38 // top frame with one canvas, status bar, and controls
39 fTopFrame = new TGHorizontalFrame(fFrame, TEfficiencyCalibrator::WindowWidth() / 2, 450);
40 fProjectionCanvas = new TRootEmbeddedCanvas("ProjectionCanvas", fTopFrame, TEfficiencyCalibrator::WindowWidth() / 2, 400);
41
42 fTopFrame->AddFrame(fProjectionCanvas, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsExpandY | kLHintsExpandX, 2, 2, 2, 2));
43
44 fFrame->AddFrame(fTopFrame, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 2, 2, 2, 2));
45
46 fStatusBar = new TGStatusBar(fFrame, TEfficiencyCalibrator::WindowWidth() / 2, 50); // NOLINT(cppcoreguidelines-prefer-member-initializer)
47 std::array<int, 5> parts = {35, 15, 20, 15, 15};
48 fStatusBar->SetParts(parts.data(), parts.size());
49
50 fFrame->AddFrame(fStatusBar, new TGLayoutHints(kLHintsBottom | kLHintsExpandX, 2, 2, 2, 2));
51 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) { std::cout << "Done with " << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
52}
53
54void TEfficiencyTab::FindPeaks()
55{
56 /// Find and fit the peaks in the singles histogram, then checks for each peak how much summing in and summing out happens.
57
58 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
59 std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
60 std::cout << "Using parent " << fParent << " and transition list " << fNucleus->GetTransitionListByEnergy() << std::endl;
61 fNucleus->GetTransitionListByEnergy()->Print();
62 std::cout << "Using parent " << fParent << std::flush << ", trying to get peak type " << TEfficiencyCalibrator::PeakType() << std::endl;
63 }
64 fProjectionCanvas->GetCanvas()->cd();
65 // loop through all gamma-rays of the source
66 // TODO: combine ranges if peak ranges overlap
67 // probably need to: change loop to using size and ->At(index), plus extra loop that finds all peaks within the range
68 // maybe also change the creation of the peak to either a function or using TClass::New()
69 for(int t = 0; t < fNucleus->GetTransitionListByEnergy()->GetSize(); ++t) {
70 auto* transition = static_cast<TTransition*>(fNucleus->GetTransitionListByEnergy()->At(t));
71 auto energy = transition->GetEnergy();
72 if(energy > fSingles->GetXaxis()->GetXmax()) {
73 // need to check if we also want to reject peaks whose fit range is partially outside the range of the histogram
74 std::cout << "Skipping peak at " << energy << " keV of " << fNucleus->GetA() << fNucleus->GetSymbol() << ", maximum range of histogram is " << fSingles->GetXaxis()->GetXmax() << std::endl;
75 continue;
76 }
77 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
78 std::cout << "Fitting peak at " << energy << " keV, using range " << energy - TEfficiencyCalibrator::Range() << ", " << energy + TEfficiencyCalibrator::Range() << " peak type " << TEfficiencyCalibrator::PeakType() << " singles histogram " << fSingles->GetName() << std::endl;
79 }
80 fPeakFitter.RemoveAllPeaks();
81 fPeakFitter.ResetInitFlag();
82 fSummingOutPeakFitter.RemoveAllPeaks();
83 fSummingOutPeakFitter.ResetInitFlag();
84
85 std::vector<TSinglePeak*> peaks;
86 peaks.push_back(NewPeak(energy));
87 double lastEnergy = energy;
88 for(int t2 = t + 1; t2 < fNucleus->GetTransitionListByEnergy()->GetSize(); ++t2) {
89 auto* transition2 = static_cast<TTransition*>(fNucleus->GetTransitionListByEnergy()->At(t2));
90 auto energy2 = transition2->GetEnergy();
91 if(lastEnergy + TEfficiencyCalibrator::Range() > energy2 - TEfficiencyCalibrator::Range()) {
92 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
93 std::cout << t << ". peak: Found " << peaks.size() << ". overlapping peak for " << lastEnergy << ", and " << energy2 << " with range " << TEfficiencyCalibrator::Range() << std::endl;
94 }
95 // peak ranges overlap, so we add this peak to the fit, skip it in the main loop, and update lastEnergy to refer to it instead
96 peaks.push_back(NewPeak(energy2));
97 ++t;
98 lastEnergy = energy2;
99 } else {
100 // list of transitions is sorted by energy, so all others will be outside the range as well
101 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
102 std::cout << t << ". peak: Found " << peaks.size() << ". overlapping peaks, stopping here with " << lastEnergy << ", and " << energy2 << " with range " << TEfficiencyCalibrator::Range() << std::endl;
103 }
104 break;
105 }
106 }
107
108 fPeakFitter.SetRange(energy - TEfficiencyCalibrator::Range(), lastEnergy + TEfficiencyCalibrator::Range());
109 for(auto& peak : peaks) {
110 fPeakFitter.AddPeak(peak);
111 }
112 std::cout << "---------------------------------------- Fitting peak(s) at " << energy << "/" << lastEnergy << " from " << energy - TEfficiencyCalibrator::Range() << " to " << energy + TEfficiencyCalibrator::Range() << std::endl;
113 fPeakFitter.Print();
114 fPeakFitter.PrintParameters();
115 fPeakFitter.Fit(fSingles, "retryfit");
116 // we also need to fit the summing out peaks, so we create a copy of the vector of peaks to be added to the summing out peak fitter
117 // we could also simply create them in the same loop as the other peaks?
118 std::vector<TSinglePeak*> summingOutPeaks = peaks;
119 fSummingOutPeakFitter.SetRange(energy - TEfficiencyCalibrator::Range(), lastEnergy + TEfficiencyCalibrator::Range());
120 // before we add the peaks to the peak fitter, we need to copy them
121 for(auto& peak : summingOutPeaks) {
122 peak = NewPeak(peak);
123 fSummingOutPeakFitter.AddPeak(peak);
124 }
125 fSummingOutPeakFitter.Fit(fSummingOut, "retryfit");
126 for(size_t p = 0; p < peaks.size(); ++p) {
127 auto* peak = peaks[p];
128 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
129 std::cout << "================================================================================" << std::endl;
130 std::cout << "Got centroid " << peak->Centroid() << " +- " << peak->CentroidErr() << " (" << 100 * peak->CentroidErr() / peak->Centroid() << " %), area " << peak->Area() << " +- " << peak->AreaErr() << " (" << 100 * peak->AreaErr() / peak->Area() << " %), FWHM " << peak->FWHM() << ", red. chi sq. " << peak->GetReducedChi2() << std::endl;
131 }
132 if(peak->Area() < TEfficiencyCalibrator::Threshold() || peak->CentroidErr() > peak->Centroid() || peak->AreaErr() > peak->Area() || std::isnan(peak->Centroid()) || std::isnan(peak->Area()) || std::isnan(peak->CentroidErr()) || std::isnan(peak->AreaErr())) {
133 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
134 std::cout << "Skipping peak at " << energy << " keV with centroid " << peak->Centroid() << " +- " << peak->CentroidErr() << " (" << 100 * peak->CentroidErr() / peak->Centroid() << " %), FWHM " << peak->FWHM() << ", and area " << peak->Area() << " +- " << peak->AreaErr() << " (" << 100 * peak->AreaErr() / peak->Area() << " %)" << std::endl;
135 std::cout << "================================================================================" << std::endl;
136 }
137 fRemovedFitFunctions.push_back(fPeakFitter.GetFitFunction()->Clone(Form("removed_fit_%.1f", peak->Centroid())));
138 continue;
139 }
140 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
141 std::cout << "================================================================================" << std::endl;
142 }
143 // increase number of points of fit function
144 fPeakFitter.GetFitFunction()->SetNpx(1000);
145 peak->GetPeakFunction()->SetNpx(1000);
146 double fwhm = peak->FWHM();
147 double centroid = peak->Centroid();
148 double centroidErr = peak->CentroidErr();
149 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
150 std::cout << "Got centroid " << centroid << " keV, FWHM " << fwhm << ":" << std::endl;
151 }
152 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
153 std::cout << "Writing '" << Form("%s_%.0fkeV", fSingles->GetName(), centroid) << "' to '" << gDirectory->GetName() << "'" << std::endl;
154 }
155 fSingles->Write(Form("%s_%.0fkeV", fSingles->GetName(), centroid), TObject::kOverwrite);
156 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
157 std::cout << "Writing '" << Form("%s_%.0fkeV", fSummingOut->GetName(), centroid) << "' to '" << gDirectory->GetName() << "'" << std::endl;
158 }
159 fSummingOut->Write(Form("%s_%.0fkeV", fSummingOut->GetName(), centroid), TObject::kOverwrite);
160 // for summing in we need to estimate the background and subtract that from the integral
161 fSummingInProj.push_back(fSummingIn->ProjectionY(Form("%s_%.0f_to_%.0f", fSummingIn->GetName(), centroid - fwhm / 2., centroid + fwhm / 2.), fSummingIn->GetXaxis()->FindBin(centroid - fwhm / 2.), fSummingIn->GetXaxis()->FindBin(centroid + fwhm / 2.)));
162 fSummingInProjBg.push_back(fSummingInProj.back()->ShowBackground(TEfficiencyCalibrator::BgParam()));
163 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
164 std::cout << "Writing '" << Form("%s_%.0fkeV", fSummingInProj.back()->GetName(), centroid) << "' and '" << Form("%s_%.0fkeV", fSummingInProjBg.back()->GetName(), centroid) << "' to '" << gDirectory->GetName() << "'" << std::endl;
165 }
166 double summingIn = fSummingInProj.back()->Integral() - fSummingInProjBg.back()->Integral();
167 fSummingInProj.back()->Write(Form("%s_%.0fkeV", fSummingInProj.back()->GetName(), centroid), TObject::kOverwrite);
168 fSummingInProjBg.back()->Write(Form("%s_%.0fkeV", fSummingInProjBg.back()->GetName(), centroid), TObject::kOverwrite);
169
170 double summingOut = summingOutPeaks[p]->Area();
171 double correctedArea = peak->Area() - summingIn + summingOutPeaks[p]->AreaErr();
172 // uncertainties for summing in and summing out is sqrt(N) (?)
173 double correctedAreaErr = TMath::Sqrt(TMath::Power(peak->AreaErr(), 2) + summingIn + summingOut);
174 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
175 std::cout << "Got summingIn " << summingIn << ", summingOut " << summingOut << ", correctedArea " << correctedArea << " +- " << correctedAreaErr << std::endl;
176 }
177 fPeaks.emplace_back(transition, centroid, centroidErr, correctedArea, correctedAreaErr, peak->Area(), peak->AreaErr(), summingIn, summingOut);
178 fFitFunctions.push_back(fPeakFitter.GetFitFunction()->Clone(Form("fit_%.1f", centroid)));
179 }
180 }
181
182 Redraw();
183 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
184 std::cout << "Unsorted peak vector:";
185 for(const auto& peak : fPeaks) { std::cout << " " << std::get<0>(peak)->GetEnergy(); }
186 std::cout << std::endl;
187 }
188 std::sort(fPeaks.begin(), fPeaks.end(), [](const std::tuple<TTransition*, double, double, double, double, double, double, double, double>& lhs, const std::tuple<TTransition*, double, double, double, double, double, double, double, double>& rhs) -> bool { return std::get<0>(lhs)->GetEnergy() < std::get<0>(rhs)->GetEnergy(); });
189 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
190 std::cout << "Sorted peak vector:";
191 for(auto& peak : fPeaks) { std::cout << " " << std::get<0>(peak)->GetEnergy(); }
192 std::cout << std::endl;
193 }
194}
195
196TSinglePeak* TEfficiencyTab::NewPeak(const double& energy)
197{
198 switch(TEfficiencyCalibrator::PeakType()) {
199 case kRWPeak:
200 return new TRWPeak(energy);
201 break;
202 case kABPeak:
203 return new TABPeak(energy);
204 break;
205 case kAB3Peak:
206 return new TAB3Peak(energy);
207 break;
208 case kGauss:
209 return new TGauss(energy);
210 break;
211 default:
212 std::cerr << "Unknow peak type " << TEfficiencyCalibrator::PeakType() << ", defaulting to TRWPeak!" << std::endl;
213 return new TRWPeak(energy);
214 }
215}
216
217TSinglePeak* TEfficiencyTab::NewPeak(TSinglePeak* peak)
218{
219 switch(TEfficiencyCalibrator::PeakType()) {
220 case kRWPeak:
221 return new TRWPeak(*static_cast<TRWPeak*>(peak));
222 break;
223 case kABPeak:
224 return new TABPeak(*static_cast<TABPeak*>(peak));
225 break;
226 case kAB3Peak:
227 return new TAB3Peak(*static_cast<TAB3Peak*>(peak));
228 break;
229 case kGauss:
230 return new TGauss(*static_cast<TGauss*>(peak));
231 break;
232 default:
233 std::cerr << "Unknow peak type " << TEfficiencyCalibrator::PeakType() << ", defaulting to TRWPeak!" << std::endl;
234 return new TRWPeak(*static_cast<TRWPeak*>(peak));
235 }
236}
237
238void TEfficiencyTab::Redraw()
239{
240 fProjectionCanvas->GetCanvas()->cd();
241 fSingles->GetListOfFunctions()->Clear();
242 for(auto& fit : fFitFunctions) {
243 static_cast<TF1*>(fit)->SetLineColor(2); // red line color for fits
244 fSingles->GetListOfFunctions()->Add(fit);
245 }
246 if(TEfficiencyCalibrator::ShowRemovedFits()) {
247 for(auto& fit : fRemovedFitFunctions) {
248 static_cast<TF1*>(fit)->SetLineColor(15); // grey line color for removed fits
249 fSingles->GetListOfFunctions()->Add(fit);
250 }
251 }
252 fSingles->Draw();
253 fProjectionCanvas->GetCanvas()->Modified();
254}
255
256void TEfficiencyTab::MakeConnections()
257{
258 fProjectionCanvas->GetCanvas()->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", "TEfficiencyTab", this, "Status(Int_t, Int_t, Int_t, TObject*)");
259}
260
261void TEfficiencyTab::Disconnect()
262{
263 fProjectionCanvas->GetCanvas()->Disconnect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", this, "Status(Int_t, Int_t, Int_t, TObject*)");
264}
265
266void TEfficiencyTab::Status(Int_t, Int_t px, Int_t py, TObject* selected)
267{
268 fStatusBar->SetText(selected->GetName(), 0);
269 fStatusBar->SetText(selected->GetObjectInfo(px, py), 1);
270}
271
272//////////////////////////////////////// TEfficiencyDatatypeTab ////////////////////////////////////////
273TEfficiencyDatatypeTab::TEfficiencyDatatypeTab(TEfficiencyCalibrator* parent, std::vector<TNucleus*> nucleus, std::vector<std::tuple<TH1*, TH1*, TH2*>> hists, TGCompositeFrame* frame, const std::string& dataType, TGHProgressBar* progressBar)
274 : fFrame(frame), fNucleus(std::move(nucleus)), fParent(parent), fDataType(dataType)
275{
276 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kBasicFlow) {
277 std::cout << "======================================== creating tab for data type " << dataType << std::endl;
278 }
279 // create new subdirectory for this tab (and its channel tabs), but store the old directory
280 fMainDirectory = gDirectory;
281 fSubDirectory = gDirectory->mkdir(dataType.c_str());
282 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
283 std::cout << "switching from gDirectory " << gDirectory->GetName() << " to sub directory " << fSubDirectory;
284 }
285 fSubDirectory->cd();
286 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
287 std::cout << " = " << fSubDirectory->GetName() << ", main directory is " << fMainDirectory << " = " << (fMainDirectory == nullptr ? "" : fMainDirectory->GetName()) << std::endl;
288 }
289
290 // left frame with histograms tabs
291 fLeftFrame = new TGVerticalFrame(fFrame, TEfficiencyCalibrator::WindowWidth() / 2, TEfficiencyCalibrator::WindowWidth() / 2);
292
293 fDataTab = new TGTab(fLeftFrame, TEfficiencyCalibrator::WindowWidth() / 2, 500);
294 fEfficiencyTab.resize(hists.size(), nullptr);
295 for(size_t i = 0; i < hists.size(); ++i) {
296 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) { std::cout << i << ": Creating efficiency tab using " << fNucleus[i] << " = " << fNucleus[i]->GetName() << ", " << std::get<0>(hists[i])->GetName() << ", " << std::get<1>(hists[i])->GetName() << ", " << std::get<2>(hists[i])->GetName() << ", " << TEfficiencyCalibrator::Range() << ", " << TEfficiencyCalibrator::Threshold() << ", " << TEfficiencyCalibrator::BgParam() << std::endl; }
297 fEfficiencyTab[i] = new TEfficiencyTab(this, fNucleus[i], hists[i], fDataTab->AddTab(fNucleus[i]->GetName()));
298 progressBar->Increment(1);
299 }
300
301 fFittingParameterFrame = new TGGroupFrame(fLeftFrame, "Fitting Parameters", kHorizontalFrame);
302 fFittingParameterFrame->SetLayoutManager(new TGTableLayout(fFittingParameterFrame, 2, 4, false, 5)); // rows, columns, not homogenous cell sizes, 5 = interval between frames in pixel
303 fRangeLabel = new TGLabel(fFittingParameterFrame, "Range");
304 fRangeEntry = new TGNumberEntry(fFittingParameterFrame, TEfficiencyCalibrator::Range(), 5, kRangeEntry, TGNumberFormat::EStyle::kNESRealTwo, TGNumberFormat::EAttribute::kNEAPositive);
305 fBgParamLabel = new TGLabel(fFittingParameterFrame, "BG Parameter");
306 fBgParamEntry = new TGNumberEntry(fFittingParameterFrame, TEfficiencyCalibrator::BgParam(), 5, kBgParamEntry, TGNumberFormat::EStyle::kNESRealTwo, TGNumberFormat::EAttribute::kNEAPositive);
307 fThresholdLabel = new TGLabel(fFittingParameterFrame, "Threshold");
308 fThresholdEntry = new TGNumberEntry(fFittingParameterFrame, TEfficiencyCalibrator::Threshold(), 5, kThresholdEntry, TGNumberFormat::EStyle::kNESRealThree, TGNumberFormat::EAttribute::kNEAPositive);
309 fPeakTypeBox = new TGComboBox(fFittingParameterFrame, kPeakTypeBox);
310 fPeakTypeBox->AddEntry("Radware", TEfficiencyTab::EPeakType::kRWPeak);
311 fPeakTypeBox->AddEntry("Addback", TEfficiencyTab::EPeakType::kABPeak);
312 fPeakTypeBox->AddEntry("Addback3", TEfficiencyTab::EPeakType::kAB3Peak);
313 fPeakTypeBox->AddEntry("Gaussian", TEfficiencyTab::EPeakType::kGauss);
314 fPeakTypeBox->SetMinHeight(200);
315 fPeakTypeBox->Resize(100, TEfficiencyCalibrator::LineHeight());
316 fPeakTypeBox->Select(TEfficiencyCalibrator::PeakType());
317 fFittingControlGroup = new TGHButtonGroup(fFittingParameterFrame, "");
318 fRefitButton = new TGTextButton(fFittingControlGroup, "Refit this source");
319 fRefitAllButton = new TGTextButton(fFittingControlGroup, "Refit all sources");
320
321 fFittingParameterFrame->AddFrame(fRangeLabel, new TGTableLayoutHints(0, 1, 0, 1));
322 fFittingParameterFrame->AddFrame(fRangeEntry, new TGTableLayoutHints(1, 2, 0, 1));
323 fFittingParameterFrame->AddFrame(fBgParamLabel, new TGTableLayoutHints(2, 3, 0, 1));
324 fFittingParameterFrame->AddFrame(fBgParamEntry, new TGTableLayoutHints(3, 4, 0, 1));
325 fFittingParameterFrame->AddFrame(fThresholdLabel, new TGTableLayoutHints(0, 1, 1, 2));
326 fFittingParameterFrame->AddFrame(fThresholdEntry, new TGTableLayoutHints(1, 2, 1, 2));
327 fFittingParameterFrame->AddFrame(fPeakTypeBox, new TGTableLayoutHints(2, 3, 1, 2));
328 fFittingParameterFrame->AddFrame(fFittingControlGroup, new TGTableLayoutHints(3, 4, 1, 2));
329
330 fLeftFrame->AddFrame(fDataTab, new TGLayoutHints(kLHintsTop | kLHintsExpandX | kLHintsExpandY, 2, 2, 2, 2));
331 fLeftFrame->AddFrame(fFittingParameterFrame, new TGLayoutHints(kLHintsBottom | kLHintsExpandX, 2, 2, 2, 2));
332
333 // right frame with canvas, status bar, and the degree entry
334 fRightFrame = new TGVerticalFrame(fFrame, TEfficiencyCalibrator::WindowWidth() / 2, TEfficiencyCalibrator::WindowWidth() / 2);
335 fEfficiencyCanvas = new TRootEmbeddedCanvas("EfficiencyCanvas", fRightFrame, TEfficiencyCalibrator::WindowWidth() / 2, 450);
336 fStatusBar = new TGStatusBar(fRightFrame, TEfficiencyCalibrator::WindowWidth() / 2, 50);
337 std::array<int, 2> parts = {35, 65};
338 fStatusBar->SetParts(parts.data(), parts.size());
339 fGraphParameterFrame = new TGGroupFrame(fRightFrame, "Graph Parameters", kHorizontalFrame);
340 fGraphParameterFrame->SetLayoutManager(new TGTableLayout(fGraphParameterFrame, 3, 4, false, 5)); // rows, columns, not homogenous cell sizes, 5 = interval between frames in pixel
341 fDegreeEntry = new TGNumberEntry(fGraphParameterFrame, TEfficiencyCalibrator::Degree(), 2, kDegreeEntry, TGNumberFormat::EStyle::kNESInteger);
342 fDegreeLabel = new TGLabel(fGraphParameterFrame, "Type of efficiency curve");
343 fCalibrationUncertaintyLabel = new TGLabel(fGraphParameterFrame, "Calibration Uncertainty");
344 fCalibrationUncertaintyEntry = new TGNumberEntry(fGraphParameterFrame, TEfficiencyCalibrator::CalibrationUncertainty(), 5, kCalibrationUncertaintyEntry, TGNumberFormat::EStyle::kNESRealOne, TGNumberFormat::EAttribute::kNEAPositive);
345 fPlotOptionFrame = new TGGroupFrame(fGraphParameterFrame, "Plot Selection", kHorizontalFrame);
346 fPlotOptionFrame->SetLayoutManager(new TGTableLayout(fPlotOptionFrame, 2, 3, false, 5)); // rows, columns, not homogenous cell sizes, 5 = interval between frames in pixel
347 fPlotEfficiencyCheck = new TGCheckButton(fPlotOptionFrame, "Efficiency", kPlotEfficiencyCheck);
348 fPlotEfficiencyCheck->SetState(kButtonDown);
349 fPlotUncorrEfficiencyCheck = new TGCheckButton(fPlotOptionFrame, "Uncorrected efficiency", kPlotUncorrEfficiencyCheck);
350 fPlotUncorrEfficiencyCheck->SetState(kButtonUp);
351 fPlotPeakAreaCheck = new TGCheckButton(fPlotOptionFrame, "Peak area", kPlotPeakAreaCheck);
352 fPlotPeakAreaCheck->SetState(kButtonUp);
353 fPlotSummingInCheck = new TGCheckButton(fPlotOptionFrame, "Summing in", kPlotSummingInCheck);
354 fPlotSummingInCheck->SetState(kButtonUp);
355 fPlotSummingOutCheck = new TGCheckButton(fPlotOptionFrame, "Summing out", kPlotSummingOutCheck);
356 fPlotSummingOutCheck->SetState(kButtonUp);
357 fPlotOptionFrame->AddFrame(fPlotEfficiencyCheck, new TGTableLayoutHints(0, 1, 0, 1));
358 fPlotOptionFrame->AddFrame(fPlotUncorrEfficiencyCheck, new TGTableLayoutHints(1, 3, 0, 1));
359 fPlotOptionFrame->AddFrame(fPlotPeakAreaCheck, new TGTableLayoutHints(0, 1, 1, 2));
360 fPlotOptionFrame->AddFrame(fPlotSummingInCheck, new TGTableLayoutHints(1, 2, 1, 2));
361 fPlotOptionFrame->AddFrame(fPlotSummingOutCheck, new TGTableLayoutHints(2, 3, 1, 2));
362 fRecalculateButton = new TGTextButton(fGraphParameterFrame, "Recalculate graphs");
363 fGraphParameterFrame->AddFrame(fDegreeLabel, new TGTableLayoutHints(0, 1, 0, 1));
364 fGraphParameterFrame->AddFrame(fDegreeEntry, new TGTableLayoutHints(1, 2, 0, 1));
365 fGraphParameterFrame->AddFrame(fCalibrationUncertaintyLabel, new TGTableLayoutHints(0, 1, 1, 2));
366 fGraphParameterFrame->AddFrame(fCalibrationUncertaintyEntry, new TGTableLayoutHints(1, 2, 1, 2));
367 fGraphParameterFrame->AddFrame(fPlotOptionFrame, new TGTableLayoutHints(2, 4, 0, 2));
368 fGraphParameterFrame->AddFrame(fRecalculateButton, new TGTableLayoutHints(0, 4, 2, 3));
369 fRightFrame->AddFrame(fEfficiencyCanvas, new TGLayoutHints(kLHintsExpandX));
370 fRightFrame->AddFrame(fStatusBar, new TGLayoutHints(kLHintsExpandX));
371 fRightFrame->AddFrame(fGraphParameterFrame, new TGLayoutHints(kLHintsExpandX));
372
373 fFrame->SetLayoutManager(new TGHorizontalLayout(fFrame));
374 fFrame->AddFrame(fLeftFrame, new TGLayoutHints(kLHintsLeft | kLHintsTop | kLHintsExpandY, 2, 2, 2, 2));
375 fFrame->AddFrame(fRightFrame, new TGLayoutHints(kLHintsRight | kLHintsTop | kLHintsExpandY, 2, 2, 2, 2));
376
377 DrawGraph();
378 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
379 std::cout << "switching from sub directory " << gDirectory->GetName() << " to main directory " << fMainDirectory;
380 }
381 fMainDirectory->cd();
382 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
383 std::cout << " = " << fMainDirectory->GetName() << ", sub directory is " << fSubDirectory << " = " << (fSubDirectory == nullptr ? "" : fSubDirectory->GetName()) << std::endl;
384 }
385 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kBasicFlow) {
386 std::cout << "======================================== done creating tab for data type " << dataType << std::endl;
387 }
388}
389
390TEfficiencyDatatypeTab::~TEfficiencyDatatypeTab()
391{
392 fMainDirectory->cd();
393}
394
395void TEfficiencyDatatypeTab::MakeConnections()
396{
397 fFittingControlGroup->Connect("Clicked(Int_t)", "TEfficiencyDatatypeTab", this, "FittingControl(Int_t)");
398 fPlotEfficiencyCheck->Connect("Clicked()", "TEfficiencyDatatypeTab", this, "DrawGraph()");
399 fPlotUncorrEfficiencyCheck->Connect("Clicked()", "TEfficiencyDatatypeTab", this, "DrawGraph()");
400 fPlotPeakAreaCheck->Connect("Clicked()", "TEfficiencyDatatypeTab", this, "DrawGraph()");
401 fPlotSummingInCheck->Connect("Clicked()", "TEfficiencyDatatypeTab", this, "DrawGraph()");
402 fPlotSummingOutCheck->Connect("Clicked()", "TEfficiencyDatatypeTab", this, "DrawGraph()");
403 fRecalculateButton->Connect("Clicked()", "TEfficiencyDatatypeTab", this, "DrawGraph()");
404 fEfficiencyCanvas->GetCanvas()->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", "TEfficiencyDatatypeTab", this, "Status(Int_t, Int_t, Int_t, TObject*)");
405 for(auto& tab : fEfficiencyTab) {
406 tab->MakeConnections();
407 }
408 fPeakTypeBox->Connect("Selected(Int_t)", "TEfficiencyDatatypeTab", this, "UpdatePeakType()");
409}
410
411void TEfficiencyDatatypeTab::Disconnect()
412{
413 fFittingControlGroup->Disconnect("Clicked(Int_t)", this, "FittingControl(Int_t)");
414 fPlotEfficiencyCheck->Disconnect("Clicked()", this, "DrawGraph()");
415 fPlotUncorrEfficiencyCheck->Disconnect("Clicked()", this, "DrawGraph()");
416 fPlotPeakAreaCheck->Disconnect("Clicked()", this, "DrawGraph()");
417 fPlotSummingInCheck->Disconnect("Clicked()", this, "DrawGraph()");
418 fPlotSummingOutCheck->Disconnect("Clicked()", this, "DrawGraph()");
419 fRecalculateButton->Disconnect("Clicked()", this, "DrawGraph()");
420 fEfficiencyCanvas->GetCanvas()->Disconnect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", this, "Status(Int_t, Int_t, Int_t, TObject*)");
421 for(auto& tab : fEfficiencyTab) {
422 tab->Disconnect();
423 }
424}
425
426void TEfficiencyDatatypeTab::Status(Int_t, Int_t px, Int_t py, TObject* selected)
427{
428 fStatusBar->SetText(selected->GetName(), 0);
429 fStatusBar->SetText(selected->GetObjectInfo(px, py), 1);
430}
431
432void TEfficiencyDatatypeTab::DrawGraph()
433{
434 ReadValues();
435 UpdateEfficiencyGraph();
436 FitEfficiency();
437 if(fLegend == nullptr) {
438 fLegend = new TLegend(0.8, 0.95 - static_cast<double>(fNucleus.size()) * 0.05, 0.95, 0.95);
439 } else {
440 fLegend->Clear();
441 }
442
443 fEfficiencyCanvas->GetCanvas()->cd();
444 bool firstPlot = true;
445 int color = 1;
446 if(fPlotEfficiencyCheck->IsDown()) {
447 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
448 std::cout << "Drawing efficiency graph " << fEfficiencyGraph << ":" << std::endl;
449 fEfficiencyGraph->Print("e");
450 }
451 for(size_t g = 0; g < fEfficiencyGraph->NumberOfGraphs(); ++g) {
452 fEfficiencyGraph->SetColorStyle(g, color++);
453 }
454 fEfficiencyGraph->DrawCalibration("*", fLegend);
455 firstPlot = false;
456 }
457 if(fPlotUncorrEfficiencyCheck->IsDown()) {
458 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
459 std::cout << "Drawing uncorrected efficiency graph " << fUncorrEfficiencyGraph << ":" << std::endl;
460 fUncorrEfficiencyGraph->Print("e");
461 }
462 for(size_t g = 0; g < fUncorrEfficiencyGraph->NumberOfGraphs(); ++g) {
463 fUncorrEfficiencyGraph->SetColorStyle(g, color++);
464 }
465 if(firstPlot) {
466 fUncorrEfficiencyGraph->DrawCalibration("*", fLegend);
467 } else {
468 fUncorrEfficiencyGraph->DrawCalibration("same*", fLegend);
469 }
470 firstPlot = false;
471 }
472 if(fPlotPeakAreaCheck->IsDown()) {
473 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
474 fPeakAreaGraph->Print("");
475 }
476 for(size_t g = 0; g < fPeakAreaGraph->NumberOfGraphs(); ++g) {
477 fPeakAreaGraph->SetColorStyle(g, color++);
478 }
479 if(firstPlot) {
480 fPeakAreaGraph->DrawCalibration("*", fLegend);
481 } else {
482 fPeakAreaGraph->DrawCalibration("same*", fLegend);
483 }
484 firstPlot = false;
485 }
486 if(fPlotSummingInCheck->IsDown()) {
487 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
488 fSummingInGraph->Print("");
489 }
490 for(size_t g = 0; g < fSummingInGraph->NumberOfGraphs(); ++g) {
491 fSummingInGraph->SetColorStyle(g, color++);
492 }
493 if(firstPlot) {
494 fSummingInGraph->DrawCalibration("*", fLegend);
495 } else {
496 fSummingInGraph->DrawCalibration("same*", fLegend);
497 }
498 firstPlot = false;
499 }
500 if(fPlotSummingInCheck->IsDown()) {
501 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
502 fSummingOutGraph->Print("");
503 }
504 for(size_t g = 0; g < fSummingOutGraph->NumberOfGraphs(); ++g) {
505 fSummingOutGraph->SetColorStyle(g, color++);
506 }
507 if(firstPlot) {
508 fSummingOutGraph->DrawCalibration("*", fLegend);
509 } else {
510 fSummingOutGraph->DrawCalibration("same*", fLegend);
511 }
512 firstPlot = false;
513 }
514 fLegend->Draw();
515 fEfficiencyCanvas->GetCanvas()->Modified();
516}
517
518void TEfficiencyDatatypeTab::UpdateEfficiencyGraph()
519{
520 if(fMainDirectory == nullptr) {
521 std::cout << "No main directory open (" << fMainDirectory << "), sub directory is " << fSubDirectory << ", gDirectory is " << gDirectory->GetName() << std::endl;
522 exit(1);
523 }
524 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
525 std::cout << __PRETTY_FUNCTION__ << ": switching from gDirectory " << gDirectory->GetName() << " to main directory " << fMainDirectory << " = " << fMainDirectory->GetName() << std::endl; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
526 }
527 fMainDirectory->cd();
528 //if(fSubDirectory == nullptr) {
529 // std::cout << "No subdirectory open (" << fSubDirectory << "), main directory is " << fMainDirectory << ", gDirectory is " << gDirectory->GetName() << std::endl;
530 //} else {
531 // if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
532 // std::cout << __PRETTY_FUNCTION__ << ": switching from gDirectory " << gDirectory->GetName() << " to sub directory " << fSubDirectory; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
533 // }
534 // fSubDirectory->cd();
535 // if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
536 // std::cout << " = " << fSubDirectory->GetName() << ", main directory is " << fMainDirectory << " = " << (fMainDirectory == nullptr ? "" : fMainDirectory->GetName()) << std::endl;
537 // }
538 //}
539 delete fEfficiencyGraph;
540 fEfficiencyGraph = new TCalibrationGraphSet();
541 delete fUncorrEfficiencyGraph;
542 fUncorrEfficiencyGraph = new TCalibrationGraphSet();
543 delete fPeakAreaGraph;
544 fPeakAreaGraph = new TCalibrationGraphSet();
545 delete fSummingInGraph;
546 fSummingInGraph = new TCalibrationGraphSet();
547 delete fSummingOutGraph;
548 fSummingOutGraph = new TCalibrationGraphSet();
549
550 for(auto& tab : fEfficiencyTab) {
551 // vector of tuple with transition and 8 doubles:
552 // centroid, centroidErr, correctedArea, correctedAreaErr, peak->Area(), peak->AreaErr(), summingIn, summingOut
553 auto peaks = tab->Peaks();
554 TTransition* transition = nullptr;
555 double centroid = 0.;
556 double centroidErr = 0.;
557 double correctedArea = 0.;
558 double correctedAreaErr = 0.;
559 double peakArea = 0.;
560 double peakAreaErr = 0.;
561 double summingIn = 0.;
562 double summingOut = 0.;
563 std::vector<double> energy;
564 std::vector<double> energyErr;
565 std::vector<double> efficiency;
566 std::vector<double> efficiencyErr;
567 std::vector<double> uncorrEfficiency;
568 std::vector<double> uncorrEfficiencyErr;
569 std::vector<double> peakAreaVec;
570 std::vector<double> peakAreaErrVec;
571 std::vector<double> summingInVec;
572 std::vector<double> summingOutVec;
573 int goodPeaks = 0;
574 for(auto& peak : peaks) {
575 std::tie(transition, centroid, centroidErr, correctedArea, correctedAreaErr, peakArea, peakAreaErr, summingIn, summingOut) = peak;
576 if(std::abs(transition->GetEnergy() - centroid) < transition->GetEnergyUncertainty() + centroidErr + TEfficiencyCalibrator::CalibrationUncertainty()) {
577 energy.push_back(transition->GetEnergy());
578 energyErr.push_back(transition->GetEnergyUncertainty());
579 efficiency.push_back(correctedArea / transition->GetIntensity());
580 efficiencyErr.push_back(TMath::Sqrt(TMath::Power(correctedAreaErr / transition->GetIntensity(), 2) + TMath::Power(correctedArea / transition->GetIntensity() * transition->GetIntensityUncertainty() / transition->GetIntensity(), 2)));
581 uncorrEfficiency.push_back(peakArea / transition->GetIntensity());
582 uncorrEfficiencyErr.push_back(TMath::Sqrt(TMath::Power(peakAreaErr / transition->GetIntensity(), 2) + TMath::Power(peakArea / transition->GetIntensity() * transition->GetIntensityUncertainty() / transition->GetIntensity(), 2)));
583 peakAreaVec.push_back(peakArea);
584 peakAreaErrVec.push_back(peakAreaErr);
585 summingInVec.push_back(summingIn);
586 summingOutVec.push_back(summingOut);
587 ++goodPeaks;
588 } else if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kSubroutines) {
589 std::cout << "Rejecting centroid " << centroid << " +- " << centroidErr << " with area " << correctedArea << " +- " << correctedAreaErr << " for transition at " << transition->GetEnergy() << " +- " << transition->GetEnergyUncertainty() << " using calibration uncertainty " << TEfficiencyCalibrator::CalibrationUncertainty() << " (" << std::abs(transition->GetEnergy() - centroid) << " >= " << transition->GetEnergyUncertainty() + centroidErr + TEfficiencyCalibrator::CalibrationUncertainty() << ")" << std::endl;
590 }
591 }
592 auto* effGraph = new TGraphErrors(goodPeaks, energy.data(), efficiency.data(), energyErr.data(), efficiencyErr.data());
593 fEfficiencyGraph->Add(effGraph, tab->GetName());
594 auto* uncorrEffGraph = new TGraphErrors(goodPeaks, energy.data(), uncorrEfficiency.data());
595 fUncorrEfficiencyGraph->Add(uncorrEffGraph, Form("%s uncorr. Eff.", tab->GetName()));
596 auto* peakAreaGraph = new TGraphErrors(goodPeaks, energy.data(), peakAreaVec.data(), energyErr.data(), peakAreaErrVec.data());
597 fPeakAreaGraph->Add(peakAreaGraph, tab->GetName());
598 auto* summingInGraph = new TGraphErrors(goodPeaks, energy.data(), summingInVec.data());
599 fSummingInGraph->Add(summingInGraph, Form("%s summing in", tab->GetName()));
600 auto* summingOutGraph = new TGraphErrors(goodPeaks, energy.data(), summingOutVec.data());
601 fSummingOutGraph->Add(summingOutGraph, Form("%s summing out", tab->GetName()));
602 }
603 fEfficiencyGraph->Scale();
604 fUncorrEfficiencyGraph->Scale();
605 fEfficiencyGraph->SetAxisTitle("energy [keV];corrected efficiency [a.u.]");
606 fUncorrEfficiencyGraph->SetAxisTitle("energy [keV];uncorrected efficiency [a.u.]");
607 fPeakAreaGraph->SetAxisTitle("energy [keV];peak areas [a.u.]");
608 fSummingInGraph->SetAxisTitle("energy [keV];summing in corrections [a.u.]");
609 fSummingOutGraph->SetAxisTitle("energy [keV];summing out corrections [a.u.]");
610 fEfficiencyGraph->Write(Form("%s_efficiency", fDataType.c_str()), TObject::kOverwrite);
611 fUncorrEfficiencyGraph->Write(Form("%s_uncorr_efficiency", fDataType.c_str()), TObject::kOverwrite);
612 fPeakAreaGraph->Write(Form("%s_peak_area", fDataType.c_str()), TObject::kOverwrite);
613 fSummingInGraph->Write(Form("%s_summing_in", fDataType.c_str()), TObject::kOverwrite);
614 fSummingOutGraph->Write(Form("%s_summing_out", fDataType.c_str()), TObject::kOverwrite);
615 fMainDirectory->cd();
616}
617
618void TEfficiencyDatatypeTab::UpdatePeakType()
619{
620 if(fPeakTypeBox == nullptr) {
621 throw std::runtime_error("Failed to find peak type box, but got a signal it was selected?");
622 }
623 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kLoops) {
624 std::cout << "peak type box " << fPeakTypeBox << std::flush << ", getting selected " << fPeakTypeBox->GetSelected() << std::endl;
625 }
626
627 TEfficiencyCalibrator::PeakType(static_cast<TEfficiencyTab::EPeakType>(fPeakTypeBox->GetSelected()));
628}
629
630int TEfficiencyDatatypeTab::Degree()
631{
632 if(fDegreeEntry != nullptr) {
633 TEfficiencyCalibrator::Degree(static_cast<int>(fDegreeEntry->GetNumber()));
634 }
635 return TEfficiencyCalibrator::Degree();
636}
637
638/// The efficiency curves can be:
639/// e(E) = ln E + (ln E)/E + (ln E)^2/E + (ln E)^3/E + (ln E)^4/E,
640/// or the radware form
641/// ln(e(E)) = ((a1 + a2 x + a3 x^2)^-a7 + (a4 + a5 y + a6 y^2)^-a7)^-1/a7
642/// with x = ln(E/100), y = ln(E/1000)
643/// or a polynomial ln(e(E)) = sum i 0->8 a_i (ln(E))^i (Ryan's & Andrew's PhD theses)
644double TEfficiencyDatatypeTab::EfficiencyDebertin(double* x, double* par) // NOLINT(readability-non-const-parameter)
645{
646 double eff = par[0] * TMath::Log(x[0]) + par[1] * TMath::Log(x[0]) / x[0] + par[2] * TMath::Power(TMath::Log(x[0]) / x[0], 2) + par[3] * TMath::Power(TMath::Log(x[0]) / x[0], 4) + par[4] * TMath::Power(TMath::Log(x[0]) / x[0], 5);
647 return eff;
648}
649
650double TEfficiencyDatatypeTab::EfficiencyRadware(double* x, double* par) // NOLINT(readability-non-const-parameter)
651{
652 double logX = TMath::Log(x[0] / 100.);
653 double logY = TMath::Log(x[0] / 1000.);
654 double logEff = TMath::Power(par[0] + par[1] * logX + par[2] * logX * logX, -par[6]) + TMath::Power(par[3] + par[4] * logY + par[5] * logY * logY, -1. / par[6]);
655 return TMath::Exp(logEff);
656}
657
658double TEfficiencyDatatypeTab::EfficiencyPolynomial(double* x, double* par) // NOLINT(readability-non-const-parameter)
659{
660 // first parameter: degree of polynomial
661 double logEff = 0;
662 for(int i = 0; i < par[0]; ++i) {
663 logEff += par[i + 1] * TMath::Power(TMath::Log(x[0]), i);
664 }
665 return TMath::Exp(logEff);
666}
667
668void TEfficiencyDatatypeTab::FitEfficiency()
669{
670 ReadValues();
671 delete fEfficiency;
672 // degree of fit function: 0 = ln(E)/E form, 1 = radware form, everything else polynomial ln(e(E)) = sum i 0->8 a_i (ln(E))^i (Ryan's & Andrew's PhD theses)
673 switch(TEfficiencyCalibrator::Degree()) {
674 case 0:
675 fEfficiency = new TF1("EfficiencyDebertin", TEfficiencyDatatypeTab::EfficiencyDebertin, 0., 10000., 5);
676 break;
677 case 1:
678 fEfficiency = new TF1("EfficiencyRadware", TEfficiencyDatatypeTab::EfficiencyRadware, 0., 10000., 7);
679 break;
680 default:
681 fEfficiency = new TF1("EfficiencyPolynomial", TEfficiencyDatatypeTab::EfficiencyPolynomial, 0., 10000., TEfficiencyCalibrator::Degree() + 1);
682 fEfficiency->FixParameter(0, TEfficiencyCalibrator::Degree());
683 break;
684 }
685
686 fEfficiencyGraph->Fit(fEfficiency);
687}
688
689void TEfficiencyDatatypeTab::FittingControl(Int_t id)
690{
691 int currentTabId = fDataTab->GetCurrent();
692 if(TEfficiencyCalibrator::VerboseLevel() > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << ": id " << id << ", current tab id " << currentTabId << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
693 ReadValues();
694 switch(id) {
695 case 1: // re-fit
696 fEfficiencyTab[currentTabId]->FindPeaks();
697 UpdateEfficiencyGraph();
698 break;
699 case 2: // re-fit all
700 for(auto& tab : fEfficiencyTab) {
701 tab->FindPeaks();
702 }
703 UpdateEfficiencyGraph();
704 break;
705 default:
706 break;
707 }
708}
709
710void TEfficiencyDatatypeTab::ReadValues()
711{
712 TEfficiencyCalibrator::Range(fRangeEntry->GetNumber());
713 TEfficiencyCalibrator::Threshold(fThresholdEntry->GetNumber());
714 TEfficiencyCalibrator::BgParam(fBgParamEntry->GetNumberEntry()->GetIntNumber());
715 TEfficiencyCalibrator::Degree(fDegreeEntry->GetNumberEntry()->GetIntNumber());
716 TEfficiencyCalibrator::CalibrationUncertainty(fCalibrationUncertaintyEntry->GetNumber());
717}
718
719//////////////////////////////////////// TEfficiencyCalibrator ////////////////////////////////////////
720EVerbosity TEfficiencyCalibrator::fVerboseLevel = EVerbosity::kQuiet;
721
722double TEfficiencyCalibrator::fRange = 20.;
723double TEfficiencyCalibrator::fThreshold = 100.;
724int TEfficiencyCalibrator::fBgParam = 20;
725TEfficiencyTab::EPeakType TEfficiencyCalibrator::fPeakType = TEfficiencyTab::EPeakType::kRWPeak;
726int TEfficiencyCalibrator::fDegree = 0;
727double TEfficiencyCalibrator::fCalibrationUncertainty = 1.;
728bool TEfficiencyCalibrator::fShowRemovedFits = false;
729
730unsigned int TEfficiencyCalibrator::fLineHeight = 20;
731unsigned int TEfficiencyCalibrator::fWindowWidth = 1200;
732
733TEfficiencyCalibrator::TEfficiencyCalibrator(int n...)
734 : TGMainFrame(nullptr, TEfficiencyCalibrator::WindowWidth() + 10, TEfficiencyCalibrator::WindowWidth() / 2) // +10 for padding between frames
735{
736 // remove old file with redirect from fitting
737 std::remove("fitOutput.txt");
738
739 // we want to store the histograms in a vector of types (suppressed/addback), but we don't know yet if we have all types present
740 // so we create a vector of 4 now (unsuppressed singles, suppressed singles, unsuppressed addback, and suppressed addback)
741 // and then remove the missing ones at the end
742 fHistograms.resize(5);
743 fDataType = {"Unsuppressed Singles", "Suppressed Singles", "Unsuppressed Addback", "Suppressed Addback", "Single Crystal"};
744
745 va_list args;
746 va_start(args, n); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
747 bool allSourcesFound = true;
748 for(int i = 0; i < n; ++i) {
749 const char* name = va_arg(args, const char*); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
750 fFiles.push_back(new TFile(name));
751 if(!fFiles.back()->IsOpen()) {
752 std::cerr << "Failed to open " << i + 1 << ". file \"" << name << "\"" << std::endl;
753 fFiles.pop_back();
754 continue;
755 }
756 bool goodFile = false;
757 if(fVerboseLevel > EVerbosity::kQuiet) {
758 std::cout << "Checking file \"" << name << "\":";
759 }
760 if(fFiles.back()->FindKey("griffinE") != nullptr && fFiles.back()->FindKey("griffinGriffinEProj") != nullptr && fFiles.back()->FindKey("griffinGriffinESum") != nullptr) {
761 // unsuppressed singles data
762 fHistograms[0].emplace_back(
763 static_cast<TH1*>(fFiles.back()->Get("griffinE")),
764 static_cast<TH1*>(fFiles.back()->Get("griffinGriffinEProj")),
765 static_cast<TH2*>(fFiles.back()->Get("griffinGriffinESum")));
766 goodFile = true;
767 if(fVerboseLevel > EVerbosity::kQuiet) {
768 std::cout << " found unsuppressed singles";
769 }
770 }
771 if(fFiles.back()->FindKey("griffinESupp") != nullptr && fFiles.back()->FindKey("griffinGriffinESuppProj") != nullptr && fFiles.back()->FindKey("griffinGriffinESuppSum") != nullptr) {
772 // suppressed singles data
773 fHistograms[1].emplace_back(
774 static_cast<TH1*>(fFiles.back()->Get("griffinESupp")),
775 static_cast<TH1*>(fFiles.back()->Get("griffinGriffinESuppProj")),
776 static_cast<TH2*>(fFiles.back()->Get("griffinGriffinESuppSum")));
777 goodFile = true;
778 if(fVerboseLevel > EVerbosity::kQuiet) {
779 std::cout << " found suppressed singles";
780 }
781 }
782 if(fFiles.back()->FindKey("griffinEAddback") != nullptr && fFiles.back()->FindKey("griffinGriffinEAddbackProj") != nullptr && fFiles.back()->FindKey("griffinGriffinEAddbackSum") != nullptr) {
783 // unsuppressed addback data
784 fHistograms[2].emplace_back(
785 static_cast<TH1*>(fFiles.back()->Get("griffinEAddback")),
786 static_cast<TH1*>(fFiles.back()->Get("griffinGriffinEAddbackProj")),
787 static_cast<TH2*>(fFiles.back()->Get("griffinGriffinEAddbackSum")));
788 goodFile = true;
789 if(fVerboseLevel > EVerbosity::kQuiet) {
790 std::cout << " found unsuppressed addback";
791 }
792 }
793 if(fFiles.back()->FindKey("griffinESuppAddback") != nullptr && fFiles.back()->FindKey("griffinGriffinESuppAddbackProj") != nullptr && fFiles.back()->FindKey("griffinGriffinESuppAddbackSum") != nullptr) {
794 // suppressed addback data
795 fHistograms[3].emplace_back(
796 static_cast<TH1*>(fFiles.back()->Get("griffinESuppAddback")),
797 static_cast<TH1*>(fFiles.back()->Get("griffinGriffinESuppAddbackProj")),
798 static_cast<TH2*>(fFiles.back()->Get("griffinGriffinESuppAddbackSum")));
799 goodFile = true;
800 if(fVerboseLevel > EVerbosity::kQuiet) {
801 std::cout << " found suppressed addback";
802 }
803 }
804 if(fFiles.back()->FindKey("griffinESingleCrystal") != nullptr && fFiles.back()->FindKey("griffinGriffinESingleCrystalProj") != nullptr && fFiles.back()->FindKey("griffinGriffinESingleCrystalSum") != nullptr) {
805 // suppressed addback data
806 fHistograms[4].emplace_back(
807 static_cast<TH1*>(fFiles.back()->Get("griffinESingleCrystal")),
808 static_cast<TH1*>(fFiles.back()->Get("griffinGriffinESingleCrystalProj")),
809 static_cast<TH2*>(fFiles.back()->Get("griffinGriffinESingleCrystalSum")));
810 goodFile = true;
811 if(fVerboseLevel > EVerbosity::kQuiet) {
812 std::cout << " found single crystal";
813 }
814 }
815 if(fVerboseLevel > EVerbosity::kQuiet) {
816 std::cout << ": got " << fFiles.size() << " files, " << fHistograms[0].size() << " unsuppressed singles, " << fHistograms[1].size() << " suppressed singles, " << fHistograms[2].size() << " unsuppressed addback, " << fHistograms[3].size() << " suppressed addback" << std::endl;
817 }
818 if(!goodFile) {
819 std::cerr << "Failed to find any histogram in " << i + 1 << ". file \"" << name << "\"" << std::endl;
820 fFiles.pop_back();
821 continue;
822 }
823 fSources.push_back(nullptr);
824 // check if the file name matches any source
825 if(std::strstr(name, "22Na") != nullptr) {
826 fSources.back() = new TNucleus("22Na");
827 } else if(std::strstr(name, "56Co") != nullptr) {
828 fSources.back() = new TNucleus("56Co");
829 } else if(std::strstr(name, "60Co") != nullptr) {
830 fSources.back() = new TNucleus("60Co");
831 } else if(std::strstr(name, "133Ba") != nullptr) {
832 fSources.back() = new TNucleus("133Ba");
833 } else if(std::strstr(name, "152Eu") != nullptr) {
834 fSources.back() = new TNucleus("152Eu");
835 } else if(std::strstr(name, "241Am") != nullptr) {
836 fSources.back() = new TNucleus("241Am");
837 } else {
838 allSourcesFound = false;
839 }
840 }
841 va_end(args); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
842
843 // now we remove any type from the histogram vector that has no entries
844 auto type = fDataType.begin();
845 for(auto it = fHistograms.begin(); it != fHistograms.end();) {
846 if(it->size() != fFiles.size()) {
847 if(fVerboseLevel > EVerbosity::kBasicFlow) {
848 std::cout << std::distance(fHistograms.begin(), it) << ": found " << it->size() << " histograms for " << fFiles.size() << " files, removing this type" << std::endl;
849 }
850 it = fHistograms.erase(it);
851 type = fDataType.erase(type);
852 } else {
853 ++it;
854 ++type;
855 }
856 }
857
858 if(fVerboseLevel > EVerbosity::kQuiet) {
859 std::cout << "Read " << fFiles.size() << " files, got";
860 for(auto& vec : fHistograms) {
861 std::cout << " " << vec.size();
862 }
863 std::cout << " histograms" << std::endl;
864 }
865
866 if(fHistograms.empty()) {
867 throw std::runtime_error("Unable to find any suitable histograms in the provided file(s)!");
868 }
869
870 // quick sanity check, should have at least one vector the size of that vector should equal the source size and file size
871 if(fSources.size() != fFiles.size() || fHistograms[0].size() != fFiles.size() || fHistograms.size() != fDataType.size()) {
872 std::ostringstream error;
873 error << "Wrong sizes, from " << fFiles.size() << " file(s) we got " << fSources.size() << " source(s), and " << fHistograms[0].size() << " histogram(s), " << fDataType.size() << " data types, and " << fHistograms.size() << " data type histogram(s)!" << std::endl;
874 throw std::runtime_error(error.str());
875 }
876
877 fOutput = new TFile("TEfficiencyCalibrator.root", "recreate");
878 if(!fOutput->IsOpen()) {
879 throw std::runtime_error("Unable to open output file \"TEfficiencyCalibrator.root\"!");
880 }
881
882 // build the first screen
883 if(!allSourcesFound) {
884 BuildFirstInterface();
885 MakeFirstConnections();
886 } else {
887 SecondWindow();
888 }
889
890 // Set a name to the main frame
891 SetWindowName("EffiencyCalibrator");
892
893 // Map all subwindows of main frame
894 MapSubwindows();
895
896 // Initialize the layout algorithm
897 Resize(GetDefaultSize());
898
899 // Map main frame
900 MapWindow();
901
902 fOutput->Close();
903}
904
905TEfficiencyCalibrator::~TEfficiencyCalibrator()
906{
907 for(auto& file : fFiles) {
908 file->Close();
909 }
910 if(fOutput != nullptr) { fOutput->Close(); }
911}
912
913void TEfficiencyCalibrator::DeleteElement(TGFrame* element)
914{
915 HideFrame(element);
916 RemoveFrame(element);
917 // delete element;
918 // element = nullptr;
919}
920
921void TEfficiencyCalibrator::BuildFirstInterface()
922{
923 /// Build initial interface with histogram <-> source assignment
924
925 auto* layoutManager = new TGTableLayout(this, fFiles.size() + 1, 2, true, 5);
926 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << "created table layout manager with 2 columns, " << fFiles.size() + 1 << " rows" << std::endl; }
927 SetLayoutManager(layoutManager);
928
929 // The matrices and source selection boxes
930 size_t i = 0;
931 for(i = 0; i < fFiles.size(); ++i) {
932 fSourceLabel.push_back(new TGLabel(this, fFiles[i]->GetName()));
933 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Text height " << fSourceLabel.back()->GetFont()->TextHeight() << std::endl; }
934 fSourceBox.push_back(new TGComboBox(this, "Select source", kSourceBox + fSourceBox.size()));
935 if(fSources[i] != nullptr) {
936 fSourceBox.back()->AddEntry(fSources[i]->GetName(), i);
937 fSourceBox.back()->Select(0);
938 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Found source, setting entry to " << fSources[i]->GetName() << " and selecting " << fSourceBox.back()->GetSelected() << std::endl; }
939 } else {
940 fSourceBox.back()->AddEntry("22Na", k22Na);
941 fSourceBox.back()->AddEntry("56Co", k56Co);
942 fSourceBox.back()->AddEntry("60Co", k60Co);
943 fSourceBox.back()->AddEntry("133Ba", k133Ba);
944 fSourceBox.back()->AddEntry("152Eu", k152Eu);
945 fSourceBox.back()->AddEntry("241Am", k241Am);
946 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Didn't find source, created source box with " << fSourceBox.back()->GetNumberOfEntries() << std::endl; }
947 }
948 fSourceBox.back()->SetMinHeight(200);
949 fSourceBox.back()->Resize(100, LineHeight());
950 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Attaching " << i << ". label to 0, 1, " << i << ", " << i + 1 << ", and box to 1, 2, " << i << ", " << i + 1 << std::endl; }
951 AddFrame(fSourceLabel.back(), new TGTableLayoutHints(0, 1, i, i + 1, kLHintsRight | kLHintsCenterY));
952 AddFrame(fSourceBox.back(), new TGTableLayoutHints(1, 2, i, i + 1, kLHintsLeft | kLHintsCenterY));
953 }
954
955 // The buttons
956 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << "Attaching start button to 0, 2, " << i << ", " << i + 1 << std::endl; }
957 fStartButton = new TGTextButton(this, "Accept && Continue", kStartButton);
958 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << "start button " << fStartButton << std::endl; }
959 AddFrame(fStartButton, new TGTableLayoutHints(0, 2, i, i + 1, kLHintsCenterX | kLHintsCenterY));
960 Layout();
961}
962
963void TEfficiencyCalibrator::MakeFirstConnections()
964{
965 /// Create connections for the file <-> source assignment interface
966
967 // Connect the selection of the source
968 for(auto* box : fSourceBox) {
969 box->Connect("Selected(Int_t, Int_t)", "TEfficiencyCalibrator", this, "SetSource(Int_t, Int_t)");
970 }
971
972 // Connect the clicking of buttons
973 fStartButton->Connect("Clicked()", "TEfficiencyCalibrator", this, "Start()");
974}
975
976void TEfficiencyCalibrator::DisconnectFirst()
977{
978 /// Disconnect all signals from the file <-> source assignment interface
979 for(auto* box : fSourceBox) {
980 box->Disconnect("Selected(Int_t, Int_t)", this, "SetSource(Int_t, Int_t)");
981 }
982 fStartButton->Disconnect("Clicked()", this, "Start()");
983}
984
985void TEfficiencyCalibrator::DeleteFirst()
986{
987
988 fSourceBox.clear();
989 DeleteElement(fStartButton);
990 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Deleted start button " << fStartButton << std::endl; }
991}
992
993void TEfficiencyCalibrator::SetSource(Int_t windowId, Int_t entryId)
994{
995 int index = windowId - kSourceBox;
996 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << ": windowId " << windowId << ", entryId " << entryId << " => " << index << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
997 TNucleus* nucleus = fSources[index];
998 delete nucleus;
999 nucleus = new TNucleus(fSourceBox[index]->GetListBox()->GetEntry(entryId)->GetTitle());
1000 fSources[index] = nucleus;
1001}
1002
1003void TEfficiencyCalibrator::Start()
1004{
1005 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << ": fEmitter " << fEmitter << ", fStartButton " << fStartButton << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1006 if(fEmitter == nullptr) { // we only want to do this once at the beginning (after fEmitter was initialized to nullptr)
1007 fEmitter = fStartButton;
1008 TTimer::SingleShot(100, "TEfficiencyCalibrator", this, "HandleTimer()");
1009 }
1010}
1011
1012void TEfficiencyCalibrator::HandleTimer()
1013{
1014 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << ": fEmitter " << fEmitter << ", fStartButton " << fStartButton << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1015 if(fEmitter == fStartButton) {
1016 // disconnect signals of first screen and remove all elements
1017 DisconnectFirst();
1018 RemoveAll();
1019 DeleteFirst();
1020
1021 SecondWindow();
1022 }
1023}
1024
1025void TEfficiencyCalibrator::SecondWindow()
1026{
1027 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1028 // check that all sources have been set
1029 for(size_t i = 0; i < fSources.size(); ++i) {
1030 if(fSources[i] == nullptr) {
1031 std::cerr << "Source " << i << " not set!" << std::endl;
1032 return;
1033 }
1034 if(fVerboseLevel > EVerbosity::kQuiet) {
1035 std::cout << i << " - source " << fSources[i] << " = " << fSources[i]->GetName() << std::endl;
1036 }
1037 }
1038 // now check that we don't have the same source twice (which wouldn't make sense)
1039 for(size_t i = 0; i < fSources.size(); ++i) {
1040 for(size_t j = i + 1; j < fSources.size(); ++j) {
1041 if(*(fSources[i]) == *(fSources[j])) {
1042 std::cerr << "Duplicate sources: " << i << " - " << fSources[i]->GetName() << " and " << j << " - " << fSources[j]->GetName() << std::endl;
1043 return;
1044 }
1045 }
1046 }
1047
1048 SetLayoutManager(new TGHorizontalLayout(this));
1049
1050 // create intermediate progress bar
1051 fProgressBar = new TGHProgressBar(this, TGProgressBar::kFancy, WindowWidth() / 2);
1052 int nofHistograms = 0;
1053 for(auto& type : fHistograms) { // loop over all data types and add the number of source to the counter
1054 nofHistograms += type.size();
1055 }
1056 nofHistograms *= 3; // there are three histograms for each data type/source combo
1057 fProgressBar->SetRange(0., static_cast<Float_t>(nofHistograms));
1058 fProgressBar->Percent(true);
1059 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Set range of progress bar to 0. - " << fProgressBar->GetMax() << " = " << fFiles.size() << std::endl; }
1060 AddFrame(fProgressBar, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY | kLHintsExpandX | kLHintsExpandY, 0, 0, 0, 0));
1061
1062 // Map all subwindows of main frame
1063 MapSubwindows();
1064
1065 // Initialize the layout algorithm
1066 Resize(TGDimension(WindowWidth(), LineHeight()));
1067
1068 // Map main frame
1069 MapWindow();
1070
1071 // create second screen and its connections
1072 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Starting to build second interface:" << std::endl; }
1073 BuildSecondInterface();
1074 MakeSecondConnections();
1075
1076 // remove progress bar
1077 DeleteElement(fProgressBar);
1078
1079 // Map all subwindows of main frame
1080 MapSubwindows();
1081
1082 // Initialize the layout algorithm
1083 Resize(TGDimension(WindowWidth(), WindowWidth() / 2));
1084
1085 // Map main frame
1086 MapWindow();
1087 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << __PRETTY_FUNCTION__ << " done" << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1088}
1089
1090void TEfficiencyCalibrator::BuildSecondInterface()
1091{
1092 SetLayoutManager(new TGHorizontalLayout(this));
1093
1094 // left frame with tabs for each source
1095 fDatatypeTab = new TGTab(this, WindowWidth(), WindowWidth() / 2);
1096 fEfficiencyDatatypeTab.resize(fHistograms.size());
1097 fEfficiencyGraph.resize(fHistograms.size());
1098 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << __PRETTY_FUNCTION__ << " creating " << fHistograms.size() << " tabs" << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1099 for(size_t i = 0; i < fHistograms.size(); ++i) {
1100 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << i << ": Creating efficiency source tab using " << fHistograms[i].size() << " histograms, and " << fSources.size() << " sources, " << fRange << ", " << fThreshold << ", " << fProgressBar << std::endl; }
1101 auto* frame = fDatatypeTab->AddTab(fDataType[i].c_str());
1102 std::replace(fDataType[i].begin(), fDataType[i].end(), ' ', '_');
1103 fEfficiencyDatatypeTab[i] = new TEfficiencyDatatypeTab(this, fSources, fHistograms[i], frame, fDataType[i], fProgressBar);
1104 // fEfficiencyDatatypeTab[i]->UpdateEfficiencyGraph();
1105 fEfficiencyGraph[i] = fEfficiencyDatatypeTab[i]->EfficiencyGraph();
1106 }
1107 AddFrame(fDatatypeTab, new TGLayoutHints(kLHintsTop | kLHintsCenterX | kLHintsExpandX, 0, 0, 0, 0));
1108
1109 if(fVerboseLevel > EVerbosity::kSubroutines) { std::cout << "Second interface done" << std::endl; }
1110}
1111
1112void TEfficiencyCalibrator::MakeSecondConnections()
1113{
1114 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1115 // we don't need to connect the range, threshold, and degree number entries, those are automatically read when we start the calibration
1116 for(auto* sourceTab : fEfficiencyDatatypeTab) {
1117 sourceTab->MakeConnections();
1118 }
1119}
1120
1121void TEfficiencyCalibrator::DisconnectSecond()
1122{
1123 if(fVerboseLevel > EVerbosity::kBasicFlow) { std::cout << __PRETTY_FUNCTION__ << std::endl; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
1124 for(auto* sourceTab : fEfficiencyDatatypeTab) {
1125 sourceTab->Disconnect();
1126 }
1127}
1128
1129#endif
EVerbosity
Definition Globals.h:143
void Draw(Option_t *opt="") override
double GetIntensityUncertainty() const
Definition TTransition.h:48
double GetIntensity() const
Definition TTransition.h:47
double GetEnergyUncertainty() const
Definition TTransition.h:46
double GetEnergy() const
Definition TTransition.h:45