/*************************************************************************** PRunNonMusr.h Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2025 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PRUNNONMUSR_H_ #define _PRUNNONMUSR_H_ #include "PMusr.h" #include "PRunBase.h" /** * \brief Class for fitting general x-y data sets (non-μSR time series). * * PRunNonMusr extends the musrfit framework to handle arbitrary x-y data that doesn't * originate from μSR experiments. This allows users to leverage musrfit's powerful * fitting engine, theory functions, and MINUIT interface for general curve fitting tasks. * * \section nonmusr_purpose Purpose and Use Cases * * This fit type is designed for: * - General time-series data: Any x vs. y measurements * - Non-μSR physics: Other experimental data (e.g., optical, electrical, thermal) * - Reusing μSR theory functions: Apply exponentials, oscillations, relaxations to non-μSR data * - Custom data analysis: Fit arbitrary functional forms to experimental data * - Method validation: Test fitting procedures on simulated or benchmark data * * \section nonmusr_data Data Structure * * Unlike μSR fits, non-μSR data is provided as simple x-y pairs: * - x-axis: Independent variable (time, temperature, field, voltage, etc.) * - y-axis: Dependent variable (signal, counts, current, etc.) * - Errors: Optional error bars on y-values * - No histograms: Data is already processed, not raw detector counts * - No t0: No time-zero concept (not time-differential μSR) * - No asymmetry: Direct fitting of y vs. x * * \section nonmusr_input Data Input Formats * * Non-μSR data can be loaded from: * - ASCII files: Space/tab-separated columns (x, y, err) * - DB files: Database format with metadata * - MuSonRoot files: Special ROOT structure for non-μSR data * * ASCII format example: * \code * # x-axis y-axis error * 0.0 100.5 3.2 * 0.1 95.3 3.1 * 0.2 90.8 3.0 * ... * \endcode * * \section nonmusr_msr MSR File Configuration * * Example MSR file RUN block for non-μSR data: * \code * RUN data/mydata.dat DB PSI MUSR-ROOT (name beamline) * fittype 12 (NonMusr) * map 1 2 (x-index, y-index in data columns) * xy-data 0 1 (column 0 = x, column 1 = y) * packing 1 (usually 1 for pre-processed data) * fit 0.0 10.0 (fit range in x-axis units) * \endcode * * \section nonmusr_theory Theory Functions * * All standard musrfit theory functions can be used: * - Exponentials: decay, growth, stretched exponentials * - Oscillations: cosine, sine, damped oscillations * - Relaxations: static/dynamic Gaussian/Lorentzian Kubo-Toyabe * - Polynomials: backgrounds, baselines * - User functions: Custom C++ functions * * Theory is evaluated at the x-values from the data file. * * \section nonmusr_differences Key Differences from μSR Fits * * * * * * * * * * *
FeatureμSR FitsNon-μSR Fits
Data typeRaw histogramsProcessed x-y pairs
Time zero (t0)RequiredNot applicable
BackgroundEstimated/subtractedIncluded in y-data
AsymmetryCalculatedNot applicable
PackingRebin histogramsAverage x-y points
Fit rangeTime (μs)x-axis units (arbitrary)
ADDRUNSupportedNOT supported
* * \section nonmusr_limitations Limitations * * - No ADDRUN: Cannot combine multiple non-μSR data sets * - No maximum likelihood: Only χ² fitting supported (not implemented for non-μSR) * - No expected χ²: Not implemented (unclear definition for general data) * - Simple error handling: Assumes independent Gaussian errors * * \section nonmusr_workflow Analysis Workflow * * 1. Prepare Data: Format as x-y(-error) columns in ASCII/DB file * 2. Create MSR File: Specify file, fit type (12), xy-data indices, fit range * 3. Define Theory: Use standard THEORY block functions * 4. Run Fit: musrfit performs χ² minimization via MINUIT * 5. Analyze Results: Standard parameter extraction, error analysis, plotting * * \see PRunSingleHisto for standard μSR single histogram fits * \see PRunBase for base class interface and common functionality */ class PRunNonMusr : public PRunBase { public: /** * \brief Default constructor creating an empty, invalid non-μSR run object. * * Initializes all member variables to default values: * - Bin counts set to 0 * - Packing set to 1 (no packing for x-y data) * - Handle tag set to kEmpty * - Raw data pointer set to nullptr * * This constructor is needed for creating vectors of PRunNonMusr objects. * The resulting object cannot be used until properly initialized via the main constructor. */ PRunNonMusr(); /** * \brief Main constructor initializing a non-μSR run from MSR file and data. * * Performs initialization for general x-y data fitting: * * 1. Base Class Initialization: * - Calls PRunBase constructor with MSR/data handlers * - Initializes theory engine * * 2. Raw Data Loading: * - Retrieves raw data using run name from MSR file * - Validates data was successfully loaded * - Marks run invalid if data cannot be loaded * * 3. Data Preparation: * - Calls PrepareData() to process x-y data * - Extracts x-y columns based on map/xy-data specification * - Applies packing if specified * - Sets up fit range in x-axis units * * The object is marked as invalid (fValid=false) if: * - Raw data file cannot be loaded * - PrepareData() fails (invalid column indices, missing data, etc.) * * \param msrInfo Pointer to MSR file handler (must remain valid) * \param rawData Pointer to raw data handler for loading data files * \param runNo Run number (0-based index in MSR file RUN blocks) * \param tag Operation mode: kFit (fitting), kView (display/plotting) * \param theoAsData Theory mode: true = at data points, false = high-resolution * * \warning Check IsValid() after construction before using for fitting * * \see PrepareData() for data processing details */ PRunNonMusr(PMsrHandler *msrInfo, PRunDataHandler *rawData, UInt_t runNo, EPMusrHandleTag tag, Bool_t theoAsData); /** * \brief Virtual destructor (no cleanup needed for this class). * * Raw data pointer (fRawRunData) is not owned by this class and is not deleted. * Base class destructor handles cleanup of theory objects and other shared resources. */ virtual ~PRunNonMusr(); /** * \brief Calculates χ² between non-μSR data and theory. * * Computes the chi-squared statistic for x-y data: * \f[ \chi^2 = \sum_{i={\rm start}}^{\rm end} \frac{(y_i^{\rm data} - y_i^{\rm theory})^2}{\sigma_i^2} \f] * * where: * - y_i^data is the measured y-value at x_i * - y_i^theory is the theory function evaluated at x_i * - σ_i is the error on y_i (from data file or assumed) * - Sum runs over all points within fit range (fFitStartTime ≤ x ≤ fFitEndTime) * * Algorithm: * 1. Evaluate FUNCTIONS block for user-defined functions * 2. Loop over data points from fStartTimeBin to fEndTimeBin * 3. For each point: * - Get x-value from fData.GetX() * - Evaluate theory at that x-value: fTheory->Func(x, par, fFuncValues) * - Compute weighted squared difference * 4. Sum contributions to get total χ² * * Unlike μSR fits, this operates on x-y data directly (not histograms). * The x-axis can represent any independent variable (time, temperature, field, etc.), * not just time in microseconds. * * \param par Parameter vector from MINUIT with current parameter values * \return Chi-squared value (sum of weighted squared residuals) * * \note No OpenMP parallelization in this implementation (typically smaller data sets) * * \see CalcMaxLikelihood() - NOT IMPLEMENTED for non-μSR */ virtual Double_t CalcChiSquare(const std::vector& par); /** * \brief Calculates expected χ² (NOT IMPLEMENTED for non-μSR). * * This method is not implemented for general x-y data because the concept * of "expected χ²" depends on the underlying statistical distribution, * which is not well-defined for arbitrary non-μSR data (unlike Poisson-distributed * histogram counts in μSR). * * Calling this method prints a warning message and returns 0.0. * * \param par Parameter vector from MINUIT * \return Always returns 0.0 * * \note Implementation would require assumptions about data statistics */ virtual Double_t CalcChiSquareExpected(const std::vector& par); /** * \brief Calculates maximum likelihood (NOT IMPLEMENTED for non-μSR). * * Maximum likelihood fitting is not implemented for general x-y data because: * - The appropriate likelihood function depends on the data's statistical distribution * - Unlike μSR histograms (Poisson), non-μSR data can have various error models * - Gaussian errors → equivalent to χ² (no advantage) * - Other distributions require user-specified likelihood functions * * Calling this method prints a warning message and returns 1.0. * * \param par Parameter vector from MINUIT * \return Always returns 1.0 * * \note Only χ² fitting is supported for non-μSR data */ virtual Double_t CalcMaxLikelihood(const std::vector& par); /** * \brief Evaluates theory function (empty implementation for non-μSR). * * For non-μSR data, theory calculation is performed directly in CalcChiSquare() * rather than pre-calculating and storing theory values. This is because: * - Theory is evaluated at arbitrary x-values (from data file) * - No high-resolution grid needed (data already defines x-points) * - Simpler to evaluate on-demand during χ² calculation * * This method exists to satisfy the PRunBase interface but does nothing. * * \see CalcChiSquare() for on-demand theory evaluation */ virtual void CalcTheory(); /** * \brief Returns the number of x-y points within the fit range. * * Counts data points where fFitStartTime ≤ x ≤ fFitEndTime. * This count is used for: * - Degrees of freedom: ν = N_points - N_params * - Reduced χ²: χ²_red = χ² / ν * - Statistical quality assessment * * The method loops through all x-values in fData.GetX() and counts * those within the specified fit range. * * \return Number of data points within fit range * * \see GetNoOfFitBins() implementation for counting algorithm */ virtual UInt_t GetNoOfFitBins(); /** * \brief Sets fit range in bin units (NOT SUPPORTED for non-μSR). * * This method is not meaningful for non-μSR data because: * - Fit range is specified in x-axis units (not bins) * - No "first good bin" or "last good bin" concept (no t0) * - x-values can be non-uniform (arbitrary spacing) * * This empty implementation exists to satisfy the PRunBase interface. * Use SetFitRange(PDoublePairVector) in the base class instead. * * \param fitRange Fit range string (ignored) * * \see PRunBase::SetFitRange() for proper fit range specification */ virtual void SetFitRangeBin(const TString fitRange) {} /** * \brief Returns the x-axis column index from MSR file specification. * * Extracts the x-data column index from: * - "xy-data" entry in RUN block (preferred) * - "map" entry first value (fallback) * - Default: 0 (first column) * * The index specifies which column in the data file contains the * independent variable (x-axis values). * * \return Column index for x-axis data (0-based) * * \see GetYIndex() for y-axis column */ virtual UInt_t GetXIndex(); /** * \brief Returns the y-axis column index from MSR file specification. * * Extracts the y-data column index from: * - "xy-data" entry in RUN block (preferred) * - "map" entry second value (fallback) * - Default: 1 (second column) * * The index specifies which column in the data file contains the * dependent variable (y-axis values to be fitted). * * \return Column index for y-axis data (0-based) * * \see GetXIndex() for x-axis column */ virtual UInt_t GetYIndex(); protected: /** * \brief Main data preparation orchestrator for non-μSR data. * * Coordinates the data loading and preprocessing pipeline: * 1. Checks for ADDRUN (warns if present - not supported for non-μSR) * 2. Retrieves packing parameter from RUN or GLOBAL block * 3. Retrieves fit range from RUN or GLOBAL block * 4. Dispatches to PrepareFitData() or PrepareViewData() based on tag * * Key validation: * - ADDRUN presence → warning (ignored) * - Missing packing → error (required) * - Missing fit range → acceptable (will use all data) * * \return True if data preparation succeeds, false on error * * \see PrepareFitData() for fitting mode processing * \see PrepareViewData() for viewing mode processing */ virtual Bool_t PrepareData(); /** * \brief Prepares x-y data for fitting. * * Performs data processing for curve fitting: * 1. Determines x-y column indices via GetXIndex() and GetYIndex() * 2. Loads x-y(-error) data from file * 3. Applies packing if specified: * - packing = 1: Use data as-is (no averaging) * - packing > 1: Average consecutive points in groups of packing * 4. Packing algorithm for x-values: midpoint of packed range * 5. Packing algorithm for y-values: sum of packed points * 6. Packing algorithm for errors: sqrt(sum of squared errors) * 7. Counts bins within fit range (fFitStartTime ≤ x ≤ fFitEndTime) * 8. Determines fStartTimeBin and fEndTimeBin indices * * Packing example (packing=3): * - Raw: x=[0, 1, 2, 3, 4, 5], y=[10, 12, 11, 15, 14, 13] * - Packed: x=[1, 4], y=[33, 42] (midpoint, sum) * * \return True on success, false if data loading fails * * \see PrepareViewData() for viewing mode (may differ in processing) */ virtual Bool_t PrepareFitData(); /** * \brief Prepares x-y data for viewing/plotting. * * Similar to PrepareFitData() but optimized for visualization: * - May use different packing for display * - May extend beyond fit range for context * - Less stringent validation * * The exact implementation mirrors PrepareFitData() for non-μSR, * but the separation allows future customization for viewing. * * \return True on success, false if data loading fails * * \see PrepareFitData() for fitting mode processing */ virtual Bool_t PrepareViewData(); private: /** * \brief Pointer to raw run data handler (not owned). * * Provides access to loaded x-y data from file. Retrieved via * fRawData->GetRunData(*runName) during construction. * * Contains the fDataNonMusr structure with: * - GetData(): Vector of vectors for data columns (x, y, etc.) * - GetErrData(): Vector of vectors for error columns * * \warning Not owned by this class - do not delete */ PRawRunData *fRawRunData; UInt_t fNoOfFitBins; ///< Number of x-y points within fit range (fFitStartTime ≤ x ≤ fFitEndTime) /** * \brief Data point averaging/grouping factor. * * Number of consecutive raw data points to average together: * - 1: No packing (use all points as-is) * - > 1: Average groups of packing points * * Packing reduces the number of data points, improving: * - Signal-to-noise ratio (averaging reduces noise) * - Fit speed (fewer points to evaluate) * * But decreases: * - Resolution (fewer x-values) * * Source priority: * 1. RUN block "packing" entry * 2. GLOBAL block "packing" entry * 3. ERROR if neither specified */ Int_t fPacking; /** * \brief Theory calculation mode flag. * * Controls theory grid resolution (currently not used for non-μSR): * - true: Theory at data x-values only (efficient) * - false: Theory on high-resolution grid (smooth plotting) * * For non-μSR, theory is always evaluated at data x-values * during CalcChiSquare(), so this flag has minimal effect. */ Bool_t fTheoAsData; /** * \brief Index of first data point in fit range. * * Points to the first x-y pair where x ≥ fFitStartTime. * Used as loop start in CalcChiSquare(). */ Int_t fStartTimeBin; /** * \brief Index of last data point in fit range (inclusive). * * Points to the last x-y pair where x ≤ fFitEndTime. * Used as loop end in CalcChiSquare() (inclusive: i <= fEndTimeBin). * * \note Unlike μSR fits, this is INCLUSIVE (≤), not exclusive (<) */ Int_t fEndTimeBin; }; #endif // _PRUNNONMUSR_H_