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 <string>
33#include <cmath>
34
35#include <TObject.h>
36#include <TString.h>
37#include <TF1.h>
38#include <TClass.h>
39#include <TMath.h>
40
41#include <Math/SpecFuncMathMore.h>
42
43#include "PMsrHandler.h"
44#include "PStringUtils.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 std::vector<std::string> tokens = PStringUtils::Split(str.Data(), " \t");
173 if (tokens.empty()) {
174 std::cerr << std::endl << ">> PTheory::PTheory: **SEVERE ERROR** Couldn't tokenize theory block line " << line->fLineNo << ".";
175 std::cerr << std::endl << ">> line content: " << line->fLine.Data();
176 std::cerr << std::endl;
177 exit(0);
178 }
179 str = tokens[0];
180
181 // search the theory function
182 UInt_t idx = SearchDataBase(str);
183
184 // function found is not defined
185 if (idx == static_cast<UInt_t>(THEORY_UNDEFINED)) {
186 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** Theory line '" << line->fLine.Data() << "'";
187 std::cerr << std::endl << ">> in line no " << line->fLineNo << " is undefined!";
188 std::cerr << std::endl;
189 fValid = false;
190 return;
191 }
192
193 // line is a valid function, hence analyze parameters
194 if ((static_cast<UInt_t>(tokens.size()-1) < fNoOfParam) &&
195 ((idx != THEORY_USER_FCN) && (idx != THEORY_POLYNOM))) {
196 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** Theory line '" << line->fLine.Data() << "'";
197 std::cerr << std::endl << ">> in line no " << line->fLineNo;
198 std::cerr << std::endl << ">> expecting " << fgTheoDataBase[idx].fNoOfParam << ", but found " << tokens.size()-1;
199 std::cerr << std::endl;
200 fValid = false;
201 }
202 // keep function index
203 fType = idx;
204 // filter out the parameters
205 Int_t status;
206 UInt_t value;
207 Bool_t ok = false;
208 for (UInt_t i=1; i<tokens.size(); i++) {
209 str = tokens[i];
210
211 // if userFcn, the first entry is the function name and needs to be handled specially
212 if ((fType == THEORY_USER_FCN) && ((i == 1) || (i == 2))) {
213 if (i == 1) {
215 }
216 if (i == 2) {
217 fUserFcnClassName = str;
218 }
219 continue;
220 }
221
222 // check if str is map
223 if (str.Contains("map")) {
224 status = sscanf(str.Data(), "map%u", &value);
225 if (status == 1) { // everthing ok
226 ok = true;
227 // get parameter from map
228 PIntVector maps = *(*msrInfo->GetMsrRunList())[runNo].GetMap();
229 if ((value <= maps.size()) && (value > 0)) { // everything fine
230 fParamNo.push_back(maps[value-1]-1);
231 } else { // map index out of range
232 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** map index " << value << " out of range! See line no " << line->fLineNo;
233 std::cerr << std::endl;
234 fValid = false;
235 }
236 } else { // something wrong
237 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR**: map '" << str.Data() << "' not allowed. See line no " << line->fLineNo;
238 std::cerr << std::endl;
239 fValid = false;
240 }
241 } else if (str.Contains("fun")) { // check if str is fun
242 status = sscanf(str.Data(), "fun%u", &value);
243 if (status == 1) { // everthing ok
244 ok = true;
245 // handle function, i.e. get, from the function number x (FUNx), the function index,
246 // add function offset and fill "parameter vector"
247 fParamNo.push_back(msrInfo->GetFuncIndex(value)+MSR_PARAM_FUN_OFFSET);
248 } else { // something wrong
249 fValid = false;
250 }
251 } else { // check if str is param no
252 status = sscanf(str.Data(), "%u", &value);
253 if (status == 1) { // everthing ok
254 ok = true;
255 fParamNo.push_back(value-1);
256 }
257 // check if one of the valid entries was found
258 if (!ok) {
259 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** '" << str.Data() << "' not allowed. See line no " << line->fLineNo;
260 std::cerr << std::endl;
261 fValid = false;
262 }
263 }
264 }
265
266 // call the next line (only if valid so far and not the last line)
267 // handle '*'
268 if (fValid && (lineNo < fullTheoryBlock->size()-1)) {
269 line = &(*fullTheoryBlock)[lineNo+1];
270 if (!line->fLine.Contains("+")) { // make sure next line is not a '+'
271 depth++;
272 lineNo++;
273 fMul = new PTheory(msrInfo, runNo, true);
274 depth--;
275 }
276 }
277 // call the next line (only if valid so far and not the last line)
278 // handle '+'
279 if (fValid && (lineNo < fullTheoryBlock->size()-1)) {
280 line = &(*fullTheoryBlock)[lineNo+1];
281 if ((depth == 0) && line->fLine.Contains("+")) {
282 lineNo += 2; // go to the next theory function line
283 fAdd = new PTheory(msrInfo, runNo, true);
284 }
285 }
286
287 // make clean and tidy theory block for the msr-file
288 if (fValid && !hasParent) { // parent theory object
289 MakeCleanAndTidyTheoryBlock(fullTheoryBlock);
290 }
291
292 // check if user function, if so, check if it is reachable (root) and if yes invoke object
293 if (!fUserFcnClassName.IsWhitespace()) {
294 std::cout << std::endl << ">> user function class name: " << fUserFcnClassName.Data() << std::endl;
295 if (!TClass::GetDict(fUserFcnClassName.Data())) {
296 if (gSystem->Load(fUserFcnSharedLibName.Data()) < 0) {
297 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** user function class '" << fUserFcnClassName.Data() << "' not found.";
298 std::cerr << std::endl << ">> Tried to load " << fUserFcnSharedLibName.Data() << " but failed.";
299 std::cerr << std::endl << ">> See line no " << line->fLineNo;
300 std::cerr << std::endl;
301 fValid = false;
302 return;
303 } else if (!TClass::GetDict(fUserFcnClassName.Data())) {
304 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** user function class '" << fUserFcnClassName.Data() << "' not found.";
305 std::cerr << std::endl << ">> " << fUserFcnSharedLibName.Data() << " loaded successfully, but no dictionary present.";
306 std::cerr << std::endl << ">> See line no " << line->fLineNo;
307 std::cerr << std::endl;
308 fValid = false;
309 return;
310 }
311 }
312
313 // invoke user function object
314 fUserFcn = nullptr;
315 fUserFcn = static_cast<PUserFcnBase*>(TClass::GetClass(fUserFcnClassName.Data())->New());
316 if (fUserFcn == nullptr) {
317 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** user function object could not be invoked. See line no " << line->fLineNo;
318 std::cerr << std::endl;
319 fValid = false;
320 return;
321 } else { // user function valid, hence expand the fUserParam vector to the proper size
322 fUserParam.resize(fParamNo.size());
323 }
324
325 // check if the global part of the user function is needed
326 if (fUserFcn->NeedGlobalPart()) {
327 fUserFcn->SetGlobalPart(gGlobalUserFcn, fUserFcnIdx); // invoke or retrieve global user function object
328 if (!fUserFcn->GlobalPartIsValid()) {
329 std::cerr << std::endl << ">> PTheory::PTheory: **ERROR** global user function object could not be invoked/retrived. See line no " << line->fLineNo;
330 std::cerr << std::endl;
331 fValid = false;
332 }
333 }
334 }
335}
336
337//--------------------------------------------------------------------------
338// Destructor
339//--------------------------------------------------------------------------
355{
356 fParamNo.clear();
357 fUserParam.clear();
358
359 fLFIntegral.clear();
360 fDynLFFuncValue.clear();
361
362 // recursive clean up
363 CleanUp(this);
364
365 if (fUserFcn) {
366 delete fUserFcn;
367 fUserFcn = nullptr;
368 }
369
370 gGlobalUserFcn.clear();
371}
372
373//--------------------------------------------------------------------------
374// IsValid
375//--------------------------------------------------------------------------
395{
396
397 if (fMul) {
398 if (fAdd) {
399 return (fValid && fMul->IsValid() && fAdd->IsValid());
400 } else {
401 return (fValid && fMul->IsValid());
402 }
403 } else {
404 if (fAdd) {
405 return (fValid && fAdd->IsValid());
406 } else {
407 return fValid;
408 }
409 }
410}
411
412//--------------------------------------------------------------------------
447Double_t PTheory::Func(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
448{
449 if (fMul) {
450 if (fAdd) { // fMul != 0 && fAdd != 0
451 switch (fType) {
452 case THEORY_CONST:
453 return Constant(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
454 fAdd->Func(t, paramValues, funcValues);
455 case THEORY_ASYMMETRY:
456 return Asymmetry(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
457 fAdd->Func(t, paramValues, funcValues);
459 return SimpleExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
460 fAdd->Func(t, paramValues, funcValues);
462 return GeneralExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
463 fAdd->Func(t, paramValues, funcValues);
465 return SimpleGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
466 fAdd->Func(t, paramValues, funcValues);
468 return StaticGaussKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
469 fAdd->Func(t, paramValues, funcValues);
471 return StaticGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
472 fAdd->Func(t, paramValues, funcValues);
474 return DynamicGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
475 fAdd->Func(t, paramValues, funcValues);
477 return StaticLorentzKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
478 fAdd->Func(t, paramValues, funcValues);
480 return StaticLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
481 fAdd->Func(t, paramValues, funcValues);
483 return DynamicLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
484 fAdd->Func(t, paramValues, funcValues);
486 return DynamicGauLorKTZFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
487 fAdd->Func(t, paramValues, funcValues);
489 return DynamicGauLorKTLFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
490 fAdd->Func(t, paramValues, funcValues);
492 return DynamicGauLorKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
493 fAdd->Func(t, paramValues, funcValues);
495 return CombiLGKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
496 fAdd->Func(t, paramValues, funcValues);
497 case THEORY_STR_KT:
498 return StrKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
499 fAdd->Func(t, paramValues, funcValues);
501 return SpinGlass(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
502 fAdd->Func(t, paramValues, funcValues);
504 return RandomAnisotropicHyperfine(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
505 fAdd->Func(t, paramValues, funcValues);
506 case THEORY_ABRAGAM:
507 return Abragam(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
508 fAdd->Func(t, paramValues, funcValues);
509 case THEORY_TF_COS:
510 return TFCos(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
511 fAdd->Func(t, paramValues, funcValues);
513 return InternalField(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
514 fAdd->Func(t, paramValues, funcValues);
516 return InternalFieldGK(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
517 fAdd->Func(t, paramValues, funcValues);
519 return InternalFieldLL(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
520 fAdd->Func(t, paramValues, funcValues);
521 case THEORY_BESSEL:
522 return Bessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
523 fAdd->Func(t, paramValues, funcValues);
525 return InternalBessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
526 fAdd->Func(t, paramValues, funcValues);
528 return SkewedGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
529 fAdd->Func(t, paramValues, funcValues);
531 return StaticNKZF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
532 fAdd->Func(t, paramValues, funcValues);
534 return StaticNKTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
535 fAdd->Func(t, paramValues, funcValues);
537 return DynamicNKZF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
538 fAdd->Func(t, paramValues, funcValues);
540 return DynamicNKTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
541 fAdd->Func(t, paramValues, funcValues);
542 case THEORY_F_MU_F:
543 return FmuF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
544 fAdd->Func(t, paramValues, funcValues);
545 case THEORY_POLYNOM:
546 return Polynom(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
547 fAdd->Func(t, paramValues, funcValues);
549 return MuMinusExpTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
550 fAdd->Func(t, paramValues, funcValues);
551 case THEORY_USER_FCN:
552 return UserFcn(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues) +
553 fAdd->Func(t, paramValues, funcValues);
554 default:
555 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
556 std::cerr << std::endl;
557 exit(0);
558 }
559 } else { // fMul !=0 && fAdd == 0
560 switch (fType) {
561 case THEORY_CONST:
562 return Constant(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
563 case THEORY_ASYMMETRY:
564 return Asymmetry(paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
566 return SimpleExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
568 return GeneralExp(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
570 return SimpleGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
572 return StaticGaussKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
574 return StaticGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
576 return DynamicGaussKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
578 return StaticLorentzKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
580 return StaticLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
582 return DynamicLorentzKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
584 return DynamicGauLorKTZFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
586 return DynamicGauLorKTLFFast(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
588 return DynamicGauLorKTLF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
590 return CombiLGKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
591 case THEORY_STR_KT:
592 return StrKT(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
594 return SpinGlass(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
596 return RandomAnisotropicHyperfine(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
597 case THEORY_ABRAGAM:
598 return Abragam(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
599 case THEORY_TF_COS:
600 return TFCos(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
602 return InternalField(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
604 return InternalFieldGK(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
606 return InternalFieldLL(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
607 case THEORY_BESSEL:
608 return Bessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
610 return InternalBessel(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
612 return SkewedGauss(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
614 return StaticNKZF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
616 return StaticNKTF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
618 return DynamicNKZF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
620 return DynamicNKTF (t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
622 return MuMinusExpTF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
623 case THEORY_F_MU_F:
624 return FmuF(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
625 case THEORY_POLYNOM:
626 return Polynom(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
627 case THEORY_USER_FCN:
628 return UserFcn(t, paramValues, funcValues) * fMul->Func(t, paramValues, funcValues);
629 default:
630 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
631 std::cerr << std::endl;
632 exit(0);
633 }
634 }
635 } else { // fMul == 0 && fAdd != 0
636 if (fAdd) {
637 switch (fType) {
638 case THEORY_CONST:
639 return Constant(paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
640 case THEORY_ASYMMETRY:
641 return Asymmetry(paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
643 return SimpleExp(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
645 return GeneralExp(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
647 return SimpleGauss(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
649 return StaticGaussKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
651 return StaticGaussKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
653 return DynamicGaussKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
655 return StaticLorentzKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
657 return StaticLorentzKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
659 return DynamicLorentzKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
661 return DynamicGauLorKTZFFast(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
663 return DynamicGauLorKTLFFast(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
665 return DynamicGauLorKTLF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
667 return CombiLGKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
668 case THEORY_STR_KT:
669 return StrKT(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
671 return SpinGlass(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
673 return RandomAnisotropicHyperfine(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
674 case THEORY_ABRAGAM:
675 return Abragam(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
676 case THEORY_TF_COS:
677 return TFCos(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
679 return InternalField(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
681 return InternalFieldGK(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
683 return InternalFieldLL(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
684 case THEORY_BESSEL:
685 return Bessel(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
687 return InternalBessel(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
689 return SkewedGauss(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
691 return StaticNKZF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
693 return StaticNKTF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
695 return DynamicNKZF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
697 return DynamicNKTF (t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
699 return MuMinusExpTF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
700 case THEORY_F_MU_F:
701 return FmuF(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
702 case THEORY_POLYNOM:
703 return Polynom(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
704 case THEORY_USER_FCN:
705 return UserFcn(t, paramValues, funcValues) + fAdd->Func(t, paramValues, funcValues);
706 default:
707 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
708 std::cerr << std::endl;
709 exit(0);
710 }
711 } else { // fMul == 0 && fAdd == 0
712 switch (fType) {
713 case THEORY_CONST:
714 return Constant(paramValues, funcValues);
715 case THEORY_ASYMMETRY:
716 return Asymmetry(paramValues, funcValues);
718 return SimpleExp(t, paramValues, funcValues);
720 return GeneralExp(t, paramValues, funcValues);
722 return SimpleGauss(t, paramValues, funcValues);
724 return StaticGaussKT(t, paramValues, funcValues);
726 return StaticGaussKTLF(t, paramValues, funcValues);
728 return DynamicGaussKTLF(t, paramValues, funcValues);
730 return StaticLorentzKT(t, paramValues, funcValues);
732 return StaticLorentzKTLF(t, paramValues, funcValues);
734 return DynamicLorentzKTLF(t, paramValues, funcValues);
736 return DynamicGauLorKTZFFast(t, paramValues, funcValues);
738 return DynamicGauLorKTLFFast(t, paramValues, funcValues);
740 return DynamicGauLorKTLF(t, paramValues, funcValues);
742 return CombiLGKT(t, paramValues, funcValues);
743 case THEORY_STR_KT:
744 return StrKT(t, paramValues, funcValues);
746 return SpinGlass(t, paramValues, funcValues);
748 return RandomAnisotropicHyperfine(t, paramValues, funcValues);
749 case THEORY_ABRAGAM:
750 return Abragam(t, paramValues, funcValues);
751 case THEORY_TF_COS:
752 return TFCos(t, paramValues, funcValues);
754 return InternalField(t, paramValues, funcValues);
756 return InternalFieldGK(t, paramValues, funcValues);
758 return InternalFieldLL(t, paramValues, funcValues);
759 case THEORY_BESSEL:
760 return Bessel(t, paramValues, funcValues);
762 return InternalBessel(t, paramValues, funcValues);
764 return SkewedGauss(t, paramValues, funcValues);
766 return StaticNKZF(t, paramValues, funcValues);
768 return StaticNKTF(t, paramValues, funcValues);
770 return DynamicNKZF(t, paramValues, funcValues);
772 return DynamicNKTF(t, paramValues, funcValues);
774 return MuMinusExpTF(t, paramValues, funcValues);
775 case THEORY_F_MU_F:
776 return FmuF(t, paramValues, funcValues);
777 case THEORY_POLYNOM:
778 return Polynom(t, paramValues, funcValues);
779 case THEORY_USER_FCN:
780 return UserFcn(t, paramValues, funcValues);
781 default:
782 std::cerr << std::endl << ">> PTheory::Func: **PANIC ERROR** You never should have reached this line?!?! (" << fType << ")";
783 std::cerr << std::endl;
784 exit(0);
785 }
786 }
787 }
788}
789
790//--------------------------------------------------------------------------
810{
811 if (theo->fMul) { // '*' present
812 delete theo->fMul;
813 theo->fMul = nullptr;
814 }
815
816 if (theo->fAdd) {
817 delete theo->fAdd;
818 theo->fAdd = nullptr;
819 }
820}
821
822//--------------------------------------------------------------------------
841Int_t PTheory::SearchDataBase(TString name)
842{
843 Int_t idx = THEORY_UNDEFINED;
844
845 for (UInt_t i=0; i<THEORY_MAX; i++) {
846 if (!name.CompareTo(fgTheoDataBase[i].fName, TString::kIgnoreCase) ||
847 !name.CompareTo(fgTheoDataBase[i].fAbbrev, TString::kIgnoreCase)) {
848 idx = static_cast<Int_t>(fgTheoDataBase[i].fType);
849 fType = fgTheoDataBase[i].fType;
850 fNoOfParam = fgTheoDataBase[i].fNoOfParam;
851 }
852 }
853
854 return idx;
855}
856
857//--------------------------------------------------------------------------
858// GetUserFcnIdx (private)
859//--------------------------------------------------------------------------
875Int_t PTheory::GetUserFcnIdx(UInt_t lineNo) const
876{
877 Int_t userFcnIdx = -1;
878
879 // retrieve the theory block from the msr-file handler
880 PMsrLines *fullTheoryBlock = fMsrInfo->GetMsrTheory();
881
882 // make sure that lineNo is within proper bounds
883 if (lineNo > fullTheoryBlock->size())
884 return userFcnIdx;
885
886 // count the number of user function present up to the lineNo
887 for (UInt_t i=1; i<=lineNo; i++) {
888 if (fullTheoryBlock->at(i).fLine.Contains("userFcn", TString::kIgnoreCase))
889 userFcnIdx++;
890 }
891
892 return userFcnIdx;
893}
894
895//--------------------------------------------------------------------------
896// MakeCleanAndTidyTheoryBlock private
897//--------------------------------------------------------------------------
923{
924 PMsrLineStructure *line;
925 TString str, tidy;
926 Char_t substr[256];
927 Int_t idx = THEORY_UNDEFINED;
928
929 for (UInt_t i=1; i<fullTheoryBlock->size(); i++) {
930 // get the line to be prettyfied
931 line = &(*fullTheoryBlock)[i];
932 // copy line content to str in order to remove comments
933 str = line->fLine.Copy();
934 // remove theory line comment if present, i.e. something starting with '('
935 Int_t index = str.Index("(");
936 if (index > 0) // theory line comment present
937 str.Resize(index);
938 // tokenize line
939 std::vector<std::string> tokens = PStringUtils::Split(str.Data(), " \t");
940 if (tokens.empty())
941 continue;
942 // make a handable string out of the asymmetry token
943 str = tokens[0];
944 // check if the line is just a '+' if so nothing to be done
945 if (str.Contains("+"))
946 continue;
947 // check if the function is a polynom
948 if (!str.CompareTo("p") || str.Contains("polynom")) {
949 MakeCleanAndTidyPolynom(i, fullTheoryBlock);
950 continue;
951 }
952 // check if the function is a userFcn
953 if (!str.CompareTo("u") || str.Contains("userFcn")) {
954 MakeCleanAndTidyUserFcn(i, fullTheoryBlock);
955 continue;
956 }
957 // search the theory function
958 for (UInt_t j=0; j<THEORY_MAX; j++) {
959 if (!str.CompareTo(fgTheoDataBase[j].fName, TString::kIgnoreCase) ||
960 !str.CompareTo(fgTheoDataBase[j].fAbbrev, TString::kIgnoreCase)) {
961 idx = static_cast<Int_t>(fgTheoDataBase[j].fType);
962 }
963 }
964 // check if theory is indeed defined. This should not be necessay at this point but ...
965 if (idx == THEORY_UNDEFINED)
966 return;
967 // check that there enough tokens. This should not be necessay at this point but ...
968 if (static_cast<UInt_t>(tokens.size()) < fgTheoDataBase[idx].fNoOfParam + 1)
969 return;
970 // make tidy string
971 snprintf(substr, sizeof(substr), "%-10s", fgTheoDataBase[idx].fName.Data());
972 tidy = TString(substr);
973 for (UInt_t j=1; j<tokens.size(); j++) {
974 str = tokens[j];
975 snprintf(substr, sizeof(substr), "%6s", str.Data());
976 tidy += TString(substr);
977 }
978 if (fgTheoDataBase[idx].fComment.Length() != 0) {
979 if (tidy.Length() < 35) {
980 for (Int_t k=0; k<35-tidy.Length(); k++)
981 tidy += TString(" ");
982 } else {
983 tidy += TString(" ");
984 }
985 if (static_cast<UInt_t>(tokens.size()) == fgTheoDataBase[idx].fNoOfParam + 1) // no tshift
986 tidy += fgTheoDataBase[idx].fComment;
987 else
988 tidy += fgTheoDataBase[idx].fCommentTimeShift;
989 }
990 // write tidy string back into theory block
991 (*fullTheoryBlock)[i].fLine = tidy;
992 }
993
994}
995
996//--------------------------------------------------------------------------
997// MakeCleanAndTidyPolynom private
998//--------------------------------------------------------------------------
1011void PTheory::MakeCleanAndTidyPolynom(UInt_t i, PMsrLines *fullTheoryBlock)
1012{
1013 PMsrLineStructure *line;
1014 TString str, tidy;
1015 Char_t substr[256];
1016
1017 // init tidy
1018 tidy = TString("polynom ");
1019 // get the line to be prettyfied
1020 line = &(*fullTheoryBlock)[i];
1021 // copy line content to str in order to remove comments
1022 str = line->fLine.Copy();
1023 // tokenize line
1024 std::vector<std::string> tokens = PStringUtils::Split(str.Data(), " \t");
1025
1026 // check if comment is already present, and if yes ignore it by setting max correctly
1027 Int_t max = static_cast<Int_t>(tokens.size());
1028 for (Int_t j=1; j<max; j++) {
1029 str = tokens[j];
1030 if (str.Contains("(")) { // comment present
1031 max=j;
1032 break;
1033 }
1034 }
1035
1036 for (Int_t j=1; j<max; j++) {
1037 str = tokens[j];
1038 snprintf(substr, sizeof(substr), "%6s", str.Data());
1039 tidy += TString(substr);
1040 }
1041
1042 // add comment
1043 tidy += " (tshift p0 p1 ... pn)";
1044
1045 // write tidy string back into theory block
1046 (*fullTheoryBlock)[i].fLine = tidy;
1047}
1048
1049//--------------------------------------------------------------------------
1050// MakeCleanAndTidyUserFcn private
1051//--------------------------------------------------------------------------
1064void PTheory::MakeCleanAndTidyUserFcn(UInt_t i, PMsrLines *fullTheoryBlock)
1065{
1066 PMsrLineStructure *line;
1067 TString str, tidy;
1068
1069 // init tidy
1070 tidy = TString("userFcn ");
1071 // get the line to be prettyfied
1072 line = &(*fullTheoryBlock)[i];
1073 // copy line content to str in order to remove comments
1074 str = line->fLine.Copy();
1075 // tokenize line
1076 std::vector<std::string> tokens = PStringUtils::Split(str.Data(), " \t");
1077
1078 for (UInt_t j=1; j<tokens.size(); j++) {
1079 str = tokens[j];
1080 tidy += TString(" ") + str;
1081 }
1082
1083 // write tidy string back into theory block
1084 (*fullTheoryBlock)[i].fLine = tidy;
1085}
1086
1087//--------------------------------------------------------------------------
1104Double_t PTheory::Constant(const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1105{
1106 // expected parameters: const
1107
1108 Double_t constant;
1109
1110 // check if FUNCTIONS are used
1111 if (fParamNo[0] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1112 constant = paramValues[fParamNo[0]];
1113 } else {
1114 constant = funcValues[fParamNo[0]-MSR_PARAM_FUN_OFFSET];
1115 }
1116
1117 return constant;
1118}
1119
1120//--------------------------------------------------------------------------
1139Double_t PTheory::Asymmetry(const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1140{
1141 // expected parameters: asym
1142
1143 Double_t asym;
1144
1145 // check if FUNCTIONS are used
1146 if (fParamNo[0] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1147 asym = paramValues[fParamNo[0]];
1148 } else {
1149 asym = funcValues[fParamNo[0]-MSR_PARAM_FUN_OFFSET];
1150 }
1151
1152 return asym;
1153}
1154
1155//--------------------------------------------------------------------------
1177Double_t PTheory::SimpleExp(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1178{
1179 // expected parameters: lambda [tshift]
1180
1181 Double_t val[2];
1182
1183 assert(fParamNo.size() <= 2);
1184
1185 // check if FUNCTIONS are used
1186 for (UInt_t i=0; i<fParamNo.size(); i++) {
1187 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1188 val[i] = paramValues[fParamNo[i]];
1189 } else { // function
1190 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1191 }
1192 }
1193
1194 Double_t tt;
1195 if (fParamNo.size() == 1) // no tshift
1196 tt = t;
1197 else // tshift present
1198 tt = t-val[1];
1199
1200 return TMath::Exp(-tt*val[0]);
1201}
1202
1203//--------------------------------------------------------------------------
1229Double_t PTheory::GeneralExp(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1230{
1231 // expected parameters: lambda beta [tshift]
1232
1233 Double_t val[3];
1234 Double_t result;
1235
1236 assert(fParamNo.size() <= 3);
1237
1238 // check if FUNCTIONS are used
1239 for (UInt_t i=0; i<fParamNo.size(); i++) {
1240 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1241 val[i] = paramValues[fParamNo[i]];
1242 } else { // function
1243 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1244 }
1245 }
1246
1247 Double_t tt;
1248 if (fParamNo.size() == 2) // no tshift
1249 tt = t;
1250 else // tshift present
1251 tt = t-val[2];
1252
1253 // check if tt*val[0] < 0 and
1254 if ((tt*val[0] < 0) && (trunc(val[1])-val[1] != 0.0)) {
1255 result = 0.0;
1256 } else {
1257 result = TMath::Exp(-TMath::Power(tt*val[0], val[1]));
1258 }
1259
1260 return result;
1261}
1262
1263//--------------------------------------------------------------------------
1286Double_t PTheory::SimpleGauss(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1287{
1288 // expected parameters: sigma [tshift]
1289
1290 Double_t val[2];
1291
1292 assert(fParamNo.size() <= 2);
1293
1294 // check if FUNCTIONS are used
1295 for (UInt_t i=0; i<fParamNo.size(); i++) {
1296 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1297 val[i] = paramValues[fParamNo[i]];
1298 } else { // function
1299 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1300 }
1301 }
1302
1303 Double_t tt;
1304 if (fParamNo.size() == 1) // no tshift
1305 tt = t;
1306 else // tshift present
1307 tt = t-val[1];
1308
1309 return TMath::Exp(-0.5*TMath::Power(tt*val[0], 2.0));
1310}
1311
1312//--------------------------------------------------------------------------
1342Double_t PTheory::StaticGaussKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1343{
1344 // expected parameters: sigma [tshift]
1345
1346 Double_t val[2];
1347
1348 assert(fParamNo.size() <= 2);
1349
1350 // check if FUNCTIONS are used
1351 for (UInt_t i=0; i<fParamNo.size(); i++) {
1352 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1353 val[i] = paramValues[fParamNo[i]];
1354 } else { // function
1355 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1356 }
1357 }
1358
1359 Double_t sigma_t_2;
1360 if (fParamNo.size() == 1) // no tshift
1361 sigma_t_2 = t*t*val[0]*val[0];
1362 else // tshift present
1363 sigma_t_2 = (t-val[1])*(t-val[1])*val[0]*val[0];
1364
1365 return 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
1366}
1367
1368//--------------------------------------------------------------------------
1384Double_t PTheory::StaticGaussKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1385{
1386
1387 // expected parameters: frequency damping [tshift]
1388
1389 Double_t val[3];
1390 Double_t result;
1391
1392 assert(fParamNo.size() <= 3);
1393
1394 // check if FUNCTIONS are used
1395 for (UInt_t i=0; i<fParamNo.size(); i++) {
1396 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1397 val[i] = paramValues[fParamNo[i]];
1398 } else { // function
1399 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1400 }
1401 }
1402
1403 // check if all parameters == 0
1404 if ((val[0] == 0.0) && (val[1] == 0.0))
1405 return 1.0;
1406
1407 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1408 // check only the first two parameters since the tshift is irrelevant for the LF-integral calculation!!
1409 Bool_t newParam = false;
1410 for (UInt_t i=0; i<2; i++) {
1411 if (val[i] != fPrevParam[i]) {
1412 newParam = true;
1413 break;
1414 }
1415 }
1416
1417 if (newParam) { // new parameters found
1418 {
1419 for (UInt_t i=0; i<2; i++)
1420 fPrevParam[i] = val[i];
1422 }
1423 }
1424
1425 Double_t tt;
1426 if (fParamNo.size() == 2) // no tshift
1427 tt = t;
1428 else // tshift present
1429 tt = t-val[2];
1430
1431 if (tt < 0.0) // for times < 0 return a function value of 1.0
1432 return 1.0;
1433
1434 Double_t sigma_t_2 = 0.0;
1435 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use the ZF formula
1436 sigma_t_2 = tt*tt*val[1]*val[1];
1437 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
1438 } else if (val[1]/val[0] > 79.5775) { // check if Delta/w0 > 500.0, in which case the ZF formula is used
1439 sigma_t_2 = tt*tt*val[1]*val[1];
1440 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
1441 } else {
1442 Double_t delta = val[1];
1443 Double_t w0 = 2.0*TMath::Pi()*val[0];
1444
1445 result = 1.0 - 2.0*TMath::Power(delta/w0,2.0)*(1.0 -
1446 TMath::Exp(-0.5*TMath::Power(delta*tt, 2.0))*TMath::Cos(w0*tt)) +
1448 }
1449
1450 return result;
1451
1452}
1453
1454//--------------------------------------------------------------------------
1473Double_t PTheory::DynamicGaussKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1474{
1475 // expected parameters: frequency damping hopping [tshift]
1476
1477 Double_t val[4];
1478 Double_t result = 0.0;
1479 Bool_t useKeren = false;
1480
1481 assert(fParamNo.size() <= 4);
1482
1483 // check if FUNCTIONS are used
1484 for (UInt_t i=0; i<fParamNo.size(); i++) {
1485 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1486 val[i] = paramValues[fParamNo[i]];
1487 } else { // function
1488 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1489 }
1490 }
1491
1492 // check if all parameters == 0
1493 if ((val[0] == 0.0) && (val[1] == 0.0) && (val[2] == 0.0))
1494 return 1.0;
1495
1496 // make sure that damping and hopping are positive definite
1497 if (val[1] < 0.0)
1498 val[1] = -val[1];
1499 if (val[2] < 0.0)
1500 val[2] = -val[2];
1501
1502 // check that Delta != 0, if not (i.e. stupid parameter) return 1, which is the correct limit
1503 if (fabs(val[1]) < 1.0e-6) {
1504 return 1.0;
1505 }
1506
1507 // check if Keren approximation can be used
1508 if (val[2]/val[1] > 5.0) // nu/Delta > 5.0
1509 useKeren = true;
1510
1511 if (!useKeren) {
1512 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1513 // check only the first three parameters since the tshift is irrelevant for the LF-integral calculation!!
1514 Bool_t newParam = false;
1515 for (UInt_t i=0; i<3; i++) {
1516 if (val[i] != fPrevParam[i]) {
1517 newParam = true;
1518 break;
1519 }
1520 }
1521
1522 if (newParam) { // new parameters found
1523 for (UInt_t i=0; i<3; i++)
1524 fPrevParam[i] = val[i];
1525 CalculateDynKTLF(val, 0); // 0 means Gauss
1526 }
1527 }
1528
1529 Double_t tt;
1530 if (fParamNo.size() == 3) // no tshift
1531 tt = t;
1532 else // tshift present
1533 tt = t-val[3];
1534
1535 if (tt < 0.0) // for times < 0 return a function value of 0.0
1536 return 0.0;
1537
1538
1539 if (useKeren) { // see PRB50, 10039 (1994)
1540 Double_t wL = TWO_PI * val[0];
1541 Double_t wL2 = wL*wL;
1542 Double_t nu2 = val[2]*val[2];
1543 Double_t Gamma_t = 2.0*val[1]*val[1]/((wL2+nu2)*(wL2+nu2))*
1544 ((wL2+nu2)*val[2]*t
1545 + (wL2-nu2)*(1.0 - TMath::Exp(-val[2]*t)*TMath::Cos(wL*t))
1546 - 2.0*val[2]*wL*TMath::Exp(-val[2]*t)*TMath::Sin(wL*t));
1547 result = TMath::Exp(-Gamma_t);
1548 } else { // from Voltera
1549 result = GetDynKTLFValue(tt);
1550 }
1551
1552 return result;
1553
1554}
1555
1556//--------------------------------------------------------------------------
1571Double_t PTheory::StaticLorentzKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1572{
1573 // expected parameters: lambda [tshift]
1574
1575 Double_t val[2];
1576
1577 assert(fParamNo.size() <= 2);
1578
1579 // check if FUNCTIONS are used
1580 for (UInt_t i=0; i<fParamNo.size(); i++) {
1581 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1582 val[i] = paramValues[fParamNo[i]];
1583 } else { // function
1584 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1585 }
1586 }
1587
1588 Double_t a_t;
1589 if (fParamNo.size() == 1) // no tshift
1590 a_t = t*val[0];
1591 else // tshift present
1592 a_t = (t-val[1])*val[0];
1593
1594 return 0.333333333333333 * (1.0 + 2.0*(1.0 - a_t)*TMath::Exp(-a_t));
1595}
1596
1597//--------------------------------------------------------------------------
1614Double_t PTheory::StaticLorentzKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1615{
1616 // expected parameters: frequency damping [tshift]
1617
1618 Double_t val[3];
1619 Double_t result;
1620
1621 assert(fParamNo.size() <= 3);
1622
1623 // check if FUNCTIONS are used
1624 for (UInt_t i=0; i<fParamNo.size(); i++) {
1625 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1626 val[i] = paramValues[fParamNo[i]];
1627 } else { // function
1628 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1629 }
1630 }
1631
1632 // check if all parameters == 0
1633 if ((val[0] == 0.0) && (val[1] == 0.0))
1634 return 1.0;
1635
1636 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1637 // check only the first two parameters since the tshift is irrelevant for the LF-integral calculation!!
1638 Bool_t newParam = false;
1639 for (UInt_t i=0; i<2; i++) {
1640 if (val[i] != fPrevParam[i]) {
1641 newParam = true;
1642 break;
1643 }
1644 }
1645
1646 if (newParam) { // new parameters found
1647 for (UInt_t i=0; i<2; i++)
1648 fPrevParam[i] = val[i];
1650 }
1651
1652 Double_t tt;
1653 if (fParamNo.size() == 2) // no tshift
1654 tt = t;
1655 else // tshift present
1656 tt = t-val[2];
1657
1658 if (tt < 0.0) // for times < 0 return a function value of 1.0
1659 return 1.0;
1660
1661 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use the ZF formula
1662 Double_t at = tt*val[1];
1663 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
1664 } else if (val[1]/val[0] > 159.1549) { // check if a/w0 > 1000.0, in which case the ZF formula is used
1665 Double_t at = tt*val[1];
1666 result = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
1667 } else {
1668 Double_t a = val[1];
1669 Double_t at = a*tt;
1670 Double_t w0 = 2.0*TMath::Pi()*val[0];
1671 Double_t a_w0 = a/w0;
1672 Double_t w0t = w0*tt;
1673
1674 Double_t j1, j0;
1675 if (fabs(w0t) < 0.001) { // check zero time limits of the spherical bessel functions j0(x) and j1(x)
1676 j0 = 1.0;
1677 j1 = 0.0;
1678 } else {
1679 j0 = sin(w0t)/w0t;
1680 j1 = (sin(w0t)-w0t*cos(w0t))/(w0t*w0t);
1681 }
1682
1683 result = 1.0 - a_w0*j1*exp(-at) - a_w0*a_w0*(j0*exp(-at) - 1.0) - GetLFIntegralValue(tt);
1684 }
1685
1686 return result;
1687
1688}
1689
1690//--------------------------------------------------------------------------
1711Double_t PTheory::DynamicLorentzKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1712{
1713 // expected parameters: frequency damping hopping [tshift]
1714
1715 Double_t val[4];
1716 Double_t result = 0.0;
1717
1718 assert(fParamNo.size() <= 4);
1719
1720 // check if FUNCTIONS are used
1721 for (UInt_t i=0; i<fParamNo.size(); i++) {
1722 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1723 val[i] = paramValues[fParamNo[i]];
1724 } else { // function
1725 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1726 }
1727 }
1728
1729 // check if all parameters == 0
1730 if ((val[0] == 0.0) && (val[1] == 0.0) && (val[2] == 0.0))
1731 return 1.0;
1732
1733 // make sure that damping and hopping are positive definite
1734 if (val[1] < 0.0)
1735 val[1] = -val[1];
1736 if (val[2] < 0.0)
1737 val[2] = -val[2];
1738
1739
1740 Double_t tt;
1741 if (fParamNo.size() == 3) // no tshift
1742 tt = t;
1743 else // tshift present
1744 tt = t-val[3];
1745
1746 if (tt < 0.0) // for times < 0 return a function value of 1.0
1747 return 1.0;
1748
1749 // check if hopping > 5 * damping, of Larmor angular frequency is > 30 * damping (BMW limit)
1750 Double_t w0 = 2.0*TMath::Pi()*val[0];
1751 Double_t a = val[1];
1752 Double_t nu = val[2];
1753 if ((nu > 5.0 * a) || (w0 >= 30.0 * a)) {
1754 // 'c' and 'd' are parameters BMW obtained by fitting large parameter space LF-curves to the model below
1755 const Double_t c[7] = {1.15331, 1.64826, -0.71763, 3.0, 0.386683, -5.01876, 2.41854};
1756 const Double_t d[4] = {2.44056, 2.92063, 1.69581, 0.667277};
1757 Double_t w0N[4];
1758 Double_t nuN[4];
1759 w0N[0] = w0;
1760 nuN[0] = nu;
1761 for (UInt_t i=1; i<4; i++) {
1762 w0N[i] = w0 * w0N[i-1];
1763 nuN[i] = nu * nuN[i-1];
1764 }
1765 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];
1766 Double_t b1 = (c[0]*w0N[2]+c[1]*w0N[1]*nuN[0]+c[2]*w0N[0]*nuN[1])/denom;
1767 Double_t b2 = (c[3]*w0N[2]+c[4]*w0N[1]*nuN[0]+c[5]*w0N[0]*nuN[1]+c[6]*nuN[2])/denom;
1768
1769 Double_t w0t = w0*tt;
1770 Double_t j1, j0;
1771 if (fabs(w0t) < 0.001) { // check zero time limits of the spherical bessel functions j0(x) and j1(x)
1772 j0 = 1.0;
1773 j1 = 0.0;
1774 } else {
1775 j0 = sin(w0t)/w0t;
1776 j1 = (sin(w0t)-w0t*cos(w0t))/(w0t*w0t);
1777 }
1778
1779 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);
1780
1781 return TMath::Exp(Gamma_t);
1782 }
1783
1784 // check if the parameter values have changed, and if yes recalculate the non-analytic integral
1785 // check only the first three parameters since the tshift is irrelevant for the LF-integral calculation!!
1786 Bool_t newParam = false;
1787 for (UInt_t i=0; i<3; i++) {
1788 if (val[i] != fPrevParam[i]) {
1789 newParam = true;
1790 break;
1791 }
1792 }
1793
1794 if (newParam) { // new parameters found
1795 for (UInt_t i=0; i<3; i++)
1796 fPrevParam[i] = val[i];
1797 CalculateDynKTLF(val, 1); // 1 means Lorentz
1798 }
1799
1800 result = GetDynKTLFValue(tt);
1801
1802 return result;
1803
1804}
1805
1806//--------------------------------------------------------------------------
1819Double_t PTheory::DynamicGauLorKTZFFast(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1820{
1821 // expected parameters: damping hopping [tshift]
1822
1823 Double_t val[3];
1824
1825 assert(fParamNo.size() <= 3);
1826
1827 // check if FUNCTIONS are used
1828 for (UInt_t i=0; i<fParamNo.size(); i++) {
1829 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1830 val[i] = paramValues[fParamNo[i]];
1831 } else { // function
1832 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1833 }
1834 }
1835
1836 Double_t tt;
1837 if (fParamNo.size() == 2) // no tshift
1838 tt = t;
1839 else // tshift present
1840 tt = t-val[2];
1841
1842 Double_t nut = val[1]*tt;
1843 return exp(-sqrt(4.0*pow(val[0]/val[1], 2.0)*(exp(-nut)-1.0+nut)));
1844}
1845
1846//--------------------------------------------------------------------------
1859Double_t PTheory::DynamicGauLorKTLFFast(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1860{
1861 // expected parameters: frequency damping hopping [tshift]
1862
1863 Double_t val[4];
1864
1865 assert(fParamNo.size() <= 4);
1866
1867 // check if FUNCTIONS are used
1868 for (UInt_t i=0; i<fParamNo.size(); i++) {
1869 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1870 val[i] = paramValues[fParamNo[i]];
1871 } else { // function
1872 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1873 }
1874 }
1875
1876 Double_t tt;
1877 if (fParamNo.size() == 3) // no tshift
1878 tt = t;
1879 else // tshift present
1880 tt = t-val[3];
1881
1882 Double_t w0 = TMath::TwoPi()*val[0];
1883 Double_t w0_2 = w0*w0;
1884 Double_t nu_2 = val[2]*val[2];
1885 Double_t nu_t = val[2]*tt;
1886 Double_t w0_t = w0*tt;
1887 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);
1888 if (Gamma_t < 0.0)
1889 Gamma_t = 0.0;
1890
1891 return exp(-sqrt(4.0*val[1]*val[1]*Gamma_t));
1892}
1893
1894//--------------------------------------------------------------------------
1906Double_t PTheory::DynamicGauLorKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
1907{
1908 // expected parameters: frequency damping hopping [tshift]
1909
1910 Double_t val[4];
1911
1912 assert(fParamNo.size() <= 4);
1913
1914 // check if FUNCTIONS are used
1915 for (UInt_t i=0; i<fParamNo.size(); i++) {
1916 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
1917 val[i] = paramValues[fParamNo[i]];
1918 } else { // function
1919 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
1920 }
1921 }
1922
1923 Double_t tt;
1924 if (fParamNo.size() == 3) // no tshift
1925 tt = t;
1926 else // tshift present
1927 tt = t-val[3];
1928
1929 // check if the parameter values have changed, and if yes recalculate DynamicGaussKTLF
1930 Bool_t newParam = false;
1931 for (UInt_t i=0; i<3; i++) {
1932 if (val[i] != fPrevParam[i]) {
1933 newParam = true;
1934 break;
1935 }
1936 }
1937
1938 if (newParam) { // new parameters found, hence calculate DynamicGauLorKTLF
1939 // keep parameters
1940 for (UInt_t i=0; i<3; i++)
1941 fPrevParam[i] = val[i];
1942
1943 // reset GL LF polarzation vector
1944 fDyn_GL_LFFuncValue.clear();
1945 fDyn_GL_LFFuncValue.resize(20000); // Tmax=20us, dt=1ns
1946
1947 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,
1948 12.8125, 15.625, 18.4375, 21.25, 26.875, 32.5, 43.75, 55.0, 77.5, 100.0};
1949 Double_t par[3] = {val[0], val[1], val[2]};
1950 Double_t sqrtTwoInv = 1.0/sqrt(2.0);
1951 Bool_t isOneVec{false};
1952 Bool_t useKeren{false};
1953 Double_t scale, up{0.0}, low{-1.0};
1954
1955 for (UInt_t i=0; i<rr.size(); i++) {
1956 useKeren = false;
1957 isOneVec = false;
1958
1959 // Delta_G = rr * Delta_L
1960 par[1] = rr[i] * val[1];
1961
1962 // check if all parameters == 0
1963 if ((par[0] == 0.0) && (par[1] == 0.0) && (par[2] == 0.0)) {
1964 isOneVec = true;
1965 }
1966
1967 // make sure that damping and hopping are positive definite
1968 if (par[1] < 0.0)
1969 par[1] = -par[1];
1970 if (par[2] < 0.0)
1971 par[2] = -par[2];
1972
1973 // check that Delta != 0, if not (i.e. stupid parameter) return 1, which is the correct limit
1974 if (fabs(par[1]) < 1.0e-6) {
1975 isOneVec = true;
1976 }
1977
1978 // check if Keren approximation can be used
1979 if (par[2]/par[1] > 5.0) // nu/Delta > 5.0
1980 useKeren = true;
1981
1982 if (!useKeren && !isOneVec) {
1983 CalculateDynKTLF(par, 0); // 0 means Gauss
1984 }
1985
1986 // calculate polarization vector for the given parameters
1987 up = -std::erf(sqrtTwoInv/rr[i]);
1988 scale = up - low;
1989 low = up;
1990
1991 const Double_t dt=0.001;
1992 for (UInt_t i=0; i<20000; i++) {
1993 if (isOneVec) {
1994 fDyn_GL_LFFuncValue[i] += scale;
1995 } else if (useKeren && !isOneVec) {// see PRB50, 10039 (1994)
1996 Double_t wL = TWO_PI * par[0];
1997 Double_t wL2 = wL*wL;
1998 Double_t nu2 = par[2]*par[2];
1999 Double_t Gamma_t = 2.0*par[1]*par[1]/((wL2+nu2)*(wL2+nu2))*
2000 ((wL2+nu2)*val[2]*i*dt
2001 + (wL2-nu2)*(1.0 - TMath::Exp(-val[2]*i*dt)*TMath::Cos(wL*i*dt))
2002 - 2.0*val[2]*wL*TMath::Exp(-val[2]*i*dt)*TMath::Sin(wL*i*dt));
2003 fDyn_GL_LFFuncValue[i] += scale*TMath::Exp(-Gamma_t);
2004 } else if (!useKeren && !isOneVec) {
2005 fDyn_GL_LFFuncValue[i] += scale*GetDynKTLFValue(i*dt);
2006 }
2007 }
2008 }
2009 }
2010
2011
2012 // get the proper value from the look-up table
2013 Double_t result{1.0};
2014 if (tt>=0)
2015 result=GetDyn_GL_KTLFValue(tt);
2016
2017 return result;
2018}
2019
2020//--------------------------------------------------------------------------
2035Double_t PTheory::CombiLGKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2036{
2037 // expected parameters: lambdaL lambdaG [tshift]
2038
2039 Double_t val[3];
2040
2041 assert(fParamNo.size() <= 3);
2042
2043 // check if FUNCTIONS are used
2044 for (UInt_t i=0; i<fParamNo.size(); i++) {
2045 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2046 val[i] = paramValues[fParamNo[i]];
2047 } else { // function
2048 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2049 }
2050 }
2051
2052 Double_t tt;
2053 if (fParamNo.size() == 2) // no tshift
2054 tt = t;
2055 else // tshift present
2056 tt = t-val[2];
2057
2058 Double_t lambdaL_t = tt*val[0];
2059 Double_t lambdaG_t_2 = tt*tt*val[1]*val[1];
2060
2061 return 0.333333333333333 *
2062 (1.0 + 2.0*(1.0-lambdaL_t-lambdaG_t_2)*TMath::Exp(-(lambdaL_t+0.5*lambdaG_t_2)));
2063}
2064
2065//--------------------------------------------------------------------------
2081Double_t PTheory::StrKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2082{
2083 // expected parameters: sigma beta [tshift]
2084
2085 Double_t val[3];
2086
2087 assert(fParamNo.size() <= 3);
2088
2089 // check if FUNCTIONS are used
2090 for (UInt_t i=0; i<fParamNo.size(); i++) {
2091 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2092 val[i] = paramValues[fParamNo[i]];
2093 } else { // function
2094 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2095 }
2096 }
2097
2098 // check for beta too small (beta < 0.1) in which case numerical problems could arise and the function is anyhow
2099 // almost identical to a constant of 1/3.
2100 if (val[1] < 0.1)
2101 return 0.333333333333333;
2102
2103 Double_t tt;
2104 if (fParamNo.size() == 2) // no tshift
2105 tt = t;
2106 else // tshift present
2107 tt = t-val[2];
2108
2109 Double_t sigma_t = TMath::Power(tt*val[0],val[1]);
2110
2111 return 0.333333333333333 *
2112 (1.0 + 2.0*(1.0-sigma_t)*TMath::Exp(-sigma_t/val[1]));
2113}
2114
2115//--------------------------------------------------------------------------
2130Double_t PTheory::SpinGlass(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2131{
2132 // expected parameters: lambda gamma q [tshift]
2133
2134 if (paramValues[fParamNo[0]] == 0.0)
2135 return 1.0;
2136
2137 Double_t val[4];
2138
2139 assert(fParamNo.size() <= 4);
2140
2141 // check if FUNCTIONS are used
2142 for (UInt_t i=0; i<fParamNo.size(); i++) {
2143 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2144 val[i] = paramValues[fParamNo[i]];
2145 } else { // function
2146 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2147 }
2148 }
2149
2150 Double_t tt;
2151 if (fParamNo.size() == 3) // no tshift
2152 tt = t;
2153 else // tshift present
2154 tt = t-val[3];
2155
2156 Double_t lambda_2 = val[0]*val[0];
2157 Double_t lambda_t_2_q = tt*tt*lambda_2*val[2];
2158 Double_t rate_2 = 4.0*lambda_2*(1.0-val[2])*tt/val[1];
2159
2160 Double_t rateL = TMath::Sqrt(fabs(rate_2));
2161 Double_t rateT = TMath::Sqrt(fabs(rate_2)+lambda_t_2_q);
2162
2163 return 0.333333333333333*(TMath::Exp(-rateL) + 2.0*(1.0-lambda_t_2_q/rateT)*TMath::Exp(-rateT));
2164}
2165
2166//--------------------------------------------------------------------------
2181Double_t PTheory::RandomAnisotropicHyperfine(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2182{
2183 // expected parameters: nu lambda [tshift]
2184
2185 Double_t val[3];
2186
2187 assert(fParamNo.size() <= 3);
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() == 2) // no tshift
2200 tt = t;
2201 else // tshift present
2202 tt = t-val[2];
2203
2204 Double_t nu_t = tt*val[0];
2205 Double_t lambda_t = tt*val[1];
2206
2207 return 0.166666666666667*(1.0-0.5*nu_t)*TMath::Exp(-0.5*nu_t) +
2208 0.333333333333333*(1.0-0.25*nu_t)*TMath::Exp(-0.25*(nu_t+2.44949*lambda_t));
2209}
2210
2211//--------------------------------------------------------------------------
2226Double_t PTheory::Abragam(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2227{
2228 // expected parameters: sigma gamma [tshift]
2229
2230 Double_t val[3];
2231
2232 assert(fParamNo.size() <= 3);
2233
2234 // check if FUNCTIONS are used
2235 for (UInt_t i=0; i<fParamNo.size(); i++) {
2236 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2237 val[i] = paramValues[fParamNo[i]];
2238 } else { // function
2239 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2240 }
2241 }
2242
2243 Double_t tt;
2244 if (fParamNo.size() == 2) // no tshift
2245 tt = t;
2246 else // tshift present
2247 tt = t-val[2];
2248
2249 Double_t gamma_t = tt*val[1];
2250
2251 return TMath::Exp(-TMath::Power(val[0]/val[1],2.0)*
2252 (TMath::Exp(-gamma_t)-1.0+gamma_t));
2253}
2254
2255//--------------------------------------------------------------------------
2270Double_t PTheory::TFCos(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2271{
2272 // expected parameters: phase frequency [tshift]
2273
2274 Double_t val[3];
2275
2276 assert(fParamNo.size() <= 3);
2277
2278 // check if FUNCTIONS are used
2279 for (UInt_t i=0; i<fParamNo.size(); i++) {
2280 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2281 val[i] = paramValues[fParamNo[i]];
2282 } else { // function
2283 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2284 }
2285 }
2286
2287 Double_t tt;
2288 if (fParamNo.size() == 2) // no tshift
2289 tt = t;
2290 else // tshift present
2291 tt = t-val[2];
2292
2293 return TMath::Cos(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2294}
2295
2296//--------------------------------------------------------------------------
2311Double_t PTheory::InternalField(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2312{
2313 // expected parameters: fraction phase frequency rateT rateL [tshift]
2314
2315 Double_t val[6];
2316
2317 assert(fParamNo.size() <= 6);
2318
2319 // check if FUNCTIONS are used
2320 for (UInt_t i=0; i<fParamNo.size(); i++) {
2321 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2322 val[i] = paramValues[fParamNo[i]];
2323 } else { // function
2324 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2325 }
2326 }
2327
2328 Double_t tt;
2329 if (fParamNo.size() == 5) // no tshift
2330 tt = t;
2331 else // tshift present
2332 tt = t-val[5];
2333
2334 return val[0]*TMath::Cos(DEG_TO_RAD*val[1]+TWO_PI*val[2]*tt)*TMath::Exp(-val[3]*tt) +
2335 (1-val[0])*TMath::Exp(-val[4]*tt);
2336}
2337
2338//--------------------------------------------------------------------------
2353Double_t PTheory::InternalFieldGK(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2354{
2355 // expected parameters: [0]:fraction [1]:frequency [2]:sigma [3]:lambda [4]:beta [[5]:tshift]
2356
2357 Double_t val[6];
2358
2359 assert(fParamNo.size() <= 6);
2360
2361 // check if FUNCTIONS are used
2362 for (UInt_t i=0; i<fParamNo.size(); i++) {
2363 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2364 val[i] = paramValues[fParamNo[i]];
2365 } else { // function
2366 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2367 }
2368 }
2369
2370 Double_t tt;
2371 if (fParamNo.size() == 5) // no tshift
2372 tt = t;
2373 else // tshift present
2374 tt = t-val[5];
2375
2376 Double_t result = 0.0;
2377 Double_t w_t = TWO_PI*val[1]*tt;
2378 Double_t rateLF = TMath::Power(val[3]*tt, val[4]);
2379 Double_t rate2 = val[2]*val[2]*tt*tt; // (sigma t)^2
2380
2381 if (val[1] < 0.01) { // internal field frequency is approaching zero
2382 result = (1.0-val[0])*TMath::Exp(-rateLF) + val[0]*(1.0-rate2)*TMath::Exp(-0.5*rate2);
2383 } else {
2384 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);
2385 }
2386
2387 return result;
2388}
2389
2390//--------------------------------------------------------------------------
2405Double_t PTheory::InternalFieldLL(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2406{
2407 // expected parameters: [0]:fraction [1]:frequency [2]:a [3]:lambda [4]:beta [[5]:tshift]
2408
2409 Double_t val[6];
2410
2411 assert(fParamNo.size() <= 6);
2412
2413 // check if FUNCTIONS are used
2414 for (UInt_t i=0; i<fParamNo.size(); i++) {
2415 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2416 val[i] = paramValues[fParamNo[i]];
2417 } else { // function
2418 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2419 }
2420 }
2421
2422 Double_t tt;
2423 if (fParamNo.size() == 5) // no tshift
2424 tt = t;
2425 else // tshift present
2426 tt = t-val[5];
2427
2428 Double_t result = 0.0;
2429 Double_t w_t = TWO_PI*val[1]*tt;
2430 Double_t rateLF = TMath::Power(val[3]*tt, val[4]);
2431 Double_t a_t = val[2]*tt; // a t
2432
2433 if (val[1] < 0.01) { // internal field frequency is approaching zero
2434 result = (1.0-val[0])*TMath::Exp(-rateLF) + val[0]*(1.0-a_t)*TMath::Exp(-a_t);
2435 } else {
2436 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);
2437 }
2438
2439 return result;
2440}
2441
2442//--------------------------------------------------------------------------
2457Double_t PTheory::Bessel(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2458{
2459 // expected parameters: phase frequency [tshift]
2460
2461 Double_t val[3];
2462
2463 assert(fParamNo.size() <= 3);
2464
2465 // check if FUNCTIONS are used
2466 for (UInt_t i=0; i<fParamNo.size(); i++) {
2467 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2468 val[i] = paramValues[fParamNo[i]];
2469 } else { // function
2470 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2471 }
2472 }
2473
2474 Double_t tt;
2475 if (fParamNo.size() == 2) // no tshift
2476 tt = t;
2477 else // tshift present
2478 tt = t-val[2];
2479
2480 return TMath::BesselJ0(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2481}
2482
2483//--------------------------------------------------------------------------
2498Double_t PTheory::InternalBessel(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2499{
2500 // expected parameters: fraction phase frequency rateT rateL [tshift]
2501
2502 Double_t val[6];
2503
2504 assert(fParamNo.size() <= 6);
2505
2506 // check if FUNCTIONS are used
2507 for (UInt_t i=0; i<fParamNo.size(); i++) {
2508 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2509 val[i] = paramValues[fParamNo[i]];
2510 } else { // function
2511 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2512 }
2513 }
2514
2515 Double_t tt;
2516 if (fParamNo.size() == 5) // no tshift
2517 tt = t;
2518 else // tshift present
2519 tt = t-val[5];
2520
2521 return val[0]* TMath::BesselJ0(DEG_TO_RAD*val[1]+TWO_PI*val[2]*tt)*
2522 TMath::Exp(-val[3]*tt) +
2523 (1.0-val[0])*TMath::Exp(-val[4]*tt);
2524}
2525
2526//--------------------------------------------------------------------------
2547Double_t PTheory::SkewedGauss(Double_t t, const PDoubleVector &paramValues,
2548 const PDoubleVector &funcValues) const {
2549 // Expected parameters: phase, frequency, sigma-, sigma+, [tshift].
2550 // To be stored in the array "val" as:
2551 // val[0] = phase
2552 // val[1] = frequency
2553 // val[2] = sigma-
2554 // val[3] = sigma+
2555 // val[4] = tshift [optional]
2556 Double_t val[5];
2557
2558 // Check that we have the correct number of fit parameters.
2559 assert(fParamNo.size() <= 5);
2560
2561 // Check if FUNCTIONS are used.
2562 for (UInt_t i = 0; i < fParamNo.size(); i++) {
2563 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2564 val[i] = paramValues[fParamNo[i]];
2565 } else { // function
2566 val[i] = funcValues[fParamNo[i] - MSR_PARAM_FUN_OFFSET];
2567 }
2568 }
2569
2570 // Apply the tshift (if required).
2571 Double_t tt = t;
2572 if (fParamNo.size() == 5) {
2573 tt = t - val[4];
2574 }
2575
2576 // Evaluate the skewed Gaussian!
2577
2578 // First, calculate some "helper" terms.
2579 Double_t sigma_p = std::abs(val[3]);
2580 Double_t sigma_m = std::abs(val[2]);
2581 Double_t arg_p = sigma_p * tt;
2582 Double_t arg_m = sigma_m * tt;
2583 Double_t z_p = arg_p / SQRT_TWO; // sigma+
2584 Double_t z_m = arg_m / SQRT_TWO; // sigma-
2585 Double_t g_p = TMath::Exp(-0.5 * arg_p * arg_p); // gauss sigma+
2586 Double_t g_m = TMath::Exp(-0.5 * arg_m * arg_m); // gauss sigma-
2587 Double_t w_p = sigma_p / (sigma_p + sigma_m);
2588 Double_t w_m = 1.0 - w_p;
2589 Double_t phase = DEG_TO_RAD * val[0];
2590 Double_t freq = TWO_PI * val[1];
2591
2592 // Evalute the EVEN frequency component of the skewed Gaussian.
2593 Double_t skg_cos = TMath::Cos(phase + freq * tt) * (w_m * g_m + w_p * g_p);
2594
2595 // Evalute the ODD frequency component of the skewed Gaussian.
2596 constexpr Double_t z_max = 26.7776;
2597 // Note: the check against z_max is needed to prevent floating-point overflow
2598 // in the return value of ROOT::Math::conf_hyperg(1/2, 3/2, z * z)
2599 // (i.e., confluent hypergeometric function of the first kind, 1F1).
2600 // In the case that z > z_max, return zero (otherwise there is some
2601 // numeric discontinuity at later times).
2602 Double_t skg_sin =
2603 TMath::Sin(phase + freq * tt) *
2604 ((z_m > z_max) or (z_p > z_max)
2605 ? 0.0
2606 : (w_m * g_m * 2.0 * z_m / SQRT_PI) *
2607 ROOT::Math::conf_hyperg(0.5, 1.5, z_m * z_m) -
2608 (w_p * g_p * 2.0 * z_p / SQRT_PI) *
2609 ROOT::Math::conf_hyperg(0.5, 1.5, z_p * z_p));
2610
2611 // Return the skewed Gaussian: skg = skg_cos + skg_sin.
2612 // Also check that skg_sin is finite!
2613 return skg_cos + (std::isfinite(skg_sin) ? skg_sin : 0.0);
2614}
2615
2616//--------------------------------------------------------------------------
2636Double_t PTheory::StaticNKZF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2637{
2638 // expected paramters: damping_D0 [0], R_b tshift [1]
2639
2640 Double_t val[3];
2641 Double_t result = 1.0;
2642
2643 assert(fParamNo.size() <= 3);
2644
2645 if (t < 0.0)
2646 return result;
2647
2648 // check if FUNCTIONS are used
2649 for (UInt_t i=0; i<fParamNo.size(); i++) {
2650 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2651 val[i] = paramValues[fParamNo[i]];
2652 } else { // function
2653 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2654 }
2655 }
2656
2657 Double_t tt;
2658 if (fParamNo.size() == 2) // no tshift
2659 tt = t;
2660 else // tshift present
2661 tt = t-val[2];
2662
2663 Double_t D2_t2 = val[0]*val[0]*tt*tt;
2664 Double_t denom = 1.0+val[1]*val[1]*D2_t2;
2665
2666 result = 0.333333333333333 + 0.666666666666666667 * TMath::Power(1.0/denom, 1.5) * (1.0 - (D2_t2/denom)) * exp(-0.5*D2_t2/denom);
2667
2668 return result;
2669}
2670
2671//--------------------------------------------------------------------------
2691Double_t PTheory::StaticNKTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2692{
2693 // expected paramters: phase [0], frequency [1], damping_D0 [2], R_b [3], [tshift [4]]
2694
2695 Double_t val[5];
2696 Double_t result = 1.0;
2697
2698 assert(fParamNo.size() <= 5);
2699
2700 if (t < 0.0)
2701 return result;
2702
2703 // check if FUNCTIONS are used
2704 for (UInt_t i=0; i<fParamNo.size(); i++) {
2705 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2706 val[i] = paramValues[fParamNo[i]];
2707 } else { // function
2708 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2709 }
2710 }
2711
2712 Double_t tt;
2713 if (fParamNo.size() == 4) // no tshift
2714 tt = t;
2715 else // tshift present
2716 tt = t-val[4];
2717
2718 Double_t D2_t2 = val[2]*val[2]*tt*tt;
2719 Double_t denom = 1.0+val[3]*val[3]*D2_t2;
2720
2721 result = sqrt(1.0/denom)*exp(-0.5*D2_t2/denom)*TMath::Cos(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2722
2723 return result;
2724}
2725
2726//--------------------------------------------------------------------------
2747Double_t PTheory::DynamicNKZF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2748{
2749 // expected paramters: damping_D0 [0], R_b [1], nu_c [2], [tshift [3]]
2750
2751 Double_t val[4];
2752 Double_t result = 1.0;
2753
2754 assert(fParamNo.size() <= 4);
2755
2756 if (t < 0.0)
2757 return result;
2758
2759 // check if FUNCTIONS are used
2760 for (UInt_t i=0; i<fParamNo.size(); i++) {
2761 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2762 val[i] = paramValues[fParamNo[i]];
2763 } else { // function
2764 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2765 }
2766 }
2767
2768 Double_t tt;
2769 if (fParamNo.size() == 3) // no tshift
2770 tt = t;
2771 else // tshift present
2772 tt = t-val[3];
2773
2774 Double_t theta;
2775 if (val[2] < 1.0e-6) { // nu_c -> 0
2776 theta = 0.5*tt*tt;
2777 } else {
2778 theta = (exp(-val[2]*tt) - 1.0 + val[2]*tt)/(val[2]*val[2]);
2779 }
2780 Double_t denom = 1.0 + 4.0*val[0]*val[0]*val[1]*val[1]*theta;
2781
2782 result = sqrt(1.0/denom)*exp(-2.0*val[0]*val[0]*theta/denom);
2783
2784 return result;
2785}
2786
2787//--------------------------------------------------------------------------
2808Double_t PTheory::DynamicNKTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2809{
2810 // expected paramters: phase [0], frequency [1], damping_D0 [2], R_b [3], nu_c [4], [tshift [5]]
2811
2812 Double_t val[6];
2813 Double_t result = 1.0;
2814
2815 assert(fParamNo.size() <= 6);
2816
2817 if (t < 0.0)
2818 return result;
2819
2820 // check if FUNCTIONS are used
2821 for (UInt_t i=0; i<fParamNo.size(); i++) {
2822 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2823 val[i] = paramValues[fParamNo[i]];
2824 } else { // function
2825 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2826 }
2827 }
2828
2829 Double_t tt;
2830 if (fParamNo.size() == 5) // no tshift
2831 tt = t;
2832 else // tshift present
2833 tt = t-val[5];
2834
2835 Double_t theta;
2836 if (val[4] < 1.0e-6) { // nu_c -> 0
2837 theta = 0.5*tt*tt;
2838 } else {
2839 theta = (exp(-val[4]*tt) - 1.0 + val[4]*tt)/(val[4]*val[4]);
2840 }
2841 Double_t denom = 1.0 + 2.0*val[2]*val[2]*val[3]*val[3]*theta;
2842
2843 result = sqrt(1.0/denom)*exp(-val[2]*val[2]*theta/denom)*TMath::Cos(DEG_TO_RAD*val[0]+TWO_PI*val[1]*tt);
2844
2845 return result;
2846}
2847
2848//--------------------------------------------------------------------------
2859Double_t PTheory::FmuF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2860{
2861 // expected paramters: w_d [0], [tshift [1]]
2862
2863 Double_t val[2];
2864
2865 assert(fParamNo.size() <= 2);
2866
2867 if (t < 0.0)
2868 return 1.0;
2869
2870 // check if FUNCTIONS are used
2871 for (UInt_t i=0; i<fParamNo.size(); i++) {
2872 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2873 val[i] = paramValues[fParamNo[i]];
2874 } else { // function
2875 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2876 }
2877 }
2878
2879 Double_t tt;
2880 if (fParamNo.size() == 1) // no tshift
2881 tt = t;
2882 else // tshift present
2883 tt = t-val[1];
2884
2885 const Double_t sqrt3 = sqrt(3.0);
2886 const Double_t wd_t = val[0]*tt;
2887
2888 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;
2889}
2890
2891//--------------------------------------------------------------------------
2905Double_t PTheory::Polynom(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2906{
2907 // expected parameters: tshift p0 p1 p2 ...
2908
2909 Double_t result = 0.0;
2910 Double_t tshift = 0.0;
2911 Double_t val;
2912 Double_t expo = 0.0;
2913
2914 // check if FUNCTIONS are used
2915 for (UInt_t i=0; i<fParamNo.size(); i++) {
2916 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2917 val = paramValues[fParamNo[i]];
2918 } else { // function
2919 val = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2920 }
2921 if (i==0) { // tshift
2922 tshift = val;
2923 continue;
2924 }
2925 result += val*pow(t-tshift, expo);
2926 expo++;
2927 }
2928
2929 return result;
2930}
2931
2932//--------------------------------------------------------------------------
2942Double_t PTheory::UserFcn(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
2943{
2944 // check if FUNCTIONS are used
2945 for (UInt_t i=0; i<fUserParam.size(); i++) {
2946 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
2947 fUserParam[i] = paramValues[fParamNo[i]];
2948 } else { // function
2949 fUserParam[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
2950 }
2951 }
2952
2953 return (*fUserFcn)(t, fUserParam);
2954}
2955
2956//--------------------------------------------------------------------------
2969void PTheory::CalculateGaussLFIntegral(const Double_t *val) const
2970{
2971 // val[0] = nu (field), val[1] = Delta
2972
2973 if (val[0] == 0.0) { // field == 0.0, hence nothing to be done
2974 return;
2975 } 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
2976 return;
2977 }
2978
2979
2980 Double_t dt=0.001; // all times in usec
2981 Double_t t, ft;
2982 Double_t w0 = TMath::TwoPi()*val[0];
2983 Double_t Delta = val[1];
2984 Double_t preFactor = 2.0*TMath::Power(Delta, 4.0) / TMath::Power(w0, 3.0);
2985
2986 // check if the time resolution needs to be increased
2987 const Int_t samplingPerPeriod = 20;
2988 const Int_t samplingOnExp = 3000;
2989 if ((Delta <= w0) && (1.0/val[0] < 20.0)) { // makes sure that the frequency sampling is fine enough
2990 if (1.0/val[0]/samplingPerPeriod < 0.001) {
2991 dt = 1.0/val[0]/samplingPerPeriod;
2992 }
2993 } else if ((Delta > w0) && (Delta <= 10.0)) {
2994 if (Delta/w0 > 10.0) {
2995 dt = 0.00005;
2996 }
2997 } else if ((Delta > w0) && (Delta > 10.0)) { // makes sure there is a fine enough sampling for large Delta's
2998 if (1.0/Delta/samplingOnExp < 0.001) {
2999 dt = 1.0/Delta/samplingOnExp;
3000 }
3001 }
3002
3003 // keep sampling time
3004 fSamplingTime = dt;
3005
3006 // clear previously allocated vector
3007 fLFIntegral.clear();
3008
3009 // calculate integral
3010 t = 0.0;
3011 fLFIntegral.push_back(0.0); // start value of the integral
3012
3013 ft = 0.0;
3014 Double_t step = 0.0, lastft = 1.0, diff = 0.0;
3015 do {
3016 t += dt;
3017 step = 0.5*dt*preFactor*(exp(-0.5*pow(Delta * (t-dt), 2.0))*sin(w0*(t-dt))+
3018 exp(-0.5*pow(Delta * t, 2.0))*sin(w0*t));
3019 ft += step;
3020 diff = fabs(fabs(lastft)-fabs(ft));
3021 lastft = ft;
3022 fLFIntegral.push_back(ft);
3023 } while ((t <= 20.0) && (diff > 1.0e-10));
3024}
3025
3026//--------------------------------------------------------------------------
3039void PTheory::CalculateLorentzLFIntegral(const Double_t *val) const
3040{
3041 // val[0] = nu, val[1] = a
3042
3043 // a few checks if the integral actually needs to be calculated
3044 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use the ZF formula and here nothing has to be done
3045 return;
3046 } 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
3047 return;
3048 }
3049
3050 Double_t dt=0.001; // all times in usec
3051 Double_t t, ft;
3052 Double_t w0 = TMath::TwoPi()*val[0];
3053 Double_t a = val[1];
3054 Double_t preFactor = a*(1+pow(a/w0,2.0));
3055
3056 // check if the time resolution needs to be increased
3057 const Int_t samplingPerPeriod = 20;
3058 const Int_t samplingOnExp = 3000;
3059 if ((a <= w0) && (1.0/val[0] < 20.0)) { // makes sure that the frequency sampling is fine enough
3060 if (1.0/val[0]/samplingPerPeriod < 0.001) {
3061 dt = 1.0/val[0]/samplingPerPeriod;
3062 }
3063 } else if ((a > w0) && (a <= 10.0)) {
3064 if (a/w0 > 10.0) {
3065 dt = 0.00005;
3066 }
3067 } else if ((a > w0) && (a > 10.0)) { // makes sure there is a fine enough sampling for large a's
3068 if (1.0/a/samplingOnExp < 0.001) {
3069 dt = 1.0/a/samplingOnExp;
3070 }
3071 }
3072
3073 // keep sampling time
3074 fSamplingTime = dt;
3075
3076 // clear previously allocated vector
3077 fLFIntegral.clear();
3078
3079 // calculate integral
3080 t = 0.0;
3081 fLFIntegral.push_back(0.0); // start value of the integral
3082
3083 ft = 0.0;
3084 // calculate first integral bin value (needed bcause of sin(x)/x x->0)
3085 t += dt;
3086 ft += 0.5*dt*preFactor*(1.0+sin(w0*t)/(w0*t)*exp(-a*t));
3087 fLFIntegral.push_back(ft);
3088 // calculate all the other integral bin values
3089 Double_t step = 0.0, lastft = 1.0, diff = 0.0;
3090 do {
3091 t += dt;
3092 step = 0.5*dt*preFactor*(sin(w0*(t-dt))/(w0*(t-dt))*exp(-a*(t-dt))+sin(w0*t)/(w0*t)*exp(-a*t));
3093 ft += step;
3094 diff = fabs(fabs(lastft)-fabs(ft));
3095 lastft = ft;
3096 fLFIntegral.push_back(ft);
3097 } while ((t <= 20.0) && (diff > 1.0e-10));
3098}
3099
3100
3101//--------------------------------------------------------------------------
3109Double_t PTheory::GetLFIntegralValue(const Double_t t) const
3110{
3111 if (t < 0.0)
3112 return 0.0;
3113
3114 UInt_t idx = static_cast<UInt_t>(t/fSamplingTime);
3115
3116 if (idx + 2 > fLFIntegral.size())
3117 return fLFIntegral.back();
3118
3119 // linearly interpolate between the two relevant function bins
3120 Double_t df = (fLFIntegral[idx+1]-fLFIntegral[idx])*(t/fSamplingTime-static_cast<Double_t>(idx));
3121
3122 return fLFIntegral[idx]+df;
3123}
3124
3125//--------------------------------------------------------------------------
3136void PTheory::CalculateDynKTLF(const Double_t *val, Int_t tag) const
3137{
3138 // val: 0=nu0, 1=Delta (Gauss) / a (Lorentz), 2=nu
3139 const Double_t Tmax = 20.0; // 20 usec
3140 UInt_t N = static_cast<UInt_t>(16.0*Tmax*val[0]);
3141
3142 // check if rate (Delta or a) is very high
3143 if (fabs(val[1]) > 0.1) {
3144 Double_t tmin = 20.0;
3145 switch (tag) {
3146 case 0: // Gauss
3147 tmin = fabs(sqrt(3.0)/val[1]);
3148 break;
3149 case 1: // Lorentz
3150 tmin = fabs(2.0/val[1]);
3151 break;
3152 default:
3153 break;
3154 }
3155 UInt_t Nrate = static_cast<UInt_t>(25.0 * Tmax / tmin);
3156 if (Nrate > N) {
3157 N = Nrate;
3158 }
3159 }
3160
3161 if (N < 300) // if too few points, i.e. nu0 very small, take 300 points
3162 N = 300;
3163
3164 if (N>1e6) // make sure that N is not too large to prevent memory overflow
3165 N = 1e6;
3166
3167 // allocate memory for dyn KT LF function vector
3168 fDynLFFuncValue.clear(); // get rid of a possible previous vector
3169 fDynLFFuncValue.resize(N);
3170
3171 // calculate the non-analytic integral of the static KT LF function
3172 switch (tag) {
3173 case 0: // Gauss
3175 break;
3176 case 1: // Lorentz
3178 break;
3179 default:
3180 std::cerr << std::endl << ">> PTheory::CalculateDynKTLF: **FATAL ERROR** You should never have reached this point." << std::endl;
3181 assert(false);
3182 break;
3183 }
3184
3185 // calculate the P^(0)(t) exp(-nu t) vector
3186 PDoubleVector p0exp(N);
3187 Double_t t = 0.0;
3188 Double_t dt = Tmax/N;
3189 fDynLFdt = dt; // keep it since it is needed in GetDynKTLFValue()
3190 for (UInt_t i=0; i<N; i++) {
3191 switch (tag) {
3192 case 0: // Gauss
3193 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use zero field formula
3194 Double_t sigma_t_2 = t*t*val[1]*val[1];
3195 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
3196 } else if (val[1]/val[0] > 79.5775) { // check if Delta/w0 > 500.0, in which case the ZF formula is used
3197 Double_t sigma_t_2 = t*t*val[1]*val[1];
3198 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - sigma_t_2)*TMath::Exp(-0.5*sigma_t_2));
3199 } else {
3200 Double_t delta = val[1];
3201 Double_t w0 = TWO_PI*val[0];
3202
3203 p0exp[i] = 1.0 - 2.0*TMath::Power(delta/w0,2.0)*(1.0 -
3204 TMath::Exp(-0.5*TMath::Power(delta*t, 2.0))*TMath::Cos(w0*t)) +
3206 }
3207 break;
3208 case 1: // Lorentz
3209 if (val[0] < 0.02) { // if smaller 20kHz ~ 0.27G use zero field formula
3210 Double_t at = t*val[1];
3211 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
3212 } else if (val[1]/val[0] > 159.1549) { // check if a/w0 > 1000.0, in which case the ZF formula is used
3213 Double_t at = t*val[1];
3214 p0exp[i] = 0.333333333333333 * (1.0 + 2.0*(1.0 - at)*TMath::Exp(-at));
3215 } else {
3216 Double_t a = val[1];
3217 Double_t at = a*t;
3218 Double_t w0 = TWO_PI*val[0];
3219 Double_t a_w0 = a/w0;
3220 Double_t w0t = w0*t;
3221
3222 Double_t j1, j0;
3223 if (fabs(w0t) < 0.001) { // check zero time limits of the spherical bessel functions j0(x) and j1(x)
3224 j0 = 1.0;
3225 j1 = 0.0;
3226 } else {
3227 j0 = sin(w0t)/w0t;
3228 j1 = (sin(w0t)-w0t*cos(w0t))/(w0t*w0t);
3229 }
3230
3231 p0exp[i] = 1.0 - a_w0*j1*exp(-at) - a_w0*a_w0*(j0*exp(-at) - 1.0) - GetLFIntegralValue(t);
3232 }
3233 break;
3234 default:
3235 break;
3236 }
3237 p0exp[i] *= TMath::Exp(-val[2]*t);
3238 t += dt;
3239 }
3240
3241 // solve the volterra equation (trapezoid integration)
3242 fDynLFFuncValue[0]=p0exp[0];
3243
3244 Double_t sum;
3245 Double_t a;
3246 Double_t preFactor = dt*val[2];
3247 for (UInt_t i=1; i<N; i++) {
3248 sum = p0exp[i];
3249 sum += 0.5*preFactor*p0exp[i]*fDynLFFuncValue[0];
3250 for (UInt_t j=1; j<i; j++) {
3251 sum += preFactor*p0exp[i-j]*fDynLFFuncValue[j];
3252 }
3253 a = 1.0-0.5*preFactor*p0exp[0];
3254
3255 fDynLFFuncValue[i]=sum/a;
3256 }
3257
3258 // clean up
3259 p0exp.clear();
3260}
3261
3262//--------------------------------------------------------------------------
3270Double_t PTheory::GetDynKTLFValue(const Double_t t) const
3271{
3272 if (t < 0.0)
3273 return 1.0;
3274
3275 UInt_t idx = static_cast<UInt_t>(t/fDynLFdt);
3276
3277 if (idx + 2 > fDynLFFuncValue.size())
3278 return fDynLFFuncValue.back();
3279
3280 // linearly interpolate between the two relevant function bins
3281 Double_t df = (fDynLFFuncValue[idx+1]-fDynLFFuncValue[idx])*(t/fDynLFdt-static_cast<Double_t>(idx));
3282
3283 return fDynLFFuncValue[idx]+df;
3284}
3285
3286//--------------------------------------------------------------------------
3294Double_t PTheory::GetDyn_GL_KTLFValue(const Double_t t) const
3295{
3296 if (t < 0.0)
3297 return 1.0;
3298
3299 const Double_t dt=0.001; // 1ns
3300 UInt_t idx = static_cast<UInt_t>(t/dt);
3301
3302 if (idx + 2 > fDyn_GL_LFFuncValue.size())
3303 return fDyn_GL_LFFuncValue.back();
3304
3305 // linearly interpolate between the two relevant function bins
3306 Double_t df = (fDyn_GL_LFFuncValue[idx+1]-fDyn_GL_LFFuncValue[idx])*(t/dt-static_cast<Double_t>(idx));
3307
3308 return fDyn_GL_LFFuncValue[idx]+df;
3309}
3310
3311//--------------------------------------------------------------------------
3325Double_t PTheory::MuMinusExpTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const
3326{
3327 // expected parameters: N0 tau A lambda phase frequency [tshift]
3328
3329 Double_t val[7];
3330
3331 assert(fParamNo.size() <= 7);
3332
3333 // check if FUNCTIONS are used
3334 for (UInt_t i=0; i<fParamNo.size(); i++) {
3335 if (fParamNo[i] < MSR_PARAM_FUN_OFFSET) { // parameter or resolved map
3336 val[i] = paramValues[fParamNo[i]];
3337 } else { // function
3338 val[i] = funcValues[fParamNo[i]-MSR_PARAM_FUN_OFFSET];
3339 }
3340 }
3341
3342 Double_t tt;
3343 if (fParamNo.size() == 6) // no tshift
3344 tt = t;
3345 else // tshift present
3346 tt = t-val[6];
3347
3348 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]));
3349}
3350
3351//--------------------------------------------------------------------------
3352// END
3353//--------------------------------------------------------------------------
#define MSR_PARAM_FUN_OFFSET
Offset added to function indices for parameter parsing.
Definition PMusr.h:265
std::vector< PMsrLineStructure > PMsrLines
Definition PMusr.h:1007
std::vector< Int_t > PIntVector
Definition PMusr.h:381
std::vector< Double_t > PDoubleVector
Definition PMusr.h:399
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:1906
virtual ~PTheory()
Destructor that recursively cleans up the expression tree.
Definition PTheory.cpp:354
virtual Double_t Constant(const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Returns constant value. Formula: c.
Definition PTheory.cpp:1104
virtual Double_t Abragam(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Abragam relaxation. Motional narrowing formula.
Definition PTheory.cpp:2226
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:1011
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:875
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:1286
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:841
virtual Double_t TFCos(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Transverse field cosine. Formula: cos(φ + 2πνt)
Definition PTheory.cpp:2270
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:1384
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:1571
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:2636
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:1473
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:1139
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:2747
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:2081
virtual Double_t GeneralExp(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
General (stretched) exponential. Formula: exp(-(λt)^β)
Definition PTheory.cpp:1229
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:1819
virtual Bool_t IsValid()
Checks if the entire theory expression tree is valid.
Definition PTheory.cpp:394
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:2181
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:2311
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:2498
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:2547
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:1342
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:1711
virtual void CleanUp(PTheory *theo)
Recursively deletes child theory nodes (fAdd and fMul).
Definition PTheory.cpp:809
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:2353
virtual void MakeCleanAndTidyUserFcn(UInt_t i, PMsrLines *fullTheoryBlock)
Formats a user function theory line with proper spacing.
Definition PTheory.cpp:1064
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:2808
virtual Double_t SimpleExp(Double_t t, const PDoubleVector &paramValues, const PDoubleVector &funcValues) const
Simple exponential relaxation. Formula: exp(-λt)
Definition PTheory.cpp:1177
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:447
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:1859
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:2457
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:2130
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:2691
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:1614
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:2035
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:2405
virtual void MakeCleanAndTidyTheoryBlock(PMsrLines *fullTheoryBlock)
Reformats the theory block for clean MSR file output.
Definition PTheory.cpp:922
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:999
TString fLine
Content of the MSR file line.
Definition PMusr.h:1000