GRSISort "v4.1.1.0"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TDecay.cxx
Go to the documentation of this file.
1#include "TDecay.h"
2
3#include <utility>
4
5#include "TCanvas.h"
6#include "TBuffer.h"
7#include "TLMFitter.h"
8#include "Math/MinimizerOptions.h"
9#include "TVirtualFitter.h"
10#include "TFitResult.h"
11
12UInt_t TSingleDecay::fCounter = 0;
14
16{
17 /// This draws the individual components on the current canvas
18 fDecay->DrawComponents("same");
19}
20
22{
23 /// This tells the TDecayFit which TVirtualDecay it belongs to
24 fDecay = decay;
25}
26
27void TDecayFit::Print(Option_t* opt) const
28{
29 /// This prints the parameters of the fit (decay rate, intensities, etc...)
30 TF1::Print(opt);
31 std::cout << "fDecay = " << fDecay << std::endl;
32}
33
35{
36 return fDecay;
37}
38
39TFitResultPtr TDecayFit::Fit(TH1* hist, Option_t* opt)
40{
41 if(hist == nullptr) {
42 return 0;
43 }
44 TFitResultPtr tmpres = hist->Fit(this, opt);
46 // Might be able to copy the style over to the new clone for the residuals.
47 // Will take a look at this later
48 // fDecay->Update();
49 // DrawClone("same");
50 Draw("same");
51 return tmpres;
52}
53
55{
56 fResiduals.SetMarkerStyle(20); // Filled circle
57 fResiduals.SetMarkerSize(0.6);
58 fResiduals.SetTitle("Residuals");
59}
60
62{
63 const Size_t oldmarker_size = fResiduals.GetMarkerSize();
64 const Color_t oldmarker_color = fResiduals.GetMarkerColor();
65 const Style_t oldmarker_style = fResiduals.GetMarkerStyle();
66
67 // Clear the data points from the old TGraph
68 for(int i = 0; i < fResiduals.GetN(); ++i) {
69 fResiduals.RemovePoint(i);
70 }
71
72 Double_t xlow = 0.;
73 Double_t xhigh = 0.;
74 GetRange(xlow, xhigh);
75 Int_t nbins = hist->GetXaxis()->GetNbins();
76
77 for(int i = 0; i < nbins; ++i) {
78 if((hist->GetBinCenter(i) <= xlow) || (hist->GetBinCenter(i) >= xhigh)) {
79 continue;
80 }
81 // This might not be correct for Poisson statistics.
82 Double_t res = (hist->GetBinContent(i) - Eval(hist->GetBinCenter(i))) /
83 hist->GetBinError(i); /// GetHist()->GetBinError(i));// + GetParameter("Height") + 10.;
84 Double_t bin = hist->GetBinCenter(i);
85 fResiduals.SetPoint(i, bin, res);
86 }
87
88 fResiduals.SetMarkerSize(oldmarker_size);
89 fResiduals.SetMarkerColor(oldmarker_color);
90 fResiduals.SetMarkerStyle(oldmarker_style);
91}
92
94{
95 if(fResiduals.GetN() != 0) {
96 new TCanvas;
97 fResiduals.Draw("AP");
98 } else {
99 std::cout << "Residuals not set yet" << std::endl;
100 }
101}
102
103void TVirtualDecay::DrawComponents(Option_t* opt, Bool_t)
104{
105 std::cout << "Draw components has not been set in " << ClassName() << std::endl;
106 Draw(Form("same%s", opt));
107}
108
109TSingleDecay::TSingleDecay(TSingleDecay* parent, Double_t tlow, Double_t thigh)
110 : fDetectionEfficiency(1.0)
111{
112 if(parent != nullptr) {
113 fParent = parent;
115 // See if the decay chain makes sense.
116 TSingleDecay* curParent = parent;
117 UInt_t gencounter = 1;
118 while(curParent != nullptr) {
119 ++gencounter;
120 fFirstParent = curParent;
121 curParent = curParent->GetParentDecay();
122 }
123
124 fGeneration = gencounter;
125 } else {
126 fFirstParent = this;
127 fGeneration = 1;
128 }
129 // This will potentially leak with ROOT IO, shouldnt be a big deal. Might come back to this later
130 fDecayFunc = new TDecayFit(Form("decayfunc_gen%d", fGeneration), this, &TSingleDecay::ActivityFunc, 0, 10, 2);
131 fDecayFunc->SetDecay(this);
132 fDecayFunc->SetParameters(fFirstParent->GetIntensity(), 0.0);
133 fDecayFunc->SetParNames("Intensity", "DecayRate");
134
135 fTotalDecayFunc = new TDecayFit(Form("totaldecayfunc_gen%d", fGeneration), this, &TSingleDecay::ActivityFunc, 0, 10, fGeneration + 1);
138 if(fFirstParent != this) {
139 FixIntensity(0);
140 }
141
142 SetRange(tlow, thigh);
143 fUnId = fCounter;
144 fCounter++;
145
146 SetName("Decay");
147}
148
149TSingleDecay::TSingleDecay(UInt_t generation, TSingleDecay* parent, Double_t tlow, Double_t thigh)
150 : fDetectionEfficiency(1.0)
151{
152 if(parent != nullptr) {
153 fParent = parent;
155 // See if the decay chain makes sense.
156 TSingleDecay* curParent = parent;
157 UInt_t gencounter = 2;
158 for(UInt_t i = 0; i < generation; ++i) {
159 if(curParent->GetParentDecay() != nullptr) {
160 curParent = parent->GetParentDecay();
161 ++gencounter;
162 } else {
163 fFirstParent = curParent;
164 }
165 }
166 if(gencounter != generation) {
167 std::cout << "Generation numbers do not make sense" << std::endl;
168 }
169 }
170 if(generation == 1) {
171 fFirstParent = this;
172 }
173
174 fGeneration = generation;
175
176 fDecayFunc = new TDecayFit("tmpname", this, &TSingleDecay::ActivityFunc, 0, 10, 2);
177 fDecayFunc->SetDecay(this);
178 fDecayFunc->SetParameters(fFirstParent->GetIntensity(), 0.0);
179 fDecayFunc->SetParNames("Intensity", "DecayRate");
180
181 fTotalDecayFunc = new TDecayFit("tmpname", this, &TSingleDecay::ActivityFunc, 0, 10, fGeneration + 1);
184 if(fFirstParent != this) {
185 FixIntensity(0);
186 }
187
188 SetName("");
189 SetRange(tlow, thigh);
190 fUnId = fCounter;
191 fCounter++;
192
193 SetName("Decay");
194}
195
197{
198 // if(fDecayFunc) delete fDecayFunc;
199 // if(fTotalDecayFunc) delete fTotalDecayFunc;
200
201 fDecayFunc = nullptr;
202 fTotalDecayFunc = nullptr;
203}
204
205void TSingleDecay::SetName(const char* name)
206{
207 TNamed::SetName(name);
208 fDecayFunc->SetName(Form("%s_df_gen%d", name, fGeneration));
209 fTotalDecayFunc->SetName(Form("%s_tdf_gen%d", name, fGeneration));
210}
211
213{
214 /// Sets the total fit function to know about the other parmaters in the decay chain.
215 Double_t low_limit = 0.;
216 Double_t high_limit = 0.;
217 // We need to include the fact that we have parents and use that TF1 to perform the fit.
218 fTotalDecayFunc->SetParameter(0, fFirstParent->GetIntensity());
219 fTotalDecayFunc->SetParNames("Intensity", "DecayRate1");
220 fFirstParent->GetDecayFunc()->GetParLimits(0, low_limit, high_limit);
221 fTotalDecayFunc->SetParLimits(0, low_limit, high_limit);
222 // Now we need to get the parameters for each of the parents
223 Int_t parCounter = 1;
224 TSingleDecay* curDecay = fFirstParent;
225 while(curDecay != nullptr) {
226 fTotalDecayFunc->SetParameter(parCounter, curDecay->GetDecayRate());
227 fTotalDecayFunc->SetParName(parCounter, Form("DecayRate%d", parCounter));
228 curDecay->GetDecayFunc()->GetParLimits(1, low_limit, high_limit);
229 if(low_limit != 0 && high_limit != 0) {
230 fTotalDecayFunc->SetParLimits(parCounter, low_limit, high_limit);
231 }
232 ++parCounter;
233 curDecay = curDecay->GetDaughterDecay();
234 }
235 UpdateDecays();
236}
237
239{
240 /// Updates the other decays in the chain to know that they have potential updates.
241 Double_t low_limit = 0.;
242 Double_t high_limit = 0.;
243 // The current (this) decay we are on is the one that is assumed to be the most recently changed.
244 // We will first update it's total decay function
245
246 // Now update the halflives of all the total decay functions.
247 TSingleDecay* curDecay = fFirstParent;
248 while(curDecay != nullptr) {
249 GetDecayFunc()->GetParLimits(0, low_limit, high_limit);
250 curDecay->fTotalDecayFunc->SetParameter(0, GetIntensity());
251 curDecay->fTotalDecayFunc->SetParLimits(0, low_limit, high_limit);
252 // curDecay->fDecayFunc->SetParameter(0,GetIntensity());
253 // curDecay->fDecayFunc->SetParLimits(0,low_limit,high_limit);
254 curDecay->fDecayFunc->SetParameter(0, GetIntensity());
255 curDecay->fDecayFunc->SetParLimits(0, low_limit, high_limit);
256 fDecayFunc->GetParLimits(0, low_limit, high_limit);
257 curDecay->fTotalDecayFunc->SetParLimits(0, low_limit, high_limit);
258
259 curDecay->fTotalDecayFunc->SetParameter(0, GetIntensity());
260
261 curDecay->fTotalDecayFunc->SetParameter(GetGeneration(), GetDecayRate());
262 fDecayFunc->GetParLimits(1, low_limit, high_limit);
263 curDecay->fTotalDecayFunc->SetParLimits(GetGeneration(), low_limit, high_limit);
264 curDecay = curDecay->GetDaughterDecay();
265 }
266}
267
268void TSingleDecay::SetHalfLifeLimits(const Double_t& low, const Double_t& high)
269{
270 if(low == 0) {
271 fDecayFunc->SetParLimits(1, std::log(2) / high, 1e30);
272 }
273
274 fDecayFunc->SetParLimits(1, std::log(2) / high, std::log(2) / low);
275 // Tell this info to the rest of the decays
276 UpdateDecays();
277}
278
279void TSingleDecay::SetIntensityLimits(const Double_t& low, const Double_t& high)
280{
281 fFirstParent->fDecayFunc->SetParLimits(0, low, high);
282 UpdateDecays();
283}
284
285void TSingleDecay::SetDecayRateLimits(const Double_t& low, const Double_t& high)
286{
287 fDecayFunc->SetParLimits(1, low, high);
288 UpdateDecays();
289}
290
291void TSingleDecay::GetHalfLifeLimits(Double_t& low, Double_t& high) const
292{
293 fDecayFunc->GetParLimits(1, high, low); // This gets the decay rates, not the half-life.
294 if(low == 0) {
295 low = 0.000000000001;
296 }
297 if(high == 0) {
298 high = 0.000000000001;
299 }
300 low = std::log(2) / low;
301 high = std::log(2) / high;
302}
303
304void TSingleDecay::GetIntensityLimits(Double_t& low, Double_t& high) const
305{
306 fFirstParent->fDecayFunc->GetParLimits(0, low, high);
307}
308
309void TSingleDecay::GetDecayRateLimits(Double_t& low, Double_t& high) const
310{
311 fDecayFunc->GetParLimits(1, low, high);
312}
313
318
323
324void TSingleDecay::Draw(Option_t* option)
325{
327 fTotalDecayFunc->Draw(option);
328}
329
330Double_t TSingleDecay::Eval(Double_t t)
331{
332 /// Evaluates the activity at a given time, t
334 return fTotalDecayFunc->Eval(t);
335}
336
337Double_t TSingleDecay::EvalPar(const Double_t* x, const Double_t* par)
338{
339 /// Evaluates the activity at a given time t using parameters par.
340 fTotalDecayFunc->InitArgs(x, par);
341 return fTotalDecayFunc->EvalPar(x, par);
342}
343
344Double_t TSingleDecay::ActivityFunc(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
345{
346 /// The general function for a decay chain
347 /// par[0] is the intensity
348 /// par[1*i] is the activity
349 Double_t result = 1.0;
350 UInt_t gencounter = 0;
351 Double_t tlow = 0.;
352 Double_t thigh = 0.;
353 fTotalDecayFunc->GetRange(tlow, thigh);
354 Double_t t = dim[0] - tlow;
355 TSingleDecay* curDecay = this;
356 // Compute the first multiplication
357 while(curDecay != nullptr) {
358 ++gencounter;
359 // par[Generation] gets the decay rate for that decay since the parameters are stored
360 // as [intensity, decayrate1,decayrate2,...]
361 result *= par[curDecay->GetGeneration()];
362
363 curDecay = curDecay->GetParentDecay();
364 }
365 if(gencounter != fGeneration) {
366 std::cout << "We have Problems!" << std::endl;
367 return 0.0;
368 }
369 // Multiply by the initial intensity of the initial parent.
370 result *= par[0] / par[1];
371 // Now we need to deal with the second term
372 Double_t sum = 0.0;
373 curDecay = this;
374 while(curDecay != nullptr) {
375 Double_t denom = 1.0;
376 TSingleDecay* denomDecay = this;
377 while(denomDecay != nullptr) {
378 if(denomDecay != curDecay) {
379 // This term has problems if two or more rates are very similar. Will have to put a taylor expansion in here
380 // if this problem comes up. I believe the solution to this also depends on the number of nuclei in the
381 // chain
382 // that have similar rates. I think either of these issues is fairly rare, so I'll fix it when it comes up.
383 denom *= par[denomDecay->GetGeneration()] - par[curDecay->GetGeneration()];
384 }
385 denomDecay = denomDecay->GetParentDecay();
386 }
387
388 sum += TMath::Exp(-par[curDecay->GetGeneration()] * t) / denom;
389
390 curDecay = curDecay->GetParentDecay();
391 }
392 result *= sum;
393
394 return result * GetEfficiency();
395}
396
397TFitResultPtr TSingleDecay::Fit(TH1* fithist, Option_t* opt)
398{
399 ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2", "Combination");
400 TVirtualFitter::SetPrecision(1.0e-10);
401 TVirtualFitter::SetMaxIterations(10000);
402 Int_t parCounter = 1;
403 TSingleDecay* curDecay = fFirstParent;
405 // TFitResultPtr fitres = fithist->Fit(fTotalDecayFunc,Form("%sWLRS",opt));
406 TFitResultPtr fitres = fTotalDecayFunc->Fit(fithist, Form("%sWLRS", opt));
407 Double_t chi2 = fitres->Chi2();
408 Double_t ndf = fitres->Ndf(); // This ndf needs to be changed by a weighted poisson.
409
410 std::cout << "Chi2/ndf = " << chi2 / ndf << std::endl;
411
412 // Now copy the fits back to the appropriate nuclei.
413 fFirstParent->SetIntensity(fTotalDecayFunc->GetParameter(0));
415 // Now we need to set the parameters for each of the parents
416 while(curDecay != nullptr) {
417 curDecay->SetDecayRate(fTotalDecayFunc->GetParameter(parCounter));
418 curDecay->SetDecayRateError(fTotalDecayFunc->GetParError(parCounter));
419 curDecay = curDecay->GetDaughterDecay();
420 ++parCounter;
421 }
422
423 return fitres;
424}
425
427{
428 FixHalfLife();
429 FixIntensity();
430}
431
437
438void TSingleDecay::SetRange(Double_t tlow, Double_t thigh)
439{
440 fDecayFunc->SetRange(tlow, thigh);
441 fTotalDecayFunc->SetRange(tlow, thigh);
442}
443
444void TSingleDecay::Print(Option_t*) const
445{
446 std::cout << " Decay Id: " << GetDecayId() << std::endl;
447 std::cout << " Intensity: " << GetIntensity() << " +/- " << GetIntensityError() << " c/s" << std::endl;
448 std::cout << " HalfLife: " << GetHalfLife() << " +/- " << GetHalfLifeError() << " s" << std::endl;
449 std::cout << "Efficiency: " << GetEfficiency() << std::endl;
450 std::cout << "My Address: " << this << std::endl;
451 if(fParent != nullptr) {
452 std::cout << "Parent Address: %p\n"
453 << fParent << std::endl;
454 }
455 if(fDaughter != nullptr) {
456 std::cout << "Daughter Address: " << fDaughter << std::endl;
457 }
458 std::cout << "First Parent: " << fFirstParent << std::endl;
459}
460
461TDecayChain::TDecayChain(UInt_t generations)
462{
463 if(generations == 0u) {
464 generations = 1;
465 }
466 fDecayChain.clear();
467 auto* parent = new TSingleDecay(nullptr);
468 parent->SetChainId(fChainCounter);
469 fDecayChain.push_back(parent);
470 for(UInt_t i = 1; i < generations; i++) {
471 auto* curDecay = new TSingleDecay(parent);
472 curDecay->SetChainId(fChainCounter);
473 fDecayChain.push_back(curDecay);
474 parent = curDecay;
475 }
476
477 fChainFunc = new TDecayFit("tmpname", this, &TDecayChain::ChainActivityFunc, 0, 10, fDecayChain.size() + 1);
478 fChainFunc->SetDecay(this);
482}
483
485{
486 // Might have to think about ownership if we allow external decays to be added
487 for(auto* decay : fDecayChain) {
488 delete decay;
489 }
490 delete fChainFunc;
491}
492
494{
495 for(auto* decay : fDecayChain) {
496 decay->SetTotalDecayParameters();
497 }
498 Double_t low_limit = 0.;
499 Double_t high_limit = 0.;
500 // We need to include the fact that we have parents and use that TF1 to perform the fit.
501 for(int i = 0; i < fChainFunc->GetNpar(); ++i) {
502 fChainFunc->SetParameter(i, fDecayChain.back()->GetTotalDecayFunc()->GetParameter(i));
503 fChainFunc->SetParError(i, fDecayChain.back()->GetTotalDecayFunc()->GetParError(i));
504 fChainFunc->SetParName(i, fDecayChain.back()->GetTotalDecayFunc()->GetParName(i));
505 fDecayChain.back()->GetTotalDecayFunc()->GetParLimits(i, low_limit, high_limit);
506 fChainFunc->SetParLimits(i, low_limit, high_limit);
507 }
508}
509
510Double_t TDecayChain::ChainActivityFunc(Double_t* dim, Double_t* par)
511{
512 /// This fits the total activity caused by the entire chain.
513 Double_t result = 0.0;
514 for(size_t i = 0; i < fDecayChain.size(); ++i) {
515 result += GetDecay(i)->EvalPar(dim, par);
516 }
517
518 return result;
519}
520
521Double_t TDecayChain::Eval(Double_t t) const
522{
523 return fChainFunc->Eval(t);
524}
525
526void TDecayChain::Draw(Option_t* opt)
527{
529 fChainFunc->Draw(opt);
530}
531
532void TDecayChain::DrawComponents(Option_t* opt, Bool_t color_flag)
533{
535 fDecayChain.at(0)->SetMinimum(0);
536 fDecayChain.at(0)->SetLineColor(1);
537 fDecayChain.at(0)->Draw("Same");
538 for(size_t i = 1; i < fDecayChain.size(); ++i) {
539 if(color_flag) {
540 fDecayChain.at(i)->SetLineColor(fDecayChain.at(i)->fUnId);
541 }
542 fDecayChain.at(i)->Draw(Form("same%s", opt));
543 }
544}
545
547{
548 if(decay != nullptr) {
549 fDecayChain.push_back(decay);
550 }
551}
552
554{
555 if(generation < fDecayChain.size()) {
556 return fDecayChain.at(generation);
557 }
559
560 return nullptr;
561}
562
563void TDecayChain::Print(Option_t*) const
564{
565 std::cout << "Number of Decays in Chain: " << fDecayChain.size() << std::endl;
566 std::cout << "Chain Id " << fDecayChain.at(0)->GetChainId() << std::endl;
567 for(auto* decay : fDecayChain) {
568 std::cout << "decay ptr: " << decay << std::endl;
569 decay->Print();
570 std::cout << std::endl;
571 }
572}
573
574TFitResultPtr TDecayChain::Fit(TH1* fithist, Option_t* opt)
575{
576 ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2", "Combination");
577 TVirtualFitter::SetPrecision(1.0e-10);
578 TVirtualFitter::SetMaxIterations(10000);
579 Int_t parCounter = 1;
580 TSingleDecay* curDecay = fDecayChain.at(0);
582 // TFitResultPtr fitres = fithist->Fit(fChainFunc,Form("%sWLRS",opt));
583 TFitResultPtr fitres = fChainFunc->Fit(fithist, Form("%sWLRS", opt));
584 Double_t chi2 = fitres->Chi2();
585 Double_t ndf = fitres->Ndf();
586
587 std::cout << "Chi2/ndf = " << chi2 / ndf << std::endl;
588
589 // Now copy the fits back to the appropriate nuclei.
590 curDecay->SetIntensity(fChainFunc->GetParameter(0));
591 curDecay->SetIntensityError(fChainFunc->GetParError(0));
592 // Now we need to set the parameters for each of the parents
593 while(curDecay != nullptr) {
594 curDecay->SetDecayRate(fChainFunc->GetParameter(parCounter));
595 curDecay->SetDecayRateError(fChainFunc->GetParError(parCounter));
596 curDecay = curDecay->GetDaughterDecay();
597 ++parCounter;
598 curDecay->UpdateDecays();
599 }
600
601 return fitres;
602}
603
604Double_t TDecayChain::EvalPar(const Double_t* x, const Double_t* par)
605{
606 fChainFunc->InitArgs(x, par);
608
609 return fChainFunc->EvalPar(x, par);
610}
611
612void TDecayChain::SetRange(Double_t xlow, Double_t xhigh)
613{
614 fChainFunc->SetRange(xlow, xhigh);
615 for(auto* decay : fDecayChain) {
616 decay->SetRange(xlow, xhigh);
617 }
618}
619
620TDecay::TDecay(std::vector<TDecayChain*> chainList)
621 : fChainList(std::move(chainList))
622{
623 fFitFunc = new TDecayFit("tmpfit", this, &TDecay::DecayFit, 0, 10, 1);
624 fFitFunc->SetDecay(this);
625 RemakeMap();
627}
628
630{
631 if(idx < fChainList.size()) {
632 return fChainList.at(idx);
633 }
634
636
637 return nullptr;
638}
639
640Double_t TDecay::DecayFit(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
641{
642 /// This fits the total activity caused by the entire chain.
643 Double_t result = 0.0;
644 // Start the fit with flat background;
645 result = par[0];
646 // Parameters might be linked, so I have to sort this out here.
647 // We Must build parameter arrays for each fit.
648 for(auto* chain : fChainList) {
649 Int_t par_counter = 0;
650 auto* tmppar = new Double_t[chain->Size() + 1];
651 tmppar[par_counter++] = par[fFitFunc->GetParNumber(Form("Intensity_ChainId%d", chain->GetChainId()))];
652 for(int j = 0; j < chain->Size(); ++j) {
653 tmppar[par_counter++] = par[fFitFunc->GetParNumber(Form("DecayRate_DecayId%d", chain->GetDecay(j)->GetDecayId()))];
654 }
655 result += chain->EvalPar(dim, tmppar);
656 delete[] tmppar;
657 }
658
659 return result;
660}
661
662TFitResultPtr TDecay::Fit(TH1* fithist, Option_t* opt)
663{
664 // Use the option "G" to use Geoff's Levenberg-Marquardt algorithm to fit.
665 TString opt1 = opt;
666 opt1.ToUpper();
667
668 ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2", "Combination");
669 TVirtualFitter::SetPrecision(1.0e-10);
670 TVirtualFitter::SetMaxIterations(10000);
671 if(fithist->GetSumw2N() == 0) {
672 fithist->Sumw2();
673 }
674 // Int_t parCounter = 1;
676
677 // TFitResultPtr fitres = fithist->Fit(fFitFunc,Form("%sWLRS0",opt));
678 TFitResultPtr fitres;
679 if(opt1.Contains("G")) {
680 // Fit using LMFitter..Doesn't do residuals yet
681 TLMFitter fitter;
682 fitter.Fit(fithist, fFitFunc);
683 } else {
684 fitres = fFitFunc->Fit(fithist, Form("%sRIS", opt));
685 Double_t chi2 = fitres->Chi2();
686 Double_t ndf = fitres->Ndf();
687 std::cout << "Chi2/ndf = " << chi2 / ndf << std::endl;
688 }
689
690 // Now Tell the decays about the results
691 for(auto* chain : fChainList) {
692 Int_t par_num = fFitFunc->GetParNumber(Form("Intensity_ChainId%d", chain->GetChainId()));
693 chain->GetDecay(0)->SetIntensity(fFitFunc->GetParameter(par_num));
694 chain->GetDecay(0)->SetIntensityError(fFitFunc->GetParError(par_num));
695 for(int j = 0; j < chain->Size(); ++j) {
696 par_num = fFitFunc->GetParNumber(Form("DecayRate_DecayId%d", chain->GetDecay(j)->GetDecayId()));
697 chain->GetDecay(j)->SetDecayRate(fFitFunc->GetParameter(par_num));
698 chain->GetDecay(j)->SetDecayRateError(fFitFunc->GetParError(par_num));
699 }
700 chain->GetDecay(0)->UpdateDecays();
701 chain->SetChainParameters();
702 }
703
704 return fitres;
705}
706
707void TDecay::Draw(Option_t* opt)
708{
710 fFitFunc->Draw(opt);
711}
712
714{
715 RemakeMap();
716 // Find the number of unique chains and decays.
717 Int_t unq_chains = fChainList.size();
718 Int_t unq_decays = fDecayMap.size();
719
720 Double_t xlow = 0.;
721 Double_t xhigh = 0.;
722 fFitFunc->GetRange(xlow, xhigh);
723
724 Double_t tmpbg = fFitFunc->GetParameter(0);
725 Double_t tmpbglow = 0.;
726 Double_t tmpbghigh = 0.;
727 fFitFunc->GetParLimits(0, tmpbglow, tmpbghigh);
728 Double_t tmpbgerr = fFitFunc->GetParError(0);
729 delete fFitFunc;
730 fFitFunc = new TDecayFit("tmpfit", this, &TDecay::DecayFit, xlow, xhigh, unq_chains + unq_decays + 1);
731 fFitFunc->SetDecay(this);
732 fFitFunc->SetParName(0, "Background");
733 fFitFunc->SetParameter(0, tmpbg);
734 fFitFunc->SetParError(0, tmpbgerr);
735 fFitFunc->SetParLimits(0, tmpbglow, tmpbghigh);
736
737 Int_t par_counter = 1;
738 Double_t low = 0.;
739 Double_t high = 0.;
740 for(auto* chain : fChainList) {
741 fFitFunc->SetParName(par_counter, Form("Intensity_ChainId%d", chain->GetDecay(0)->GetChainId()));
742 chain->SetChainParameters();
743 chain->GetDecay(0)->GetIntensityLimits(low, high);
744 fFitFunc->SetParLimits(par_counter, low, high);
745 fFitFunc->SetParameter(par_counter++, chain->GetDecay(0)->GetIntensity());
746 }
747 for(auto& iter : fDecayMap) {
748 fFitFunc->SetParName(par_counter, Form("DecayRate_DecayId%d", iter.first));
749 iter.second.at(0)->GetDecayRateLimits(low, high);
750 fFitFunc->SetParLimits(par_counter, low, high);
751 fFitFunc->SetParameter(par_counter++, iter.second.at(0)->GetDecayRate());
752 }
753}
754
755Double_t TDecay::ComponentFunc(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
756{
757 /// Function for drawing summed components.
758 Double_t result = 0;
759 /// This function takes 1 parameter, the decay Id.
760 auto id = static_cast<Int_t>(par[0]);
761 auto iter = fDecayMap.find(id);
762
763 for(auto* decay : iter->second) {
764 result += decay->Eval(dim[0]);
765 }
766 return result;
767}
768
769void TDecay::DrawComponents(Option_t*, Bool_t)
770{
771 /// Loop over all of the ids and draw them seperately on the pad
772 Double_t low = 0.;
773 Double_t high = 0.;
774 fFitFunc->GetRange(low, high);
775
776 TF1* tmp_comp = new TF1("tmpname", this, &TDecay::ComponentFunc, low, high, 1);
777 for(auto& iter : fDecayMap) {
778 tmp_comp->SetName(Form("Component_%d", iter.first));
779 tmp_comp->SetParameter(0, iter.first);
780 if(iter.first == kWhite) {
781 tmp_comp->SetLineColor(kOrange);
782 } else {
783 tmp_comp->SetLineColor(static_cast<Color_t>(iter.first));
784 }
785 tmp_comp->DrawClone("same");
786 }
787 delete tmp_comp;
789}
790
792{
793 Double_t low = 0.;
794 Double_t high = 0.;
795 fFitFunc->GetRange(low, high);
796 auto* bg = new TF1("bg", "pol0", low, high);
797 bg->SetParameter(0, GetBackground());
798 bg->SetLineColor(kMagenta);
799 bg->DrawClone("same");
800 delete bg;
801}
802
803void TDecay::SetHalfLife(Int_t Id, Double_t halflife)
804{
805 auto it = fDecayMap.find(Id);
806 if(it == fDecayMap.end()) {
807 std::cout << "Could not find Id = : " << Id << std::endl;
808 return;
809 }
810 for(auto& i : it->second) {
811 i->SetHalfLife(halflife);
812 i->SetTotalDecayParameters();
813 }
814}
815
816void TDecay::SetHalfLifeLimits(Int_t Id, Double_t low, Double_t high)
817{
818 auto it = fDecayMap.find(Id);
819 if(it == fDecayMap.end()) {
820 std::cout << "Could not find Id = : " << Id << std::endl;
821 return;
822 }
823 for(auto& i : it->second) {
824 i->SetHalfLifeLimits(low, high);
825 i->SetTotalDecayParameters();
826 }
827}
828
829void TDecay::SetDecayRateLimits(Int_t Id, Double_t low, Double_t high)
830{
831 auto iter = fDecayMap.find(Id);
832 if(iter == fDecayMap.end()) {
833 std::cout << "Could not find Id = : " << Id << std::endl;
834 return;
835 }
836 for(auto* decay : iter->second) {
837 decay->SetDecayRateLimits(low, high);
838 decay->SetTotalDecayParameters();
839 }
840}
841
842void TDecay::Print(Option_t*) const
843{
844 std::cout << "Background: " << GetBackground() << " +/- " << GetBackgroundError() << std::endl
845 << std::endl;
846 for(const auto& it : fDecayMap) {
847 std::cout << "ID: " << it.first << " Name: " << it.second.at(0)->GetName() << std::endl;
848 it.second.at(0)->Print();
849 std::cout << std::endl;
850 }
851}
852
854{
855 for(const auto& iter : fDecayMap) {
856 std::cout << "ID: " << iter.first << std::endl;
857 for(auto* decay : iter.second) {
858 decay->Print();
859 }
860 std::cout << std::endl;
861 }
862}
863
864void TDecay::SetRange(Double_t xlow, Double_t xhigh)
865{
866 fFitFunc->SetRange(xlow, xhigh);
867 for(auto* chain : fChainList) {
868 chain->SetRange(xlow, xhigh);
869 }
870}
871
873{
874 fDecayMap.clear();
875 for(auto* chain : fChainList) {
876 for(int j = 0; j < chain->Size(); ++j) {
877 UInt_t id = chain->GetDecay(j)->GetDecayId();
878 if(fDecayMap.count(id) == 0) {
879 fDecayMap.insert(std::make_pair(id, std::vector<TSingleDecay*>()));
880 }
881 fDecayMap.find(id)->second.push_back(chain->GetDecay(j));
882 }
883 }
884}
TH1D * hist
Definition UserFillObj.h:3
std::vector< TSingleDecay * > fDecayChain
Definition TDecay.h:304
void Print(Option_t *option="") const override
Definition TDecay.cxx:563
TDecayFit * fChainFunc
Definition TDecay.h:305
Double_t EvalPar(const Double_t *x, const Double_t *par=nullptr)
Definition TDecay.cxx:604
Double_t Eval(Double_t t) const
Definition TDecay.cxx:521
TSingleDecay * GetDecay(UInt_t generation)
Definition TDecay.cxx:553
static UInt_t fChainCounter
Definition TDecay.h:297
void AddToChain(TSingleDecay *decay)
Definition TDecay.cxx:546
void SetChainParameters()
Definition TDecay.cxx:493
Double_t ChainActivityFunc(Double_t *dim, Double_t *par)
Definition TDecay.cxx:510
TDecayChain()=default
TFitResultPtr Fit(TH1 *fithist, Option_t *opt="")
Definition TDecay.cxx:574
void DrawComponents(Option_t *opt="", Bool_t color_flag=true) override
Definition TDecay.cxx:532
Int_t fChainId
Definition TDecay.h:306
void SetRange(Double_t xlow, Double_t xhigh)
Definition TDecay.cxx:612
void Draw(Option_t *opt="") override
Definition TDecay.cxx:526
TVirtualDecay * fDecay
Definition TDecay.h:83
void DefaultGraphs()
Definition TDecay.cxx:54
void Print(Option_t *opt="") const override
Definition TDecay.cxx:27
TFitResultPtr Fit(TH1 *hist, Option_t *opt="")
Definition TDecay.cxx:39
TGraph fResiduals
Definition TDecay.h:84
void SetDecay(TVirtualDecay *decay)
Definition TDecay.cxx:21
void DrawComponents() const
Definition TDecay.cxx:15
void UpdateResiduals(TH1 *hist)
Definition TDecay.cxx:61
void DrawResiduals()
Definition TDecay.cxx:93
TVirtualDecay * GetDecay() const
Definition TDecay.cxx:34
void DrawComponents(Option_t *opt="", Bool_t color_flag=true) override
Definition TDecay.cxx:769
void PrintMap() const
Definition TDecay.cxx:853
void SetDecayRateLimits(Int_t Id, Double_t low, Double_t high)
Definition TDecay.cxx:829
Double_t DecayFit(Double_t *dim, Double_t *par)
Definition TDecay.cxx:640
Double_t GetBackgroundError() const
Definition TDecay.h:362
TDecayFit * fFitFunc
Definition TDecay.h:381
std::map< Int_t, std::vector< TSingleDecay * > > fDecayMap
Definition TDecay.h:382
TFitResultPtr Fit(TH1 *fithist, Option_t *opt="")
Definition TDecay.cxx:662
std::vector< TDecayChain * > fChainList
Definition TDecay.h:380
void Print(Option_t *opt="") const override
Definition TDecay.cxx:842
void DrawBackground(Option_t *opt="")
Definition TDecay.cxx:791
void RemakeMap()
Definition TDecay.cxx:872
Double_t GetBackground() const
Definition TDecay.h:361
void SetRange(Double_t xlow, Double_t xhigh)
Definition TDecay.cxx:864
void SetHalfLifeLimits(Int_t Id, Double_t low, Double_t high)
Definition TDecay.cxx:816
void SetHalfLife(Int_t Id, Double_t halflife)
Definition TDecay.cxx:803
TDecay()=default
Double_t ComponentFunc(Double_t *dim, Double_t *par)
Definition TDecay.cxx:755
void Draw(Option_t *opt="") override
Definition TDecay.cxx:707
void SetParameters()
Definition TDecay.cxx:713
TDecayChain * GetChain(UInt_t idx)
Definition TDecay.cxx:629
void Fit(TH1 *hist, TF1 *func)
Definition TLMFitter.cxx:35
void SetDecayRate(const Double_t &decayrate)
Definition TDecay.h:150
void Print(Option_t *option="") const override
Definition TDecay.cxx:444
void SetIntensityLimits(const Double_t &low, const Double_t &high)
Definition TDecay.cxx:279
TDecayFit * fTotalDecayFunc
Definition TDecay.h:251
TSingleDecay * GetDaughterDecay()
Definition TDecay.cxx:319
void Fix()
Definition TDecay.cxx:426
void SetDaughterDecay(TSingleDecay *daughter)
Definition TDecay.h:213
Int_t GetDecayId() const
Definition TDecay.h:217
static UInt_t fCounter
Definition TDecay.h:256
Double_t GetHalfLife() const
Definition TDecay.h:132
Double_t GetIntensityError() const
Definition TDecay.h:144
Double_t Eval(Double_t t)
Definition TDecay.cxx:330
void UpdateDecays()
Definition TDecay.cxx:238
void SetTotalDecayParameters()
Definition TDecay.cxx:212
friend class TDecayFit
Definition TDecay.h:113
void GetDecayRateLimits(Double_t &low, Double_t &high) const
Definition TDecay.cxx:309
void Draw(Option_t *option="") override
Definition TDecay.cxx:324
TSingleDecay * GetParentDecay()
Definition TDecay.cxx:314
TSingleDecay * fDaughter
Definition TDecay.h:253
void SetDecayRateLimits(const Double_t &low, const Double_t &high)
Definition TDecay.cxx:285
void SetRange(Double_t tlow, Double_t thigh)
Definition TDecay.cxx:438
Double_t ActivityFunc(Double_t *dim, Double_t *par)
Definition TDecay.cxx:344
void GetIntensityLimits(Double_t &low, Double_t &high) const
Definition TDecay.cxx:304
void FixIntensity()
Definition TDecay.h:182
Double_t GetEfficiency() const
Definition TDecay.h:138
void FixHalfLife()
Definition TDecay.h:166
const TDecayFit * GetDecayFunc() const
Definition TDecay.h:220
TSingleDecay * fFirstParent
Definition TDecay.h:254
void SetName(const char *name) override
Definition TDecay.cxx:205
void SetDecayRateError(Double_t err)
Definition TDecay.h:235
void SetIntensity(const Double_t &intens)
Definition TDecay.h:155
TSingleDecay * fParent
Definition TDecay.h:252
Double_t GetDecayRate() const
Definition TDecay.h:136
TDecayFit * fDecayFunc
Definition TDecay.h:250
void ReleaseIntensity()
Definition TDecay.h:191
TFitResultPtr Fit(TH1 *fithist, Option_t *opt="")
Definition TDecay.cxx:397
void GetHalfLifeLimits(Double_t &low, Double_t &high) const
Definition TDecay.cxx:291
Double_t GetHalfLifeError() const
Definition TDecay.h:139
Double_t GetIntensity() const
Definition TDecay.h:137
void SetIntensityError(Double_t err)
Definition TDecay.h:236
void ReleaseHalfLife()
Definition TDecay.h:189
void Release()
Definition TDecay.cxx:432
UInt_t GetGeneration() const
Definition TDecay.h:131
UInt_t fGeneration
Definition TDecay.h:248
Double_t EvalPar(const Double_t *x, const Double_t *par=nullptr)
Definition TDecay.cxx:337
Int_t fUnId
Definition TDecay.h:255
void SetHalfLifeLimits(const Double_t &low, const Double_t &high)
Definition TDecay.cxx:268
virtual void DrawComponents(Option_t *opt="", Bool_t color_flag=true)
Definition TDecay.cxx:103