diff --git a/src/classes/PRunListCollection.cpp b/src/classes/PRunListCollection.cpp
index f5e7ec784..dd52173e4 100644
--- a/src/classes/PRunListCollection.cpp
+++ b/src/classes/PRunListCollection.cpp
@@ -35,10 +35,28 @@
// Constructor
//--------------------------------------------------------------------------
/**
- *
Constructor.
+ * \brief Constructor initializing the run collection manager.
*
- * \param msrInfo pointer to the msr-file handler
- * \param data pointer to the run-data handler
+ * Creates an empty collection ready to receive processed run objects via Add() calls.
+ * The collection maintains separate lists for each fit type (single histogram, asymmetry,
+ * RRF variants, etc.) and dispatches operations to the appropriate lists.
+ *
+ * Initialization:
+ * - Stores pointers to MSR file handler and raw data handler (not owned)
+ * - Sets theory calculation mode flag (for plotting vs. fitting)
+ * - All run lists start empty; populated via subsequent Add() calls
+ *
+ * The typical workflow is:
+ * 1. Create PRunListCollection
+ * 2. Call Add() for each RUN block in MSR file
+ * 3. Use Get*Chisq() or Get*MaximumLikelihood() during fitting
+ * 4. Use Get*() accessors for visualization and analysis
+ *
+ * \param msrInfo Pointer to MSR file handler (must remain valid for object lifetime)
+ * \param data Pointer to raw data handler for loading histogram files
+ * \param theoAsData Theory calculation mode: true = at data points only, false = high-resolution grid
+ *
+ * \see Add() for adding processed runs to the collection
*/
PRunListCollection::PRunListCollection(PMsrHandler *msrInfo, PRunDataHandler *data, Bool_t theoAsData) :
fMsrInfo(msrInfo), fData(data), fTheoAsData(theoAsData)
@@ -49,7 +67,24 @@ PRunListCollection::PRunListCollection(PMsrHandler *msrInfo, PRunDataHandler *da
// Destructor
//--------------------------------------------------------------------------
/**
- *
Destructor
+ * \brief Destructor that cleans up all run objects.
+ *
+ * Systematically destroys all PRunBase-derived objects in the collection:
+ * 1. Calls CleanUp() on each run object to release internal resources
+ * 2. Explicitly calls destructor to free memory
+ * 3. Clears the vector to release the pointer storage
+ *
+ * This process is repeated for all seven run type lists:
+ * - Single histogram runs
+ * - Single histogram RRF runs
+ * - Asymmetry runs
+ * - Asymmetry RRF runs
+ * - β-NMR asymmetry runs
+ * - μ⁻ (mu-minus) runs
+ * - Non-μSR runs
+ *
+ * The MSR handler (fMsrInfo) and data handler (fData) are NOT deleted
+ * as they are owned by the calling code.
*/
PRunListCollection::~PRunListCollection()
{
@@ -100,14 +135,35 @@ PRunListCollection::~PRunListCollection()
// Add (public)
//--------------------------------------------------------------------------
/**
- *
Adds a processed set of data to the handler.
+ * \brief Adds a processed run to the appropriate list based on fit type.
*
- * return:
- * - true if a processed data set could be added successfully
- * - false otherwise
+ * Creates a new PRunBase-derived object for the specified MSR file RUN block and
+ * adds it to the appropriate type-specific list. The method performs fit type
+ * dispatching by:
+ * 1. Reading fit type from the RUN block (if specified)
+ * 2. Falling back to GLOBAL block fit type if not specified in RUN
+ * 3. Creating the appropriate run object based on fit type
+ * 4. Calling PrepareData() on the new object to load and process data
+ * 5. Checking validity and returning success/failure status
*
- * \param runNo msr-file run number
- * \param tag tag showing what shall be done: kFit == fitting, kView == viewing
+ * Supported fit types and corresponding classes:
+ * - PRUN_SINGLE_HISTO → PRunSingleHisto
+ * - PRUN_SINGLE_HISTO_RRF → PRunSingleHistoRRF
+ * - PRUN_ASYMMETRY → PRunAsymmetry
+ * - PRUN_ASYMMETRY_RRF → PRunAsymmetryRRF
+ * - PRUN_ASYMMETRY_BNMR → PRunAsymmetryBNMR
+ * - PRUN_MU_MINUS → PRunMuMinus
+ * - PRUN_NON_MUSR → PRunNonMusr
+ *
+ * If data preprocessing fails (e.g., file not found, invalid t0, theory errors),
+ * the run object is still added to the list but marked as invalid, and this
+ * method returns false.
+ *
+ * \param runNo MSR file run number (0-based index into RUN blocks)
+ * \param tag Operation mode: kFit (for fitting), kView (for display/plotting)
+ * \return True if run was added and initialized successfully, false if initialization failed
+ *
+ * \see PRunBase::PrepareData() for data preprocessing details
*/
Bool_t PRunListCollection::Add(Int_t runNo, EPMusrHandleTag tag)
{
@@ -167,15 +223,32 @@ Bool_t PRunListCollection::Add(Int_t runNo, EPMusrHandleTag tag)
// SetFitRange (public)
//--------------------------------------------------------------------------
/**
- *
Set the current fit range in bins. The string has the structure:
- * 'fit_range fgb0+n00 lgb0-n01 [fgb1+n10 lgb-n11 fgb2+n20 lgb2-n21 .. fgbN+nN0 lgbN-nN1]'
- * where fgb is the first good bin, lgb is the last good bin. nXY are offsets in bins.
- * N is the number of runs in the msr-file.
+ * \brief Sets fit range in bin units using string specification (COMMANDS block syntax).
*
- *
This means there are 2 options: (i) a globle fit range in bins for all runs in the
- * msr-file, or (ii) each run block in the msr-file needs its individual range.
+ * Parses and applies fit range specified in bin offsets from t0 markers.
+ * This method supports the COMMANDS block FIT_RANGE syntax used for dynamic
+ * range adjustments during optimization.
*
- * \param fitRange string holding the fit range(s).
+ * String format:
+ * - Single range: "fit_range fgb+n0 lgb-n1"
+ * - Multiple ranges: "fit_range fgb0+n00 lgb0-n01 fgb1+n10 lgb1-n11 ..."
+ *
+ * Where:
+ * - fgb = first good bin (t0 marker from MSR file)
+ * - lgb = last good bin (end marker, often from data_range or automatic)
+ * - nXY = offset in bins (can be positive or negative)
+ *
+ * Example:
+ * - "fit_range fgb+10 lgb-20" → Start 10 bins after t0, end 20 bins before last good bin
+ * - For multiple runs, each gets its own fgb/lgb pair in sequence
+ *
+ * This method broadcasts the range specification to all run objects in all lists.
+ * Each run's SetFitRangeBin() method interprets the string based on its position
+ * in the MSR file.
+ *
+ * \param fitRange String holding fit range specification in bin offsets
+ *
+ * \see SetFitRange(PDoublePairVector) for time-based range specification
*/
void PRunListCollection::SetFitRange(const TString fitRange)
{
@@ -199,11 +272,33 @@ void PRunListCollection::SetFitRange(const TString fitRange)
// SetFitRange (public)
//--------------------------------------------------------------------------
/**
- *
Set the current fit range in time. If fitRange.size()==1 the given fit range will be used for all the runs,
- * otherwise fitRange.size()==the number of runs in the msr-file, and for each run there will be an individual
- * fit range.
+ * \brief Sets fit range in time units (microseconds from t0).
*
- * \param fitRange vector holding the fit range(s).
+ * Applies time-based fit ranges to all runs in the collection. This is the
+ * standard method for specifying fit ranges in the MSR file FIT block or
+ * during interactive range adjustments.
+ *
+ * Range specification modes:
+ * - Global range: fitRange.size() == 1
+ * - Same (start, end) time pair applies to all runs
+ * - Example: {(0.1, 10.0)} → All runs fit from 0.1 μs to 10.0 μs after t0
+ *
+ * - Individual ranges: fitRange.size() == number of MSR file runs
+ * - Each run gets its own (start, end) time pair
+ * - fitRange[i] corresponds to MSR file RUN block i
+ * - Example: {(0.1, 10.0), (0.2, 8.0)} → Run 0: 0.1-10.0 μs, Run 1: 0.2-8.0 μs
+ *
+ * Processing steps for each run:
+ * 1. SetFitRange() updates internal start/end time members
+ * 2. CalcNoOfFitBins() recalculates bin indices (fStartTimeBin, fEndTimeBin)
+ *
+ * The bin recalculation is necessary because the fit range is initially specified
+ * in time but χ² calculation operates on bin indices.
+ *
+ * \param fitRange Vector of (start_time, end_time) pairs in microseconds (μs) from t0
+ *
+ * \see SetFitRange(TString) for bin-based range specification
+ * \see PRunBase::CalcNoOfFitBins() for time-to-bin conversion
*/
void PRunListCollection::SetFitRange(const PDoublePairVector fitRange)
{
@@ -239,12 +334,21 @@ void PRunListCollection::SetFitRange(const PDoublePairVector fitRange)
// GetSingleHistoChisq (public)
//--------------------------------------------------------------------------
/**
- *
Calculates chi-square of all single histogram runs of a msr-file.
+ * \brief Calculates total χ² for all single histogram runs (global fit metric).
*
- * return:
- * - chi-square of all single histogram runs of the msr-file
+ * Sums the chi-squared statistic over all single histogram runs in the collection:
+ * \f[ \chi^2_{\rm total} = \sum_{i=1}^{N_{\rm runs}} \chi^2_i \f]
*
- * \param par fit parameter vector
+ * where each run's χ² is:
+ * \f[ \chi^2_i = \sum_{j=1}^{N_{\rm bins,i}} \frac{(y_j^{\rm data} - y_j^{\rm theory})^2}{\sigma_j^2} \f]
+ *
+ * This is the objective function minimized by MINUIT during global fitting of
+ * multiple single histogram runs. Called repeatedly during each fit iteration.
+ *
+ * \param par Parameter vector from MINUIT with current parameter values
+ * \return Total χ² summed over all single histogram runs
+ *
+ * \see PRunSingleHisto::CalcChiSquare() for per-run χ² calculation
*/
Double_t PRunListCollection::GetSingleHistoChisq(const std::vector& par) const
{
@@ -281,12 +385,19 @@ Double_t PRunListCollection::GetSingleHistoRRFChisq(const std::vector&
// GetAsymmetryChisq (public)
//--------------------------------------------------------------------------
/**
- * Calculates chi-square of all asymmetry runs of a msr-file.
+ * \brief Calculates total χ² for all asymmetry runs (global fit metric).
*
- * return:
- * - chi-square of all asymmetry runs of the msr-file
+ * Sums the chi-squared statistic over all asymmetry runs in the collection.
+ * For asymmetry fits, χ² is calculated from the asymmetry values:
+ * \f[ A_i = \frac{F_i - \alpha B_i}{F_i + \alpha B_i} \f]
*
- * \param par fit parameter vector
+ * with proper error propagation. This is the objective function for global
+ * asymmetry fits involving multiple runs (e.g., temperature or field scans).
+ *
+ * \param par Parameter vector from MINUIT with current parameter values
+ * \return Total χ² summed over all asymmetry runs
+ *
+ * \see PRunAsymmetry::CalcChiSquare() for per-run asymmetry χ² calculation
*/
Double_t PRunListCollection::GetAsymmetryChisq(const std::vector& par) const
{
diff --git a/src/include/PRunListCollection.h b/src/include/PRunListCollection.h
index acf1937b1..3d4d64307 100644
--- a/src/include/PRunListCollection.h
+++ b/src/include/PRunListCollection.h
@@ -44,81 +44,747 @@
#include "PRunNonMusr.h"
/**
- * Handler class handling all processed data of an msr-file. All calls of minuit2 are going through this class.
+ * \brief Manager class for all processed μSR run data during fitting.
+ *
+ * PRunListCollection is the central orchestrator for musrfit, managing all processed
+ * run data and serving as the interface between the MINUIT minimizer and the various
+ * run types. It acts as a container and dispatcher for different fit types, routing
+ * χ² and maximum likelihood calculations to the appropriate run objects.
+ *
+ * \section architecture Architecture
+ *
+ * The collection maintains separate lists for each fit type:
+ * - Single Histogram: Basic time-differential μSR (one detector)
+ * - Single Histogram RRF: Single detector in rotating reference frame
+ * - Asymmetry: Forward-backward asymmetry fits
+ * - Asymmetry RRF: Asymmetry in rotating reference frame
+ * - Asymmetry β-NMR: Beta-detected NMR asymmetry
+ * - Mu-Minus: Negative muon fits (different lifetime)
+ * - Non-μSR: General time-series data fits
+ *
+ * \section responsibilities Core Responsibilities
+ *
+ * Run management:
+ * - Creating and storing PRunBase-derived objects for each run
+ * - Organizing runs by fit type for efficient access
+ * - Managing run lifetime and cleanup
+ *
+ * MINUIT interface:
+ * - Aggregating χ² from all runs of each type
+ * - Providing maximum likelihood calculations
+ * - Supporting both global fits (all runs) and single run evaluation
+ * - Calculating degrees of freedom (total bins fitted)
+ *
+ * Fit range management:
+ * - Dynamically updating fit ranges via COMMAND block
+ * - Supporting both time-based and bin-based range specifications
+ * - Applying ranges to appropriate run lists
+ *
+ * Data access:
+ * - Retrieving processed data for plotting
+ * - Accessing metadata (field, temperature, energy)
+ * - Supporting access by index or run number
+ *
+ * \section workflow Typical Workflow
+ *
+ * 1. Construction: Pass MSR handler and data handler
+ * 2. Add runs: Call Add() for each RUN block to create appropriate run objects
+ * 3. Fitting: MINUIT calls Get*Chisq() methods to evaluate fit quality
+ * 4. Visualization: Retrieve processed data via Get*() methods for plotting
+ *
+ * \section fit_types Fit Type Dispatching
+ *
+ * The collection routes operations based on fit type:
+ * - fittype 0: Single histogram → fRunSingleHistoList
+ * - fittype 1: Asymmetry → fRunAsymmetryList
+ * - fittype 2: Single histogram RRF → fRunSingleHistoRRFList
+ * - fittype 3: Asymmetry RRF → fRunAsymmetryRRFList
+ * - fittype 4: Mu-minus → fRunMuMinusList
+ * - fittype 5: β-NMR asymmetry → fRunAsymmetryBNMRList
+ * - fittype 6: Non-μSR → fRunNonMusrList
+ *
+ * \section global_fits Global Fitting
+ *
+ * For global fits (multiple runs sharing parameters):
+ * - Get*Chisq() methods sum χ² over all runs of that type
+ * - Each run is fitted with the same parameter set
+ * - Total χ² = Σ χ²_i across all runs
+ * - Degrees of freedom = Σ N_bins,i - N_parameters
+ *
+ * \section example_usage Example Usage
+ *
+ * \code
+ * // Create collection
+ * PRunListCollection collection(msrInfo, dataHandler);
+ *
+ * // Add all runs from MSR file
+ * for (UInt_t i = 0; i < msrInfo->GetMsrRunList()->size(); i++) {
+ * collection.Add(i, kFit);
+ * }
+ *
+ * // MINUIT minimization (called internally)
+ * Double_t chisq = collection.GetAsymmetryChisq(parameters);
+ *
+ * // Retrieve data for plotting
+ * PRunData *data = collection.GetAsymmetry(0);
+ * \endcode
+ *
+ * \section thread_safety Thread Safety
+ * NOT thread-safe. MINUIT evaluation must be serialized. For parallel fitting
+ * of independent datasets, create separate PRunListCollection instances.
+ *
+ * \see PRunBase for individual run processing
+ * \see PMsrHandler for MSR file configuration
+ * \see PRunDataHandler for raw data access
*/
class PRunListCollection
{
public:
+ /**
+ * \brief Constructor that initializes the collection.
+ *
+ * Creates an empty collection ready to receive runs via Add(). Does not
+ * automatically load runs - caller must explicitly add each run.
+ *
+ * \param msrInfo Pointer to MSR file handler (must remain valid for object lifetime)
+ * \param data Pointer to raw data handler (must remain valid for object lifetime)
+ * \param theoAsData If true, theory calculated only at data points; if false, extra points for visualization
+ */
PRunListCollection(PMsrHandler *msrInfo, PRunDataHandler *data, Bool_t theoAsdata=false);
+
+ /**
+ * \brief Virtual destructor that cleans up all run objects.
+ *
+ * Calls CleanUp() and destructor for all run objects in all lists.
+ * Clears all run vectors. Does NOT delete fMsrInfo or fData (owned externally).
+ */
virtual ~PRunListCollection();
+ /**
+ * \brief Enumeration for data access mode.
+ *
+ * Controls how runs are retrieved by Get*() methods:
+ * - kIndex: Retrieve by position in the list (0-based)
+ * - kRunNo: Retrieve by run number from MSR file
+ */
enum EDataSwitch { kIndex, kRunNo };
+ /**
+ * \brief Adds a run to the appropriate list based on fit type.
+ *
+ * Creates a PRunBase-derived object matching the fit type specified in the
+ * MSR file RUN block, processes the data, and adds it to the corresponding
+ * internal list. This is the primary method for populating the collection.
+ *
+ * The method:
+ * 1. Determines fit type from MSR RUN block (fittype 0-6)
+ * 2. Creates appropriate PRunBase-derived object (PRunAsymmetry, etc.)
+ * 3. Object loads and processes data in its constructor
+ * 4. Adds object to correct list (fRunAsymmetryList, etc.)
+ *
+ * \param runNo Run number (0-based index into MSR file RUN blocks)
+ * \param tag Operation mode: kFit (fitting), kView (visualization only)
+ * \return True if run added successfully, false if creation/processing failed
+ *
+ * \note Invalid runs (failed data loading) are still added but marked invalid
+ */
virtual Bool_t Add(Int_t runNo, EPMusrHandleTag tag);
+ /**
+ * \brief Sets fit range for all runs (time-based or bin-based).
+ *
+ * Updates the fitting window for all runs in the collection. Supports:
+ * - Single range applied to all runs
+ * - Individual ranges per run
+ *
+ * \param fitRange Vector of (start, end) pairs in microseconds
+ *
+ * If one pair: applies to all runs. If multiple: fitRange[i] applies to run i.
+ */
virtual void SetFitRange(const PDoublePairVector fitRange);
+
+ /**
+ * \brief Sets fit range from string specification (bin-based).
+ *
+ * Parses and applies bin-based fit ranges from FIT_RANGE command.
+ * Format: "fgb[+offset] lgb[-offset]" for each run.
+ *
+ * \param fitRange String with fit range specification
+ *
+ * Example: "10+5 200-10" → bins [15, 190]
+ */
virtual void SetFitRange(const TString fitRange);
+ //--- Chi-square calculation methods (for global fits) ---
+
+ /**
+ * \brief Calculates total χ² for all single histogram runs.
+ *
+ * Sums χ² over all runs in fRunSingleHistoList. Each run compares its
+ * measured data with theory at the given parameters.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all single histogram runs
+ */
virtual Double_t GetSingleHistoChisq(const std::vector& par) const;
+
+ /** \brief Calculates total χ² for all single histogram RRF runs.
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all RRF single histogram runs */
virtual Double_t GetSingleHistoRRFChisq(const std::vector& par) const;
+
+ /** \brief Calculates total χ² for all asymmetry runs.
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all asymmetry runs */
virtual Double_t GetAsymmetryChisq(const std::vector& par) const;
+
+ /** \brief Calculates total χ² for all asymmetry RRF runs.
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all RRF asymmetry runs */
virtual Double_t GetAsymmetryRRFChisq(const std::vector& par) const;
+
+ /** \brief Calculates total χ² for all β-NMR asymmetry runs.
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all β-NMR runs */
virtual Double_t GetAsymmetryBNMRChisq(const std::vector& par) const;
+
+ /** \brief Calculates total χ² for all mu-minus runs.
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all mu-minus runs */
virtual Double_t GetMuMinusChisq(const std::vector& par) const;
+
+ /** \brief Calculates total χ² for all non-μSR runs.
+ * \param par Parameter vector from MINUIT
+ * \return Σ χ²_i for all non-μSR runs */
virtual Double_t GetNonMusrChisq(const std::vector& par) const;
+ //--- Single run chi-square methods ---
+
+ /**
+ * \brief Calculates expected χ² for a single run by index.
+ *
+ * Returns expected χ² based on theory and error estimates for one run.
+ * Useful for evaluating fit quality and error bar estimation.
+ *
+ * \param par Parameter vector from MINUIT
+ * \param idx Run index (searches all lists sequentially)
+ * \return Expected χ² for the specified run
+ */
virtual Double_t GetSingleRunChisqExpected(const std::vector& par, const UInt_t idx) const;
+
+ /**
+ * \brief Calculates χ² for a single run by index.
+ *
+ * Evaluates χ² for one specific run, searching across all fit type lists.
+ * Used for individual run analysis or diagnostics.
+ *
+ * \param par Parameter vector from MINUIT
+ * \param idx Run index (absolute index across all run lists)
+ * \return χ² for the specified run
+ */
virtual Double_t GetSingleRunChisq(const std::vector& par, const UInt_t idx) const;
+ //! \name Maximum Likelihood Calculation Methods (Global Fits)
+ //@{
+ /**
+ * \brief Calculates total maximum likelihood for all single histogram runs.
+ *
+ * Computes the negative 2×log-likelihood summed over all single histogram runs:
+ * \f[ -2\ln L_{\rm total} = \sum_{i=1}^{N_{\rm runs}} (-2\ln L_i) \f]
+ *
+ * For each run, the maximum likelihood is calculated using Poisson statistics:
+ * \f[ -2\ln L = 2\sum_{j=1}^{N_{\rm bins}} \left[y_j^{\rm theory} - y_j^{\rm data} \ln(y_j^{\rm theory})\right] \f]
+ *
+ * Maximum likelihood fitting is preferred over χ² for low-count data (< 10-20 counts/bin)
+ * where Gaussian approximations break down. It naturally handles Poisson statistics
+ * without requiring error estimates.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all single histogram runs
+ *
+ * \see CalcMaxLikelihood() in PRunBase for implementation details
+ */
virtual Double_t GetSingleHistoMaximumLikelihood(const std::vector& par) const;
+
+ /**
+ * \brief Calculates total maximum likelihood for all single histogram RRF runs.
+ *
+ * Computes -2×ln(L) summed over all single histogram rotating reference frame runs.
+ * Uses the same Poisson likelihood formula as GetSingleHistoMaximumLikelihood(),
+ * but applied to RRF-transformed data.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all single histogram RRF runs
+ */
virtual Double_t GetSingleHistoRRFMaximumLikelihood(const std::vector& par) const;
+
+ /**
+ * \brief Calculates total maximum likelihood for all asymmetry runs.
+ *
+ * Computes -2×ln(L) summed over all asymmetry runs. For asymmetry data,
+ * the likelihood is applied to the reconstructed forward/backward histograms
+ * rather than directly to the asymmetry values.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all asymmetry runs
+ */
virtual Double_t GetAsymmetryMaximumLikelihood(const std::vector& par) const;
+
+ /**
+ * \brief Calculates total maximum likelihood for all asymmetry RRF runs.
+ *
+ * Computes -2×ln(L) summed over all asymmetry rotating reference frame runs.
+ * Combines RRF transformation with asymmetry analysis in likelihood calculation.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all asymmetry RRF runs
+ */
virtual Double_t GetAsymmetryRRFMaximumLikelihood(const std::vector& par) const;
+
+ /**
+ * \brief Calculates total maximum likelihood for all β-NMR asymmetry runs.
+ *
+ * Computes -2×ln(L) summed over all beta-detected NMR asymmetry runs.
+ * Handles helicity-dependent measurements with appropriate likelihood formula.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all β-NMR asymmetry runs
+ */
virtual Double_t GetAsymmetryBNMRMaximumLikelihood(const std::vector& par) const;
+
+ /**
+ * \brief Calculates total maximum likelihood for all μ⁻ runs.
+ *
+ * Computes -2×ln(L) summed over all negative muon runs. Negative muons have
+ * different decay characteristics than positive muons.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all μ⁻ runs
+ */
virtual Double_t GetMuMinusMaximumLikelihood(const std::vector& par) const;
+
+ /**
+ * \brief Calculates total maximum likelihood for all non-μSR runs.
+ *
+ * Computes -2×ln(L) summed over all general time-series (non-μSR) data runs.
+ * Uses the same Poisson likelihood framework applied to generic x-y data.
+ *
+ * \param par Parameter vector from MINUIT
+ * \return Total -2×ln(L) summed over all non-μSR runs
+ */
virtual Double_t GetNonMusrMaximumLikelihood(const std::vector& par) const;
+ //@}
+ //! \name Single Run Maximum Likelihood Methods
+ //@{
+ /**
+ * \brief Calculates expected maximum likelihood for a single run (theoretical expectation).
+ *
+ * Computes the expected -2×ln(L) value based on the theory predictions and error
+ * estimates for a specific run. Useful for statistical diagnostics and validating
+ * error bars. For properly estimated errors and valid model, expected likelihood
+ * should be comparable to actual likelihood.
+ *
+ * \param par Parameter vector from MINUIT
+ * \param idx Run index (absolute index across all run lists)
+ * \return Expected -2×ln(L) for the specified run
+ *
+ * \note Not all run types implement this method; some may return 0.0
+ */
virtual Double_t GetSingleRunMaximumLikelihoodExpected(const std::vector& par, const UInt_t idx) const;
+
+ /**
+ * \brief Calculates maximum likelihood for a single run.
+ *
+ * Computes -2×ln(L) for a specific run identified by absolute index.
+ * This is useful for identifying problematic runs in a global fit or
+ * for analyzing individual run contributions to the total likelihood.
+ *
+ * \param par Parameter vector from MINUIT
+ * \param idx Run index (absolute index across all run lists)
+ * \return -2×ln(L) for the specified run
+ */
virtual Double_t GetSingleRunMaximumLikelihood(const std::vector& par, const UInt_t idx) const;
+ //@}
+ //! \name Fit Statistics Methods
+ //@{
+ /**
+ * \brief Returns the number of bins fitted for a specific run.
+ *
+ * Queries a single run to determine how many data bins fall within its
+ * fit range. This depends on:
+ * - The fit time range (start/end times from FIT block)
+ * - Time resolution and bin packing settings
+ * - Valid data range after background subtraction
+ *
+ * Used for calculating degrees of freedom: ν = N_bins_total - N_params
+ *
+ * \param idx Run index (absolute index across all run lists)
+ * \return Number of bins included in the fit for this run
+ *
+ * \see GetTotalNoOfBinsFitted() for total across all runs
+ */
virtual UInt_t GetNoOfBinsFitted(const UInt_t idx) const;
+
+ /**
+ * \brief Returns total number of bins fitted across all runs.
+ *
+ * Sums the number of fitted bins over all runs in the collection:
+ * \f[ N_{\rm bins,total} = \sum_{i=1}^{N_{\rm runs}} N_{\rm bins,i} \f]
+ *
+ * This is the numerator for calculating reduced chi-squared:
+ * \f[ \chi^2_{\rm red} = \frac{\chi^2}{N_{\rm bins,total} - N_{\rm params}} \f]
+ *
+ * For a good fit: χ²_red ≈ 1.0
+ *
+ * \return Total number of bins across all runs within fit ranges
+ *
+ * \see GetNoOfBinsFitted() for single run bin count
+ */
virtual UInt_t GetTotalNoOfBinsFitted() const;
+ //@}
- virtual UInt_t GetNoOfSingleHisto() const { return fRunSingleHistoList.size(); } ///< returns the number of single histogram data sets present in the msr-file
- virtual UInt_t GetNoOfSingleHistoRRF() const { return fRunSingleHistoRRFList.size(); } ///< returns the number of single histogram RRF data sets present in the msr-file
- virtual UInt_t GetNoOfAsymmetry() const { return fRunAsymmetryList.size(); } ///< returns the number of asymmetry data sets present in the msr-file
- virtual UInt_t GetNoOfAsymmetryRRF() const { return fRunAsymmetryRRFList.size(); } ///< returns the number of asymmetry RRF data sets present in the msr-file
- virtual UInt_t GetNoOfAsymmetryBNMR() const { return fRunAsymmetryBNMRList.size(); } ///< returns the number of asymmetry BNMR data sets present in the msr-file
- virtual UInt_t GetNoOfMuMinus() const { return fRunMuMinusList.size(); } ///< returns the number of mu minus data sets present in the msr-file
- virtual UInt_t GetNoOfNonMusr() const { return fRunNonMusrList.size(); } ///< returns the number of non-muSR data sets present in the msr-file
+ //! \name Run Count Accessors
+ //@{
+ /**
+ * \brief Returns the number of single histogram runs in the collection.
+ * \return Count of single histogram data sets from MSR file
+ */
+ virtual UInt_t GetNoOfSingleHisto() const { return fRunSingleHistoList.size(); }
+ /**
+ * \brief Returns the number of single histogram RRF runs in the collection.
+ * \return Count of single histogram rotating reference frame data sets from MSR file
+ */
+ virtual UInt_t GetNoOfSingleHistoRRF() const { return fRunSingleHistoRRFList.size(); }
+
+ /**
+ * \brief Returns the number of asymmetry runs in the collection.
+ * \return Count of asymmetry data sets from MSR file
+ */
+ virtual UInt_t GetNoOfAsymmetry() const { return fRunAsymmetryList.size(); }
+
+ /**
+ * \brief Returns the number of asymmetry RRF runs in the collection.
+ * \return Count of asymmetry rotating reference frame data sets from MSR file
+ */
+ virtual UInt_t GetNoOfAsymmetryRRF() const { return fRunAsymmetryRRFList.size(); }
+
+ /**
+ * \brief Returns the number of β-NMR asymmetry runs in the collection.
+ * \return Count of beta-detected NMR asymmetry data sets from MSR file
+ */
+ virtual UInt_t GetNoOfAsymmetryBNMR() const { return fRunAsymmetryBNMRList.size(); }
+
+ /**
+ * \brief Returns the number of μ⁻ runs in the collection.
+ * \return Count of negative muon data sets from MSR file
+ */
+ virtual UInt_t GetNoOfMuMinus() const { return fRunMuMinusList.size(); }
+
+ /**
+ * \brief Returns the number of non-μSR runs in the collection.
+ * \return Count of general time-series (non-μSR) data sets from MSR file
+ */
+ virtual UInt_t GetNoOfNonMusr() const { return fRunNonMusrList.size(); }
+ //@}
+
+ //! \name Processed Data Accessors
+ //@{
+ /**
+ * \brief Retrieves processed data for a single histogram run.
+ *
+ * Provides access to the PRunData object containing background-corrected,
+ * packed histogram data with theory values and error bars.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into single histogram list (0-based)
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ *
+ * \see PRunData for data structure contents
+ */
virtual PRunData* GetSingleHisto(UInt_t index, EDataSwitch tag=kIndex);
- virtual PRunData* GetSingleHistoRRF(UInt_t index, EDataSwitch tag=kIndex);
- virtual PRunData* GetAsymmetry(UInt_t index, EDataSwitch tag=kIndex);
- virtual PRunData* GetAsymmetryRRF(UInt_t index, EDataSwitch tag=kIndex);
- virtual PRunData* GetAsymmetryBNMR(UInt_t index, EDataSwitch tag=kIndex);
- virtual PRunData* GetMuMinus(UInt_t index, EDataSwitch tag=kIndex);
- virtual PRunData* GetNonMusr(UInt_t index, EDataSwitch tag=kIndex);
+ /**
+ * \brief Retrieves processed data for a single histogram RRF run.
+ *
+ * Provides access to RRF-transformed single histogram data including
+ * filtered theory curves and RRF-specific metadata.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into single histogram RRF list
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ */
+ virtual PRunData* GetSingleHistoRRF(UInt_t index, EDataSwitch tag=kIndex);
+
+ /**
+ * \brief Retrieves processed data for an asymmetry run.
+ *
+ * Provides access to calculated asymmetry data with proper error propagation,
+ * including α-corrected forward/backward combinations.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into asymmetry list
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ */
+ virtual PRunData* GetAsymmetry(UInt_t index, EDataSwitch tag=kIndex);
+
+ /**
+ * \brief Retrieves processed data for an asymmetry RRF run.
+ *
+ * Provides access to RRF-transformed asymmetry data combining asymmetry
+ * calculation with rotating reference frame analysis.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into asymmetry RRF list
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ */
+ virtual PRunData* GetAsymmetryRRF(UInt_t index, EDataSwitch tag=kIndex);
+
+ /**
+ * \brief Retrieves processed data for a β-NMR asymmetry run.
+ *
+ * Provides access to beta-detected NMR asymmetry data with helicity-dependent
+ * analysis and appropriate error handling.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into β-NMR asymmetry list
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ */
+ virtual PRunData* GetAsymmetryBNMR(UInt_t index, EDataSwitch tag=kIndex);
+
+ /**
+ * \brief Retrieves processed data for a μ⁻ run.
+ *
+ * Provides access to negative muon data accounting for different decay
+ * properties compared to positive muons.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into μ⁻ list
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ */
+ virtual PRunData* GetMuMinus(UInt_t index, EDataSwitch tag=kIndex);
+
+ /**
+ * \brief Retrieves processed data for a non-μSR run.
+ *
+ * Provides access to general time-series data (x-y pairs) processed through
+ * the same framework as μSR data but without μSR-specific assumptions.
+ *
+ * \param index Run identifier (interpretation depends on tag parameter)
+ * \param tag Access mode:
+ * - kIndex (default): Direct index into non-μSR list
+ * - kRunNumber: MSR file run number
+ * \return Pointer to PRunData object, or nullptr if index is invalid
+ */
+ virtual PRunData* GetNonMusr(UInt_t index, EDataSwitch tag=kIndex);
+ //@}
+
+ //! \name Experimental Metadata Accessors
+ //@{
+ /**
+ * \brief Retrieves temperature information for a specific run.
+ *
+ * Returns temperature data extracted from the raw data file header.
+ * Temperature may be recorded as a time-series (multiple values) or
+ * a single value depending on the data acquisition system.
+ *
+ * \param runName Run identifier string (e.g., "2425" or "/path/to/run2425.root")
+ * \return Pointer to vector of (time, temperature) pairs, or nullptr if not available
+ *
+ * \note Temperature units depend on the data file format (typically Kelvin or Celsius)
+ */
virtual const PDoublePairVector *GetTemp(const TString &runName) const;
+
+ /**
+ * \brief Retrieves magnetic field value for a specific run.
+ *
+ * Returns the applied magnetic field extracted from the raw data file header.
+ * This is typically the field measured at the sample position.
+ *
+ * \param runName Run identifier string (e.g., "2425" or "/path/to/run2425.root")
+ * \return Magnetic field value in Gauss, or PMUSR_UNDEFINED if not available
+ *
+ * \note Field values may be recorded in various units (G, T, Oe) depending on facility
+ */
virtual Double_t GetField(const TString &runName) const;
+
+ /**
+ * \brief Retrieves beam energy for a specific run.
+ *
+ * Returns the muon beam implantation energy extracted from the raw data file header.
+ * Energy determines the stopping profile (implantation depth) in the sample.
+ *
+ * \param runName Run identifier string (e.g., "2425" or "/path/to/run2425.root")
+ * \return Beam energy in keV, or PMUSR_UNDEFINED if not available
+ *
+ * \note Low-energy muons (LE-μSR) typically: 1-30 keV; surface muons: ~4 MeV
+ */
virtual Double_t GetEnergy(const TString &runName) const;
+
+ /**
+ * \brief Retrieves experimental setup identifier for a specific run.
+ *
+ * Returns the beamline or spectrometer name extracted from the raw data file header.
+ * This identifies the experimental station where data was collected.
+ *
+ * \param runName Run identifier string (e.g., "2425" or "/path/to/run2425.root")
+ * \return Setup name string (e.g., "GPS", "LTF", "DOLLY"), or nullptr if not available
+ *
+ * \note Setup names are facility-specific (PSI: GPS, LTF, HAL-9500; ISIS: EMU, ARGUS, etc.)
+ */
virtual const Char_t* GetSetup(const TString &runName) const;
+
+ /**
+ * \brief Retrieves x-axis label for plotting.
+ *
+ * Returns the appropriate x-axis title based on fit type and run settings.
+ * Typically "Time (μs)" for time-domain fits, "Frequency (MHz)" for Fourier transforms,
+ * or custom labels for non-μSR data.
+ *
+ * \param runName Run identifier string (e.g., "2425" or "/path/to/run2425.root")
+ * \param idx Run index within the specified fit type
+ * \return X-axis title string, or nullptr if not available
+ *
+ * \see PRunData for plot axis information storage
+ */
virtual const Char_t* GetXAxisTitle(const TString &runName, const UInt_t idx) const;
+
+ /**
+ * \brief Retrieves y-axis label for plotting.
+ *
+ * Returns the appropriate y-axis title based on fit type:
+ * - Single histogram: "Counts" or "Positron Rate (MHz)"
+ * - Asymmetry: "Asymmetry" or "Asymmetry (%)"
+ * - Custom labels for non-μSR data
+ *
+ * \param runName Run identifier string (e.g., "2425" or "/path/to/run2425.root")
+ * \param idx Run index within the specified fit type
+ * \return Y-axis title string, or nullptr if not available
+ *
+ * \see PRunData for plot axis information storage
+ */
virtual const Char_t* GetYAxisTitle(const TString &runName, const UInt_t idx) const;
+ //@}
private:
- Bool_t fTheoAsData; ///< if true: calculate theory points only at the data points
- PMsrHandler *fMsrInfo; ///< pointer to the msr-file handler
- PRunDataHandler *fData; ///< pointer to the run-data handler
+ /**
+ * \brief Theory calculation mode flag.
+ *
+ * Controls whether theory is calculated at:
+ * - true: Only at data point times (efficient for fitting, exact data-theory comparison)
+ * - false: On a high-resolution grid (smooth curves for visualization)
+ *
+ * Set from MSR PLOT block. For fitting, always uses fTheoAsData=true internally
+ * regardless of this setting. This flag primarily affects plotting and export.
+ */
+ Bool_t fTheoAsData;
- std::vector fRunSingleHistoList; ///< stores all processed single histogram data
- std::vector fRunSingleHistoRRFList; ///< stores all processed single histogram RRF data
- std::vector fRunAsymmetryList; ///< stores all processed asymmetry data
- std::vector fRunAsymmetryRRFList; ///< stores all processed asymmetry RRF data
- std::vector fRunAsymmetryBNMRList; ///< stores all processed asymmetry BNMR data
- std::vector fRunMuMinusList; ///< stores all processed mu-minus data
- std::vector fRunNonMusrList; ///< stores all processed non-muSR data
+ /**
+ * \brief Pointer to MSR file handler (not owned).
+ *
+ * Provides access to all MSR file content including PARAMETER, THEORY, FUNCTIONS,
+ * RUN, COMMANDS, FOURIER, and PLOT blocks. Must remain valid for the lifetime
+ * of this PRunListCollection object.
+ *
+ * \warning This pointer is NOT owned by PRunListCollection and will not be deleted.
+ */
+ PMsrHandler *fMsrInfo;
+
+ /**
+ * \brief Pointer to raw data handler (not owned).
+ *
+ * Provides access to raw histogram data files via unified interface supporting
+ * multiple formats (ROOT, NeXus, MUD, PSI-BIN, etc.). Used during Add() calls
+ * to load data for each run.
+ *
+ * \warning This pointer is NOT owned by PRunListCollection and will not be deleted.
+ */
+ PRunDataHandler *fData;
+
+ /**
+ * \brief Collection of single histogram run objects.
+ *
+ * Each element is a PRunSingleHisto object containing processed data for one
+ * single-detector histogram fit. Objects are heap-allocated and owned by this
+ * vector; deleted in destructor.
+ *
+ * \see PRunSingleHisto for single histogram fit implementation
+ */
+ std::vector fRunSingleHistoList;
+
+ /**
+ * \brief Collection of single histogram RRF run objects.
+ *
+ * Each element is a PRunSingleHistoRRF object containing RRF-transformed
+ * single histogram data with Kaiser filtering. Objects are owned by this vector.
+ *
+ * \see PRunSingleHistoRRF for RRF single histogram implementation
+ */
+ std::vector fRunSingleHistoRRFList;
+
+ /**
+ * \brief Collection of asymmetry run objects.
+ *
+ * Each element is a PRunAsymmetry object containing calculated asymmetry data
+ * from forward/backward detector pairs. Objects are owned by this vector.
+ *
+ * \see PRunAsymmetry for asymmetry fit implementation
+ */
+ std::vector fRunAsymmetryList;
+
+ /**
+ * \brief Collection of asymmetry RRF run objects.
+ *
+ * Each element is a PRunAsymmetryRRF object combining asymmetry calculation
+ * with RRF transformation for high-frequency analysis. Objects are owned by this vector.
+ *
+ * \see PRunAsymmetryRRF for RRF asymmetry implementation
+ */
+ std::vector fRunAsymmetryRRFList;
+
+ /**
+ * \brief Collection of β-NMR asymmetry run objects.
+ *
+ * Each element is a PRunAsymmetryBNMR object for beta-detected NMR measurements
+ * with helicity-dependent analysis. Objects are owned by this vector.
+ *
+ * \see PRunAsymmetryBNMR for β-NMR asymmetry implementation
+ */
+ std::vector fRunAsymmetryBNMRList;
+
+ /**
+ * \brief Collection of μ⁻ (negative muon) run objects.
+ *
+ * Each element is a PRunMuMinus object for negative muon measurements with
+ * different decay characteristics than μ⁺. Objects are owned by this vector.
+ *
+ * \see PRunMuMinus for negative muon fit implementation
+ */
+ std::vector fRunMuMinusList;
+
+ /**
+ * \brief Collection of non-μSR run objects.
+ *
+ * Each element is a PRunNonMusr object for general time-series (x-y) data fits
+ * using the musrfit framework without μSR-specific assumptions. Objects are owned.
+ *
+ * \see PRunNonMusr for generic time-series fit implementation
+ */
+ std::vector fRunNonMusrList;
};
#endif // _PRUNLISTCOLLECTION_H_