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_