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