improve the doxygen docu of PUserFcn.* and PUserFcnBase.*
All checks were successful
Build and Deploy Documentation / build-and-deploy (push) Successful in 18s
All checks were successful
Build and Deploy Documentation / build-and-deploy (push) Successful in 18s
This commit is contained in:
@@ -35,7 +35,15 @@ ClassImp(PUserFcn)
|
||||
|
||||
//------------------------------------------------------
|
||||
/**
|
||||
* <p>Constructor
|
||||
* \brief Default constructor for PUserFcn.
|
||||
*
|
||||
* Initializes a third-order polynomial user function. This implementation
|
||||
* requires no special initialization as it has no internal state - all
|
||||
* computation is done directly in the operator() method.
|
||||
*
|
||||
* \note This simple constructor serves as a template for more complex user
|
||||
* functions. Functions requiring initialization (e.g., loading lookup tables,
|
||||
* precomputing constants) should perform that work here or in SetGlobalPart().
|
||||
*/
|
||||
PUserFcn::PUserFcn()
|
||||
{
|
||||
@@ -43,7 +51,16 @@ PUserFcn::PUserFcn()
|
||||
|
||||
//------------------------------------------------------
|
||||
/**
|
||||
* <p>Destructor
|
||||
* \brief Destructor for PUserFcn.
|
||||
*
|
||||
* Cleans up any resources allocated by the polynomial function. Since this
|
||||
* implementation has no dynamically allocated resources, the destructor is
|
||||
* empty.
|
||||
*
|
||||
* \note User functions with allocated resources (lookup tables, buffers,
|
||||
* external library handles) must clean them up here to prevent memory leaks.
|
||||
* If using the global part interface, ensure proper coordination with
|
||||
* gGlobalUserFcn cleanup.
|
||||
*/
|
||||
PUserFcn::~PUserFcn()
|
||||
{
|
||||
@@ -51,16 +68,48 @@ PUserFcn::~PUserFcn()
|
||||
|
||||
//------------------------------------------------------
|
||||
/**
|
||||
* <p> user function example: polynome of 3rd order
|
||||
* \brief Evaluates the third-order polynomial at the given time.
|
||||
*
|
||||
* \f[ = \sum_{k=0}^3 c_k t^k \f]
|
||||
* Computes a cubic polynomial of the form:
|
||||
*
|
||||
* <b>meaning of paramValues:</b> \f$c_0\f$, \f$c_1\f$, \f$c_2\f$, \f$c_3\f$
|
||||
* \f[ P(t) = c_0 + c_1 t + c_2 t^2 + c_3 t^3 = \sum_{k=0}^{3} c_k t^k \f]
|
||||
*
|
||||
* <b>return:</b> function value
|
||||
* where the coefficients \f$c_k\f$ are provided in the parameter vector.
|
||||
*
|
||||
* \param t time in \f$(\mu\mathrm{s})\f$, or x-axis value for non-muSR fit
|
||||
* \param param parameter vector
|
||||
* \section puserfcn_op_example Example MSR Configuration
|
||||
*
|
||||
* \code
|
||||
* FITPARAMETER
|
||||
* # No Name Value Step Pos_Error Boundaries
|
||||
* 1 c0 0.95 0.01 none
|
||||
* 2 c1 -0.001 0.0001 none
|
||||
* 3 c2 0.00001 0.000001 none
|
||||
* 4 c3 0.0 0.0000001 none 0 none (fixed to zero for quadratic)
|
||||
*
|
||||
* THEORY
|
||||
* userFcn libPUserFcn.so PUserFcn 1 2 3 4
|
||||
* \endcode
|
||||
*
|
||||
* \section puserfcn_op_notes Implementation Notes
|
||||
*
|
||||
* - Uses direct polynomial evaluation (Horner's method could improve
|
||||
* numerical stability for high-precision applications)
|
||||
* - Asserts exactly 4 parameters to catch MSR file configuration errors
|
||||
* - No special handling for negative time values
|
||||
*
|
||||
* \param t Independent variable (time in μs for μSR, or general x-axis
|
||||
* value for non-μSR fits)
|
||||
* \param param Vector containing exactly 4 polynomial coefficients:
|
||||
* - param[0]: \f$c_0\f$ - constant term (dimensionless)
|
||||
* - param[1]: \f$c_1\f$ - linear coefficient (μs⁻¹)
|
||||
* - param[2]: \f$c_2\f$ - quadratic coefficient (μs⁻²)
|
||||
* - param[3]: \f$c_3\f$ - cubic coefficient (μs⁻³)
|
||||
*
|
||||
* \return The polynomial value \f$P(t)\f$ at the specified time
|
||||
*
|
||||
* \pre param.size() == 4 (enforced by assertion)
|
||||
*
|
||||
* \see PUserFcnBase::operator() for the virtual interface specification
|
||||
*/
|
||||
Double_t PUserFcn::operator()(Double_t t, const std::vector<Double_t> ¶m) const
|
||||
{
|
||||
|
||||
@@ -34,21 +34,58 @@
|
||||
|
||||
ClassImp(PUserFcnBase)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This function is a replacement for the ParseFile method of TSAXParser.
|
||||
// It is needed because in certain environments ParseFile does not work but ParseBuffer does.
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* <p> Replacement for the ParseFile method of TSAXParser
|
||||
* that can be used in user functions.
|
||||
* \brief Parses an XML file using buffer-based parsing for better compatibility.
|
||||
*
|
||||
* <p><b>return:</b>
|
||||
* - 1 if file cannot be read
|
||||
* - 0 if the file has been parsed successfully
|
||||
* - parse error code otherwise
|
||||
* This function provides a replacement for TSAXParser::ParseFile() that works
|
||||
* reliably across different environments. Some systems have issues with direct
|
||||
* file parsing, but buffer-based parsing (ParseBuffer) works consistently.
|
||||
*
|
||||
* \param saxParser pointer to a TSAXParser object
|
||||
* \param startup_path_name full path to the XML file to be read
|
||||
* \section parsexml_usage Usage in User Functions
|
||||
*
|
||||
* User functions that need to read XML configuration files should use this
|
||||
* function instead of TSAXParser::ParseFile():
|
||||
*
|
||||
* \code{.cpp}
|
||||
* class TMyConfigurableFcn : public PUserFcnBase {
|
||||
* private:
|
||||
* MyConfigHandler fHandler; // Derived from TSAXParser callbacks
|
||||
*
|
||||
* public:
|
||||
* Bool_t LoadConfig(const char* configFile) {
|
||||
* TSAXParser parser;
|
||||
* parser.ConnectToHandler("MyConfigHandler", &fHandler);
|
||||
*
|
||||
* Int_t status = parseXmlFile(&parser, configFile);
|
||||
* if (status != 0) {
|
||||
* std::cerr << "Failed to parse config: " << configFile << std::endl;
|
||||
* return false;
|
||||
* }
|
||||
* return true;
|
||||
* }
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* \section parsexml_algorithm Algorithm
|
||||
*
|
||||
* 1. Opens the file in binary mode, seeking to end
|
||||
* 2. Determines file size from stream position
|
||||
* 3. Allocates buffer and reads entire file
|
||||
* 4. Passes buffer to TSAXParser::ParseBuffer()
|
||||
* 5. Cleans up buffer memory
|
||||
*
|
||||
* \param saxParser Pointer to a configured TSAXParser object. The parser
|
||||
* should have its handler connected before calling this function.
|
||||
* \param startup_path_name Full filesystem path to the XML file to parse.
|
||||
*
|
||||
* \return Status code:
|
||||
* - 0: Success - file parsed without errors
|
||||
* - 1: File error - could not open or read the file
|
||||
* - >1: XML parse error from TSAXParser::ParseBuffer()
|
||||
*
|
||||
* \see PStartupHandler for an example of XML parsing in musrfit
|
||||
* \see TSAXParser for ROOT's SAX parser documentation
|
||||
*/
|
||||
Int_t parseXmlFile(TSAXParser *saxParser, const char *startup_path_name)
|
||||
{
|
||||
@@ -76,5 +113,43 @@ Int_t parseXmlFile(TSAXParser *saxParser, const char *startup_path_name)
|
||||
return status;
|
||||
}
|
||||
|
||||
// place a void pointer vector for global user function objects which might be needed
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* \brief Global storage for user function objects requiring persistent state.
|
||||
*
|
||||
* This vector provides a global container for user functions that need to
|
||||
* maintain state across multiple evaluations or share data between runs.
|
||||
* It is primarily used by user functions implementing the "global part"
|
||||
* interface (NeedGlobalPart(), SetGlobalPart(), GlobalPartIsValid()).
|
||||
*
|
||||
* \section gGlobalUserFcn_usage Usage Pattern
|
||||
*
|
||||
* User functions with expensive initialization (lookup tables, precomputed
|
||||
* grids, loaded data files) store their global objects here:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* // In user function's SetGlobalPart implementation:
|
||||
* void TMyFcn::SetGlobalPart(std::vector<void*> &globalPart, UInt_t idx) {
|
||||
* if (idx < globalPart.size() && globalPart[idx] != nullptr) {
|
||||
* fGlobal = static_cast<MyGlobalData*>(globalPart[idx]);
|
||||
* } else {
|
||||
* fGlobal = new MyGlobalData();
|
||||
* fGlobal->Initialize(); // Expensive one-time computation
|
||||
* if (idx < globalPart.size())
|
||||
* globalPart[idx] = fGlobal;
|
||||
* else
|
||||
* globalPart.push_back(fGlobal);
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \note The vector stores void pointers, so user functions must cast
|
||||
* appropriately and manage memory for their specific data types.
|
||||
*
|
||||
* \warning User functions are responsible for proper cleanup of their
|
||||
* global objects to avoid memory leaks.
|
||||
*
|
||||
* \see PUserFcnBase::SetGlobalPart() for the interface to populate this vector
|
||||
* \see PTheory for how global parts are initialized during theory setup
|
||||
*/
|
||||
std::vector<void *> gGlobalUserFcn;
|
||||
|
||||
@@ -34,15 +34,79 @@
|
||||
|
||||
#include "PUserFcnBase.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>User function example class. Polynome of 3rd order.
|
||||
* \brief Example user function implementing a third-order polynomial.
|
||||
*
|
||||
* PUserFcn demonstrates how to create custom theory functions by deriving
|
||||
* from PUserFcnBase. This example implements a cubic polynomial:
|
||||
*
|
||||
* \f[ P(t) = a_0 + a_1 t + a_2 t^2 + a_3 t^3 \f]
|
||||
*
|
||||
* where \f$a_0, a_1, a_2, a_3\f$ are the polynomial coefficients passed
|
||||
* as fit parameters.
|
||||
*
|
||||
* \section puserfcn_usage Usage in MSR File
|
||||
*
|
||||
* To use this function in your analysis:
|
||||
*
|
||||
* \code
|
||||
* FITPARAMETER
|
||||
* # No Name Value Step Pos_Error Boundaries
|
||||
* 1 a0 1.0 0.1 none
|
||||
* 2 a1 0.01 0.001 none
|
||||
* 3 a2 0.001 0.0001 none
|
||||
* 4 a3 0.0001 0.00001 none
|
||||
*
|
||||
* THEORY
|
||||
* userFcn libPUserFcn.so PUserFcn 1 2 3 4 (a0, a1, a2, a3)
|
||||
* \endcode
|
||||
*
|
||||
* \section puserfcn_applications Applications
|
||||
*
|
||||
* Polynomial backgrounds are useful for:
|
||||
* - Modeling baseline drifts in long-time measurements
|
||||
* - Phenomenological fits to slowly varying relaxation
|
||||
* - Testing the user function infrastructure
|
||||
*
|
||||
* \section puserfcn_template As a Template
|
||||
*
|
||||
* This class serves as a minimal working example for creating custom
|
||||
* user functions. To create your own:
|
||||
*
|
||||
* 1. Copy PUserFcn.h and PUserFcn.cpp
|
||||
* 2. Rename the class and update the ClassDef/ClassImp macros
|
||||
* 3. Implement your physics in the operator() method
|
||||
* 4. Create a LinkDef.h and build as a shared library
|
||||
*
|
||||
* \see PUserFcnBase for the abstract interface and detailed implementation guide
|
||||
* \see PTheory for how user functions are loaded and evaluated
|
||||
*/
|
||||
class PUserFcn : public PUserFcnBase
|
||||
{
|
||||
public:
|
||||
/// \brief Default constructor.
|
||||
PUserFcn();
|
||||
|
||||
/// \brief Destructor.
|
||||
~PUserFcn();
|
||||
|
||||
/**
|
||||
* \brief Evaluates the third-order polynomial at time t.
|
||||
*
|
||||
* Computes:
|
||||
* \f[ P(t) = \texttt{param[0]} + \texttt{param[1]} \cdot t
|
||||
* + \texttt{param[2]} \cdot t^2 + \texttt{param[3]} \cdot t^3 \f]
|
||||
*
|
||||
* \param t Time value (typically in microseconds)
|
||||
* \param param Vector of polynomial coefficients:
|
||||
* - param[0]: constant term \f$a_0\f$
|
||||
* - param[1]: linear coefficient \f$a_1\f$ (per μs)
|
||||
* - param[2]: quadratic coefficient \f$a_2\f$ (per μs²)
|
||||
* - param[3]: cubic coefficient \f$a_3\f$ (per μs³)
|
||||
*
|
||||
* \return The polynomial value at time t
|
||||
*/
|
||||
Double_t operator()(Double_t t, const std::vector<Double_t> ¶m) const;
|
||||
|
||||
ClassDef(PUserFcn, 1)
|
||||
|
||||
@@ -37,52 +37,134 @@
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Abstract base class for user-defined theory functions.
|
||||
* \brief Abstract base class for user-defined theory functions in musrfit.
|
||||
*
|
||||
* <p>PUserFcnBase enables extending musrfit with custom theory functions
|
||||
* beyond the 33 built-in functions. Users create derived classes implementing
|
||||
* PUserFcnBase enables extending musrfit with custom theory functions
|
||||
* beyond the 34 built-in functions. Users create derived classes implementing
|
||||
* specific physics models, compile them into shared libraries, and load them
|
||||
* dynamically at runtime.
|
||||
* dynamically at runtime via ROOT's plugin mechanism.
|
||||
*
|
||||
* <p><b>Use cases:</b>
|
||||
* \section userfcn_use_cases Use Cases
|
||||
*
|
||||
* User functions are valuable for:
|
||||
* - Novel relaxation mechanisms not in standard library
|
||||
* - Material-specific models (e.g., Skyrmion lattices)
|
||||
* - Complex multi-component functions
|
||||
* - Proprietary or experimental theory functions
|
||||
* - Functions requiring external libraries (GSL, CUDA, etc.)
|
||||
* - Material-specific models (e.g., Skyrmion lattices, spin ice)
|
||||
* - Complex multi-component functions requiring custom logic
|
||||
* - Proprietary or experimental theory functions under development
|
||||
* - Functions requiring external libraries (GSL, CUDA, MKL, etc.)
|
||||
* - Performance-critical implementations with custom optimization
|
||||
*
|
||||
* <p><b>Implementation steps:</b>
|
||||
* 1. Create a class deriving from PUserFcnBase
|
||||
* 2. Implement operator()(t, param) with your theory
|
||||
* 3. Optionally implement global part for heavy initialization
|
||||
* 4. Compile to shared library (.so/.dylib/.dll)
|
||||
* 5. Reference in MSR file THEORY block: "userFcn libMyFunc TMyFuncClass"
|
||||
* \section userfcn_implementation Implementation Guide
|
||||
*
|
||||
* <b>Step 1: Create header file (MyUserFcn.h)</b>
|
||||
* \code{.cpp}
|
||||
* #ifndef MY_USER_FCN_H
|
||||
* #define MY_USER_FCN_H
|
||||
*
|
||||
* #include "PUserFcnBase.h"
|
||||
*
|
||||
* <p><b>Example minimal implementation:</b>
|
||||
* @code
|
||||
* class TMyRelaxation : public PUserFcnBase {
|
||||
* public:
|
||||
* Double_t operator()(Double_t t, const std::vector<Double_t> &par) const {
|
||||
* // par[0] = rate, par[1] = exponent, par[2] = time shift
|
||||
* Double_t tt = t - par[2];
|
||||
* if (tt < 0) return 0.0;
|
||||
* return exp(-pow(par[0]*tt, par[1]));
|
||||
* }
|
||||
* TMyRelaxation() {}
|
||||
* virtual ~TMyRelaxation() {}
|
||||
*
|
||||
* virtual Double_t operator()(Double_t t, const std::vector<Double_t> &par) const;
|
||||
*
|
||||
* ClassDef(TMyRelaxation, 1)
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* <p><b>Global part:</b> For expensive one-time computations (lookup tables,
|
||||
* matrix inversions), override NeedGlobalPart(), SetGlobalPart(), and
|
||||
* GlobalPartIsValid(). The global part is initialized once and shared across
|
||||
* all fit iterations.
|
||||
* #endif
|
||||
* \endcode
|
||||
*
|
||||
* <p><b>MSR file usage:</b>
|
||||
* @code
|
||||
* <b>Step 2: Implement source file (MyUserFcn.cpp)</b>
|
||||
* \code{.cpp}
|
||||
* #include "MyUserFcn.h"
|
||||
* #include <cmath>
|
||||
*
|
||||
* ClassImp(TMyRelaxation)
|
||||
*
|
||||
* Double_t TMyRelaxation::operator()(Double_t t, const std::vector<Double_t> &par) const {
|
||||
* // par[0] = rate (lambda), par[1] = exponent (beta)
|
||||
* if (t < 0) return 1.0;
|
||||
* return exp(-pow(par[0] * t, par[1]));
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* <b>Step 3: Create LinkDef file (MyUserFcnLinkDef.h)</b>
|
||||
* \code{.cpp}
|
||||
* #ifdef __CINT__
|
||||
* #pragma link off all globals;
|
||||
* #pragma link off all classes;
|
||||
* #pragma link off all functions;
|
||||
*
|
||||
* #pragma link C++ class TMyRelaxation+;
|
||||
* #endif
|
||||
* \endcode
|
||||
*
|
||||
* <b>Step 4: Build shared library</b>
|
||||
* \code{.sh}
|
||||
* rootcint -f MyUserFcnDict.cxx -c MyUserFcn.h MyUserFcnLinkDef.h
|
||||
* g++ -shared -fPIC -o libMyUserFcn.so MyUserFcn.cpp MyUserFcnDict.cxx \
|
||||
* $(root-config --cflags --libs) -I$MUSRFIT/include
|
||||
* \endcode
|
||||
*
|
||||
* <b>Step 5: Use in MSR file</b>
|
||||
* \code
|
||||
* THEORY
|
||||
* asymmetry 1
|
||||
* userFcn libMyRelax.so TMyRelaxation map1 2 0.5 (rate, expo, tshift)
|
||||
* @endcode
|
||||
* userFcn libMyUserFcn.so TMyRelaxation 2 3 (rate, exponent)
|
||||
* \endcode
|
||||
*
|
||||
* \section userfcn_global Global Part for Expensive Computations
|
||||
*
|
||||
* For functions requiring expensive one-time setup (lookup tables, matrix
|
||||
* decompositions, file loading), implement the global part interface:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* class TMyComplexFcn : public PUserFcnBase {
|
||||
* private:
|
||||
* mutable void *fGlobal; // Pointer to global data
|
||||
*
|
||||
* public:
|
||||
* virtual Bool_t NeedGlobalPart() const { return true; }
|
||||
*
|
||||
* virtual void SetGlobalPart(std::vector<void*> &globalPart, UInt_t idx) {
|
||||
* if (idx < globalPart.size() && globalPart[idx] != nullptr) {
|
||||
* fGlobal = globalPart[idx]; // Reuse existing
|
||||
* } else {
|
||||
* fGlobal = new MyGlobalData(); // Create new
|
||||
* static_cast<MyGlobalData*>(fGlobal)->Initialize();
|
||||
* if (idx < globalPart.size())
|
||||
* globalPart[idx] = fGlobal;
|
||||
* else
|
||||
* globalPart.push_back(fGlobal);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* virtual Bool_t GlobalPartIsValid() const {
|
||||
* return fGlobal != nullptr;
|
||||
* }
|
||||
*
|
||||
* // ... operator() uses fGlobal for fast lookup
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* \section userfcn_parameters Parameter Conventions
|
||||
*
|
||||
* <b>In the MSR file THEORY block:</b>
|
||||
* \code
|
||||
* userFcn libName.so ClassName param1 param2 ... paramN
|
||||
* \endcode
|
||||
*
|
||||
* Parameters can be:
|
||||
* - Direct numbers: \c 1, \c 2 → parameter indices from FITPARAMETER block
|
||||
* - Map references: \c map1, \c map2 → via RUN block map
|
||||
* - Function references: \c fun1, \c fun2 → evaluated FUNCTIONS
|
||||
*
|
||||
* <b>Convention:</b> The last parameter is typically a time shift.
|
||||
*
|
||||
* \see PTheory for how user functions are loaded and called
|
||||
* \see PUserFcn for a simple example implementation
|
||||
*/
|
||||
class PUserFcnBase : public TObject
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user