GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TCalibrator.cxx
Go to the documentation of this file.
1#include "TCalibrator.h"
2
3#include <cmath>
4#include <cstdio>
5#include <utility>
6#include <vector>
7#include <map>
8#include <algorithm>
9#include <fstream>
10
11#include "TH1.h"
12#include "TSpectrum.h"
13#include "TLinearFitter.h"
14#include "TGraphErrors.h"
15
16#include "TChannel.h"
17#include "TNucleus.h"
18#include "TTransition.h"
19
20#include "GRootFunctions.h"
21#include "GRootCommands.h"
22#include "GCanvas.h"
23#include "GPeak.h"
24#include "Globals.h"
25
26#include "combinations.h"
27
32
34{
35 delete fLinFit;
36 delete fEffFit;
37}
38
39void TCalibrator::Copy(TObject&) const
40{
41}
42
43void TCalibrator::Print(Option_t*) const
44{
45 int counter = 0;
46 std::cout << "\t senergy scent scalc sarea snuc sintensity" << std::endl;
47 for(const auto& it : fPeaks) {
48 double caleng = it.centroid * GetParameter(1) + GetParameter(0);
49 double pdiff = std::abs(caleng - it.energy) / it.energy;
50 std::cout << counter++ << ":\t" << std::setw(7) << it.energy << std::setw(16) << it.centroid << std::setw(8) << caleng
51 << " [%%" << std::setw(3) << pdiff * 100. << "]" << std::setw(16) << it.area << std::setw(8) << it.nucleus << std::setw(16) << it.intensity << std::endl;
52 }
53 std::cout << "-------------------------------" << std::endl;
54}
55
56std::string TCalibrator::PrintEfficency(const char* filename)
57{
58 std::string toprint;
59 std::string file = filename;
60 int counter = 1;
61 toprint.append("line\teng\tcounts\tt1/2\tactivity\n");
62 toprint.append("--------------------------------------\n");
63 for(const auto& it : fPeaks) {
64 toprint.append(
65 Form("%i\t%.02f\t%.02f\t%i\t%.02f\n", counter++, it.energy, it.area, 100, (it.intensity / 100) * 1e5));
66 }
67 toprint.append("--------------------------------------\n");
68
69 if(file.length() != 0u) {
70 std::ofstream ofile;
71 ofile.open(file.c_str());
72 ofile << toprint;
73 ofile.close();
74 }
75 std::cout << toprint << std::endl;
76 return toprint;
77}
78
79TGraphErrors& TCalibrator::MakeEffGraph(double seconds, double bq, Option_t* opt)
80{
81 // this currently assumes it only has 152Eu data.
82 // one day it may be smarter, but today is not that day.
83 TString option(opt);
84 TString fitopt;
85 if(option.Contains("Q")) {
86 fitopt.Append("Q");
87 option.ReplaceAll("Q", "");
88 }
89 std::vector<double> energy;
90 std::vector<double> error_e;
91 std::vector<double> observed;
92 std::vector<double> error_o;
93 for(const auto& it : fPeaks) {
94 energy.push_back(it.energy);
95 error_e.push_back(0.0);
96 observed.push_back((it.area / seconds) / ((it.intensity / 100) * bq));
97 error_o.push_back(observed.back() * (sqrt(it.area) / it.area));
98 }
99
100 fEffGraph.Clear();
101 fEffGraph = TGraphErrors(static_cast<Int_t>(fPeaks.size()), energy.data(), observed.data(), error_e.data(), error_o.data());
102
103 if(fEffFit != nullptr) {
104 fEffFit->Delete();
105 }
106 static int counter = 0;
107 fEffFit = new TF1(Form("eff_fit_%i", counter++), GRootFunctions::GammaEff, 0, 1500, 4);
108 fEffGraph.Fit(fEffFit, fitopt.Data());
109
110 if(option.Contains("draw", TString::kIgnoreCase)) {
111 TVirtualPad* current = gPad;
112 new GCanvas;
113 fEffGraph.Draw("AP");
114 if(current != nullptr) {
115 current->cd();
116 }
117 }
118 for(unsigned int i = 0; i < energy.size(); i++) {
119 std::cout << "[" << energy.at(i) << "] Observed = " << observed.at(i) << " | Calculated = " << fEffFit->Eval(energy.at(i)) << " | per diff = "
120 << (std::abs(observed.at(i) - fEffFit->Eval(energy.at(i))) / observed.at(i)) * 100. << std::endl;
121 }
122 return fEffGraph;
123}
124
125void TCalibrator::Clear(Option_t* opt)
126{
127 fFitGraph.Clear(opt);
128 fEffGraph.Clear(opt);
129 // all_fits.clear();
130
131 for(double& i : fEffPar) {
132 i = 0.;
133 }
134}
135
136void TCalibrator::Draw(Option_t* opt)
137{
138 // if((graph_of_everything.GetN()<1) &&
139 // (all_fits.size()>0))
140 // MakeCalibrationGraph();
141 // Fit();
142 TString option(opt);
143 if(option.Contains("new", TString::kIgnoreCase)) {
144 new GCanvas;
145 }
146 fFitGraph.Draw("AP");
147}
148
149void TCalibrator::Fit(int order)
150{
151
152 // if((graph_of_everything.GetN()<1) &&
153 // (all_fits.size()>0))
155 if(fFitGraph.GetN() < 1) {
156 return;
157 }
158 if(order == 1) {
159 fLinFit = new TF1("fLinFit", GRootFunctions::LinFit, 0, 1, 2);
160 fLinFit->SetParameter(0, 0.0);
161 fLinFit->SetParameter(1, 1.0);
162 fLinFit->SetParName(0, "intercept");
163 fLinFit->SetParName(1, "slope");
164 } else if(order == 2) {
165 fLinFit = new TF1("fLinFit", GRootFunctions::QuadFit, 0, 1, 3);
166 fLinFit->SetParameter(0, 0.0);
167 fLinFit->SetParameter(1, 1.0);
168 fLinFit->SetParameter(2, 0.0);
169 fLinFit->SetParName(0, "A");
170 fLinFit->SetParName(1, "B");
171 fLinFit->SetParName(2, "C");
172 }
173 fFitGraph.Fit(fLinFit);
174 Print();
175}
176
177double TCalibrator::GetParameter(int i) const
178{
179 if(fLinFit != nullptr) {
180 return fLinFit->GetParameter(i);
181 }
182 return sqrt(-1);
183}
184
186{
187 if(fEffFit != nullptr) {
188 return fEffFit->GetParameter(i);
189 }
190 return sqrt(-1);
191}
192
194{
195 std::vector<double> xvalues;
196 std::vector<double> yvalues;
197 // std::vector<double> xerrors;
198 // std::vector<double> yerrors;
199
200 for(const auto& it : fPeaks) {
201 xvalues.push_back(it.centroid);
202 yvalues.push_back(it.energy);
203 }
204 fFitGraph.Clear();
205 fFitGraph = TGraph(static_cast<Int_t>(xvalues.size()), xvalues.data(), yvalues.data());
206
207 return fFitGraph;
208}
209
210std::vector<double> TCalibrator::Calibrate(double)
211{
212 std::vector<double> vec;
213 return vec;
214}
215
216int TCalibrator::AddData(TH1* data, const std::string& source, double sigma, double threshold, double error)
217{
218 if((data == nullptr) || (source.length() == 0u)) {
219 std::cout << "data not added. data = " << data << " \t source = " << source << std::endl;
220 return 0;
221 }
222 TNucleus n(source.c_str());
223 return AddData(data, &n, sigma, threshold, error);
224}
225
226int TCalibrator::AddData(TH1* data, TNucleus* source, double sigma, double threshold, double)
227{
228 if((data == nullptr) || (source == nullptr)) {
229 std::cout << "data not added. data = " << data << " \t source = " << source << std::endl;
230 return 0;
231 }
232 int actual_x_max = std::floor(data->GetXaxis()->GetXmax());
233 int actual_x_min = std::floor(data->GetXaxis()->GetXmax());
234 int displayed_x_max = std::floor(data->GetXaxis()->GetBinUpEdge(data->GetXaxis()->GetLast()));
235 int displayed_x_min = std::floor(data->GetXaxis()->GetBinLowEdge(data->GetXaxis()->GetFirst()));
236
237 std::string name;
238 if((actual_x_max == displayed_x_max) && (actual_x_min == displayed_x_min)) {
239 name = source->GetName();
240 } else {
241 name = Form("%s_%i_%i", source->GetName(), displayed_x_min, displayed_x_max);
242 }
243
244 TIter iter(source->GetTransitionList());
245 std::vector<double> source_energy;
246 std::map<double, double> src_eng_int;
247 while(auto* transition = static_cast<TTransition*>(iter.Next())) {
248 source_energy.push_back(transition->GetEnergy());
249 src_eng_int[transition->GetEnergy()] = transition->GetIntensity();
250 }
251 std::sort(source_energy.begin(), source_energy.end());
252
253 TSpectrum spectrum;
254 spectrum.Search(data, sigma, "", threshold);
255 std::vector<double> data_channels;
256 std::map<double, double> peak_area;
257 for(int x = 0; x < spectrum.GetNPeaks(); x++) {
258 double range = 8 * data->GetXaxis()->GetBinWidth(1);
259 GPeak* fit =
260 PhotoPeakFit(data, spectrum.GetPositionX()[x] - range, spectrum.GetPositionX()[x] + range, "no-print");
261 // data_channels
262 data_channels.push_back(fit->GetCentroid());
263 data->GetListOfFunctions()->Remove(fit);
264 peak_area[fit->GetCentroid()] = fit->GetSum();
265 }
266
267 std::map<double, double> datatosource = Match(data_channels, source_energy);
268
269 for(const auto& it : datatosource) {
270 AddPeak(it.first, it.second, source->GetName(), peak_area.at(it.first), src_eng_int[it.second]);
271 }
272
273 // Print();
274 int counter = 0;
275 for(const auto& it : datatosource) {
276 if(!std::isnan(it.second)) {
277 counter++;
278 }
279 }
280 return counter; // CheckMap(datatosource);
281}
282
283void TCalibrator::ResetMap(std::map<double, double>& inmap)
284{
285 for(auto& it : inmap) {
286 it.second = sqrt(-1);
287 }
288}
289
290void TCalibrator::PrintMap(std::map<double, double>& inmap)
291{
292 std::cout << "\tfirst\tsecond" << std::endl;
293 int counter = 0;
294 for(const auto& it : inmap) {
295 std::cout << counter++ << "\t" << it.first << "\t" << it.second << std::endl;
296 }
297}
298
299std::map<double, double> TCalibrator::Match(std::vector<double> peaks, std::vector<double> source)
300{
301 std::map<double, double> map;
302 std::sort(peaks.begin(), peaks.end());
303 std::sort(source.begin(), source.end());
304
305 // Peaks are the fitted points.
306 // source are the known values
307
308 std::vector<bool> filled(source.size());
309 std::fill(filled.begin(), filled.begin() + peaks.size(), true);
310
311 TLinearFitter fitter(1, "1 ++ x");
312
313 for(size_t num_data_points = peaks.size(); num_data_points > 0; num_data_points--) {
314 double best_chi2 = DBL_MAX;
315 for(auto peak_values : combinations(peaks, num_data_points)) {
316 // Add a (0,0) point to the calibration.
317 peak_values.push_back(0);
318 for(auto source_values : combinations(source, num_data_points)) {
319 source_values.push_back(0);
320
321 if(peaks.size() > 3) {
322 double max_err = 0.02;
323 double pratio = peak_values.front() / peak_values.at(peak_values.size() - 2);
324 double sratio = source_values.front() / source_values.at(source_values.size() - 2);
325 // std::cout<<"ratio: "<<pratio<<" - "<<sratio<<" = "<<std::abs(pratio-sratio)<<std::endl;
326 if(std::abs(pratio - sratio) > max_err) {
327 // std::cout<<"skipping"<<std::endl;
328 continue;
329 }
330 }
331
332 fitter.ClearPoints();
333 fitter.AssignData(static_cast<Int_t>(source_values.size()), 1, peak_values.data(), source_values.data());
334 fitter.Eval();
335
336 if(fitter.GetChisquare() < best_chi2) {
337 map.clear();
338 for(size_t i = 0; i < num_data_points; i++) {
339 map[peak_values[i]] = source_values[i];
340 }
341 best_chi2 = fitter.GetChisquare();
342 }
343 }
344 }
345
346 // Remove one peak value from the best fit, make sure that we reproduce (0,0) intercept.
347 if(map.size() > 2) {
348 std::vector<double> peak_values;
349 std::vector<double> source_values;
350 for(auto& item : map) {
351 peak_values.push_back(item.first);
352 source_values.push_back(item.second);
353 }
354
355 for(size_t skipped_point = 0; skipped_point < source_values.size(); skipped_point++) {
356 std::swap(peak_values[skipped_point], peak_values.back());
357 std::swap(source_values[skipped_point], source_values.back());
358
359 fitter.ClearPoints();
360 fitter.AssignData(static_cast<Int_t>(source_values.size() - 1), 1, peak_values.data(), source_values.data());
361 fitter.Eval();
362
363 if(std::abs(fitter.GetParameter(0)) > 10) {
364 map.clear();
365 break;
366 }
367
368 std::swap(peak_values[skipped_point], peak_values.back());
369 std::swap(source_values[skipped_point], source_values.back());
370 }
371 }
372
373 if(!map.empty()) {
374 return map;
375 }
376 }
377
378 map.clear();
379 return map;
380}
381
382bool TCalibrator::CheckMap(const std::map<double, double>& inmap)
383{
384 /// Return false if any member of map is nan (not a number).
385 // all_of returns false if the condition is false for any member
386 return std::all_of(inmap.begin(), inmap.end(), [](auto iter) { return !std::isnan(iter.second); });
387}
388
392
393void TCalibrator::AddPeak(double cent, double eng, std::string nuc, double a, double inten)
394{
395 Peak p;
396 p.centroid = cent;
397 p.energy = eng;
398 p.nucleus = std::move(nuc);
399 p.area = a;
400 p.intensity = inten;
401 fPeaks.push_back(p);
402}
GPeak * PhotoPeakFit(TH1 *, double, double, Option_t *opt="")
Definition GPeak.h:11
Double_t GetCentroid() const
Definition GPeak.h:33
Double_t GetSum() const
Definition GPeak.h:37
static void PrintMap(std::map< double, double > &inmap)
TGraphErrors & MakeEffGraph(double seconds=3600., double bq=100000., Option_t *opt="draw")
int AddData(TH1 *data, const std::string &source, double sigma=2.0, double threshold=0.05, double error=0.001)
std::vector< double > Calibrate(double min_figure_of_merit=0.001)
TGraph fFitGraph
Definition TCalibrator.h:81
void Fit(int order=1)
static std::map< double, double > Match(std::vector< double >, std::vector< double >)
TF1 * fEffFit
Definition TCalibrator.h:84
double GetParameter(int i=0) const
void Draw(Option_t *opt="") override
void Copy(TObject &obj) const override
std::array< double, 4 > fEffPar
Definition TCalibrator.h:88
static bool CheckMap(const std::map< double, double > &inmap)
void AddPeak(double cent, double eng, std::string nuc, double a=0.0, double inten=0.0)
double GetEffParameter(int i=0) const
TGraphErrors fEffGraph
Definition TCalibrator.h:82
TF1 * fLinFit
Definition TCalibrator.h:83
void UpdateTChannel(TChannel *channel)
void Print(Option_t *opt="") const override
std::string PrintEfficency(const char *filename="")
static void ResetMap(std::map< double, double > &inmap)
std::vector< Peak > fPeaks
Definition TCalibrator.h:79
TGraph & MakeCalibrationGraph(double min_figure_of_merit=0.001)
void Clear(Option_t *opt="") override
const TSortedList * GetTransitionList() const
Definition TNucleus.h:84
Double_t GammaEff(Double_t *x, Double_t *par)
Double_t LinFit(Double_t *dim, Double_t *par)
Double_t QuadFit(Double_t *dim, Double_t *par)
std::string nucleus
Definition TCalibrator.h:52