diff --git a/src/classes/PUserFcn.cpp b/src/classes/PUserFcn.cpp index 6a7458270..8c52130a7 100644 --- a/src/classes/PUserFcn.cpp +++ b/src/classes/PUserFcn.cpp @@ -35,7 +35,15 @@ ClassImp(PUserFcn) //------------------------------------------------------ /** - *
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() //------------------------------------------------------ /** - *
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() //------------------------------------------------------ /** - *
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:
*
- * meaning of paramValues: \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]
*
- * return: 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 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.
*
- * return:
- * - 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 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 Abstract base class for user-defined theory functions.
+ * \brief Abstract base class for user-defined theory functions in musrfit.
*
- * 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.
*
- * Use cases:
+ * \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
*
- * Implementation steps:
- * 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
+ *
+ * Step 1: Create header file (MyUserFcn.h)
+ * \code{.cpp}
+ * #ifndef MY_USER_FCN_H
+ * #define MY_USER_FCN_H
+ *
+ * #include "PUserFcnBase.h"
*
- * Example minimal implementation:
- * @code
* class TMyRelaxation : public PUserFcnBase {
* public:
- * Double_t operator()(Double_t t, const std::vector Global part: 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
*
- * MSR file usage:
- * @code
+ * Step 2: Implement source file (MyUserFcn.cpp)
+ * \code{.cpp}
+ * #include "MyUserFcn.h"
+ * #include