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