GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TGRSIFunctions.cxx
Go to the documentation of this file.
1#include "TGRSIFunctions.h"
2
3#include <iostream>
4
5#include "TMath.h"
6#include "TFitResult.h"
7#ifdef HAS_MATHMORE
8#include "Math/SpecFuncMathMore.h"
9#endif
10
11#include "Globals.h"
12
13// Without this macro the THtml doc for TGRSIFunctions can't be generated
14/// \cond NAMESPACEIMP
16/// \endcond
17
18///////////////////////////////////////////////////////////////////////
19///
20/// \namespace TGRSIFunctions
21///
22/// This namespace is where we store all of our commonly used functions.
23/// This makes it easier to create fits etc.
24///
25////////////////////////////////////////////////////////////////////////
26
27bool TGRSIFunctions::CheckParameterErrors(const TFitResultPtr& fitres, std::string opt)
28{
29 /// This function compares the parameter error with the square root of the corresponding
30 /// diagonal entry of the covariance matrix. If the difference between the two is larger
31 /// than 0.1 (arbitrarily chosen cutoff), the check fails.
32 /// Implemented options are "q" to be quiet (prints nothing), or "v" to be verbose
33 /// (prints message not just for failed parameters but also ones that pass the test).
34
35 // if we do not have a fit result, we have to assume everything is okay for now
36 if(fitres.Get() == nullptr) { return true; }
37 std::transform(opt.begin(), opt.end(), opt.begin(), [](unsigned char c) { return std::tolower(c); });
38 bool quiet = (opt.find('q') != std::string::npos);
39 bool verbose = (opt.find('v') != std::string::npos);
40 if(quiet && verbose) {
41 std::cout << "Don't know how to be quiet and verbose at once (" << opt << "), going to be verbose!" << std::endl;
42 quiet = false;
43 }
44 bool result = true;
45 // loop over all parameters and compare the parameter error with the square root
46 // of the diagonal element of the covariance matrix
47 auto covarianceMatrix = fitres->GetCovarianceMatrix();
48 // if we fail to get a covariance matrix we assume there was a problem in the fit
49 if(covarianceMatrix.GetNrows() != static_cast<Int_t>(fitres->NPar()) || covarianceMatrix.GetNcols() != static_cast<Int_t>(fitres->NPar())) { return false; }
50 for(unsigned int i = 0; i < fitres->NPar(); ++i) {
51 if(std::fabs(fitres->ParError(i) - TMath::Sqrt(covarianceMatrix[i][i])) > 0.1) {
52 if(!quiet) {
53 std::cout << RED << "Parameter " << i << " = " << fitres->GetParameterName(i) << " is at or close to the limit, error is " << fitres->ParError(i) << ", and square root of diagonal is " << TMath::Sqrt(covarianceMatrix[i][i]) << RESET_COLOR << std::endl;
54 }
55 result = false;
56 // we don't break here even though we could, because we want to print out
57 // all parameters with issues
58 } else if(verbose) {
59 std::cout << GREEN << "Parameter " << i << " = " << fitres->GetParameterName(i) << " is not close to the limit, error is " << fitres->ParError(i) << ", and square root of diagonal is " << TMath::Sqrt(covarianceMatrix[i][i]) << RESET_COLOR << std::endl;
60 }
61 }
62 return result;
63}
64
65Double_t TGRSIFunctions::CsIFitFunction(Double_t* time, Double_t* par) // NOLINT(readability-non-const-parameter)
66{
67 /// p[0]-p[4] are t0, tRC, tF, TS, TGamma
68 /// p[5]-p[8] are baseline, AF, AS, AGamma
69
70 Double_t x = time[0] - par[0];
71 Double_t e = exp(-x / par[1]);
72 if(x <= 0) {
73 return par[5];
74 }
75 Double_t s = par[5];
76 s += par[6] * (1 - exp(-x / par[2])) * e;
77 s += par[7] * (1 - exp(-x / par[3])) * e;
78 s += par[8] * (1 - exp(-x / par[4])) * e;
79 return s;
80}
81
82Double_t TGRSIFunctions::PolyBg(Double_t* x, Double_t* par, Int_t order)
83{
84 /// Polynomial function of the form SUM(par[i]*(x - shift)^i). The shift is done to match parameters with Radware output.
85
86 Double_t result = 0.;
87 for(Int_t i = 0; i <= order; i++) {
88 result += par[i] * TMath::Power(x[0] - par[order + 1], i);
89 }
90 return result;
91}
92
93Double_t TGRSIFunctions::StepFunction(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
94{
95 /// This function uses the same parameters as the photopeak and gaussian. This is because in the photopeak, the shapes are correlated.
96 /// Requires the following parameters:
97 /// - dim[0]: channels being fit
98 /// - par[0]: height of photopeak
99 /// - par[1]: centroid of gaussian
100 /// - par[2]: standard deviation of gaussian
101 /// - par[5]: Size of the step in the step function
102
103 Double_t x = dim[0];
104 Double_t height = par[0];
105 Double_t centroid = par[1];
106 Double_t sigma = par[2];
107 Double_t step = par[5];
108
109 return TMath::Abs(step) * height / 100. * TMath::Erfc((x - centroid) / (TMath::Sqrt(2.) * sigma));
110}
111
112Double_t TGRSIFunctions::StepBG(Double_t* dim, Double_t* par)
113{
114 return StepFunction(dim, par) + PolyBg(dim, &par[6], 2);
115}
116
117Double_t TGRSIFunctions::PhotoPeak(Double_t* dim, Double_t* par)
118{
119 /// Returns the combination of a TGRSIFunctions::Gaus + a TGRSIFunctions::SkewedGaus
120 return Gaus(dim, par) + SkewedGaus(dim, par);
121}
122
123Double_t TGRSIFunctions::PhotoPeakBG(Double_t* dim, Double_t* par)
124{
125 /// Returns a single RadWare style peak
126 double result = Gaus(dim, par) + SkewedGaus(dim, par) + StepFunction(dim, par) + PolyBg(dim, &par[6], 2);
127 if(std::isfinite(result)) { return result; }
128 return 0.;
129}
130
131Double_t TGRSIFunctions::MultiPhotoPeakBG(Double_t* dim, Double_t* par)
132{
133 // Limits need to be imposed or error states may occour.
134 int nPeaks = static_cast<int>(par[0] + 0.5);
135 double result = PolyBg(dim, &par[1], 2); // polynomial background. uses par[1->4]
136 for(int i = 0; i < nPeaks; i++) { // par[0] is number of peaks
137 std::array<Double_t, 6> tmpPar;
138 tmpPar[0] = par[6 * i + 5]; // height of photopeak
139 tmpPar[1] = par[6 * i + 6]; // Peak Centroid of non skew gaus
140 tmpPar[2] = par[6 * i + 7]; // standard deviation of gaussian
141 tmpPar[3] = par[6 * i + 8]; //"skewedness" of the skewed gaussian
142 tmpPar[4] = par[6 * i + 9]; // relative height of skewed gaussian
143 tmpPar[5] = par[6 * i + 10]; // Size of step in background
144 result += PhotoPeak(dim, tmpPar.data()) + StepFunction(dim, tmpPar.data());
145 }
146 return result;
147}
148
149Double_t TGRSIFunctions::Gaus(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
150{
151 /// This is a gaussian that has been scaled to match up with Radware photopeak results.
152 /// It contains a scaling factor for the relative height of the skewed gaussian to the
153 /// normal gaussian. Requires the following parameters:
154 /// - dim[0]: channels being fit
155 /// - par[0]: height of photopeak
156 /// - par[1]: centroid of gaussian
157 /// - par[2]: standard deviation of gaussian
158 /// - par[4]: relative height of skewed gaus to gaus
159
160 Double_t x = dim[0]; // channel number used for fitting
161 Double_t height = par[0]; // height of photopeak
162 Double_t centroid = par[1]; // Peak Centroid of non skew gaus
163 Double_t sigma = par[2]; // standard deviation of gaussian
164 Double_t relHeight = par[4]; // relative height of skewed gaussian
165
166 return height * (1. - relHeight / 100.) * TMath::Gaus(x, centroid, sigma);
167}
168
169Double_t TGRSIFunctions::SkewedGaus(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
170{
171 /// This function uses the same parameters as the photopeak and gaussian. This is because in the photopeak,
172 /// the shapes are correlated.
173 /// Requires the following parameters:
174 /// - dim[0]: channels being fit
175 /// - par[0]: height of photopeak
176 /// - par[1]: centroid of gaussian
177 /// - par[2]: standard deviation of gaussian
178 /// - par[3]: "skewedness" of the skewed gaussin
179 /// - par[4]: relative height of skewed gaus to gaus
180
181 Double_t x = dim[0]; // channel number used for fitting
182 Double_t height = par[0]; // height of photopeak
183 Double_t centroid = par[1]; // Peak Centroid of non skew gaus
184 Double_t sigma = par[2]; // standard deviation of gaussian
185 Double_t beta = par[3]; //"skewedness" of the skewed gaussian
186 Double_t relHeight = par[4]; // relative height of skewed gaussian
187 if(beta == 0.) {
188 return 0.;
189 }
190
191 return relHeight * height / 100. * (TMath::Exp((x - centroid) / beta)) *
192 (TMath::Erfc(((x - centroid) / (TMath::Sqrt(2.) * sigma)) + sigma / (TMath::Sqrt(2.) * beta)));
193}
194
195Double_t TGRSIFunctions::MultiSkewedGausWithBG(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
196{
197 // TGRSIFunctions::Set(int num);
198 //
199 // Limits need to be imposed or error states may occour.
200 //
201 double result = par[1] + dim[0] * par[2]; // background.
202 for(int i = 0; i < par[0]; i++) { // par[0] is number of peaks
203 std::array<Double_t, 5> tmpPar;
204 tmpPar[0] = par[5 * i + 3]; // height of photopeak
205 tmpPar[1] = par[5 * i + 4]; // Peak Centroid of non skew gaus
206 tmpPar[2] = par[5 * i + 5]; // standard deviation of gaussian
207 tmpPar[3] = par[5 * i + 6]; //"skewedness" of the skewed gaussian
208 tmpPar[4] = par[5 * i + 7]; // relative height of skewed gaussian
209 result += SkewedGaus(dim, tmpPar.data());
210 }
211 return result;
212}
213
214////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
215////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
216Double_t TGRSIFunctions::SkewedGaus2(Double_t* x, Double_t* par) // NOLINT(readability-non-const-parameter)
217{
218 /// This function is derived from the convolution of a gaussian with an exponential
219 /// Requires the following parameters:
220 /// - par[0]: height of photopeak
221 /// - par[1]: centroid of gaussian
222 /// - par[2]: standard deviation of gaussian
223 /// - par[3]: "skewedness" of the skewed gaussin
224
225 return par[0] * (TMath::Exp((x[0] - par[1]) / par[3])) *
226 (TMath::Erfc(((x[0] - par[1]) / (TMath::Sqrt(2.) * par[2])) + par[2] / (TMath::Sqrt(2.) * par[3])));
227}
228
229Double_t TGRSIFunctions::MultiSkewedGausWithBG2(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
230{
231 // TGRSIFunctions::Set(int num);
232 //
233 // Limits need to be impossed or error states may occour.
234 //
235 double result = par[1] + dim[0] * par[2]; // background.
236 for(int i = 0; i < static_cast<int>(par[0] + 0.5); i++) { // par[0] is number of peaks
237 std::array<Double_t, 4> tmpPar;
238 tmpPar[0] = par[4 * i + 3]; // height of photopeak
239 tmpPar[1] = par[4 * i + 4]; // Peak Centroid of non skew gaus
240 tmpPar[2] = par[4 * i + 5]; // standard deviation of gaussian
241 tmpPar[3] = par[4 * i + 6]; //"skewedness" of the skewed gaussian
242
243 result += SkewedGaus2(dim, tmpPar.data());
244 }
245 return result;
246}
247
248Double_t TGRSIFunctions::LanGaus(Double_t* x, Double_t* pars)
249{
250 double dy = 0.;
251 double y = 0.;
252 double conv = 0.;
253 double spec = 0.;
254 double gaus = 0.;
255
256 for(int i = 0; i < 10; i++) {
257 dy = 5 * pars[3] / 10.; // truncate the convolution by decreasing number of evaluation points and decreasing
258 // range [2.5 sigma still covers 98.8% of gaussian]
259 y = x[0] - 2.5 * pars[3] + dy * i;
260
261 spec = pars[1] +
262 pars[2] * y; // define background SHOULD THIS BE CONVOLUTED ????? *************************************
263 for(int n = 0; n < static_cast<int>(pars[0] + 0.5); n++) {
264 // the implementation of landau function should be done using the landau function
265 spec += pars[3 * n + 4] * TMath::Landau(-y, -pars[3 * n + 5], pars[3 * n + 6]) /
266 TMath::Landau(0, 0, 100); // add peaks, dividing by max height of landau
267 }
268
269 gaus = TMath::Gaus(-x[0], -y, pars[3]) /
270 sqrt(2 * TMath::Pi() * pars[3] * pars[3]); // gaus must be normalisd so there is no sigma weighting
271 conv += gaus * spec * dy; // now convolve this [integrate the product] with a gaussian centered at x;
272 }
273
274 return conv;
275}
276
277Double_t TGRSIFunctions::LanGausHighRes(Double_t* x, Double_t* pars)
278{ // 5x more convolution points with 1.6x larger range
279 double dy = 0.;
280 double y = 0.;
281 double conv = 0.;
282 double spec = 0.;
283 double gaus = 0.;
284
285 for(int i = 0; i < 50; i++) {
286 dy = 8 * pars[3] / 50.; // 4 sigma covers 99.99% of gaussian
287 y = x[0] - 4 * pars[3] + dy * i;
288
289 spec = pars[1] + pars[2] * y;
290 for(int n = 0; n < static_cast<int>(pars[0] + 0.5); n++) {
291 spec += pars[3 * n + 4] * TMath::Landau(-y, -pars[3 * n + 5], pars[3 * n + 6]) / TMath::Landau(0, 0, 100);
292 }
293
294 gaus = TMath::Gaus(-x[0], -y, pars[3]) / sqrt(2 * TMath::Pi() * pars[3] * pars[3]);
295 conv += gaus * spec * dy;
296 }
297 return conv;
298}
299
300Double_t TGRSIFunctions::MultiGausWithBG(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
301{
302 // TGRSIFunctions::Set(int num);
303 //
304 // Limits need to be impossed or error states may occour.
305 //
306 double amp = 0.;
307 double mean = 0.;
308 double sigma = 0.;
309 double result = par[1] + dim[0] * par[2]; // background.
310 for(int i = 0; i < static_cast<int>(par[0] + 0.5); i++) {
311 amp = par[3 * i + 3];
312 mean = par[3 * i + 4];
313 sigma = par[3 * i + 5];
314 result += amp * TMath::Gaus(dim[0], mean, sigma);
315 }
316 return result;
317}
318////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
319////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
320
321Double_t TGRSIFunctions::Bateman(std::vector<Double_t>& dim, std::vector<Double_t>& par, UInt_t nChain, Double_t)
322{
323 ///****NOT TESTED****The Bateman equation is the general closed form for a decay chain of nuclei. This functions
324 /// returns
325 /// the total activity from a given chain of nuclei.
326 /// Requires the following parameters:
327 /// - dim[0]: channels being fit
328 /// - par[0+3*i]: Initial Activity s^(-1)
329 /// - par[1+3*i]: Decay Rate in seconds^(-1)
330 /// - par[2+3*i]: Activity at time t s^(-1)
331 /// NOTE: The lowest paramters correspond to the most 'senior' nuclei
332
333 if(par.size() < (nChain * 3)) {
334 std::cout << "not enough parameters passed to function" << std::endl;
335 return 0;
336 }
337
338 Double_t totalActivity = 0.;
339
340 // LOOP OVER ALL NUCLEI
341
342 for(UInt_t n = 0; n < nChain; n++) {
343 // Calculate this equation for the nth nucleus.
344 Double_t firstterm = 1.;
345 // Compute the first multiplication
346 for(UInt_t j = 0; j < n - 1; j++) {
347 firstterm *= par[1 + 3 * j];
348 }
349 Double_t secondterm = 0.;
350 for(UInt_t i = 0; i < n; i++) {
351 Double_t sum = 0.;
352 for(UInt_t j = i; j < n; j++) {
353 Double_t denom = 1.;
354 for(UInt_t p = i; p < n; p++) {
355 if(p != j) {
356 denom *= par[1 + 3 * p] - par[1 + 3 * j];
357 }
358 }
359 sum += par[0 + 3 * i] / par[1 + 3 * i] * TMath::Exp(-par[1 + 3 * j] * dim[0]) / denom;
360 }
361 secondterm += sum;
362 }
363 par[2 + 3 * n] = par[1 + 3 * n] * firstterm * secondterm;
364 totalActivity += par[2 + 3 * n];
365 }
366 return totalActivity;
367}
368
369Double_t TGRSIFunctions::DeadTimeCorrect(Double_t* dim, Double_t deadtime, Double_t binWidth) // NOLINT(readability-non-const-parameter)
370{
371 // This function deadtime corrects data. Not to be confused with dead time affecting of fit functions
372 // Dead time is in us.
373 // binWidth is in s/bin.
374
375 return dim[0] / (1. - dim[0] * deadtime / (binWidth * 1000000.));
376}
377
378Double_t TGRSIFunctions::DeadTimeAffect(Double_t function, Double_t deadtime, Double_t binWidth)
379{
380 // This function deadtime affects fitting functions. This is useful for counting the number of decays.
381 // Dead time is in us.
382 // binWidth is in s/bin.
383
384 return function / (1. + function * deadtime / (binWidth * 1000000.));
385}
386
387Double_t TGRSIFunctions::LegendrePolynomial(Double_t* x, Double_t* p) // NOLINT(readability-non-const-parameter)
388{
389#ifdef HAS_MATHMORE
390 Double_t val = p[0] * (1 + p[1] * ::ROOT::Math::legendre(2, x[0]) + p[2] * ::ROOT::Math::legendre(4, x[0]));
391 return val;
392#else
393 std::cout << "Mathmore feature of ROOT is missing, " << __PRETTY_FUNCTION__ << " will always return 1!" << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
394 return 1.;
395#endif
396}
397
398Double_t TGRSIFunctions::PhotoEfficiency(Double_t* dim, Double_t* par) // NOLINT(readability-non-const-parameter)
399{
400 double sum = 0.;
401 for(int i = 0; i < 9; ++i) {
402 sum += par[i] * TMath::Power(TMath::Log(dim[0]), i);
403 }
404
405 return TMath::Exp(sum);
406}
407
408//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
409Double_t TGRSIFunctions::ConvolutedDecay(Double_t* x, Double_t* par) // NOLINT(readability-non-const-parameter)
410{
411 /// This function is derived from the convolution of a gaussian with an exponential decay, to fit TAC spectra of long half-lives (above 100 ps)
412 /// Requires the following parameters:
413 /// - par[0]: Normalization factor
414 /// - par[1]: Centroid of gaussian
415 /// - par[2]: Sigma of gaussian
416 /// - par[3]: Lambda of the level
417
418 return TMath::Sqrt(TMath::Pi()) * par[0] * par[3] / 2 * TMath::Exp(par[3] / 2 * (2 * par[1] + par[3] * TMath::Power(par[2], 2) - 2 * x[0])) * TMath::Erfc((par[1] + par[3] * TMath::Power(par[2], 2) - x[0]) / (TMath::Sqrt(2) * par[2])) + par[4];
419}
420
421Double_t TGRSIFunctions::ConvolutedDecay2(Double_t* x, Double_t* par) // NOLINT(readability-non-const-parameter)
422{
423 /// This function is the same as ConvolutedDecay but should be use when the lifetime has two different components.
424 /// Requires the following parameters:
425 /// - par[0]: Weight of lifetime-1
426 /// - par[1]: Centroid of gaussian
427 /// - par[2]: Width of gaussian
428 /// - par[3]: Lambda of the level-1
429 /// - par[4]: Weight of lifetime-2
430 /// - par[5]: Lambda of the level-2
431
432 return TMath::Sqrt(TMath::Pi()) * par[0] * par[3] / 2 * TMath::Exp(par[3] / 2 * (2 * par[1] + par[3] * TMath::Power(par[2], 2) - 2 * x[0])) * TMath::Erfc((par[1] + par[3] * TMath::Power(par[2], 2) - x[0]) / (TMath::Sqrt(2) * par[2])) + TMath::Sqrt(TMath::Pi()) * par[4] * par[5] / 2 * TMath::Exp(par[5] / 2 * (2 * par[1] + par[5] * TMath::Power(par[2], 2) - 2 * x[0])) * TMath::Erfc((par[1] + par[5] * TMath::Power(par[2], 2) - x[0]) / (TMath::Sqrt(2) * par[2]));
433}
434
435////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
436////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
437
438double TGRSIFunctions::ClebschGordan(double j1, double m1, double j2, double m2, double j, double m)
439{
440 // Conditions check
441 if(2 * j1 != floor(2 * j1) ||
442 2 * j2 != floor(2 * j2) ||
443 2 * j != floor(2 * j) ||
444 2 * m1 != floor(2 * m1) ||
445 2 * m2 != floor(2 * m2) ||
446 2 * m != floor(2 * m)) {
447 return 0;
448 }
449 if((m1 + m2) != m) {
450 return 0;
451 }
452 if((j1 - m1) != floor(j1 - m1)) {
453 return 0;
454 }
455 if((j2 - m2) != floor(j2 - m2)) {
456 return 0;
457 }
458 if(j - m != floor(j - m)) {
459 return 0;
460 }
461 if(j > (j1 + j2) || j < abs(j1 - j2)) {
462 return 0;
463 }
464 if(abs(m1) > j1) {
465 return 0;
466 }
467 if(abs(m2) > j2) {
468 return 0;
469 }
470 if(abs(m) > j) {
471 return 0;
472 }
473
474 double term1 = TMath::Sqrt((((2 * j + 1) / TMath::Factorial(static_cast<Int_t>(j1 + j2 + j + 1))) * TMath::Factorial(static_cast<Int_t>(j2 + j - j1)) * TMath::Factorial(static_cast<Int_t>(j + j1 - j2)) * TMath::Factorial(static_cast<Int_t>(j1 + j2 - j)) * TMath::Factorial(static_cast<Int_t>(j1 + m1)) * TMath::Factorial(static_cast<Int_t>(j1 - m1)) * TMath::Factorial(static_cast<Int_t>(j2 + m2)) * TMath::Factorial(static_cast<Int_t>(j2 - m2)) * TMath::Factorial(static_cast<Int_t>(j + m)) * TMath::Factorial(static_cast<Int_t>(j - m))));
475 double sum = 0.;
476 for(int k = 0; k <= 99; k++) {
477 if((j1 + j2 - j - k < 0) || (j1 - m1 - k < 0) || (j2 + m2 - k < 0)) {
478 // no further terms will contribute to sum, exit loop
479 break;
480 }
481 if((j - j1 - m2 + k < 0) || (j - j2 + m1 + k < 0)) {
482 // jump ahead to next term that will contribute
483 const auto a1 = static_cast<Int_t>(j - j1 - m2);
484 const auto a2 = static_cast<Int_t>(j - j2 + m1);
485 k = TMath::Max(-TMath::Min(a1, a2) - 1, k);
486 } else {
487 double term = TMath::Factorial(static_cast<Int_t>(j1 + j2 - j - k)) * TMath::Factorial(static_cast<Int_t>(j - j1 - m2 + k)) * TMath::Factorial(static_cast<Int_t>(j - j2 + m1 + k)) * TMath::Factorial(static_cast<Int_t>(j1 - m1 - k)) * TMath::Factorial(static_cast<Int_t>(j2 + m2 - k)) * TMath::Factorial(k);
488 if((k % 2) == 1) {
489 term *= -1.;
490 }
491 sum += 1. / term;
492 }
493 }
494 return term1 * sum;
495 // Reference: An Effective Algorithm for Calculation of the C.G.
496 // Coefficients Liang Zuo, et. al.
497 // J. Appl. Cryst. (1993). 26, 302-304
498}
499
500double TGRSIFunctions::RacahW(double a, double b, double c, double d, double e, double f)
501{
502#ifdef HAS_MATHMORE
503 // not sure why these are out of order in calling wigner_6j(a, b, e, d, c, f)
504 return TMath::Power(-1., static_cast<int>(a + b + d + c)) * ::ROOT::Math::wigner_6j(static_cast<int>(2 * a), static_cast<int>(2 * b), static_cast<int>(2 * e), static_cast<int>(2 * d), static_cast<int>(2 * c), static_cast<int>(2 * f));
505#else
506 std::cout << "Mathmore feature of ROOT is missing, " << __PRETTY_FUNCTION__ << " will always return 1!" << std::endl; // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-bounds-array-to-pointer-decay)
507 return 1.;
508#endif
509}
510
511double TGRSIFunctions::F(double k, double jf, double L1, double L2, double ji)
512{
513 double cg = TGRSIFunctions::ClebschGordan(L1, 1, L2, -1, k, 0);
514 if(cg == 0) {
515 return 0;
516 }
517 double w = TGRSIFunctions::RacahW(ji, ji, L1, L2, k, jf);
518 if(w == 0) {
519 return 0;
520 }
521 return TMath::Power((-1), (jf - ji - 1)) * TMath::Power((2 * L1 + 1) * (2 * L2 + 1) * (2 * ji + 1), (1. / 2.)) * cg * w;
522 // Reference: Tables of coefficients for angular distribution of gamma rays from aligned nuclei
523 // T. Yamazaki. Nuclear Data A, 3(1):1?23, 1967.
524}
525
526double TGRSIFunctions::A(double k, double ji, double jf, double L1, double L2, double delta)
527{
528 double f1 = F(k, ji, L1, L1, jf);
529 double f2 = F(k, ji, L1, L2, jf);
530 double f3 = F(k, ji, L2, L2, jf);
531
532 return (1. / (1. + TMath::Power(delta, 2))) * (f1 + 2 * delta * f2 + delta * delta * f3);
533}
534
535double TGRSIFunctions::B(double k, double ji, double jf, double L1, double L2, double delta)
536{
537 double f1 = F(k, jf, L1, L1, ji);
538 double f2 = F(k, jf, L1, L2, ji);
539 double f3 = F(k, jf, L2, L2, ji);
540 return (1. / (1. + TMath::Power(delta, 2))) * (f1 + TMath::Power((-1), L1 + L2) * 2 * delta * f2 + delta * delta * f3);
541}
542
543double TGRSIFunctions::CalculateA2(double j1, double j2, double j3, double l1a, double l1b, double l2a, double l2b, double delta1, double delta2)
544{
545 return B(2, j2, j1, l1a, l1b, delta1) * A(2, j3, j2, l2a, l2b, delta2);
546}
547
548double TGRSIFunctions::CalculateA4(double j1, double j2, double j3, double l1a, double l1b, double l2a, double l2b, double delta1, double delta2)
549{
550 return B(4, j2, j1, l1a, l1b, delta1) * A(4, j3, j2, l2a, l2b, delta2);
551}
NamespaceImp(GRootFunctions) Double_t GRootFunctions
#define RED
Definition Globals.h:9
#define GREEN
Definition Globals.h:8
#define RESET_COLOR
Definition Globals.h:5
Double_t MultiPhotoPeakBG(Double_t *dim, Double_t *par)
Double_t MultiSkewedGausWithBG(Double_t *dim, Double_t *par)
Double_t MultiSkewedGausWithBG2(Double_t *dim, Double_t *par)
double F(double k, double jf, double L1, double L2, double ji)
Double_t MultiGausWithBG(Double_t *dim, Double_t *par)
Double_t StepFunction(Double_t *dim, Double_t *par)
double CalculateA2(double j1, double j2, double j3, double l1a, double l1b, double l2a, double l2b, double delta1, double delta2)
Double_t PhotoPeak(Double_t *dim, Double_t *par)
Double_t LegendrePolynomial(Double_t *x, Double_t *p)
Double_t CsIFitFunction(Double_t *time, Double_t *par)
Double_t Bateman(std::vector< Double_t > &dim, std::vector< Double_t > &par, UInt_t nChain=1, Double_t SecondsPerBin=1.0)
Double_t LanGausHighRes(Double_t *x, Double_t *pars)
double CalculateA4(double j1, double j2, double j3, double l1a, double l1b, double l2a, double l2b, double delta1, double delta2)
double RacahW(double a, double b, double c, double d, double e, double f)
Double_t PhotoPeakBG(Double_t *dim, Double_t *par)
Double_t ConvolutedDecay(Double_t *x, Double_t *par)
Double_t DeadTimeAffect(Double_t function, Double_t deadtime, Double_t binWidth=1.0)
Double_t PolyBg(Double_t *x, Double_t *par, Int_t order)
double B(double k, double ji, double jf, double L1, double L2, double delta)
Double_t SkewedGaus2(Double_t *x, Double_t *par)
Double_t DeadTimeCorrect(Double_t *dim, Double_t deadtime, Double_t binWidth=1.0)
double A(double k, double ji, double jf, double L1, double L2, double delta)
Double_t StepBG(Double_t *dim, Double_t *par)
double ClebschGordan(double j1, double m1, double j2, double m2, double j, double m)
Double_t Gaus(Double_t *dim, Double_t *par)
Double_t PhotoEfficiency(Double_t *dim, Double_t *par)
Double_t SkewedGaus(Double_t *dim, Double_t *par)
Double_t ConvolutedDecay2(Double_t *x, Double_t *par)
Double_t LanGaus(Double_t *x, Double_t *pars)