musrfit 1.10.0
PTheory.cpp
Go to the documentation of this file.
1/***************************************************************************
2
3 PTheory.cpp
4
5 Author: Andreas Suter
6 e-mail: andreas.suter@psi.ch
7
8***************************************************************************/
9
10/***************************************************************************
11 * Copyright (C) 2007-2026 by Andreas Suter *
12 * andreas.suter@psi.ch *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
28 ***************************************************************************/
29
30#include <iostream>
31#include <vector>
32#include <cmath>
33
34#include <TObject.h>
35#include <TString.h>
36#include <TF1.h>
37#include <TObjString.h>
38#include <TObjArray.h>
39#include <TClass.h>
40#include <TMath.h>
41
42#include <Math/SpecFuncMathMore.h>
43
44#include "PMsrHandler.h"
45#include "PTheory.h"
46
47#define SQRT_TWO 1.41421356237
48#define SQRT_PI 1.77245385091
49
50extern std::vector<void*> gGlobalUserFcn;
51
52//--------------------------------------------------------------------------
53// Constructor
54//--------------------------------------------------------------------------
125PTheory::PTheory(PMsrHandler *msrInfo, UInt_t runNo, const Bool_t hasParent) : fMsrInfo(msrInfo)
126{
127 // init stuff
128 fValid = true;
129 fAdd = nullptr;
130 fMul = nullptr;
131 fUserFcnClassName = TString("");
132 fUserFcn = nullptr;
133 fDynLFdt = 0.0;
134 fSamplingTime = 0.001; // default = 1ns (units in us)
135
136 static UInt_t lineNo = 1; // lineNo
137 static UInt_t depth = 0; // needed to handle '+' properly
138
139 if (hasParent == false) { // reset static counters if root object
140 lineNo = 1; // the lineNo counter and the depth counter need to be
141 depth = 0; // reset for every root object (new run).
142 }
143
144 for (UInt_t i=0; i<THEORY_MAX_PARAM; i++)
145 fPrevParam[i] = 0.0;
146
147 // keep the number of user functions found up to this point
148 fUserFcnIdx = GetUserFcnIdx(lineNo);
149
150 // get the input to be analyzed from the msr handler
151 PMsrLines *fullTheoryBlock = msrInfo->GetMsrTheory();
152 if (lineNo > fullTheoryBlock->size()-1) {
153 return;
154 }
155 // get the line to be parsed
156 PMsrLineStructure *line = &(*fullTheoryBlock)[lineNo];
157
158 // copy line content to str in order to remove comments
159 TString str = line->fLine.Copy();
160
161 // remove theory line comment if present, i.e. something starting with '('
162 Int_t index = str.Index("(");
163 if (index > 0) // theory line comment present
164 str.Resize(index);
165
166 // remove msr-file comment if present, i.e. something starting with '#'
167 index = str.Index("#");
168 if (index > 0) // theory line comment present
169 str.Resize(index);
170
171 // tokenize line
172 TObjArray *tokens;
173 TObjString *ostr;
174
175 tokens = str.Tokenize(" \t");
176 if (!tokens) {
177 std::cerr << std::endl << ">> PTheory::PTheory: **SEVERE ERROR** Couldn't tokenize theory block line " << line->fLineNo << ".";
178 std::cerr << std::endl << ">> line content: " << line->fLine.Data();
179 std::cerr << std::endl;
180 exit(0);
181 }
182 ostr = dynamic_cast<TObjString*>(tokens->At(0));
183 str = ostr->GetString();
184
185 // search the theory function
186 UInt_t idx = SearchDataBase(str);
187
188 // function found is not defined
189 if (idx == static_cast<UInt_t>(THEORY_UNDEFINED)) {
190 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** Theory line '" << line->fLine.Data() << "'";
191 std::cerr << std::endl << ">> in line no " << line->fLineNo << " is undefined!";
192 std::cerr << std::endl;
193 fValid = false;
194 return;
195 }
196
197 // line is a valid function, hence analyze parameters
198 if ((static_cast<UInt_t>(tokens->GetEntries()-1) < fNoOfParam) &&
199 ((idx != THEORY_USER_FCN) && (idx != THEORY_POLYNOM))) {
200 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** Theory line '" << line->fLine.Data() << "'";
201 std::cerr << std::endl << ">> in line no " << line->fLineNo;
202 std::cerr << std::endl << ">> expecting " << fgTheoDataBase[idx].fNoOfParam << ", but found " << tokens->GetEntries()-1;
203 std::cerr << std::endl;
204 fValid = false;
205 }
206 // keep function index
207 fType = idx;
208 // filter out the parameters
209 Int_t status;
210 UInt_t value;
211 Bool_t ok = false;
212 for (Int_t i=1; i<tokens->GetEntries(); i++) {
213 ostr = dynamic_cast<TObjString*>(tokens->At(i));
214 str = ostr->GetString();
215
216 // if userFcn, the first entry is the function name and needs to be handled specially
217 if ((fType == THEORY_USER_FCN) && ((i == 1) || (i == 2))) {
218 if (i == 1) {
220 }
221 if (i == 2) {
222 fUserFcnClassName = str;
223 }
224 continue;
225 }
226
227 // check if str is map
228 if (str.Contains("map")) {
229 status = sscanf(str.Data(), "map%u", &value);
230 if (status == 1) { // everthing ok
231 ok = true;
232 // get parameter from map
233 PIntVector maps = *(*msrInfo->GetMsrRunList())[runNo].GetMap();
234 if ((value <= maps.size()) && (value > 0)) { // everything fine
235 fParamNo.push_back(maps[value-1]-1);
236 } else { // map index out of range
237 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** map index " << value << " out of range! See line no " << line->fLineNo;
238 std::cerr << std::endl;
239 fValid = false;
240 }
241 } else { // something wrong
242 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR**: map '" << str.Data() << "' not allowed. See line no " << line->fLineNo;
243 std::cerr << std::endl;
244 fValid = false;
245 }
246 } else if (str.Contains("fun")) { // check if str is fun
247 status = sscanf(str.Data(), "fun%u", &value);
248 if (status == 1) { // everthing ok
249 ok = true;
250 // handle function, i.e. get, from the function number x (FUNx), the function index,
251 // add function offset and fill "parameter vector"
252 fParamNo.push_back(msrInfo->GetFuncIndex(value)+MSR_PARAM_FUN_OFFSET);
253 } else { // something wrong
254 fValid = false;
255 }
256 } else { // check if str is param no
257 status = sscanf(str.Data(), "%u", &value);
258 if (status == 1) { // everthing ok
259 ok = true;
260 fParamNo.push_back(value-1);
261 }
262 // check if one of the valid entries was found
263 if (!ok) {
264 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** '" << str.Data() << "' not allowed. See line no " << line->fLineNo;
265 std::cerr << std::endl;
266 fValid = false;
267 }
268 }
269 }
270
271 // call the next line (only if valid so far and not the last line)
272 // handle '*'
273 if (fValid && (lineNo < fullTheoryBlock->size()-1)) {
274 line = &(*fullTheoryBlock)[lineNo+1];
275 if (!line->fLine.Contains("+")) { // make sure next line is not a '+'
276 depth++;
277 lineNo++;
278 fMul = new PTheory(msrInfo, runNo, true);
279 depth--;
280 }
281 }
282 // call the next line (only if valid so far and not the last line)
283 // handle '+'
284 if (fValid && (lineNo < fullTheoryBlock->size()-1)) {
285 line = &(*fullTheoryBlock)[lineNo+1];
286 if ((depth == 0) && line->fLine.Contains("+")) {
287 lineNo += 2; // go to the next theory function line
288 fAdd = new PTheory(msrInfo, runNo, true);
289 }
290 }
291
292 // make clean and tidy theory block for the msr-file
293 if (fValid && !hasParent) { // parent theory object
294 MakeCleanAndTidyTheoryBlock(fullTheoryBlock);
295 }
296
297 // check if user function, if so, check if it is reachable (root) and if yes invoke object
298 if (!fUserFcnClassName.IsWhitespace()) {
299 std::cout << std::endl << ">> user function class name: " << fUserFcnClassName.Data() << std::endl;
300 if (!TClass::GetDict(fUserFcnClassName.Data())) {
301 if (gSystem->Load(fUserFcnSharedLibName.Data()) < 0) {
302 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** user function class '" << fUserFcnClassName.Data() << "' not found.";
303 std::cerr << std::endl << ">> Tried to load " << fUserFcnSharedLibName.Data() << " but failed.";
304 std::cerr << std::endl << ">> See line no " << line->fLineNo;
305 std::cerr << std::endl;
306 fValid = false;
307 // clean up
308 if (tokens) {
309 delete tokens;
310 tokens = nullptr;
311 }
312 return;
313 } else if (!TClass::GetDict(fUserFcnClassName.Data())) {
314 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** user function class '" << fUserFcnClassName.Data() << "' not found.";
315 std::cerr << std::endl << ">> " << fUserFcnSharedLibName.Data() << " loaded successfully, but no dictionary present.";
316 std::cerr << std::endl << ">> See line no " << line->fLineNo;
317 std::cerr << std::endl;
318 fValid = false;
319 // clean up
320 if (tokens) {
321 delete tokens;
322 tokens = nullptr;
323 }
324 return;
325 }
326 }
327
328 // invoke user function object
329 fUserFcn = nullptr;
330 fUserFcn = static_cast<PUserFcnBase*>(TClass::GetClass(fUserFcnClassName.Data())->New());
331 if (fUserFcn == nullptr) {
332 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** user function object could not be invoked. See line no " << line->fLineNo;
333 std::cerr << std::endl;
334 fValid = false;
335 return;
336 } else { // user function valid, hence expand the fUserParam vector to the proper size
337 fUserParam.resize(fParamNo.size());
338 }
339
340 // check if the global part of the user function is needed
341 if (fUserFcn->NeedGlobalPart()) {
342 fUserFcn->SetGlobalPart(gGlobalUserFcn, fUserFcnIdx); // invoke or retrieve global user function object
343 if (!fUserFcn->GlobalPartIsValid()) {
344 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** global user function object could not be invoked/retrived. See line no " << line->fLineNo;
345 std::cerr << std::endl;
346 fValid = false;
347 }
348 }
349 }
350
351 // clean up
352 if (tokens) {
353 delete tokens;
354 tokens = nullptr;
355 }
356}
357
358//--------------------------------------------------------------------------
359// Destructor
360//--------------------------------------------------------------------------
376{
377 fParamNo.clear();
378 fUserParam.clear();
379
380 fLFIntegral.clear();
381 fDynLFFuncValue.clear();
382
383 // recursive clean up
384 CleanUp(this);
385
386 if (fUserFcn) {
387 delete fUserFcn;
388 fUserFcn = nullptr;
389 }
390
391 gGlobalUserFcn.clear();
392}
393
394//--------------------------------------------------------------------------
395// IsValid
396//--------------------------------------------------------------------------
416{
417
418 if (fMul) {
419 if (fAdd) {
420 return (fValid && fMul->IsValid() && fAdd->IsValid());
421 } else {
422 return (fValid && fMul->IsValid());
423 }
424 } else {
425 if (fAdd) {
426 return (fValid && fAdd->IsValid());
427 } else {
428 return fValid;
429 }
430 }
431}
432
433//--------------------------------------------------------------------------
468Double_t PTheory::Func(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
469{
470 if (fMul) {
471 if (fAdd) { // fMul != 0 && fAdd != 0
472 switch (fType) {
473 case THEORY_CONST:
474 return Constant(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
475 fAdd->Func(t, paramValues, funcValues);
476 case THEORY_ASYMMETRY:
477 return Asymmetry(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
478 fAdd->Func(t, paramValues, funcValues);
480 return SimpleExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
481 fAdd->Func(t, paramValues, funcValues);
483 return GeneralExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
484 fAdd->Func(t, paramValues, funcValues);
486 return SimpleGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
487 fAdd->Func(t, paramValues, funcValues);
489 return StaticGaussKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
490 fAdd->Func(t, paramValues, funcValues);
492 return StaticGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
493 fAdd->Func(t, paramValues, funcValues);
495 return DynamicGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
496 fAdd->Func(t, paramValues, funcValues);
498 return StaticLorentzKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
499 fAdd->Func(t, paramValues, funcValues);
501 return StaticLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
502 fAdd->Func(t, paramValues, funcValues);
504 return DynamicLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
505 fAdd->Func(t, paramValues, funcValues);
507 return DynamicGauLorKTZFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
508 fAdd->Func(t, paramValues, funcValues);
510 return DynamicGauLorKTLFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
511 fAdd->Func(t, paramValues, funcValues);
513 return DynamicGauLorKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
514 fAdd->Func(t, paramValues, funcValues);
516 return CombiLGKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
517 fAdd->Func(t, paramValues, funcValues);
518 case THEORY_STR_KT:
519 return StrKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
520 fAdd->Func(t, paramValues, funcValues);
522 return SpinGlass(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
523 fAdd->Func(t, paramValues, funcValues);
525 return RandomAnisotropicHyperfine(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
526 fAdd->Func(t, paramValues, funcValues);
527 case THEORY_ABRAGAM:
528 return Abragam(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
529 fAdd->Func(t, paramValues, funcValues);
530 case THEORY_TF_COS:
531 return TFCos(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
532 fAdd->Func(t, paramValues, funcValues);
534 return InternalField(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
535 fAdd->Func(t, paramValues, funcValues);
537 return InternalFieldGK(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
538 fAdd->Func(t, paramValues, funcValues);
540 return InternalFieldLL(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
541 fAdd->Func(t, paramValues, funcValues);
542 case THEORY_BESSEL:
543 return Bessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
544 fAdd->Func(t, paramValues, funcValues);
546 return InternalBessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
547 fAdd->Func(t, paramValues, funcValues);
549 return SkewedGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
550 fAdd->Func(t, paramValues, funcValues);
552 return StaticNKZF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
553 fAdd->Func(t, paramValues, funcValues);
555 return StaticNKTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
556 fAdd->Func(t, paramValues, funcValues);
558 return DynamicNKZF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
559 fAdd->Func(t, paramValues, funcValues);
561 return DynamicNKTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
562 fAdd->Func(t, paramValues, funcValues);
563 case THEORY_F_MU_F:
564 return FmuF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
565 fAdd->Func(t, paramValues, funcValues);
566 case THEORY_POLYNOM:
567 return Polynom(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
568 fAdd->Func(t, paramValues, funcValues);
570 return MuMinusExpTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
571 fAdd->Func(t, paramValues, funcValues);
572 case THEORY_USER_FCN:
573 return UserFcn(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
574 fAdd->Func(t, paramValues, funcValues);
575 default:
576 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
577 std::cerr << std::endl;
578 exit(0);
579 }
580 } else { // fMul !=0 && fAdd == 0
581 switch (fType) {
582 case THEORY_CONST:
583 return Constant(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
584 case THEORY_ASYMMETRY:
585 return Asymmetry(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
587 return SimpleExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
589 return GeneralExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
591 return SimpleGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
593 return StaticGaussKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
595 return StaticGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
597 return DynamicGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
599 return StaticLorentzKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
601 return StaticLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
603 return DynamicLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
605 return DynamicGauLorKTZFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
607 return DynamicGauLorKTLFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
609 return DynamicGauLorKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
611 return CombiLGKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
612 case THEORY_STR_KT:
613 return StrKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
615 return SpinGlass(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
617 return RandomAnisotropicHyperfine(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
618 case THEORY_ABRAGAM:
619 return Abragam(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
620 case THEORY_TF_COS:
621 return TFCos(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
623 return InternalField(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
625 return InternalFieldGK(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
627 return InternalFieldLL(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
628 case THEORY_BESSEL:
629 return Bessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
631 return InternalBessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
633 return SkewedGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
635 return StaticNKZF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
637 return StaticNKTF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
639 return DynamicNKZF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
641 return DynamicNKTF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
643 return MuMinusExpTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
644 case THEORY_F_MU_F:
645 return FmuF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
646 case THEORY_POLYNOM:
647 return Polynom(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
648 case THEORY_USER_FCN:
649 return UserFcn(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
650 default:
651 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
652 std::cerr << std::endl;
653 exit(0);
654 }
655 }
656 } else { // fMul == 0 && fAdd != 0
657 if (fAdd) {
658 switch (fType) {
659 case THEORY_CONST:
660 return Constant(paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
661 case THEORY_ASYMMETRY:
662 return Asymmetry(paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
664 return SimpleExp(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
666 return GeneralExp(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
668 return SimpleGauss(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
670 return StaticGaussKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
672 return StaticGaussKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
674 return DynamicGaussKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
676 return StaticLorentzKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
678 return StaticLorentzKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
680 return DynamicLorentzKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
682 return DynamicGauLorKTZFFast(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
684 return DynamicGauLorKTLFFast(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
686 return DynamicGauLorKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
688 return CombiLGKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
689 case THEORY_STR_KT:
690 return StrKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
692 return SpinGlass(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
694 return RandomAnisotropicHyperfine(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
695 case THEORY_ABRAGAM:
696 return Abragam(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
697 case THEORY_TF_COS:
698 return TFCos(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
700 return InternalField(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
702 return InternalFieldGK(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
704 return InternalFieldLL(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
705 case THEORY_BESSEL:
706 return Bessel(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
708 return InternalBessel(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
710 return SkewedGauss(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
712 return StaticNKZF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
714 return StaticNKTF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
716 return DynamicNKZF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
718 return DynamicNKTF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
720 return MuMinusExpTF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
721 case THEORY_F_MU_F:
722 return FmuF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
723 case THEORY_POLYNOM:
724 return Polynom(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
725 case THEORY_USER_FCN:
726 return UserFcn(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
727 default:
728 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
729 std::cerr << std::endl;
730 exit(0);
731 }
732 } else { // fMul == 0 && fAdd == 0
733 switch (fType) {
734 case THEORY_CONST:
735 return Constant(paramValues, funcValues);
736 case THEORY_ASYMMETRY:
737 return Asymmetry(paramValues, funcValues);
739 return SimpleExp(t, paramValues, funcValues);
741 return GeneralExp(t, paramValues, funcValues);
743 return SimpleGauss(t, paramValues, funcValues);
745 return StaticGaussKT(t, paramValues, funcValues);
747 return StaticGaussKTLF(t, paramValues, funcValues);
749 return DynamicGaussKTLF(t, paramValues, funcValues);
751 return StaticLorentzKT(t, paramValues, funcValues);
753 return StaticLorentzKTLF(t, paramValues, funcValues);
755 return DynamicLorentzKTLF(t, paramValues, funcValues);
757 return DynamicGauLorKTZFFast(t, paramValues, funcValues);
759 return DynamicGauLorKTLFFast(t, paramValues, funcValues);
761 return DynamicGauLorKTLF(t, paramValues, funcValues);
763 return CombiLGKT(t, paramValues, funcValues);
764 case THEORY_STR_KT:
765 return StrKT(t, paramValues, funcValues);
767 return SpinGlass(t, paramValues, funcValues);
769 return RandomAnisotropicHyperfine(t, paramValues, funcValues);
770 case THEORY_ABRAGAM:
771 return Abragam(t, paramValues, funcValues);
772 case THEORY_TF_COS:
773 return TFCos(t, paramValues, funcValues);
775 return InternalField(t, paramValues, funcValues);
777 return InternalFieldGK(t, paramValues, funcValues);
779 return InternalFieldLL(t, paramValues, funcValues);
780 case THEORY_BESSEL:
781 return Bessel(t, paramValues, funcValues);
783 return InternalBessel(t, paramValues, funcValues);
785 return SkewedGauss(t, paramValues, funcValues);
787 return StaticNKZF(t, paramValues, funcValues);
789 return StaticNKTF(t, paramValues, funcValues);
791 return DynamicNKZF(t, paramValues, funcValues);
793 return DynamicNKTF(t, paramValues, funcValues);
795 return MuMinusExpTF(t, paramValues, funcValues);
796 case THEORY_F_MU_F:
797 return FmuF(t, paramValues, funcValues);
798 case THEORY_POLYNOM:
799 return Polynom(t, paramValues, funcValues);
800 case THEORY_USER_FCN:
801 return UserFcn(t, paramValues, funcValues);
802 default:
803 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
804 std::cerr << std::endl;
805 exit(0);
806 }
807 }
808 }
809}
810
811//--------------------------------------------------------------------------
831{
832 if (theo->fMul) { // '*' present
833 delete theo->fMul;
834 theo->fMul = nullptr;
835 }
836
837 if (theo->fAdd) {
838 delete theo->fAdd;
839 theo->fAdd = nullptr;
840 }
841}
842
843//--------------------------------------------------------------------------
862Int_t PTheory::SearchDataBase(TString name)
863{
864 Int_t idx = THEORY_UNDEFINED;
865
866 for (UInt_t i=0; i<THEORY_MAX; i++) {
867 if (!name.CompareTo(fgTheoDataBase[i].fName, TString::kIgnoreCase) ||
868 !name.CompareTo(fgTheoDataBase[i].fAbbrev, TString::kIgnoreCase)) {
869 idx = static_cast<Int_t>(fgTheoDataBase[i].fType);
870 fType = fgTheoDataBase[i].fType;
871 fNoOfParam = fgTheoDataBase[i].fNoOfParam;
872 }
873 }
874
875 return idx;
876}
877
878//--------------------------------------------------------------------------
879// GetUserFcnIdx (private)
880//--------------------------------------------------------------------------
896Int_t PTheory::GetUserFcnIdx(UInt_t lineNo) const
897{
898 Int_t userFcnIdx = -1;
899
900 // retrieve the theory block from the msr-file handler
901 PMsrLines *fullTheoryBlock = fMsrInfo->GetMsrTheory();
902
903 // make sure that lineNo is within proper bounds
904 if (lineNo > fullTheoryBlock->size())
905 return userFcnIdx;
906
907 // count the number of user function present up to the lineNo
908 for (UInt_t i=1; i<=lineNo; i++) {
909 if (fullTheoryBlock->at(i).fLine.Contains("userFcn", TString::kIgnoreCase))
910 userFcnIdx++;
911 }
912
913 return userFcnIdx;
914}
915
916//--------------------------------------------------------------------------
917// MakeCleanAndTidyTheoryBlock private
918//--------------------------------------------------------------------------
944{
945 PMsrLineStructure *line;
946 TString str, tidy;
947 Char_t substr[256];
948 TObjArray *tokens = nullptr;
949 TObjString *ostr = nullptr;
950 Int_t idx = THEORY_UNDEFINED;
951
952 for (UInt_t i=1; i<fullTheoryBlock->size(); i++) {
953 // get the line to be prettyfied
954 line = &(*fullTheoryBlock)[i];
955 // copy line content to str in order to remove comments
956 str = line->fLine.Copy();
957 // remove theory line comment if present, i.e. something starting with '('
958 Int_t index = str.Index("(");
959 if (index > 0) // theory line comment present
960 str.Resize(index);
961 // tokenize line
962 tokens = str.Tokenize(" \t");
963 // make a handable string out of the asymmetry token
964 ostr = dynamic_cast<TObjString*>(tokens->At(0));
965 str = ostr->GetString();
966 // check if the line is just a '+' if so nothing to be done
967 if (str.Contains("+"))
968 continue;
969 // check if the function is a polynom
970 if (!str.CompareTo("p") || str.Contains("polynom")) {
971 MakeCleanAndTidyPolynom(i, fullTheoryBlock);
972 continue;
973 }
974 // check if the function is a userFcn
975 if (!str.CompareTo("u") || str.Contains("userFcn")) {
976 MakeCleanAndTidyUserFcn(i, fullTheoryBlock);
977 continue;
978 }
979 // search the theory function
980 for (UInt_t j=0; j<THEORY_MAX; j++) {
981 if (!str.CompareTo(fgTheoDataBase[j].fName, TString::kIgnoreCase) ||
982 !str.CompareTo(fgTheoDataBase[j].fAbbrev, TString::kIgnoreCase)) {
983 idx = static_cast<Int_t>(fgTheoDataBase[j].fType);
984 }
985 }
986 // check if theory is indeed defined. This should not be necessay at this point but ...
987 if (idx == THEORY_UNDEFINED)
988 return;
989 // check that there enough tokens. This should not be necessay at this point but ...
990 if (static_cast<UInt_t>(tokens->GetEntries()) < fgTheoDataBase[idx].fNoOfParam + 1)
991 return;
992 // make tidy string
993 snprintf(substr, sizeof(substr), "%-10s", fgTheoDataBase[idx].fName.Data());
994 tidy = TString(substr);
995 for (Int_t j=1; j<tokens->GetEntries(); j++) {
996 ostr = dynamic_cast<TObjString*>(tokens->At(j));
997 str = ostr->GetString();
998 snprintf(substr, sizeof(substr), "%6s", str.Data());
999 tidy += TString(substr);
1000 }
1001 if (fgTheoDataBase[idx].fComment.Length() != 0) {
1002 if (tidy.Length() < 35) {
1003 for (Int_t k=0; k<35-tidy.Length(); k++)
1004 tidy += TString(" ");
1005 } else {
1006 tidy += TString(" ");
1007 }
1008 if (static_cast<UInt_t>(tokens->GetEntries()) == fgTheoDataBase[idx].fNoOfParam + 1) // no tshift
1009 tidy += fgTheoDataBase[idx].fComment;
1010 else
1011 tidy += fgTheoDataBase[idx].fCommentTimeShift;
1012 }
1013 // write tidy string back into theory block
1014 (*fullTheoryBlock)[i].fLine = tidy;
1015
1016 // clean up
1017 if (tokens) {
1018 delete tokens;
1019 tokens = nullptr;
1020 }
1021 }
1022
1023}
1024
1025//--------------------------------------------------------------------------
1026// MakeCleanAndTidyPolynom private
1027//--------------------------------------------------------------------------
1040void PTheory::MakeCleanAndTidyPolynom(UInt_t i, PMsrLines *fullTheoryBlock)
1041{
1042 PMsrLineStructure *line;
1043 TString str, tidy;
1044 TObjArray *tokens = nullptr;
1045 TObjString *ostr;
1046 Char_t substr[256];
1047
1048 // init tidy
1049 tidy = TString("polynom ");
1050 // get the line to be prettyfied
1051 line = &(*fullTheoryBlock)[i];
1052 // copy line content to str in order to remove comments
1053 str = line->fLine.Copy();
1054 // tokenize line
1055 tokens = str.Tokenize(" \t");
1056
1057 // check if comment is already present, and if yes ignore it by setting max correctly
1058 Int_t max = tokens->GetEntries();
1059 for (Int_t j=1; j<max; j++) {
1060 ostr = dynamic_cast<TObjString*>(tokens->At(j));
1061 str = ostr->GetString();
1062 if (str.Contains("(")) { // comment present
1063 max=j;
1064 break;
1065 }
1066 }
1067
1068 for (Int_t j=1; j<max; j++) {
1069 ostr = dynamic_cast<TObjString*>(tokens->At(j));
1070 str = ostr->GetString();
1071 snprintf(substr, sizeof(substr), "%6s", str.Data());
1072 tidy += TString(substr);
1073 }
1074
1075 // add comment
1076 tidy += " (tshift p0 p1 ... pn)";
1077
1078 // write tidy string back into theory block
1079 (*fullTheoryBlock)[i].fLine = tidy;
1080
1081 // clean up
1082 if (tokens) {
1083 delete tokens;
1084 tokens = nullptr;
1085 }
1086}
1087
1088//--------------------------------------------------------------------------
1089// MakeCleanAndTidyUserFcn private
1090//--------------------------------------------------------------------------
1103void PTheory::MakeCleanAndTidyUserFcn(UInt_t i, PMsrLines *fullTheoryBlock)
1104{
1105 PMsrLineStructure *line;
1106 TString str, tidy;
1107 TObjArray *tokens = nullptr;
1108 TObjString *ostr;
1109
1110 // init tidy
1111 tidy = TString("userFcn ");
1112 // get the line to be prettyfied
1113 line = &(*fullTheoryBlock)[i];
1114 // copy line content to str in order to remove comments
1115 str = line->fLine.Copy();
1116 // tokenize line
1117 tokens = str.Tokenize(" \t");
1118
1119 for (Int_t j=1; j<tokens->GetEntries(); j++) {
1120 ostr = dynamic_cast<TObjString*>(tokens->At(j));
1121 str = ostr->GetString();
1122 tidy += TString(" ") + str;
1123 }
1124
1125 // write tidy string back into theory block
1126 (*fullTheoryBlock)[i].fLine = tidy;
1127
1128 // clean up
1129 if (tokens) {
1130 delete tokens;
1131 tokens = nullptr;
1132 }
1133}
1134
1135//--------------------------------------------------------------------------
1152Double_t PTheory::Constant(const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1153{
1154 // expected parameters: const
1155
1156 Double_t constant;
1157
1158 // check if FUNCTIONS are used
1159 if (fParamNo[0] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1160 constant = paramValues[fParamNo[0]];
1161 } else {
1162 constant = funcValues[fParamNo[0]-MSR_PARAM_FUN_OFFSET];
1163 }
1164
1165 return constant;
1166}
1167
1168//--------------------------------------------------------------------------
1187Double_t PTheory::Asymmetry(const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1188{
1189 // expected parameters: asym
1190
1191 Double_t asym;
1192
1193 // check if FUNCTIONS are used
1194 if (fParamNo[0] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1195 asym = paramValues[fParamNo[0]];
1196 } else {
1197 asym = funcValues[fParamNo[0]-MSR_PARAM_FUN_OFFSET];
1198 }
1199
1200 return asym;
1201}
1202
1203//--------------------------------------------------------------------------
1225Double_t PTheory::SimpleExp(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1226{
1227 // expected parameters: lambda [tshift]
1228
1229 Double_t val[2];
1230
1231 assert(fParamNo.size() <= 2);
1232
1233 // check if FUNCTIONS are used
1234 for (UInt_t i=0; i<fParamNo.size(); i++) {
1235 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1236 val[i] = paramValues[fParamNo[i]];
1237 } else { // function
1238 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1239 }
1240 }
1241
1242 Double_t tt;
1243 if (fParamNo.size() == 1) // no tshift
1244 tt = t;
1245 else // tshift present
1246 tt = t-val[1];
1247
1248 return TMath::Exp(-tt*val[0]);
1249}
1250
1251//--------------------------------------------------------------------------
1277Double_t PTheory::GeneralExp(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1278{
1279 // expected parameters: lambda beta [tshift]
1280
1281 Double_t val[3];
1282 Double_t result;
1283
1284 assert(fParamNo.size() <= 3);
1285
1286 // check if FUNCTIONS are used
1287 for (UInt_t i=0; i<fParamNo.size(); i++) {
1288 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1289 val[i] = paramValues[fParamNo[i]];
1290 } else { // function
1291 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1292 }
1293 }
1294
1295 Double_t tt;
1296 if (fParamNo.size() == 2) // no tshift
1297 tt = t;
1298 else // tshift present
1299 tt = t-val[2];
1300
1301 // check if tt*val[0] < 0 and
1302 if ((tt*val[0] < 0) && (trunc(val[1])-val[1] != 0.0)) {
1303 result = 0.0;
1304 } else {
1305 result = TMath::Exp(-TMath::Power(tt*val[0], val[1]));
1306 }
1307
1308 return result;
1309}
1310
1311//--------------------------------------------------------------------------
1334Double_t PTheory::SimpleGauss(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1335{
1336 // expected parameters: sigma [tshift]
1337
1338 Double_t val[2];
1339
1340 assert(fParamNo.size() <= 2);
1341
1342 // check if FUNCTIONS are used
1343 for (UInt_t i=0; i<fParamNo.size(); i++) {
1344 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1345 val[i] = paramValues[fParamNo[i]];
1346 } else { // function
1347 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1348 }
1349 }
1350
1351 Double_t tt;
1352 if (fParamNo.size() == 1) // no tshift
1353 tt = t;
1354 else // tshift present
1355 tt = t-val[1];
1356
1357 return TMath::Exp(-0.5*TMath::Power(tt*val[0], 2.0));
1358}
1359
1360//--------------------------------------------------------------------------
1390Double_t PTheory::StaticGaussKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1391{
1392 // expected parameters: sigma [tshift]
1393
1394 Double_t val[2];
1395
1396 assert(fParamNo.size() <= 2);
1397
1398 // check if FUNCTIONS are used
1399 for (UInt_t i=0; i<fParamNo.size(); i++) {
1400 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1401 val[i] = paramValues[fParamNo[i]];
1402 } else { // function
1403 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1404 }
1405 }
1406
1407 Double_t sigma_t_2;
1408 if (fParamNo.size() == 1) // no tshift
1409 sigma_t_2 = t*t*val[0]*val[0];
1410 else // tshift present
1411 sigma_t_2 = (t-val[1])*(t-val[1])*val[0]*val[0];
1412
1413 return 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
1414}
1415
1416//--------------------------------------------------------------------------
1432Double_t PTheory::StaticGaussKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1433{
1434
1435 // expected parameters: frequency damping [tshift]
1436
1437 Double_t val[3];
1438 Double_t result;
1439
1440 assert(fParamNo.size() <= 3);
1441
1442 // check if FUNCTIONS are used
1443 for (UInt_t i=0; i<fParamNo.size(); i++) {
1444 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1445 val[i] = paramValues[fParamNo[i]];
1446 } else { // function
1447 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1448 }
1449 }
1450
1451 // check if all parameters == 0
1452 if ((val[0] == 0.0) && (val[1] == 0.0))
1453 return 1.0;
1454
1455 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1456 // check only the first two parameters since the tshift is irrelevant for the LF-integral calculation!!
1457 Bool_t newParam = false;
1458 for (UInt_t i=0; i<2; i++) {
1459 if (val[i] != fPrevParam[i]) {
1460 newParam = true;
1461 break;
1462 }
1463 }
1464
1465 if (newParam) { // new parameters found
1466 {
1467 for (UInt_t i=0; i<2; i++)
1468 fPrevParam[i] = val[i];
1470 }
1471 }
1472
1473 Double_t tt;
1474 if (fParamNo.size() == 2) // no tshift
1475 tt = t;
1476 else // tshift present
1477 tt = t-val[2];
1478
1479 if (tt < 0.0) // for times < 0 return a function value of 1.0
1480 return 1.0;
1481
1482 Double_t sigma_t_2 = 0.0;
1483 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use the ZF formula
1484 sigma_t_2 = tt*tt*val[1]*val[1];
1485 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
1486 } else if (val[1]/val[0] > 79.5775) { // check if Delta/w0 > 500.0, in which case the ZF formula is used
1487 sigma_t_2 = tt*tt*val[1]*val[1];
1488 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
1489 } else {
1490 Double_t delta = val[1];
1491 Double_t w0 = 2.0*TMath::Pi()*val[0];
1492
1493 result = 1.0 - 2.0*TMath::Power(delta/w0,2.0)*(1.0 -
1494 TMath::Exp(-0.5*TMath::Power(delta*tt, 2.0))*TMath::Cos(w0*tt)) +
1496 }
1497
1498 return result;
1499
1500}
1501
1502//--------------------------------------------------------------------------
1521Double_t PTheory::DynamicGaussKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1522{
1523 // expected parameters: frequency damping hopping [tshift]
1524
1525 Double_t val[4];
1526 Double_t result = 0.0;
1527 Bool_t useKeren = false;
1528
1529 assert(fParamNo.size() <= 4);
1530
1531 // check if FUNCTIONS are used
1532 for (UInt_t i=0; i<fParamNo.size(); i++) {
1533 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1534 val[i] = paramValues[fParamNo[i]];
1535 } else { // function
1536 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1537 }
1538 }
1539
1540 // check if all parameters == 0
1541 if ((val[0] == 0.0) && (val[1] == 0.0) && (val[2] == 0.0))
1542 return 1.0;
1543
1544 // make sure that damping and hopping are positive definite
1545 if (val[1] < 0.0)
1546 val[1] = -val[1];
1547 if (val[2] < 0.0)
1548 val[2] = -val[2];
1549
1550 // check that Delta != 0, if not (i.e. stupid parameter) return 1, which is the correct limit
1551 if (fabs(val[1]) < 1.0e-6) {
1552 return 1.0;
1553 }
1554
1555 // check if Keren approximation can be used
1556 if (val[2]/val[1] > 5.0) // nu/Delta > 5.0
1557 useKeren = true;
1558
1559 if (!useKeren) {
1560 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1561 // check only the first three parameters since the tshift is irrelevant for the LF-integral calculation!!
1562 Bool_t newParam = false;
1563 for (UInt_t i=0; i<3; i++) {
1564 if (val[i] != fPrevParam[i]) {
1565 newParam = true;
1566 break;
1567 }
1568 }
1569
1570 if (newParam) { // new parameters found
1571 for (UInt_t i=0; i<3; i++)
1572 fPrevParam[i] = val[i];
1573 CalculateDynKTLF(val, 0); // 0 means Gauss
1574 }
1575 }
1576
1577 Double_t tt;
1578 if (fParamNo.size() == 3) // no tshift
1579 tt = t;
1580 else // tshift present
1581 tt = t-val[3];
1582
1583 if (tt < 0.0) // for times < 0 return a function value of 0.0
1584 return 0.0;
1585
1586
1587 if (useKeren) { // see PRB50, 10039 (1994)
1588 Double_t wL = TWO_PI * val[0];
1589 Double_t wL2 = wL*wL;
1590 Double_t nu2 = val[2]*val[2];
1591 Double_t Gamma_t = 2.0*val[1]*val[1]/((wL2+nu2)*(wL2+nu2))*
1592 ((wL2+nu2)*val[2]*t
1593 + (wL2-nu2)*(1.0 - TMath::Exp(-val[2]*t)*TMath::Cos(wL*t))
1594 - 2.0*val[2]*wL*TMath::Exp(-val[2]*t)*TMath::Sin(wL*t));
1595 result = TMath::Exp(-Gamma_t);
1596 } else { // from Voltera
1597 result = GetDynKTLFValue(tt);
1598 }
1599
1600 return result;
1601
1602}
1603
1604//--------------------------------------------------------------------------
1619Double_t PTheory::StaticLorentzKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1620{
1621 // expected parameters: lambda [tshift]
1622
1623 Double_t val[2];
1624
1625 assert(fParamNo.size() <= 2);
1626
1627 // check if FUNCTIONS are used
1628 for (UInt_t i=0; i<fParamNo.size(); i++) {
1629 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1630 val[i] = paramValues[fParamNo[i]];
1631 } else { // function
1632 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1633 }
1634 }
1635
1636 Double_t a_t;
1637 if (fParamNo.size() == 1) // no tshift
1638 a_t = t*val[0];
1639 else // tshift present
1640 a_t = (t-val[1])*val[0];
1641
1642 return 0.333333333333333 * (1.0 + 2.0*(1.0 - a_t)*TMath::Exp(-a_t));
1643}
1644
1645//--------------------------------------------------------------------------
1662Double_t PTheory::StaticLorentzKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1663{
1664 // expected parameters: frequency damping [tshift]
1665
1666 Double_t val[3];
1667 Double_t result;
1668
1669 assert(fParamNo.size() <= 3);
1670
1671 // check if FUNCTIONS are used
1672 for (UInt_t i=0; i<fParamNo.size(); i++) {
1673 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1674 val[i] = paramValues[fParamNo[i]];
1675 } else { // function
1676 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1677 }
1678 }
1679
1680 // check if all parameters == 0
1681 if ((val[0] == 0.0) && (val[1] == 0.0))
1682 return 1.0;
1683
1684 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1685 // check only the first two parameters since the tshift is irrelevant for the LF-integral calculation!!
1686 Bool_t newParam = false;
1687 for (UInt_t i=0; i<2; i++) {
1688 if (val[i] != fPrevParam[i]) {
1689 newParam = true;
1690 break;
1691 }
1692 }
1693
1694 if (newParam) { // new parameters found
1695 for (UInt_t i=0; i<2; i++)
1696 fPrevParam[i] = val[i];
1698 }
1699
1700 Double_t tt;
1701 if (fParamNo.size() == 2) // no tshift
1702 tt = t;
1703 else // tshift present
1704 tt = t-val[2];
1705
1706 if (tt < 0.0) // for times < 0 return a function value of 1.0
1707 return 1.0;
1708
1709 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use the ZF formula
1710 Double_t at = tt*val[1];
1711 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
1712 } else if (val[1]/val[0] > 159.1549) { // check if a/w0 > 1000.0, in which case the ZF formula is used
1713 Double_t at = tt*val[1];
1714 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
1715 } else {
1716 Double_t a = val[1];
1717 Double_t at = a*tt;
1718 Double_t w0 = 2.0*TMath::Pi()*val[0];
1719 Double_t a_w0 = a/w0;
1720 Double_t w0t = w0*tt;
1721
1722 Double_t j1, j0;
1723 if (fabs(w0t) < 0.001) { // check zero time limits of the spherical bessel functions j0(x) and j1(x)
1724 j0 = 1.0;
1725 j1 = 0.0;
1726 } else {
1727 j0 = sin(w0t)/w0t;
1728 j1 = (sin(w0t)-w0t*cos(w0t))/(w0t*w0t);
1729 }
1730
1731 result = 1.0 - a_w0*j1*exp(-at) - a_w0*a_w0*(j0*exp(-at) - 1.0) - GetLFIntegralValue(tt);
1732 }
1733
1734 return result;
1735
1736}
1737
1738//--------------------------------------------------------------------------
1759Double_t PTheory::DynamicLorentzKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1760{
1761 // expected parameters: frequency damping hopping [tshift]
1762
1763 Double_t val[4];
1764 Double_t result = 0.0;
1765
1766 assert(fParamNo.size() <= 4);
1767
1768 // check if FUNCTIONS are used
1769 for (UInt_t i=0; i<fParamNo.size(); i++) {
1770 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1771 val[i] = paramValues[fParamNo[i]];
1772 } else { // function
1773 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1774 }
1775 }
1776
1777 // check if all parameters == 0
1778 if ((val[0] == 0.0) && (val[1] == 0.0) && (val[2] == 0.0))
1779 return 1.0;
1780
1781 // make sure that damping and hopping are positive definite
1782 if (val[1] < 0.0)
1783 val[1] = -val[1];
1784 if (val[2] < 0.0)
1785 val[2] = -val[2];
1786
1787
1788 Double_t tt;
1789 if (fParamNo.size() == 3) // no tshift
1790 tt = t;
1791 else // tshift present
1792 tt = t-val[3];
1793
1794 if (tt < 0.0) // for times < 0 return a function value of 1.0
1795 return 1.0;
1796
1797 // check if hopping > 5 * damping, of Larmor angular frequency is > 30 * damping (BMW limit)
1798 Double_t w0 = 2.0*TMath::Pi()*val[0];
1799 Double_t a = val[1];
1800 Double_t nu = val[2];
1801 if ((nu > 5.0 * a) || (w0 >= 30.0 * a)) {
1802 // 'c' and 'd' are parameters BMW obtained by fitting large parameter space LF-curves to the model below
1803 const Double_t c[7] = {1.15331, 1.64826, -0.71763, 3.0, 0.386683, -5.01876, 2.41854};
1804 const Double_t d[4] = {2.44056, 2.92063, 1.69581, 0.667277};
1805 Double_t w0N[4];
1806 Double_t nuN[4];
1807 w0N[0] = w0;
1808 nuN[0] = nu;
1809 for (UInt_t i=1; i<4; i++) {
1810 w0N[i] = w0 * w0N[i-1];
1811 nuN[i] = nu * nuN[i-1];
1812 }
1813 Double_t denom = w0N[3]+d[0]*w0N[2]*nuN[0]+d[1]*w0N[1]*nuN[1]+d[2]*w0N[0]*nuN[2]+d[3]*nuN[3];
1814 Double_t b1 = (c[0]*w0N[2]+c[1]*w0N[1]*nuN[0]+c[2]*w0N[0]*nuN[1])/denom;
1815 Double_t b2 = (c[3]*w0N[2]+c[4]*w0N[1]*nuN[0]+c[5]*w0N[0]*nuN[1]+c[6]*nuN[2])/denom;
1816
1817 Double_t w0t = w0*tt;
1818 Double_t j1, j0;
1819 if (fabs(w0t) < 0.001) { // check zero time limits of the spherical bessel functions j0(x) and j1(x)
1820 j0 = 1.0;
1821 j1 = 0.0;
1822 } else {
1823 j0 = sin(w0t)/w0t;
1824 j1 = (sin(w0t)-w0t*cos(w0t))/(w0t*w0t);
1825 }
1826
1827 Double_t Gamma_t = -4.0/3.0*a*(b1*(1.0-j0*TMath::Exp(-nu*tt))+b2*j1*TMath::Exp(-nu*tt)+(1.0-b2*w0/3.0-b1*nu)*tt);
1828
1829 return TMath::Exp(Gamma_t);
1830 }
1831
1832 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1833 // check only the first three parameters since the tshift is irrelevant for the LF-integral calculation!!
1834 Bool_t newParam = false;
1835 for (UInt_t i=0; i<3; i++) {
1836 if (val[i] != fPrevParam[i]) {
1837 newParam = true;
1838 break;
1839 }
1840 }
1841
1842 if (newParam) { // new parameters found
1843 for (UInt_t i=0; i<3; i++)
1844 fPrevParam[i] = val[i];
1845 CalculateDynKTLF(val, 1); // 1 means Lorentz
1846 }
1847
1848 result = GetDynKTLFValue(tt);
1849
1850 return result;
1851
1852}
1853
1854//--------------------------------------------------------------------------
1867Double_t PTheory::DynamicGauLorKTZFFast(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1868{
1869 // expected parameters: damping hopping [tshift]
1870
1871 Double_t val[3];
1872
1873 assert(fParamNo.size() <= 3);
1874
1875 // check if FUNCTIONS are used
1876 for (UInt_t i=0; i<fParamNo.size(); i++) {
1877 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1878 val[i] = paramValues[fParamNo[i]];
1879 } else { // function
1880 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1881 }
1882 }
1883
1884 Double_t tt;
1885 if (fParamNo.size() == 2) // no tshift
1886 tt = t;
1887 else // tshift present
1888 tt = t-val[2];
1889
1890 Double_t nut = val[1]*tt;
1891 return exp(-sqrt(4.0*pow(val[0]/val[1], 2.0)*(exp(-nut)-1.0+nut)));
1892}
1893
1894//--------------------------------------------------------------------------
1907Double_t PTheory::DynamicGauLorKTLFFast(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1908{
1909 // expected parameters: frequency damping hopping [tshift]
1910
1911 Double_t val[4];
1912
1913 assert(fParamNo.size() <= 4);
1914
1915 // check if FUNCTIONS are used
1916 for (UInt_t i=0; i<fParamNo.size(); i++) {
1917 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1918 val[i] = paramValues[fParamNo[i]];
1919 } else { // function
1920 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1921 }
1922 }
1923
1924 Double_t tt;
1925 if (fParamNo.size() == 3) // no tshift
1926 tt = t;
1927 else // tshift present
1928 tt = t-val[3];
1929
1930 Double_t w0 = TMath::TwoPi()*val[0];
1931 Double_t w0_2 = w0*w0;
1932 Double_t nu_2 = val[2]*val[2];
1933 Double_t nu_t = val[2]*tt;
1934 Double_t w0_t = w0*tt;
1935 Double_t Gamma_t = ((w0_2+nu_2)*nu_t+(w0_2-nu_2)*(1.0-exp(-nu_t)*cos(w0_t))-2.0*val[2]*w0*exp(-nu_t)*sin(w0_t))/pow(w0_2+nu_2,2.0);
1936 if (Gamma_t < 0.0)
1937 Gamma_t = 0.0;
1938
1939 return exp(-sqrt(4.0*val[1]*val[1]*Gamma_t));
1940}
1941
1942//--------------------------------------------------------------------------
1954Double_t PTheory::DynamicGauLorKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1955{
1956 // expected parameters: frequency damping hopping [tshift]
1957
1958 Double_t val[4];
1959
1960 assert(fParamNo.size() <= 4);
1961
1962 // check if FUNCTIONS are used
1963 for (UInt_t i=0; i<fParamNo.size(); i++) {
1964 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1965 val[i] = paramValues[fParamNo[i]];
1966 } else { // function
1967 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1968 }
1969 }
1970
1971 Double_t tt;
1972 if (fParamNo.size() == 3) // no tshift
1973 tt = t;
1974 else // tshift present
1975 tt = t-val[3];
1976
1977 // check if the parameter values have changed, and if yes recalculate DynamicGaussKTLF
1978 Bool_t newParam = false;
1979 for (UInt_t i=0; i<3; i++) {
1980 if (val[i] != fPrevParam[i]) {
1981 newParam = true;
1982 break;
1983 }
1984 }
1985
1986 if (newParam) { // new parameters found, hence calculate DynamicGauLorKTLF
1987 // keep parameters
1988 for (UInt_t i=0; i<3; i++)
1989 fPrevParam[i] = val[i];
1990
1991 // reset GL LF polarzation vector
1992 fDyn_GL_LFFuncValue.clear();
1993 fDyn_GL_LFFuncValue.resize(20000); // Tmax=20us, dt=1ns
1994
1995 PDoubleVector rr={0.2, 0.4, 0.6, 0.8, 1.0, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 4.0, 5.0, 7.5, 10.0,
1996 12.8125, 15.625, 18.4375, 21.25, 26.875, 32.5, 43.75, 55.0, 77.5, 100.0};
1997 Double_t par[3] = {val[0], val[1], val[2]};
1998 Double_t sqrtTwoInv = 1.0/sqrt(2.0);
1999 Bool_t isOneVec{false};
2000 Bool_t useKeren{false};
2001 Double_t scale, up{0.0}, low{-1.0};
2002
2003 for (UInt_t i=0; i<rr.size(); i++) {
2004 useKeren = false;
2005 isOneVec = false;
2006
2007 // Delta_G = rr * Delta_L
2008 par[1] = rr[i] * val[1];
2009
2010 // check if all parameters == 0
2011 if ((par[0] == 0.0) && (par[1] == 0.0) && (par[2] == 0.0)) {
2012 isOneVec = true;
2013 }
2014
2015 // make sure that damping and hopping are positive definite
2016 if (par[1] < 0.0)
2017 par[1] = -par[1];
2018 if (par[2] < 0.0)
2019 par[2] = -par[2];
2020
2021 // check that Delta != 0, if not (i.e. stupid parameter) return 1, which is the correct limit
2022 if (fabs(par[1]) < 1.0e-6) {
2023 isOneVec = true;
2024 }
2025
2026 // check if Keren approximation can be used
2027 if (par[2]/par[1] > 5.0) // nu/Delta > 5.0
2028 useKeren = true;
2029
2030 if (!useKeren && !isOneVec) {
2031 CalculateDynKTLF(par, 0); // 0 means Gauss
2032 }
2033
2034 // calculate polarization vector for the given parameters
2035 up = -std::erf(sqrtTwoInv/rr[i]);
2036 scale = up - low;
2037 low = up;
2038
2039 const Double_t dt=0.001;
2040 for (UInt_t i=0; i<20000; i++) {
2041 if (isOneVec) {
2042 fDyn_GL_LFFuncValue[i] += scale;
2043 } else if (useKeren && !isOneVec) {// see PRB50, 10039 (1994)
2044 Double_t wL = TWO_PI * par[0];
2045 Double_t wL2 = wL*wL;
2046 Double_t nu2 = par[2]*par[2];
2047 Double_t Gamma_t = 2.0*par[1]*par[1]/((wL2+nu2)*(wL2+nu2))*
2048 ((wL2+nu2)*val[2]*i*dt
2049 + (wL2-nu2)*(1.0 - TMath::Exp(-val[2]*i*dt)*TMath::Cos(wL*i*dt))
2050 - 2.0*val[2]*wL*TMath::Exp(-val[2]*i*dt)*TMath::Sin(wL*i*dt));
2051 fDyn_GL_LFFuncValue[i] += scale*TMath::Exp(-Gamma_t);
2052 } else if (!useKeren && !isOneVec) {
2053 fDyn_GL_LFFuncValue[i] += scale*GetDynKTLFValue(i*dt);
2054 }
2055 }
2056 }
2057 }
2058
2059
2060 // get the proper value from the look-up table
2061 Double_t result{1.0};
2062 if (tt>=0)
2063 result=GetDyn_GL_KTLFValue(tt);
2064
2065 return result;
2066}
2067
2068//--------------------------------------------------------------------------
2083Double_t PTheory::CombiLGKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2084{
2085 // expected parameters: lambdaL lambdaG [tshift]
2086
2087 Double_t val[3];
2088
2089 assert(fParamNo.size() <= 3);
2090
2091 // check if FUNCTIONS are used
2092 for (UInt_t i=0; i<fParamNo.size(); i++) {
2093 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2094 val[i] = paramValues[fParamNo[i]];
2095 } else { // function
2096 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2097 }
2098 }
2099
2100 Double_t tt;
2101 if (fParamNo.size() == 2) // no tshift
2102 tt = t;
2103 else // tshift present
2104 tt = t-val[2];
2105
2106 Double_t lambdaL_t = tt*val[0];
2107 Double_t lambdaG_t_2 = tt*tt*val[1]*val[1];
2108
2109 return 0.333333333333333 *
2110 (1.0 + 2.0*(1.0-lambdaL_t-lambdaG_t_2)*TMath::Exp(-(lambdaL_t+0.5*lambdaG_t_2)));
2111}
2112
2113//--------------------------------------------------------------------------
2129Double_t PTheory::StrKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2130{
2131 // expected parameters: sigma beta [tshift]
2132
2133 Double_t val[3];
2134
2135 assert(fParamNo.size() <= 3);
2136
2137 // check if FUNCTIONS are used
2138 for (UInt_t i=0; i<fParamNo.size(); i++) {
2139 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2140 val[i] = paramValues[fParamNo[i]];
2141 } else { // function
2142 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2143 }
2144 }
2145
2146 // check for beta too small (beta < 0.1) in which case numerical problems could arise and the function is anyhow
2147 // almost identical to a constant of 1/3.
2148 if (val[1] < 0.1)
2149 return 0.333333333333333;
2150
2151 Double_t tt;
2152 if (fParamNo.size() == 2) // no tshift
2153 tt = t;
2154 else // tshift present
2155 tt = t-val[2];
2156
2157 Double_t sigma_t = TMath::Power(tt*val[0],val[1]);
2158
2159 return 0.333333333333333 *
2160 (1.0 + 2.0*(1.0-sigma_t)*TMath::Exp(-sigma_t/val[1]));
2161}
2162
2163//--------------------------------------------------------------------------
2178Double_t PTheory::SpinGlass(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2179{
2180 // expected parameters: lambda gamma q [tshift]
2181
2182 if (paramValues[fParamNo[0]] == 0.0)
2183 return 1.0;
2184
2185 Double_t val[4];
2186
2187 assert(fParamNo.size() <= 4);
2188
2189 // check if FUNCTIONS are used
2190 for (UInt_t i=0; i<fParamNo.size(); i++) {
2191 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2192 val[i] = paramValues[fParamNo[i]];
2193 } else { // function
2194 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2195 }
2196 }
2197
2198 Double_t tt;
2199 if (fParamNo.size() == 3) // no tshift
2200 tt = t;
2201 else // tshift present
2202 tt = t-val[3];
2203
2204 Double_t lambda_2 = val[0]*val[0];
2205 Double_t lambda_t_2_q = tt*tt*lambda_2*val[2];
2206 Double_t rate_2 = 4.0*lambda_2*(1.0-val[2])*tt/val[1];
2207
2208 Double_t rateL = TMath::Sqrt(fabs(rate_2));
2209 Double_t rateT = TMath::Sqrt(fabs(rate_2)+lambda_t_2_q);
2210
2211 return 0.333333333333333*(TMath::Exp(-rateL) + 2.0*(1.0-lambda_t_2_q/rateT)*TMath::Exp(-rateT));
2212}
2213
2214//--------------------------------------------------------------------------
2229Double_t PTheory::RandomAnisotropicHyperfine(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2230{
2231 // expected parameters: nu lambda [tshift]
2232
2233 Double_t val[3];
2234
2235 assert(fParamNo.size() <= 3);
2236
2237 // check if FUNCTIONS are used
2238 for (UInt_t i=0; i<fParamNo.size(); i++) {
2239 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2240 val[i] = paramValues[fParamNo[i]];
2241 } else { // function
2242 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2243 }
2244 }
2245
2246 Double_t tt;
2247 if (fParamNo.size() == 2) // no tshift
2248 tt = t;
2249 else // tshift present
2250 tt = t-val[2];
2251
2252 Double_t nu_t = tt*val[0];
2253 Double_t lambda_t = tt*val[1];
2254
2255 return 0.166666666666667*(1.0-0.5*nu_t)*TMath::Exp(-0.5*nu_t) +
2256 0.333333333333333*(1.0-0.25*nu_t)*TMath::Exp(-0.25*(nu_t+2.44949*lambda_t));
2257}
2258
2259//--------------------------------------------------------------------------
2274Double_t PTheory::Abragam(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2275{
2276 // expected parameters: sigma gamma [tshift]
2277
2278 Double_t val[3];
2279
2280 assert(fParamNo.size() <= 3);
2281
2282 // check if FUNCTIONS are used
2283 for (UInt_t i=0; i<fParamNo.size(); i++) {
2284 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2285 val[i] = paramValues[fParamNo[i]];
2286 } else { // function
2287 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2288 }
2289 }
2290
2291 Double_t tt;
2292 if (fParamNo.size() == 2) // no tshift
2293 tt = t;
2294 else // tshift present
2295 tt = t-val[2];
2296
2297 Double_t gamma_t = tt*val[1];
2298
2299 return TMath::Exp(-TMath::Power(val[0]/val[1],2.0)*
2300 (TMath::Exp(-gamma_t)-1.0+gamma_t));
2301}
2302
2303//--------------------------------------------------------------------------
2318Double_t PTheory::TFCos(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2319{
2320 // expected parameters: phase frequency [tshift]
2321
2322 Double_t val[3];
2323
2324 assert(fParamNo.size() <= 3);
2325
2326 // check if FUNCTIONS are used
2327 for (UInt_t i=0; i<fParamNo.size(); i++) {
2328 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2329 val[i] = paramValues[fParamNo[i]];
2330 } else { // function
2331 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2332 }
2333 }
2334
2335 Double_t tt;
2336 if (fParamNo.size() == 2) // no tshift
2337 tt = t;
2338 else // tshift present
2339 tt = t-val[2];
2340
2341 return TMath::Cos(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2342}
2343
2344//--------------------------------------------------------------------------
2359Double_t PTheory::InternalField(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2360{
2361 // expected parameters: fraction phase frequency rateT rateL [tshift]
2362
2363 Double_t val[6];
2364
2365 assert(fParamNo.size() <= 6);
2366
2367 // check if FUNCTIONS are used
2368 for (UInt_t i=0; i<fParamNo.size(); i++) {
2369 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2370 val[i] = paramValues[fParamNo[i]];
2371 } else { // function
2372 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2373 }
2374 }
2375
2376 Double_t tt;
2377 if (fParamNo.size() == 5) // no tshift
2378 tt = t;
2379 else // tshift present
2380 tt = t-val[5];
2381
2382 return val[0]*TMath::Cos(DEG_TO_RAD*val[1]+TWO_PI*val[2]*tt)*TMath::Exp(-val[3]*tt) +
2383 (1-val[0])*TMath::Exp(-val[4]*tt);
2384}
2385
2386//--------------------------------------------------------------------------
2401Double_t PTheory::InternalFieldGK(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2402{
2403 // expected parameters: [0]:fraction [1]:frequency [2]:sigma [3]:lambda [4]:beta [[5]:tshift]
2404
2405 Double_t val[6];
2406
2407 assert(fParamNo.size() <= 6);
2408
2409 // check if FUNCTIONS are used
2410 for (UInt_t i=0; i<fParamNo.size(); i++) {
2411 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2412 val[i] = paramValues[fParamNo[i]];
2413 } else { // function
2414 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2415 }
2416 }
2417
2418 Double_t tt;
2419 if (fParamNo.size() == 5) // no tshift
2420 tt = t;
2421 else // tshift present
2422 tt = t-val[5];
2423
2424 Double_t result = 0.0;
2425 Double_t w_t = TWO_PI*val[1]*tt;
2426 Double_t rateLF = TMath::Power(val[3]*tt, val[4]);
2427 Double_t rate2 = val[2]*val[2]*tt*tt; // (sigma t)^2
2428
2429 if (val[1] < 0.01) { // internal field frequency is approaching zero
2430 result = (1.0-val[0])*TMath::Exp(-rateLF) + val[0]*(1.0-rate2)*TMath::Exp(-0.5*rate2);
2431 } else {
2432 result = (1.0-val[0])*TMath::Exp(-rateLF) + val[0]*(TMath::Cos(w_t)-val[2]*val[2]*tt/(TWO_PI*val[1])*TMath::Sin(w_t))*TMath::Exp(-0.5*rate2);
2433 }
2434
2435 return result;
2436}
2437
2438//--------------------------------------------------------------------------
2453Double_t PTheory::InternalFieldLL(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2454{
2455 // expected parameters: [0]:fraction [1]:frequency [2]:a [3]:lambda [4]:beta [[5]:tshift]
2456
2457 Double_t val[6];
2458
2459 assert(fParamNo.size() <= 6);
2460
2461 // check if FUNCTIONS are used
2462 for (UInt_t i=0; i<fParamNo.size(); i++) {
2463 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2464 val[i] = paramValues[fParamNo[i]];
2465 } else { // function
2466 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2467 }
2468 }
2469
2470 Double_t tt;
2471 if (fParamNo.size() == 5) // no tshift
2472 tt = t;
2473 else // tshift present
2474 tt = t-val[5];
2475
2476 Double_t result = 0.0;
2477 Double_t w_t = TWO_PI*val[1]*tt;
2478 Double_t rateLF = TMath::Power(val[3]*tt, val[4]);
2479 Double_t a_t = val[2]*tt; // a t
2480
2481 if (val[1] < 0.01) { // internal field frequency is approaching zero
2482 result = (1.0-val[0])*TMath::Exp(-rateLF) + val[0]*(1.0-a_t)*TMath::Exp(-a_t);
2483 } else {
2484 result = (1.0-val[0])*TMath::Exp(-rateLF) + val[0]*(TMath::Cos(w_t)-val[3]/(TWO_PI*val[1])*TMath::Sin(w_t))*TMath::Exp(-a_t);
2485 }
2486
2487 return result;
2488}
2489
2490//--------------------------------------------------------------------------
2505Double_t PTheory::Bessel(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2506{
2507 // expected parameters: phase frequency [tshift]
2508
2509 Double_t val[3];
2510
2511 assert(fParamNo.size() <= 3);
2512
2513 // check if FUNCTIONS are used
2514 for (UInt_t i=0; i<fParamNo.size(); i++) {
2515 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2516 val[i] = paramValues[fParamNo[i]];
2517 } else { // function
2518 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2519 }
2520 }
2521
2522 Double_t tt;
2523 if (fParamNo.size() == 2) // no tshift
2524 tt = t;
2525 else // tshift present
2526 tt = t-val[2];
2527
2528 return TMath::BesselJ0(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2529}
2530
2531//--------------------------------------------------------------------------
2546Double_t PTheory::InternalBessel(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2547{
2548 // expected parameters: fraction phase frequency rateT rateL [tshift]
2549
2550 Double_t val[6];
2551
2552 assert(fParamNo.size() <= 6);
2553
2554 // check if FUNCTIONS are used
2555 for (UInt_t i=0; i<fParamNo.size(); i++) {
2556 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2557 val[i] = paramValues[fParamNo[i]];
2558 } else { // function
2559 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2560 }
2561 }
2562
2563 Double_t tt;
2564 if (fParamNo.size() == 5) // no tshift
2565 tt = t;
2566 else // tshift present
2567 tt = t-val[5];
2568
2569 return val[0]* TMath::BesselJ0(DEG_TO_RAD*val[1]+TWO_PI*val[2]*tt)*
2570 TMath::Exp(-val[3]*tt) +
2571 (1.0-val[0])*TMath::Exp(-val[4]*tt);
2572}
2573
2574//--------------------------------------------------------------------------
2595Double_t PTheory::SkewedGauss(Double_t t, const PDoubleVector &paramValues,
2596 const PDoubleVector &funcValues) const {
2597 // Expected parameters: phase, frequency, sigma-, sigma+, [tshift].
2598 // To be stored in the array "val" as:
2599 // val[0] = phase
2600 // val[1] = frequency
2601 // val[2] = sigma-
2602 // val[3] = sigma+
2603 // val[4] = tshift [optional]
2604 Double_t val[5];
2605
2606 // Check that we have the correct number of fit parameters.
2607 assert(fParamNo.size() <= 5);
2608
2609 // Check if FUNCTIONS are used.
2610 for (UInt_t i = 0; i < fParamNo.size(); i++) {
2611 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2612 val[i] = paramValues[fParamNo[i]];
2613 } else { // function
2614 val[i] = funcValues[fParamNo[i] - MSR_PARAM_FUN_OFFSET];
2615 }
2616 }
2617
2618 // Apply the tshift (if required).
2619 Double_t tt = t;
2620 if (fParamNo.size() == 5) {
2621 tt = t - val[4];
2622 }
2623
2624 // Evaluate the skewed Gaussian!
2625
2626 // First, calculate some "helper" terms.
2627 Double_t sigma_p = std::abs(val[3]);
2628 Double_t sigma_m = std::abs(val[2]);
2629 Double_t arg_p = sigma_p * tt;
2630 Double_t arg_m = sigma_m * tt;
2631 Double_t z_p = arg_p / SQRT_TWO; // sigma+
2632 Double_t z_m = arg_m / SQRT_TWO; // sigma-
2633 Double_t g_p = TMath::Exp(-0.5 * arg_p * arg_p); // gauss sigma+
2634 Double_t g_m = TMath::Exp(-0.5 * arg_m * arg_m); // gauss sigma-
2635 Double_t w_p = sigma_p / (sigma_p + sigma_m);
2636 Double_t w_m = 1.0 - w_p;
2637 Double_t phase = DEG_TO_RAD * val[0];
2638 Double_t freq = TWO_PI * val[1];
2639
2640 // Evalute the EVEN frequency component of the skewed Gaussian.
2641 Double_t skg_cos = TMath::Cos(phase + freq * tt) * (w_m * g_m + w_p * g_p);
2642
2643 // Evalute the ODD frequency component of the skewed Gaussian.
2644 constexpr Double_t z_max = 26.7776;
2645 // Note: the check against z_max is needed to prevent floating-point overflow
2646 // in the return value of ROOT::Math::conf_hyperg(1/2, 3/2, z * z)
2647 // (i.e., confluent hypergeometric function of the first kind, 1F1).
2648 // In the case that z > z_max, return zero (otherwise there is some
2649 // numeric discontinuity at later times).
2650 Double_t skg_sin =
2651 TMath::Sin(phase + freq * tt) *
2652 ((z_m > z_max) or (z_p > z_max)
2653 ? 0.0
2654 : (w_m * g_m * 2.0 * z_m / SQRT_PI) *
2655 ROOT::Math::conf_hyperg(0.5, 1.5, z_m * z_m) -
2656 (w_p * g_p * 2.0 * z_p / SQRT_PI) *
2657 ROOT::Math::conf_hyperg(0.5, 1.5, z_p * z_p));
2658
2659 // Return the skewed Gaussian: skg = skg_cos + skg_sin.
2660 // Also check that skg_sin is finite!
2661 return skg_cos + (std::isfinite(skg_sin) ? skg_sin : 0.0);
2662}
2663
2664//--------------------------------------------------------------------------
2684Double_t PTheory::StaticNKZF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2685{
2686 // expected paramters: damping_D0 [0], R_b tshift [1]
2687
2688 Double_t val[3];
2689 Double_t result = 1.0;
2690
2691 assert(fParamNo.size() <= 3);
2692
2693 if (t < 0.0)
2694 return result;
2695
2696 // check if FUNCTIONS are used
2697 for (UInt_t i=0; i<fParamNo.size(); i++) {
2698 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2699 val[i] = paramValues[fParamNo[i]];
2700 } else { // function
2701 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2702 }
2703 }
2704
2705 Double_t tt;
2706 if (fParamNo.size() == 2) // no tshift
2707 tt = t;
2708 else // tshift present
2709 tt = t-val[2];
2710
2711 Double_t D2_t2 = val[0]*val[0]*tt*tt;
2712 Double_t denom = 1.0+val[1]*val[1]*D2_t2;
2713
2714 result = 0.333333333333333 + 0.666666666666666667 * TMath::Power(1.0/denom, 1.5) * (1.0 - (D2_t2/denom)) * exp(-0.5*D2_t2/denom);
2715
2716 return result;
2717}
2718
2719//--------------------------------------------------------------------------
2739Double_t PTheory::StaticNKTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2740{
2741 // expected paramters: phase [0], frequency [1], damping_D0 [2], R_b [3], [tshift [4]]
2742
2743 Double_t val[5];
2744 Double_t result = 1.0;
2745
2746 assert(fParamNo.size() <= 5);
2747
2748 if (t < 0.0)
2749 return result;
2750
2751 // check if FUNCTIONS are used
2752 for (UInt_t i=0; i<fParamNo.size(); i++) {
2753 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2754 val[i] = paramValues[fParamNo[i]];
2755 } else { // function
2756 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2757 }
2758 }
2759
2760 Double_t tt;
2761 if (fParamNo.size() == 4) // no tshift
2762 tt = t;
2763 else // tshift present
2764 tt = t-val[4];
2765
2766 Double_t D2_t2 = val[2]*val[2]*tt*tt;
2767 Double_t denom = 1.0+val[3]*val[3]*D2_t2;
2768
2769 result = sqrt(1.0/denom)*exp(-0.5*D2_t2/denom)*TMath::Cos(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2770
2771 return result;
2772}
2773
2774//--------------------------------------------------------------------------
2795Double_t PTheory::DynamicNKZF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2796{
2797 // expected paramters: damping_D0 [0], R_b [1], nu_c [2], [tshift [3]]
2798
2799 Double_t val[4];
2800 Double_t result = 1.0;
2801
2802 assert(fParamNo.size() <= 4);
2803
2804 if (t < 0.0)
2805 return result;
2806
2807 // check if FUNCTIONS are used
2808 for (UInt_t i=0; i<fParamNo.size(); i++) {
2809 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2810 val[i] = paramValues[fParamNo[i]];
2811 } else { // function
2812 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2813 }
2814 }
2815
2816 Double_t tt;
2817 if (fParamNo.size() == 3) // no tshift
2818 tt = t;
2819 else // tshift present
2820 tt = t-val[3];
2821
2822 Double_t theta;
2823 if (val[2] < 1.0e-6) { // nu_c -> 0
2824 theta = 0.5*tt*tt;
2825 } else {
2826 theta = (exp(-val[2]*tt) - 1.0 + val[2]*tt)/(val[2]*val[2]);
2827 }
2828 Double_t denom = 1.0 + 4.0*val[0]*val[0]*val[1]*val[1]*theta;
2829
2830 result = sqrt(1.0/denom)*exp(-2.0*val[0]*val[0]*theta/denom);
2831
2832 return result;
2833}
2834
2835//--------------------------------------------------------------------------
2856Double_t PTheory::DynamicNKTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2857{
2858 // expected paramters: phase [0], frequency [1], damping_D0 [2], R_b [3], nu_c [4], [tshift [5]]
2859
2860 Double_t val[6];
2861 Double_t result = 1.0;
2862
2863 assert(fParamNo.size() <= 6);
2864
2865 if (t < 0.0)
2866 return result;
2867
2868 // check if FUNCTIONS are used
2869 for (UInt_t i=0; i<fParamNo.size(); i++) {
2870 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2871 val[i] = paramValues[fParamNo[i]];
2872 } else { // function
2873 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2874 }
2875 }
2876
2877 Double_t tt;
2878 if (fParamNo.size() == 5) // no tshift
2879 tt = t;
2880 else // tshift present
2881 tt = t-val[5];
2882
2883 Double_t theta;
2884 if (val[4] < 1.0e-6) { // nu_c -> 0
2885 theta = 0.5*tt*tt;
2886 } else {
2887 theta = (exp(-val[4]*tt) - 1.0 + val[4]*tt)/(val[4]*val[4]);
2888 }
2889 Double_t denom = 1.0 + 2.0*val[2]*val[2]*val[3]*val[3]*theta;
2890
2891 result = sqrt(1.0/denom)*exp(-val[2]*val[2]*theta/denom)*TMath::Cos(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2892
2893 return result;
2894}
2895
2896//--------------------------------------------------------------------------
2907Double_t PTheory::FmuF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2908{
2909 // expected paramters: w_d [0], [tshift [1]]
2910
2911 Double_t val[2];
2912
2913 assert(fParamNo.size() <= 2);
2914
2915 if (t < 0.0)
2916 return 1.0;
2917
2918 // check if FUNCTIONS are used
2919 for (UInt_t i=0; i<fParamNo.size(); i++) {
2920 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2921 val[i] = paramValues[fParamNo[i]];
2922 } else { // function
2923 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2924 }
2925 }
2926
2927 Double_t tt;
2928 if (fParamNo.size() == 1) // no tshift
2929 tt = t;
2930 else // tshift present
2931 tt = t-val[1];
2932
2933 const Double_t sqrt3 = sqrt(3.0);
2934 const Double_t wd_t = val[0]*tt;
2935
2936 return (3.0+cos(sqrt3*wd_t)+(1.0-1.0/sqrt3)*cos(((3.0-sqrt3)/2.0)*wd_t)+(1.0+1.0/sqrt3)*cos(((3.0 + sqrt3)/2.0)*wd_t))/6.0;
2937}
2938
2939//--------------------------------------------------------------------------
2953Double_t PTheory::Polynom(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2954{
2955 // expected parameters: tshift p0 p1 p2 ...
2956
2957 Double_t result = 0.0;
2958 Double_t tshift = 0.0;
2959 Double_t val;
2960 Double_t expo = 0.0;
2961
2962 // check if FUNCTIONS are used
2963 for (UInt_t i=0; i<fParamNo.size(); i++) {
2964 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2965 val = paramValues[fParamNo[i]];
2966 } else { // function
2967 val = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2968 }
2969 if (i==0) { // tshift
2970 tshift = val;
2971 continue;
2972 }
2973 result += val*pow(t-tshift, expo);
2974 expo++;
2975 }
2976
2977 return result;
2978}
2979
2980//--------------------------------------------------------------------------
2990Double_t PTheory::UserFcn(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2991{
2992 // check if FUNCTIONS are used
2993 for (UInt_t i=0; i<fUserParam.size(); i++) {
2994 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2995 fUserParam[i] = paramValues[fParamNo[i]];
2996 } else { // function
2997 fUserParam[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2998 }
2999 }
3000
3001 return (*fUserFcn)(t, fUserParam);
3002}
3003
3004//--------------------------------------------------------------------------
3017void PTheory::CalculateGaussLFIntegral(const Double_t *val) const
3018{
3019 // val[0] = nu (field), val[1] = Delta
3020
3021 if (val[0] == 0.0) { // field == 0.0, hence nothing to be done
3022 return;
3023 } else if (val[1]/val[0] > 79.5775) { // check if a/w0 > 500.0, in which case the ZF formula is used and here nothing has to be done
3024 return;
3025 }
3026
3027
3028 Double_t dt=0.001; // all times in usec
3029 Double_t t, ft;
3030 Double_t w0 = TMath::TwoPi()*val[0];
3031 Double_t Delta = val[1];
3032 Double_t preFactor = 2.0*TMath::Power(Delta, 4.0) / TMath::Power(w0, 3.0);
3033
3034 // check if the time resolution needs to be increased
3035 const Int_t samplingPerPeriod = 20;
3036 const Int_t samplingOnExp = 3000;
3037 if ((Delta <= w0) && (1.0/val[0] < 20.0)) { // makes sure that the frequency sampling is fine enough
3038 if (1.0/val[0]/samplingPerPeriod < 0.001) {
3039 dt = 1.0/val[0]/samplingPerPeriod;
3040 }
3041 } else if ((Delta > w0) && (Delta <= 10.0)) {
3042 if (Delta/w0 > 10.0) {
3043 dt = 0.00005;
3044 }
3045 } else if ((Delta > w0) && (Delta > 10.0)) { // makes sure there is a fine enough sampling for large Delta's
3046 if (1.0/Delta/samplingOnExp < 0.001) {
3047 dt = 1.0/Delta/samplingOnExp;
3048 }
3049 }
3050
3051 // keep sampling time
3052 fSamplingTime = dt;
3053
3054 // clear previously allocated vector
3055 fLFIntegral.clear();
3056
3057 // calculate integral
3058 t = 0.0;
3059 fLFIntegral.push_back(0.0); // start value of the integral
3060
3061 ft = 0.0;
3062 Double_t step = 0.0, lastft = 1.0, diff = 0.0;
3063 do {
3064 t += dt;
3065 step = 0.5*dt*preFactor*(exp(-0.5*pow(Delta * (t-dt), 2.0))*sin(w0*(t-dt))+
3066 exp(-0.5*pow(Delta * t, 2.0))*sin(w0*t));
3067 ft += step;
3068 diff = fabs(fabs(lastft)-fabs(ft));
3069 lastft = ft;
3070 fLFIntegral.push_back(ft);
3071 } while ((t <= 20.0) && (diff > 1.0e-10));
3072}
3073
3074//--------------------------------------------------------------------------
3087void PTheory::CalculateLorentzLFIntegral(const Double_t *val) const
3088{
3089 // val[0] = nu, val[1] = a
3090
3091 // a few checks if the integral actually needs to be calculated
3092 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use the ZF formula and here nothing has to be done
3093 return;
3094 } else if (val[1]/val[0] > 159.1549) { // check if a/w0 > 1000.0, in which case the ZF formula is used and here nothing has to be done
3095 return;
3096 }
3097
3098 Double_t dt=0.001; // all times in usec
3099 Double_t t, ft;
3100 Double_t w0 = TMath::TwoPi()*val[0];
3101 Double_t a = val[1];
3102 Double_t preFactor = a*(1+pow(a/w0,2.0));
3103
3104 // check if the time resolution needs to be increased
3105 const Int_t samplingPerPeriod = 20;
3106 const Int_t samplingOnExp = 3000;
3107 if ((a <= w0) && (1.0/val[0] < 20.0)) { // makes sure that the frequency sampling is fine enough
3108 if (1.0/val[0]/samplingPerPeriod < 0.001) {
3109 dt = 1.0/val[0]/samplingPerPeriod;
3110 }
3111 } else if ((a > w0) && (a <= 10.0)) {
3112 if (a/w0 > 10.0) {
3113 dt = 0.00005;
3114 }
3115 } else if ((a > w0) && (a > 10.0)) { // makes sure there is a fine enough sampling for large a's
3116 if (1.0/a/samplingOnExp < 0.001) {
3117 dt = 1.0/a/samplingOnExp;
3118 }
3119 }
3120
3121 // keep sampling time
3122 fSamplingTime = dt;
3123
3124 // clear previously allocated vector
3125 fLFIntegral.clear();
3126
3127 // calculate integral
3128 t = 0.0;
3129 fLFIntegral.push_back(0.0); // start value of the integral
3130
3131 ft = 0.0;
3132 // calculate first integral bin value (needed bcause of sin(x)/x x->0)
3133 t += dt;
3134 ft += 0.5*dt*preFactor*(1.0+sin(w0*t)/(w0*t)*exp(-a*t));
3135 fLFIntegral.push_back(ft);
3136 // calculate all the other integral bin values
3137 Double_t step = 0.0, lastft = 1.0, diff = 0.0;
3138 do {
3139 t += dt;
3140 step = 0.5*dt*preFactor*(sin(w0*(t-dt))/(w0*(t-dt))*exp(-a*(t-dt))+sin(w0*t)/(w0*t)*exp(-a*t));
3141 ft += step;
3142 diff = fabs(fabs(lastft)-fabs(ft));
3143 lastft = ft;
3144 fLFIntegral.push_back(ft);
3145 } while ((t <= 20.0) && (diff > 1.0e-10));
3146}
3147
3148
3149//--------------------------------------------------------------------------
3157Double_t PTheory::GetLFIntegralValue(const Double_t t) const
3158{
3159 if (t < 0.0)
3160 return 0.0;
3161
3162 UInt_t idx = static_cast<UInt_t>(t/fSamplingTime);
3163
3164 if (idx + 2 > fLFIntegral.size())
3165 return fLFIntegral.back();
3166
3167 // linearly interpolate between the two relevant function bins
3168 Double_t df = (fLFIntegral[idx+1]-fLFIntegral[idx])*(t/fSamplingTime-static_cast<Double_t>(idx));
3169
3170 return fLFIntegral[idx]+df;
3171}
3172
3173//--------------------------------------------------------------------------
3184void PTheory::CalculateDynKTLF(const Double_t *val, Int_t tag) const
3185{
3186 // val: 0=nu0, 1=Delta (Gauss) / a (Lorentz), 2=nu
3187 const Double_t Tmax = 20.0; // 20 usec
3188 UInt_t N = static_cast<UInt_t>(16.0*Tmax*val[0]);
3189
3190 // check if rate (Delta or a) is very high
3191 if (fabs(val[1]) > 0.1) {
3192 Double_t tmin = 20.0;
3193 switch (tag) {
3194 case 0: // Gauss
3195 tmin = fabs(sqrt(3.0)/val[1]);
3196 break;
3197 case 1: // Lorentz
3198 tmin = fabs(2.0/val[1]);
3199 break;
3200 default:
3201 break;
3202 }
3203 UInt_t Nrate = static_cast<UInt_t>(25.0 * Tmax / tmin);
3204 if (Nrate > N) {
3205 N = Nrate;
3206 }
3207 }
3208
3209 if (N < 300) // if too few points, i.e. nu0 very small, take 300 points
3210 N = 300;
3211
3212 if (N>1e6) // make sure that N is not too large to prevent memory overflow
3213 N = 1e6;
3214
3215 // allocate memory for dyn KT LF function vector
3216 fDynLFFuncValue.clear(); // get rid of a possible previous vector
3217 fDynLFFuncValue.resize(N);
3218
3219 // calculate the non-analytic integral of the static KT LF function
3220 switch (tag) {
3221 case 0: // Gauss
3223 break;
3224 case 1: // Lorentz
3226 break;
3227 default:
3228 std::cerr << std::endl << ">> PTheory::CalculateDynKTLF: **FATAL ERROR** You should never have reached this point." << std::endl;
3229 assert(false);
3230 break;
3231 }
3232
3233 // calculate the P^(0)(t) exp(-nu t) vector
3234 PDoubleVector p0exp(N);
3235 Double_t t = 0.0;
3236 Double_t dt = Tmax/N;
3237 fDynLFdt = dt; // keep it since it is needed in GetDynKTLFValue()
3238 for (UInt_t i=0; i<N; i++) {
3239 switch (tag) {
3240 case 0: // Gauss
3241 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use zero field formula
3242 Double_t sigma_t_2 = t*t*val[1]*val[1];
3243 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
3244 } else if (val[1]/val[0] > 79.5775) { // check if Delta/w0 > 500.0, in which case the ZF formula is used
3245 Double_t sigma_t_2 = t*t*val[1]*val[1];
3246 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
3247 } else {
3248 Double_t delta = val[1];
3249 Double_t w0 = TWO_PI*val[0];
3250
3251 p0exp[i] = 1.0 - 2.0*TMath::Power(delta/w0,2.0)*(1.0 -
3252 TMath::Exp(-0.5*TMath::Power(delta*t, 2.0))*TMath::Cos(w0*t)) +
3254 }
3255 break;
3256 case 1: // Lorentz
3257 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use zero field formula
3258 Double_t at = t*val[1];
3259 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
3260 } else if (val[1]/val[0] > 159.1549) { // check if a/w0 > 1000.0, in which case the ZF formula is used
3261 Double_t at = t*val[1];
3262 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
3263 } else {
3264 Double_t a = val[1];
3265 Double_t at = a*t;
3266 Double_t w0 = TWO_PI*val[0];
3267 Double_t a_w0 = a/w0;
3268 Double_t w0t = w0*t;
3269
3270 Double_t j1, j0;
3271 if (fabs(w0t) < 0.001) { // check zero time limits of the spherical bessel functions j0(x) and j1(x)
3272 j0 = 1.0;
3273 j1 = 0.0;
3274 } else {
3275 j0 = sin(w0t)/w0t;
3276 j1 = (sin(w0t)-w0t*cos(w0t))/(w0t*w0t);
3277 }
3278
3279 p0exp[i] = 1.0 - a_w0*j1*exp(-at) - a_w0*a_w0*(j0*exp(-at) - 1.0) - GetLFIntegralValue(t);
3280 }
3281 break;
3282 default:
3283 break;
3284 }
3285 p0exp[i] *= TMath::Exp(-val[2]*t);
3286 t += dt;
3287 }
3288
3289 // solve the volterra equation (trapezoid integration)
3290 fDynLFFuncValue[0]=p0exp[0];
3291
3292 Double_t sum;
3293 Double_t a;
3294 Double_t preFactor = dt*val[2];
3295 for (UInt_t i=1; i<N; i++) {
3296 sum = p0exp[i];
3297 sum += 0.5*preFactor*p0exp[i]*fDynLFFuncValue[0];
3298 for (UInt_t j=1; j<i; j++) {
3299 sum += preFactor*p0exp[i-j]*fDynLFFuncValue[j];
3300 }
3301 a = 1.0-0.5*preFactor*p0exp[0];
3302
3303 fDynLFFuncValue[i]=sum/a;
3304 }
3305
3306 // clean up
3307 p0exp.clear();
3308}
3309
3310//--------------------------------------------------------------------------
3318Double_t PTheory::GetDynKTLFValue(const Double_t t) const
3319{
3320 if (t < 0.0)
3321 return 1.0;
3322
3323 UInt_t idx = static_cast<UInt_t>(t/fDynLFdt);
3324
3325 if (idx + 2 > fDynLFFuncValue.size())
3326 return fDynLFFuncValue.back();
3327
3328 // linearly interpolate between the two relevant function bins
3329 Double_t df = (fDynLFFuncValue[idx+1]-fDynLFFuncValue[idx])*(t/fDynLFdt-static_cast<Double_t>(idx));
3330
3331 return fDynLFFuncValue[idx]+df;
3332}
3333
3334//--------------------------------------------------------------------------
3342Double_t PTheory::GetDyn_GL_KTLFValue(const Double_t t) const
3343{
3344 if (t < 0.0)
3345 return 1.0;
3346
3347 const Double_t dt=0.001; // 1ns
3348 UInt_t idx = static_cast<UInt_t>(t/dt);
3349
3350 if (idx + 2 > fDyn_GL_LFFuncValue.size())
3351 return fDyn_GL_LFFuncValue.back();
3352
3353 // linearly interpolate between the two relevant function bins
3354 Double_t df = (fDyn_GL_LFFuncValue[idx+1]-fDyn_GL_LFFuncValue[idx])*(t/dt-static_cast<Double_t>(idx));
3355
3356 return fDyn_GL_LFFuncValue[idx]+df;
3357}
3358
3359//--------------------------------------------------------------------------
3373Double_t PTheory::MuMinusExpTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
3374{
3375 // expected parameters: N0 tau A lambda phase frequency [tshift]
3376
3377 Double_t val[7];
3378
3379 assert(fParamNo.size() <= 7);
3380
3381 // check if FUNCTIONS are used
3382 for (UInt_t i=0; i<fParamNo.size(); i++) {
3383 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
3384 val[i] = paramValues[fParamNo[i]];
3385 } else { // function
3386 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
3387 }
3388 }
3389
3390 Double_t tt;
3391 if (fParamNo.size() == 6) // no tshift
3392 tt = t;
3393 else // tshift present
3394 tt = t-val[6];
3395
3396 return val[0]*exp(-tt/val[1])*(1.0+val[2]*exp(-val[3]*tt)*cos(TWO_PI*val[5]*tt+DEG_TO_RAD*val[4]));
3397}
3398
3399//--------------------------------------------------------------------------
3400// END
3401//--------------------------------------------------------------------------
#define MSR_PARAM_FUN_OFFSET
Offset added to function indices for parameter parsing.
Definition PMusr.h:260
std::vector< PMsrLineStructure > PMsrLines
Definition PMusr.h:989
std::vector< Int_t > PIntVector
Definition PMusr.h:367
std::vector< Double_t > PDoubleVector
Definition PMusr.h:385
return status
std::vector< void * > gGlobalUserFcn
Global storage for user function objects requiring persistent state.
#define SQRT_PI
Definition PTheory.cpp:48
#define SQRT_TWO
Definition PTheory.cpp:47
static PTheoDataBase fgTheoDataBase[THEORY_MAX]
Definition PTheory.h:240
#define THEORY_GENERAL_EXP
General exponential relaxation: exp(-(λt)^β)
Definition PTheory.h:70
#define THEORY_DYNAMIC_LORENTZ_KT_LF
Dynamic Lorentzian Kubo-Toyabe in longitudinal field.
Definition PTheory.h:84
#define THEORY_RANDOM_ANISOTROPIC_HYPERFINE
Random anisotropic hyperfine coupling.
Definition PTheory.h:98
#define THEORY_CONST
Constant value (baseline, background)
Definition PTheory.h:64
#define THEORY_DYNAMIC_GAUSS_KT_LF
Dynamic Gaussian Kubo-Toyabe in longitudinal field.
Definition PTheory.h:78
#define THEORY_ABRAGAM
Abragam relaxation function (diffusion)
Definition PTheory.h:100
#define DEG_TO_RAD
Definition PTheory.h:202
#define THEORY_ASYMMETRY
Initial asymmetry (multiplicative factor)
Definition PTheory.h:66
#define THEORY_SIMPLE_GAUSS
Simple Gaussian relaxation: exp(-σ²t²/2)
Definition PTheory.h:72
#define THEORY_STATIC_ZF_NK
Static Nakajima zero-field function.
Definition PTheory.h:116
#define TWO_PI
Definition PTheory.h:210
#define THEORY_MU_MINUS_EXP
Negative muon (μ-) exponential TF decay.
Definition PTheory.h:126
#define THEORY_SIMPLE_EXP
Simple exponential relaxation: exp(-λt)
Definition PTheory.h:68
#define THEORY_INTERNAL_BESSEL
Internal Bessel (field distribution with Bessel)
Definition PTheory.h:112
#define THEORY_SPIN_GLASS
Spin glass order parameter function.
Definition PTheory.h:96
#define THEORY_STATIC_GAUSS_KT
Static Gaussian Kubo-Toyabe (zero-field)
Definition PTheory.h:74
#define THEORY_DYNAMIC_ZF_NK
Dynamic Nakajima zero-field function.
Definition PTheory.h:120
#define THEORY_TF_COS
Transverse field cosine precession.
Definition PTheory.h:102
#define THEORY_UNDEFINED
Undefined or invalid theory function.
Definition PTheory.h:62
#define THEORY_POLYNOM
Polynomial function (arbitrary order)
Definition PTheory.h:128
#define THEORY_STATIC_GAUSS_KT_LF
Static Gaussian Kubo-Toyabe in longitudinal field.
Definition PTheory.h:76
#define THEORY_INTERNAL_FIELD_LARKIN
Internal field (Larkin-Ovchinnikov model)
Definition PTheory.h:108
#define THEORY_DYNAMIC_GAULOR_FAST_KT_ZF
Fast dynamic Gauss-Lorentz Kubo-Toyabe (zero-field)
Definition PTheory.h:86
#define THEORY_INTERNAL_FIELD
Internal magnetic field distribution (superconductors)
Definition PTheory.h:104
#define THEORY_INTERNAL_FIELD_KORNILOV
Internal field (Kornilov vortex lattice model)
Definition PTheory.h:106
#define THEORY_DYNAMIC_TF_NK
Dynamic Nakajima transverse field function.
Definition PTheory.h:122
#define THEORY_MAX
Definition PTheory.h:183
#define THEORY_BESSEL
Bessel function (modulated precession)
Definition PTheory.h:110
#define THEORY_STATIC_TF_NK
Static Nakajima transverse field function.
Definition PTheory.h:118
#define THEORY_DYNAMIC_GAULOR_FAST_KT_LF
Fast dynamic Gauss-Lorentz Kubo-Toyabe in longitudinal field.
Definition PTheory.h:88
#define THEORY_STR_KT
Stretched Kubo-Toyabe relaxation.
Definition PTheory.h:94
#define THEORY_F_MU_F
F-μ-F (μ-fluorine) oscillation.
Definition PTheory.h:124
#define THEORY_STATIC_LORENTZ_KT
Static Lorentzian Kubo-Toyabe (zero-field)
Definition PTheory.h:80
#define THEORY_MAX_PARAM
Definition PTheory.h:192
#define THEORY_USER_FCN
User-defined external function (shared library)
Definition PTheory.h:130
#define THEORY_SKEWED_GAUSS
Skewed Gaussian relaxation (asymmetric rates)
Definition PTheory.h:114
#define THEORY_COMBI_LGKT
Combined Lorentzian-Gaussian Kubo-Toyabe.
Definition PTheory.h:92
#define THEORY_DYNAMIC_GAULOR_KT_LF
Dynamic Gauss-Lorentz Kubo-Toyabe in longitudinal field.
Definition PTheory.h:90
#define THEORY_STATIC_LORENTZ_KT_LF
Static Lorentzian Kubo-Toyabe in longitudinal field.
Definition PTheory.h:82
MSR file parser and manager for the musrfit framework.
virtual PMsrLines * GetMsrTheory()
Returns pointer to THEORY block lines.
virtual PMsrRunList * GetMsrRunList()
Returns pointer to list of RUN blocks.
virtual UInt_t GetFuncIndex(Int_t funNo)
virtual Double_t DynamicGauLorKTLF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Dynamic Gaussian-Lorentzian KT (LF). Full numerical calculation.
Definition PTheory.cpp:1954
virtual ~PTheory()
Destructor that recursively cleans up the expression tree.
Definition PTheory.cpp:375
virtual Double_t Constant(const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Returns constant value. Formula: c.
Definition PTheory.cpp:1152
virtual Double_t Abragam(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Abragam relaxation. Motional narrowing formula.
Definition PTheory.cpp:2274
virtual void CalculateGaussLFIntegral(const Double_t *val) const
Calculates and caches Gaussian LF integral for static KT.
Bool_t fValid
True if this theory node and its parse state are valid.
Definition PTheory.h:633
PTheory * fAdd
Pointer to addition child node (left branch of tree)
Definition PTheory.h:637
virtual void MakeCleanAndTidyPolynom(UInt_t i, PMsrLines *fullTheoryBlock)
Formats a polynomial theory line with proper spacing.
Definition PTheory.cpp:1040
Double_t fDynLFdt
Time step for dynamic LF integral equation.
Definition PTheory.h:653
PUserFcnBase * fUserFcn
Pointer to instantiated user function object.
Definition PTheory.h:644
PDoubleVector fUserParam
Resolved parameter values for user function calls.
Definition PTheory.h:645
virtual Int_t GetUserFcnIdx(UInt_t lineNo) const
Returns the index of user functions up to the given line.
Definition PTheory.cpp:896
Double_t fSamplingTime
Time step for LF integral calculation (default 1 ns = 0.001 μs)
Definition PTheory.h:650
PTheory(PMsrHandler *msrInfo, UInt_t runNo, const Bool_t hasParent=false)
Constructor that parses the THEORY block and builds the expression tree.
Definition PTheory.cpp:125
virtual Double_t SimpleGauss(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Simple Gaussian relaxation. Formula: exp(-σ²t²/2)
Definition PTheory.cpp:1334
PDoubleVector fLFIntegral
Cached static LF KT integral values.
Definition PTheory.h:652
virtual Int_t SearchDataBase(TString name)
Searches fgTheoDataBase for a function by name or abbreviation.
Definition PTheory.cpp:862
virtual Double_t TFCos(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Transverse field cosine. Formula: cos(φ + 2πνt)
Definition PTheory.cpp:2318
virtual Double_t StaticGaussKTLF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Static Gaussian Kubo-Toyabe (LF). Requires numerical integration.
Definition PTheory.cpp:1432
virtual Double_t StaticLorentzKT(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Static Lorentzian Kubo-Toyabe (ZF). Formula: 1/3 + 2/3(1-at)exp(-at)
Definition PTheory.cpp:1619
PDoubleVector fDyn_GL_LFFuncValue
Cached dynamic Gauss-Lorentz LF KT values.
Definition PTheory.h:655
virtual Double_t StaticNKZF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Static Nakajima-Keren (ZF). Combined nuclear and electronic relaxation.
Definition PTheory.cpp:2684
virtual Double_t DynamicGaussKTLF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Dynamic Gaussian Kubo-Toyabe (LF). Strong collision model.
Definition PTheory.cpp:1521
virtual Double_t GetLFIntegralValue(const Double_t t) const
Retrieves cached LF integral value at time t using interpolation.
virtual Double_t Asymmetry(const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Returns asymmetry value. Formula: A.
Definition PTheory.cpp:1187
PTheory * fMul
Pointer to multiplication child node (right branch of tree)
Definition PTheory.h:638
virtual Double_t DynamicNKZF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Dynamic Nakajima-Keren (ZF). With spin fluctuations.
Definition PTheory.cpp:2795
virtual Double_t StrKT(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Stretched Kubo-Toyabe. Formula: exp(-(σt)^β) with KT-like recovery.
Definition PTheory.cpp:2129
virtual Double_t GeneralExp(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
General (stretched) exponential. Formula: exp(-(λt)^β)
Definition PTheory.cpp:1277
Double_t fPrevParam[THEORY_MAX_PARAM]
Previous parameter values for cache invalidation check.
Definition PTheory.h:651
virtual Double_t DynamicGauLorKTZFFast(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Fast dynamic Gaussian-Lorentzian KT (ZF). Approximate fast calculation.
Definition PTheory.cpp:1867
virtual Bool_t IsValid()
Checks if the entire theory expression tree is valid.
Definition PTheory.cpp:415
virtual Double_t RandomAnisotropicHyperfine(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Random anisotropic hyperfine coupling. Powder average of anisotropic coupling.
Definition PTheory.cpp:2229
virtual void CalculateDynKTLF(const Double_t *val, Int_t tag) const
Calculates dynamic KT in LF using integral equation approach.
PDoubleVector fDynLFFuncValue
Cached dynamic Gaussian/Lorentzian LF KT values.
Definition PTheory.h:654
virtual Double_t InternalField(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Internal field distribution. Gaussian field distribution model.
Definition PTheory.cpp:2359
Int_t fUserFcnIdx
Index of this user function among all userFcn entries (for global state)
Definition PTheory.h:641
TString fUserFcnClassName
ROOT class name for user function (e.g., "TMyFunction")
Definition PTheory.h:642
virtual Double_t InternalBessel(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Internal Bessel field distribution. Combines Bessel with relaxation.
Definition PTheory.cpp:2546
virtual Double_t SkewedGauss(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Skewed Gaussian. Asymmetric relaxation rates before/after zero crossing.
Definition PTheory.cpp:2595
virtual Double_t StaticGaussKT(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Static Gaussian Kubo-Toyabe (ZF). Formula: 1/3 + 2/3(1-σ²t²)exp(-σ²t²/2)
Definition PTheory.cpp:1390
virtual Double_t DynamicLorentzKTLF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Dynamic Lorentzian Kubo-Toyabe (LF). Strong collision model.
Definition PTheory.cpp:1759
virtual void CleanUp(PTheory *theo)
Recursively deletes child theory nodes (fAdd and fMul).
Definition PTheory.cpp:830
virtual Double_t InternalFieldGK(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Internal field (Kornilov model). Vortex lattice field distribution.
Definition PTheory.cpp:2401
virtual void MakeCleanAndTidyUserFcn(UInt_t i, PMsrLines *fullTheoryBlock)
Formats a user function theory line with proper spacing.
Definition PTheory.cpp:1103
virtual Double_t DynamicNKTF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Dynamic Nakajima-Keren (TF). With spin fluctuations and precession.
Definition PTheory.cpp:2856
virtual Double_t SimpleExp(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Simple exponential relaxation. Formula: exp(-λt)
Definition PTheory.cpp:1225
virtual Double_t Func(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Evaluates the theory function at a given time point.
Definition PTheory.cpp:468
UInt_t fType
Theory function type (THEORY_CONST, THEORY_SIMPLE_EXP, etc.)
Definition PTheory.h:634
virtual Double_t GetDyn_GL_KTLFValue(const Double_t t) const
Retrieves cached dynamic Gauss-Lorentz KT LF value at time t.
std::vector< UInt_t > fParamNo
Resolved parameter indices (0-based). Values >= MSR_PARAM_FUN_OFFSET are function references.
Definition PTheory.h:635
virtual Double_t DynamicGauLorKTLFFast(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Fast dynamic Gaussian-Lorentzian KT (LF). Approximate fast calculation.
Definition PTheory.cpp:1907
PMsrHandler * fMsrInfo
Pointer to MSR file handler (not owned)
Definition PTheory.h:647
virtual Double_t UserFcn(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
User-defined function. Calls external shared library function.
virtual Double_t Bessel(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Bessel function precession. Formula: J₀(2πνt + φ)
Definition PTheory.cpp:2505
virtual void CalculateLorentzLFIntegral(const Double_t *val) const
Calculates and caches Lorentzian LF integral for static KT.
virtual Double_t SpinGlass(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Spin glass relaxation function. Edwards-Anderson order parameter.
Definition PTheory.cpp:2178
virtual Double_t StaticNKTF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Static Nakajima-Keren (TF). Combined nuclear and electronic relaxation with precession.
Definition PTheory.cpp:2739
virtual Double_t FmuF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
F-μ-F oscillation. Muon bound between two fluorine atoms.
virtual Double_t StaticLorentzKTLF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Static Lorentzian Kubo-Toyabe (LF). Requires numerical integration.
Definition PTheory.cpp:1662
virtual Double_t CombiLGKT(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Combined Lorentzian-Gaussian KT. Product of both relaxation types.
Definition PTheory.cpp:2083
virtual Double_t MuMinusExpTF(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
μ⁻ exponential TF. Negative muon in transverse field.
virtual Double_t Polynom(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Polynomial function. Formula: Σᵢ pᵢtⁱ
UInt_t fNoOfParam
Expected number of parameters for this function type.
Definition PTheory.h:636
virtual Double_t InternalFieldLL(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Internal field (Larkin-Ovchinnikov model). Vortex lattice field distribution.
Definition PTheory.cpp:2453
virtual void MakeCleanAndTidyTheoryBlock(PMsrLines *fullTheoryBlock)
Reformats the theory block for clean MSR file output.
Definition PTheory.cpp:943
TString fUserFcnSharedLibName
Shared library path (e.g., "libMyFunctions.so")
Definition PTheory.h:643
virtual Double_t GetDynKTLFValue(const Double_t t) const
Retrieves cached dynamic KT LF value at time t.
Abstract base class for user-defined theory functions in musrfit.
Int_t fLineNo
Line number in original MSR file (1-based)
Definition PMusr.h:981
TString fLine
Content of the MSR file line.
Definition PMusr.h:982