GamR  0.0.0
GammaROOT
Loading...
Searching...
No Matches
Gain.cc
Go to the documentation of this file.
1/* STD */
2#include <algorithm>
3#include <iostream>
4#include <memory>
5#include <sstream>
6#include <string>
7
8/* ROOT */
9#include <TCanvas.h>
10#include <TFitResult.h>
11#include <TGraph.h>
12#include <TPaveText.h>
13#include <TSpectrum.h>
14#include <TSystem.h>
15
16/* GAMR */
17#include "Gain.hh"
18
19namespace GamR {
20namespace TK {
21
22Int_t GainMatchEnergy(TH1 *spec1, TH1 *spec2, std::vector<Double_t> &pars, bool draw, UInt_t target, std::string outfn,
23 Double_t step, TCanvas *c1)
24{
25 if (!pars.size()) {
26 std::cout << "ERROR: parameter vector should have some size. use resize(n)." << std::endl;
27 return -1;
28 }
29 if (step > 1 || step < 0) {
30 std::cout << "ERROR: step should be between 0 and 1" << std::endl;
31 return -1;
32 }
33 if (!c1) {
34 c1 = new TCanvas("gainmatchenergy", "Gain Match: Energy", 1280, 720);
35 }
36
37 auto UpdateCanvas = [&]() {
38 c1->Modified();
39 c1->Update();
40 c1->Draw();
41 gSystem->ProcessEvents();
42 };
43
44 UpdateCanvas();
45
46 if (draw) {
47 c1->SetBatch(kFALSE);
48 } else {
49 c1->SetBatch(kTRUE);
50 }
51 // xlo, ylo, xhi, yhi
52 TPad *padspec1 = new TPad("padspec1", "Spectrum 1", 0.0, 0.5, 0.6, 1.0);
53 padspec1->Draw();
54 padspec1->SetGrid(); // Top left
55 TPad *padspec2 = new TPad("padspec2", "Spectrum 2", 0.0, 0.0, 0.6, 0.5);
56 padspec2->Draw();
57 padspec2->SetGrid(); // Bottom left
58 TPad *padgraph = new TPad("padgraph", "Peak Correlation", 0.6, 0.3, 1.0, 1.0);
59 padgraph->Draw();
60 padgraph->SetGrid();
61 padgraph->SetLeftMargin(0.15); // Top Right
62 TPad *padtext = new TPad("padtext", "Fit Results", 0.6, 0.0, 1.0, 0.3);
63 padtext->Draw(); // Top Right
64 TSpectrum analyser;
65
66 UInt_t nspec1 = 1;
67 Double_t thresh1 = 0.05;
68 UInt_t nspec2 = 0;
69 Double_t thresh2 = 0.05;
70 int nsigma1 = 3;
71 int nsigma2 = 3;
72
73 std::vector<Double_t> peaks1(target);
74 std::vector<Double_t> peaks2(target);
75
76 // Graph to display detected
77 TGraph graph((nspec1 > nspec2) ? nspec2 : nspec1, peaks1.data(), peaks2.data());
78 graph.SetMarkerStyle(21);
79 graph.SetTitle("Peak positions");
80 graph.GetXaxis()->SetTitle(spec1->GetTitle());
81 graph.GetYaxis()->SetTitle(spec2->GetTitle());
82
83 Int_t steps = 0;
84 while (nspec1 != target or nspec2 != target) {
85 if (nspec1 < target) {
86 thresh1 *= step;
87 } else if (nspec1 > target) {
88 thresh1 *= (1 + step);
89 }
90 if (nspec2 < target) {
91 thresh2 *= step;
92 } else if (nspec2 > target) {
93 thresh2 *= (1 + step);
94 thresh2 = (nspec2 > nspec1) ? thresh2 : (1 + step) * thresh2;
95 }
96
97 if (thresh1 < 0.002 || thresh2 < 0.002) {
98 std::cout << "hit threshold limit (0.002) on search, try lower target." << std::endl;
99 break;
100 }
101 // search
102 bool update = false;
103 // spectrum 1
104 nspec1 = analyser.Search(spec1, nsigma1, "nodraw", thresh1);
105 if (nspec1 != peaks1.size() || !steps) {
106 peaks1.clear();
107 peaks1.insert(peaks1.begin(), analyser.GetPositionX(), analyser.GetPositionX() + nspec1);
108 std::sort(peaks1.begin(), peaks1.end());
109 update = true;
110 }
111 // spectrum 2
112 nspec2 = analyser.Search(spec2, nsigma2, "nodraw", thresh2);
113 if (nspec2 != peaks2.size() || !steps) {
114 peaks2.clear();
115 peaks2.insert(peaks2.begin(), analyser.GetPositionX(), analyser.GetPositionX() + nspec2);
116 std::sort(peaks2.begin(), peaks2.end());
117 update = true;
118 }
119
120 if (update || !steps) {
121 padspec1->cd();
122 nspec1 = analyser.Search(spec1, nsigma1, "", thresh1);
123
124 padspec2->cd();
125 nspec2 = analyser.Search(spec2, nsigma2, "", thresh2);
126
127 padgraph->cd();
128 graph.DrawGraph((nspec1 > nspec2) ? nspec2 : nspec1, peaks1.data(), peaks2.data(), "AP");
129 UpdateCanvas();
130 }
131 ++steps;
132 } // Done searching for peaks
133
134 if (nspec1 != nspec2) {
135 std::cout << "num peaks found in spec1 != spec2 ... " << nspec1 << "!=" << nspec2 << std::endl;
136 steps *= -1;
137 }
138
139 // Lambda functions
140
141 auto MakeCalibration = [&pars, &padgraph, &spec1, &spec2](std::vector<double> uncal, std::vector<double> cal) {
142 padgraph->cd();
143 auto maxn = uncal.size() > cal.size() ? uncal.size() : cal.size();
144 TGraph *calgr = new TGraph(maxn, uncal.data(), cal.data());
145 // calgr -> LeastSquareFit(pars.size(), pars.data());
146 TF1 *calfunc = new TF1("cal", ("pol" + std::to_string(pars.size() - 1)).c_str(), 0, 1.1 * uncal.back());
147 calgr->Fit(calfunc);
148 pars.assign(calfunc->GetParameters(), calfunc->GetParameters() + pars.size());
149
150 // calfunc -> SetParameters(pars.data());
151 // Pretty
152 calgr->SetMarkerStyle(21);
153 calgr->SetTitle("Peak positions");
154 calgr->GetXaxis()->SetTitle(spec1->GetTitle());
155 calgr->GetYaxis()->SetTitle(spec2->GetTitle());
156 calgr->Draw("AP");
157 // And the function
158 calfunc->Draw("SAME");
159 };
160
161 auto UpdateFitText = [&]() {
162 // The text
163 padtext->cd();
164 padtext->Clear();
165 TPaveText *pavetext = new TPaveText(0.1, 0.1, 0.9, 0.9); // margins low / high in %
166 pavetext->SetTextFont(53);
167 pavetext->SetTextSize(18);
168 std::stringstream ss;
169 ss << "Polynomial order " << pars.size() - 1;
170 pavetext->AddText(ss.str().c_str());
171 for (size_t i = 0; i < pars.size(); ++i) {
172 ss.str("");
173 ss << "p_{" << i << "} = " << pars[i];
174 pavetext->AddText(ss.str().c_str());
175 }
176 pavetext->Draw();
177 };
178
179 MakeCalibration(peaks1, peaks2);
180 UpdateFitText();
181 UpdateCanvas();
182
183 // If all else fails, let's go manual -- else return here
184
185 std::string input("");
186 while (true) {
187 std::cout << std::endl << "Proceed manually? [y/n] ";
188 std::getline(std::cin, input);
189
190 if (input == "y")
191 break;
192 if (input == "n") {
193 if (outfn != "") {
194 c1->SaveAs(outfn.c_str());
195 }
196 return steps;
197 }
198 std::cout << "Please answer y or n" << std::endl;
199 }
200
201 // Lambda helper
202 auto PrintVector = [](std::vector<double> vec) {
203 for (auto i : vec)
204 std::cout << i << ", ";
205 std::cout << std::endl;
206 };
207
208 while (true) {
209 std::vector<Double_t> accepted_uncal;
210 std::vector<std::unique_ptr<TH1>> accepted_uncal_hists;
211
212 std::vector<Double_t> accepted_cal;
213 std::vector<std::unique_ptr<TH1>> accepted_cal_hists;
214
215 // First go through the uncalibrated spectrum.
216
217 padspec1->cd();
218 padspec1->Clear();
219 spec1->Draw();
220
221 for (size_t n = 0; n < peaks1.size();) {
222 auto &X = peaks1[n];
223 float window = 10;
224
225 padspec1->cd();
226 auto highlighter = std::unique_ptr<TH1>(static_cast<TH1 *>(spec1->Clone()));
227 highlighter->SetFillColor(kMagenta);
228 highlighter->GetXaxis()->SetRangeUser(X - window, X + window);
229 highlighter->Draw("SAME");
230
231 auto zoomed = std::unique_ptr<TH1>(static_cast<TH1 *>(spec1->Clone()));
232 zoomed->SetFillColor(kBlue);
233 zoomed->SetFillStyle(3001);
234 zoomed->GetXaxis()->SetRangeUser(X - 20 * window, X + 20 * window);
235 zoomed->Draw("SAME");
236
237 padgraph->cd();
238 zoomed->Draw();
239 highlighter->Draw("SAME");
240
241 // perm highlighter
242 accepted_uncal_hists.push_back(std::unique_ptr<TH1>(static_cast<TH1 *>(spec1->Clone(""))));
243
244 UpdateCanvas();
245
246 while (true) {
247 UpdateCanvas();
248 std::cout << "Accept peak at " << X << " [y/n/z/u/p] ";
249 std::getline(std::cin, input);
250
251 if (input == "p") {
252 std::cout << "Raw Histogram: " << accepted_uncal.size() << std::endl;
253 PrintVector(accepted_uncal);
254 std::cout << " Calibrated: " << accepted_cal.size() << std::endl;
255 PrintVector(accepted_cal);
256 break;
257 } else if (input == "u") {
258 if (n > 0) {
259 accepted_uncal.pop_back();
260 accepted_uncal_hists.pop_back();
261 accepted_uncal_hists.pop_back();
262 std::cout << "UNDO!" << std::endl;
263 --n;
264 }
265 break;
266 } else if (input == "z") {
267 window *= 0.5;
268 padgraph->cd();
269 padgraph->Clear();
270 highlighter->GetXaxis()->SetRangeUser(X - window, X + window);
271 zoomed->GetXaxis()->SetRangeUser(X - 15 * window, X + 15 * window);
272 zoomed->Draw();
273 highlighter->Draw("SAME");
274 UpdateCanvas();
275 } else if (input == "y") {
276 accepted_uncal.push_back(X);
277 padspec1->cd();
278 auto &accepted = accepted_uncal_hists.back();
279 accepted->SetFillColor(kGreen);
280 accepted->GetXaxis()->SetRangeUser(X - window, X + window);
281 accepted->Draw("SAME");
282 UpdateCanvas();
283 ++n;
284 break;
285 } else if (input == "n") {
286 ++n;
287 break;
288 } else {
289 std::cout << "Please answer y or n" << std::endl;
290 }
291 }
292 } // for peaks1
293
294 // Now the calibrated histograms
295
296 padspec2->cd();
297 padspec2->Clear();
298 spec2->Draw();
299
300 for (size_t n = 0; n < peaks2.size();) {
301 auto &X = peaks2[n];
302 float window = 10;
303
304 padspec2->cd();
305 auto highlighter = std::unique_ptr<TH1>(static_cast<TH1 *>(spec2->Clone()));
306 highlighter->SetFillColor(kMagenta);
307 highlighter->GetXaxis()->SetRangeUser(X - window, X + window);
308 highlighter->Draw("SAME");
309
310 auto zoomed = std::unique_ptr<TH1>(static_cast<TH1 *>(spec2->Clone()));
311 zoomed->SetFillColor(kBlue);
312 zoomed->SetFillStyle(3001);
313 zoomed->GetXaxis()->SetRangeUser(X - 20 * window, X + 20 * window);
314 zoomed->Draw("SAME");
315
316 padgraph->cd();
317 zoomed->Draw();
318 highlighter->Draw("SAME");
319
320 // perm highlighter
321 accepted_cal_hists.push_back(std::unique_ptr<TH1>(static_cast<TH1 *>(spec2->Clone(""))));
322 UpdateCanvas();
323
324 while (true) {
325 UpdateCanvas();
326 std::cout << "Accept peak at " << X << " [y/n/z/u/p] ";
327 std::getline(std::cin, input);
328
329 if (input == "p") {
330 std::cout << "Raw Histogram: " << accepted_uncal.size() << std::endl;
331 PrintVector(accepted_uncal);
332 std::cout << " Calibrated: " << accepted_cal.size() << std::endl;
333 PrintVector(accepted_cal);
334 break;
335 } else if (input == "u") {
336 if (n > 0) {
337 accepted_cal.pop_back();
338 accepted_cal_hists.pop_back();
339 accepted_cal_hists.pop_back();
340 std::cout << "UNDO!" << std::endl;
341 --n;
342 }
343 break;
344 } else if (input == "z") {
345 window *= 0.5;
346 padgraph->cd();
347 padgraph->Clear();
348 highlighter->GetXaxis()->SetRangeUser(X - window, X + window);
349 zoomed->GetXaxis()->SetRangeUser(X - 15 * window, X + 15 * window);
350 zoomed->Draw();
351 highlighter->Draw("SAME");
352 UpdateCanvas();
353 } else if (input == "y") {
354 accepted_cal.push_back(X);
355 padspec2->cd();
356 auto &accepted = accepted_cal_hists.back();
357 accepted->SetFillColor(kGreen);
358 accepted->GetXaxis()->SetRangeUser(X - window, X + window);
359 accepted->Draw("SAME");
360 UpdateCanvas();
361 ++n;
362 break;
363 } else if (input == "n") {
364 ++n;
365 break;
366 } else {
367 std::cout << "Please answer y or n" << std::endl;
368 }
369 }
370 } // for peaks1
371
372 // All selected, fit
373
374 MakeCalibration(accepted_uncal, accepted_cal);
375 UpdateFitText();
376 UpdateCanvas();
377
378 std::cout << "Raw Histogram: ";
379 PrintVector(accepted_uncal);
380 std::cout << " Calibrated: ";
381 PrintVector(accepted_cal);
382
383 std::cout << std::endl << "Restart? [y/n] ";
384 std::getline(std::cin, input);
385
386 if (input == "y")
387 continue;
388 else if (input == "n") {
389 if (outfn != "") {
390 c1->SaveAs(outfn.c_str());
391 }
392 return 0;
393 }
394 }
395
396 if (outfn != "") {
397 c1->SaveAs(outfn.c_str());
398 }
399 return 0;
400}
401
402} // namespace TK
403} // namespace GamR
void ss(std::vector< int > indexes, TCanvas *canvas, Option_t *option)
Int_t GainMatchEnergy(TH1 *spec1, TH1 *spec2, std::vector< Double_t > &pars, bool draw, UInt_t target, std::string outfn, Double_t step, TCanvas *c1)
Definition Gain.cc:22
Definition Gain.cc:19