improve the doxygen docu of PTheory.*

This commit is contained in:
2025-11-23 17:47:46 +01:00
parent 9452d7ec6b
commit 8e2949e7a9
2 changed files with 500 additions and 139 deletions

View File

@@ -344,135 +344,315 @@ static PTheoDataBase fgTheoDataBase[THEORY_MAX] = {
//--------------------------------------------------------------------------------------
/**
* <p>Theory function evaluator and manager.
* \brief Theory function evaluator and expression tree manager.
*
* <p>This class parses, validates, and evaluates theory functions specified
* in the THEORY block of MSR files. It handles:
* - Parsing theory syntax (function names, parameters, operators)
* - Building theory expression trees (addition/multiplication)
* - Resolving parameter mappings and user functions
* - Evaluating theory at specific time points
* - Caching longitudinal field calculations
* - Loading and managing user-defined shared library functions
* PTheory is the core class responsible for parsing, validating, and evaluating
* theory functions specified in the THEORY block of MSR files. It implements
* a binary expression tree to handle complex combinations of theory functions.
*
* <p><b>Theory syntax:</b>
* - Single function: <tt>asymmetry simpleExp 1 3</tt>
* - Addition: <tt>func1 par1... + func2 par1...</tt>
* - Multiplication: <tt>func1 par1... * func2 par1...</tt>
* - Nested: <tt>(func1 + func2) * func3</tt>
* \section theory_overview Overview
*
* <p><b>Parameter resolution:</b>
* Parameters can be direct numbers, parameter references (1, 2, 3, ...),
* map references (map1, map2, ...), or function references (fun1, fun2, ...).
* The theory describes the expected muon polarization as a function of time.
* Different physical phenomena (relaxation, precession, field distributions)
* are represented by different theory functions that can be combined.
*
* <p><b>Example:</b>
* @code
* \section theory_tree Expression Tree Structure
*
* Theory expressions are parsed into a binary tree where:
* - Each node represents a theory function
* - Left child (fAdd) represents addition (+)
* - Right child (fMul) represents multiplication (*)
*
* Example MSR theory block:
* \verbatim
* THEORY
* asymmetry 1
* TFieldCos 2 3 (phase, freq)
* +
* simpleExp 4 (rate)
* @endcode
* This evaluates to: par1 * cos(par2 + 2π*par3*t) + exp(-par4*t)
* a 1 # asymmetry
* tf 2 3 # TFieldCos
* se 4 # simpleExp
* +
* a 5
* tf 6 7
* \endverbatim
*
* Becomes: (par1 * cos(φ₂ + 2πν₃t) * exp(-λ₄t)) + (par5 * cos(φ₆ + 2πν₇t))
*
* \section theory_syntax Syntax Details
*
* <b>Function specification:</b>
* \code
* function_name param1 param2 ... paramN (optional comment)
* \endcode
*
* <b>Parameter types:</b>
* - Direct number: \c 1, \c 2, \c 3 → parameter index (1-based)
* - Map reference: \c map1, \c map2 → indirection via RUN block map
* - Function reference: \c fun1, \c fun2 → evaluated FUNCTIONS block entry
*
* <b>Operators:</b>
* - \c + on separate line: Addition of following terms
* - Consecutive lines without +: Implicit multiplication
*
* \section theory_functions Available Functions
*
* <b>Basic:</b>
* - \c const (c): Constant value
* - \c asymmetry (a): Initial asymmetry
* - \c simplExpo (se): exp(-λt)
* - \c generExpo (ge): exp(-(λt)^β)
* - \c simpleGss (sg): exp(-σ²t²/2)
*
* <b>Kubo-Toyabe (Gaussian):</b>
* - \c statGssKt (stg): Static ZF Gaussian KT
* - \c statGssKTLF (sgktlf): Static LF Gaussian KT
* - \c dynGssKTLF (dgktlf): Dynamic LF Gaussian KT
*
* <b>Kubo-Toyabe (Lorentzian):</b>
* - \c statExpKT (sekt): Static ZF Lorentzian KT
* - \c statExpKTLF (sektlf): Static LF Lorentzian KT
* - \c dynExpKTLF (dektlf): Dynamic LF Lorentzian KT
*
* <b>Precession:</b>
* - \c TFieldCos (tf): cos(φ + 2πνt)
* - \c bessel (b): J₀(2πνt + φ)
* - \c internFld (ifld): Internal field distribution
*
* <b>Special:</b>
* - \c spinGlass (spg): Spin glass relaxation
* - \c abragam (ab): Motional narrowing
* - \c userFcn (u): User-defined external function
*
* \section theory_lf Longitudinal Field Calculations
*
* LF Kubo-Toyabe functions require numerical integration which is cached
* for efficiency. The cache is invalidated when parameters change.
* Caching variables:
* - fPrevParam: Previous parameter values for change detection
* - fLFIntegral: Cached integral values
* - fDynLFFuncValue: Dynamic KT function cache
*
* \section theory_user User Functions
*
* External functions can be loaded from shared libraries:
* \code
* userFcn libMyFunctions.so MyFunctionClass param1 param2 ...
* \endcode
*
* User functions must inherit from PUserFcnBase and implement:
* - operator()(Double_t t, const std::vector<Double_t>& par)
*
* \see PUserFcnBase, PMsrHandler, fgTheoDataBase
*/
class PTheory
{
public:
/**
* <p>Constructor for theory handler.
* \brief Constructor that parses the THEORY block and builds the expression tree.
*
* @param msrInfo Pointer to MSR file handler
* @param runNo Run number for this theory (0-based)
* @param hasParent True if this is a sub-theory (for + / * operators)
* Parses the theory block from the MSR file, validates function names and
* parameter counts, resolves parameter references, and recursively builds
* the expression tree for operators (+ and *).
*
* <b>Parsing algorithm:</b>
* -# Get current line from theory block
* -# Remove comments (text after '(' or '#')
* -# Tokenize to extract function name and parameters
* -# Look up function in fgTheoDataBase
* -# Validate parameter count
* -# Resolve parameter references (direct, map, fun)
* -# If next line is not '+', recursively create fMul child
* -# If next line is '+', skip it and recursively create fAdd child
* -# For user functions: load shared library and instantiate class
*
* \param msrInfo Pointer to MSR file handler containing theory block
* \param runNo Run number (0-based) for parameter map resolution
* \param hasParent False for root theory, true for child nodes.
* Controls static counter reset for recursive parsing.
*
* \warning If parsing fails, fValid is set to false and error messages
* are output to stderr. Always check IsValid() after construction.
*/
PTheory(PMsrHandler *msrInfo, UInt_t runNo, const Bool_t hasParent = false);
/**
* \brief Destructor that recursively cleans up the expression tree.
*
* Releases all allocated resources:
* - Clears parameter and function value vectors
* - Clears LF integral caches
* - Recursively deletes child theory nodes (fAdd, fMul)
* - Deletes user function object if present
* - Clears global user function vector
*/
virtual ~PTheory();
/// Returns true if theory is valid and ready for evaluation
/**
* \brief Checks if the entire theory expression tree is valid.
*
* Recursively validates all nodes in the tree. A theory is valid only
* if this node and all its children (fAdd and fMul) are valid.
*
* \return true if all nodes are valid, false if any node has errors
*
* \note Call this after construction to verify the theory was parsed
* successfully before attempting evaluation.
*/
virtual Bool_t IsValid();
/**
* <p>Evaluates the theory function at time t.
* \brief Evaluates the theory function at a given time point.
*
* @param t Time in microseconds (μs)
* @param paramValues Vector of fit parameter values
* @param funcValues Vector of evaluated user function values
* @return Theory value at time t
* Recursively evaluates the expression tree at time t using the provided
* parameter values. The evaluation follows the tree structure:
* - If both fMul and fAdd exist: this_func * fMul + fAdd
* - If only fMul exists: this_func * fMul
* - If only fAdd exists: this_func + fAdd
* - If neither exists: this_func
*
* \param t Time in microseconds (μs) for μSR fits, or x-value for non-μSR
* \param paramValues Vector of current fit parameter values (FITPARAMETER block)
* \param funcValues Vector of evaluated function values (FUNCTIONS block)
*
* \return Evaluated theory value (polarization or asymmetry) at time t
*
* \note For thread-safety, LF calculations cache results which may need
* recalculation if parameters change between calls.
*/
virtual Double_t Func(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
private:
/** \brief Recursively deletes child theory nodes (fAdd and fMul). */
virtual void CleanUp(PTheory *theo);
/** \brief Searches fgTheoDataBase for a function by name or abbreviation.
* \param name Function name (e.g., "simplExpo") or abbreviation (e.g., "se")
* \return Index in fgTheoDataBase, or THEORY_UNDEFINED if not found */
virtual Int_t SearchDataBase(TString name);
/** \brief Returns the index of user functions up to the given line.
* \param lineNo Current line number in theory block
* \return Count of userFcn entries before this line */
virtual Int_t GetUserFcnIdx(UInt_t lineNo) const;
/** \brief Reformats the theory block for clean MSR file output. */
virtual void MakeCleanAndTidyTheoryBlock(PMsrLines* fullTheoryBlock);
/** \brief Formats a polynomial theory line with proper spacing. */
virtual void MakeCleanAndTidyPolynom(UInt_t i, PMsrLines* fullTheoryBlock);
/** \brief Formats a user function theory line with proper spacing. */
virtual void MakeCleanAndTidyUserFcn(UInt_t i, PMsrLines* fullTheoryBlock);
// -------------------- Theory Function Implementations --------------------
// Each function evaluates its specific physical model at time t.
// Parameters are resolved from fParamNo using paramValues and funcValues.
/** \brief Returns constant value. Formula: c */
virtual Double_t Constant(const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Returns asymmetry value. Formula: A */
virtual Double_t Asymmetry(const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Simple exponential relaxation. Formula: exp(-λt) */
virtual Double_t SimpleExp(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief General (stretched) exponential. Formula: exp(-(λt)^β) */
virtual Double_t GeneralExp(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Simple Gaussian relaxation. Formula: exp(-σ²t²/2) */
virtual Double_t SimpleGauss(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Static Gaussian Kubo-Toyabe (ZF). Formula: 1/3 + 2/3(1-σ²t²)exp(-σ²t²/2) */
virtual Double_t StaticGaussKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Static Gaussian Kubo-Toyabe (LF). Requires numerical integration. */
virtual Double_t StaticGaussKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Dynamic Gaussian Kubo-Toyabe (LF). Strong collision model. */
virtual Double_t DynamicGaussKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Static Lorentzian Kubo-Toyabe (ZF). Formula: 1/3 + 2/3(1-at)exp(-at) */
virtual Double_t StaticLorentzKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Static Lorentzian Kubo-Toyabe (LF). Requires numerical integration. */
virtual Double_t StaticLorentzKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Dynamic Lorentzian Kubo-Toyabe (LF). Strong collision model. */
virtual Double_t DynamicLorentzKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Fast dynamic Gaussian-Lorentzian KT (ZF). Approximate fast calculation. */
virtual Double_t DynamicGauLorKTZFFast(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Fast dynamic Gaussian-Lorentzian KT (LF). Approximate fast calculation. */
virtual Double_t DynamicGauLorKTLFFast(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Dynamic Gaussian-Lorentzian KT (LF). Full numerical calculation. */
virtual Double_t DynamicGauLorKTLF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Combined Lorentzian-Gaussian KT. Product of both relaxation types. */
virtual Double_t CombiLGKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Stretched Kubo-Toyabe. Formula: exp(-(σt)^β) with KT-like recovery. */
virtual Double_t StrKT(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Spin glass relaxation function. Edwards-Anderson order parameter. */
virtual Double_t SpinGlass(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Random anisotropic hyperfine coupling. Powder average of anisotropic coupling. */
virtual Double_t RandomAnisotropicHyperfine(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Abragam relaxation. Motional narrowing formula. */
virtual Double_t Abragam(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Transverse field cosine. Formula: cos(φ + 2πνt) */
virtual Double_t TFCos(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Internal field distribution. Gaussian field distribution model. */
virtual Double_t InternalField(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Internal field (Kornilov model). Vortex lattice field distribution. */
virtual Double_t InternalFieldGK(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Internal field (Larkin-Ovchinnikov model). Vortex lattice field distribution. */
virtual Double_t InternalFieldLL(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Bessel function precession. Formula: J₀(2πνt + φ) */
virtual Double_t Bessel(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Internal Bessel field distribution. Combines Bessel with relaxation. */
virtual Double_t InternalBessel(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Skewed Gaussian. Asymmetric relaxation rates before/after zero crossing. */
virtual Double_t SkewedGauss(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Static Nakajima-Keren (ZF). Combined nuclear and electronic relaxation. */
virtual Double_t StaticNKZF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Static Nakajima-Keren (TF). Combined nuclear and electronic relaxation with precession. */
virtual Double_t StaticNKTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Dynamic Nakajima-Keren (ZF). With spin fluctuations. */
virtual Double_t DynamicNKZF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Dynamic Nakajima-Keren (TF). With spin fluctuations and precession. */
virtual Double_t DynamicNKTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief F-μ-F oscillation. Muon bound between two fluorine atoms. */
virtual Double_t FmuF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief μ⁻ exponential TF. Negative muon in transverse field. */
virtual Double_t MuMinusExpTF(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief Polynomial function. Formula: Σᵢ pᵢtⁱ */
virtual Double_t Polynom(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
/** \brief User-defined function. Calls external shared library function. */
virtual Double_t UserFcn(Double_t t, const PDoubleVector& paramValues, const PDoubleVector& funcValues) const;
// -------------------- LF Calculation Helpers --------------------
/** \brief Calculates and caches Gaussian LF integral for static KT. */
virtual void CalculateGaussLFIntegral(const Double_t *val) const;
/** \brief Calculates and caches Lorentzian LF integral for static KT. */
virtual void CalculateLorentzLFIntegral(const Double_t *val) const;
/** \brief Retrieves cached LF integral value at time t using interpolation. */
virtual Double_t GetLFIntegralValue(const Double_t t) const;
/** \brief Calculates dynamic KT in LF using integral equation approach. */
virtual void CalculateDynKTLF(const Double_t *val, Int_t tag) const;
/** \brief Retrieves cached dynamic KT LF value at time t. */
virtual Double_t GetDynKTLFValue(const Double_t t) const;
/** \brief Retrieves cached dynamic Gauss-Lorentz KT LF value at time t. */
virtual Double_t GetDyn_GL_KTLFValue(const Double_t t) const;
// variables
Bool_t fValid; ///< flag to tell if the theory is valid
UInt_t fType; ///< function tag
std::vector<UInt_t> fParamNo; ///< holds the parameter numbers for the theory (including maps and functions, see constructor desciption)
UInt_t fNoOfParam; ///< number of parameters for the given function
PTheory *fAdd, *fMul; ///< pointers to the add-sub-function or the multiply-sub-function
// -------------------- Member Variables --------------------
Bool_t fValid; ///< True if this theory node and its parse state are valid
UInt_t fType; ///< Theory function type (THEORY_CONST, THEORY_SIMPLE_EXP, etc.)
std::vector<UInt_t> fParamNo; ///< Resolved parameter indices (0-based). Values >= MSR_PARAM_FUN_OFFSET are function references.
UInt_t fNoOfParam; ///< Expected number of parameters for this function type
PTheory *fAdd; ///< Pointer to addition child node (left branch of tree)
PTheory *fMul; ///< Pointer to multiplication child node (right branch of tree)
Int_t fUserFcnIdx; ///< index of the user function within the theory tree
TString fUserFcnClassName; ///< name of the user function class for within root
TString fUserFcnSharedLibName; ///< name of the shared lib to which the user function belongs
PUserFcnBase *fUserFcn; ///< pointer to the user function object
mutable PDoubleVector fUserParam; ///< vector holding the resolved user function parameters, i.e. map and function resolved.
// User function members
Int_t fUserFcnIdx; ///< Index of this user function among all userFcn entries (for global state)
TString fUserFcnClassName; ///< ROOT class name for user function (e.g., "TMyFunction")
TString fUserFcnSharedLibName; ///< Shared library path (e.g., "libMyFunctions.so")
PUserFcnBase *fUserFcn; ///< Pointer to instantiated user function object
mutable PDoubleVector fUserParam; ///< Resolved parameter values for user function calls
PMsrHandler *fMsrInfo; ///< pointer to the msr-file handler
PMsrHandler *fMsrInfo; ///< Pointer to MSR file handler (not owned)
mutable Double_t fSamplingTime; ///< needed for LF. Keeps the sampling time of the non-analytic integral
mutable Double_t fPrevParam[THEORY_MAX_PARAM]; ///< needed for LF. Keeps the previous fitting parameters
mutable PDoubleVector fLFIntegral; ///< needed for LF. Keeps the non-analytic integral values
mutable Double_t fDynLFdt; ///< needed for LF. Keeps the time step for the dynamic LF calculation, used in the integral equation approach
mutable PDoubleVector fDynLFFuncValue; ///< needed for LF. Keeps the dynamic LF KT function values
mutable PDoubleVector fDyn_GL_LFFuncValue; ///< needed for LF. Keeps the dynamic LF local Gauss/global Lorentzian KT function values
// LF calculation caching (mutable for const Func() calls)
mutable Double_t fSamplingTime; ///< Time step for LF integral calculation (default 1 ns = 0.001 μs)
mutable Double_t fPrevParam[THEORY_MAX_PARAM]; ///< Previous parameter values for cache invalidation check
mutable PDoubleVector fLFIntegral; ///< Cached static LF KT integral values
mutable Double_t fDynLFdt; ///< Time step for dynamic LF integral equation
mutable PDoubleVector fDynLFFuncValue; ///< Cached dynamic Gaussian/Lorentzian LF KT values
mutable PDoubleVector fDyn_GL_LFFuncValue; ///< Cached dynamic Gauss-Lorentz LF KT values
};
#endif // _PTHEORY_H_