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