/*************************************************************************** PFitter.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 _PFITTER_H_ #define _PFITTER_H_ #include #include "Minuit2/MnUserParameters.h" #include "Minuit2/FunctionMinimum.h" #include "PMusr.h" #include "PMsrHandler.h" #include "PRunListCollection.h" #include "PFitterFcn.h" //------------------------------------------------------------- /** *

Minuit2 command identifiers for COMMANDS block. * *

These constants map MSR file COMMANDS block keywords to internal * command identifiers. Commands control the fitting process, including * minimization algorithms, parameter fixing/releasing, error analysis, * and output options. * *

Categories: * - Minimizers: MIGRAD (gradient descent), SIMPLEX (non-gradient), MINIMIZE (automatic) * - Error analysis: HESSE (covariance matrix), MINOS (asymmetric errors) * - Parameter control: FIX, RELEASE, RESTORE, SAVE * - Exploration: SCAN (1D/2D parameter space), CONTOURS (error ellipses) * - Settings: STRATEGY, MACHINE_PRECISION, PRINT * - Analysis: FIT_RANGE (time-window scan), SECTOR (chisq vs. time) */ /// Interactive mode (not implemented in musrfit) #define PMN_INTERACTIVE 0 /// Contour plot command (2D error ellipses) #define PMN_CONTOURS 1 /// Eigenvalue analysis (not implemented) #define PMN_EIGEN 2 /// Fit range scan to find optimal fitting window #define PMN_FIT_RANGE 3 /// Fix parameters at current values #define PMN_FIX 4 /// Calculate Hessian matrix for error estimation #define PMN_HESSE 5 /// Set machine precision for numerical derivatives #define PMN_MACHINE_PRECISION 6 /// MIGRAD minimizer (gradient-based, recommended) #define PMN_MIGRAD 7 /// MINIMIZE (automatic algorithm selection) #define PMN_MINIMIZE 8 /// MINOS error analysis (asymmetric confidence intervals) #define PMN_MINOS 9 /// Plot command (for scan/contour results) #define PMN_PLOT 10 /// Release previously fixed parameters #define PMN_RELEASE 11 /// Restore parameters from previous SAVE #define PMN_RESTORE 12 /// Save current parameter state #define PMN_SAVE 13 /// Parameter scan (1D or 2D) #define PMN_SCAN 14 /// SIMPLEX minimizer (robust but slow) #define PMN_SIMPLEX 15 /// Set minimization strategy (0=fast, 1=default, 2=careful) #define PMN_STRATEGY 16 /// Set user covariance matrix (not implemented) #define PMN_USER_COVARIANCE 17 /// Set user parameter state (not implemented) #define PMN_USER_PARAM_STATE 18 /// Set print level for fit output (0=quiet, 1=normal, 2=verbose) #define PMN_PRINT 19 /// Calculate χ² vs. time in sectors (time-window analysis) #define PMN_SECTOR 20 //----------------------------------------------------------------------------- /** *

Container for sector χ² (or max likelihood) analysis results. * *

The SECTOR command analyzes how χ² changes as the fit range is extended * from the first good bin (fgb) to progressively later times. This helps * identify: * - Optimal fitting windows * - Time regions with systematic deviations * - Data quality issues * - Relaxation component contributions * *

A "sector" is a time window [fgb, fLast] where fLast < lgb. The class * stores χ²/maxLH and NDF for each sector, both for the total fit and for * individual runs. * *

Use case: If early-time data shows poor χ², the sector analysis * reveals whether to adjust t0, fgb, or background estimation. */ class PSectorChisq { public: /** *

Constructor. * * @param noOfRuns Number of runs in the fit (allocates storage for per-run statistics) */ PSectorChisq(UInt_t noOfRuns); /// Sets the first good bin time for a specific run /// @param first First good bin time in microseconds /// @param idx Run index void SetRunFirstTime(Double_t first, UInt_t idx); /// Sets the sector end time (last bin included in this sector) /// @param last Sector end time in microseconds void SetSectorTime(Double_t last) { fLast = last; } /// Sets the total χ² (or max likelihood) for this sector /// @param chisq Chi-squared or maximum likelihood value void SetChisq(Double_t chisq) { fChisq = chisq; } /// Sets the χ² for a specific run in this sector /// @param chisq Chi-squared value for run /// @param idx Run index void SetChisq(Double_t chisq, UInt_t idx); /// Sets the expected total χ² for this sector /// @param expChisq Expected chi-squared value void SetExpectedChisq(Double_t expChisq) { fExpectedChisq = expChisq; } /// Sets the expected χ² for a specific run /// @param chisq Expected chi-squared value /// @param idx Run index void SetExpectedChisq(Double_t chisq, UInt_t idx); /// Sets the total number of degrees of freedom for this sector /// @param ndf Degrees of freedom void SetNDF(UInt_t ndf) { fNDF = ndf; } /// Sets the NDF for a specific run /// @param ndf Degrees of freedom for run /// @param idx Run index void SetNDF(UInt_t ndf, UInt_t idx); /// Gets the first good bin time for a specific run /// @param idx Run index /// @return First good bin time in microseconds Double_t GetTimeRangeFirst(UInt_t idx); /// Returns the sector end time /// @return Last bin time in microseconds Double_t GetTimeRangeLast() { return fLast; } /// Returns the total χ² for this sector /// @return Chi-squared or max likelihood value Double_t GetChisq() { return fChisq; } /// Returns the χ² for a specific run /// @param idx Run index /// @return Chi-squared value Double_t GetChisq(UInt_t idx); /// Returns the expected total χ² /// @return Expected chi-squared value Double_t GetExpectedChisq() { return fExpectedChisq; } /// Returns the expected χ² for a specific run /// @param idx Run index /// @return Expected chi-squared value Double_t GetExpectedChisq(UInt_t idx); /// Returns the total NDF for this sector /// @return Degrees of freedom UInt_t GetNDF() { return fNDF; } /// Returns the NDF for a specific run /// @param idx Run index /// @return Degrees of freedom UInt_t GetNDF(UInt_t idx); /// Returns the number of runs /// @return Number of runs in the analysis UInt_t GetNoRuns() { return fNoOfRuns; } private: UInt_t fNoOfRuns; ///< number of runs presesent Double_t fLast; ///< requested time stamp Double_t fChisq; ///< chisq or maxLH for the sector Double_t fExpectedChisq; ///< keep the expected chisq or maxLH for the sector UInt_t fNDF; ///< NDF for the sector PDoubleVector fFirst; ///< time stamp for fgb for a given run PDoubleVector fChisqRun; ///< chisq or maxLH for the sector and run PDoubleVector fExpectedChisqRun; ///< expected chisq or maxLH for the sector and run PUIntVector fNDFRun; ///< NDF for the sector and run }; //----------------------------------------------------------------------------- /** *

Main fitting engine interfacing with ROOT Minuit2. * *

PFitter orchestrates the entire fitting process for musrfit: * - Initializes Minuit2 with parameters from MSR file * - Executes COMMANDS block directives (MIGRAD, HESSE, MINOS, etc.) * - Manages parameter fixing, releasing, and boundaries * - Performs error analysis (Hessian, MINOS) * - Conducts parameter scans and contour plots * - Calculates sector χ² for time-window analysis * - Generates fit output and statistics * *

Fitting workflow: * 1. Initialize parameters and set boundaries * 2. Execute COMMANDS block sequentially: * - MIGRAD: Find minimum using gradient descent * - HESSE: Calculate symmetric errors from covariance matrix * - MINOS: Calculate asymmetric errors (optional, slower) * - SAVE: Save parameter state * 3. Update MSR file with fitted parameters and statistics * *

Minimization modes: * - χ² minimization: Standard least-squares fitting * - Maximum likelihood: Poisson statistics (better for low counts) * *

Example COMMANDS block: * @code * COMMANDS * SET PRINT 1 * MIGRAD * MINOS * SAVE * @endcode */ class PFitter { public: /** *

Constructor for fitting engine. * * @param runInfo Pointer to MSR handler containing fit configuration * @param runListCollection Pointer to collection of data runs to fit * @param chisq_only If true, only calculate χ² without fitting * @param yaml_out If true, generate YAML output file with fit results */ PFitter(PMsrHandler *runInfo, PRunListCollection *runListCollection, Bool_t chisq_only = false, Bool_t yaml_out = false); virtual ~PFitter(); /// Returns true if fitter initialized successfully /// @return Validity status Bool_t IsValid() { return fIsValid; } /// Returns true if only parameter scan requested (no minimization) /// @return Scan-only flag Bool_t IsScanOnly() { return fIsScanOnly; } /// Returns true if fit converged successfully /// @return Convergence status Bool_t HasConverged() { return fConverged; } /** *

Executes the complete fitting procedure. * *

Processes all commands from the COMMANDS block sequentially, * performs the fit, calculates errors, and prepares output statistics. * * @return true if fit completed successfully, false on error */ Bool_t DoFit(); private: // State flags Bool_t fIsValid; ///< Overall validity flag: true if fitter initialized successfully Bool_t fIsScanOnly; ///< Scan mode flag: true if only parameter scans requested (no minimization) Bool_t fConverged; ///< Convergence flag: true if fit converged to a valid minimum Bool_t fChisqOnly; ///< Evaluation-only flag: true to calculate χ² without fitting Bool_t fYamlOut; ///< Output flag: true to generate YAML output file (MINUIT2.OUTPUT → yaml) Bool_t fUseChi2; ///< Fit mode: true = χ² minimization, false = log-max-likelihood UInt_t fPrintLevel; ///< Verbosity level: 0=quiet, 1=normal, 2=verbose (Minuit output) UInt_t fStrategy; ///< Minuit2 strategy: 0=fast/low-accuracy, 1=default, 2=careful/high-accuracy // Core data structures PMsrHandler *fRunInfo; ///< Pointer to MSR file handler (parameters, theory, commands) PRunListCollection *fRunListCollection; ///< Pointer to preprocessed run data collection PMsrParamList fParams; ///< Copy of parameter list from MSR file PMsrLines fCmdLines; ///< Raw command lines from MSR COMMANDS block PIntPairVector fCmdList; ///< Parsed commands: first=command ID, second=line number std::unique_ptr fFitterFcn; ///< Objective function for Minuit2 minimization ROOT::Minuit2::MnUserParameters fMnUserParams; ///< Minuit2 parameter state (values, errors, limits) std::unique_ptr fFcnMin; ///< Minuit2 function minimum result // Scan and contour analysis Bool_t fScanAll; ///< Multi-parameter scan flag: false=1D scan, true=2D scan (not fully implemented) UInt_t fScanParameter[2]; ///< Parameter indices: [0]=primary scan/contour, [1]=secondary (contours only) UInt_t fScanNoPoints; ///< Number of scan/contour evaluation points (default=41) Double_t fScanLow; ///< Scan lower bound: 0.0 = auto (2σ below current value) Double_t fScanHigh; ///< Scan upper bound: 0.0 = auto (2σ above current value) PDoublePairVector fScanData; ///< Scan results: (parameter_value, χ²) pairs PDoublePairVector fOriginalFitRange; ///< Original fit ranges per run (saved for FIT_RANGE command) PStringVector fElapsedTime; ///< Timing information for each fit command // Sector χ² analysis Bool_t fSectorFlag; ///< SECTOR command present flag std::vector fSector; ///< Sector analysis results (χ² vs. time windows) std::vector fPhase; ///< Phase parameter flags: true if parameter is a phase angle //---------------------------------------------------------------------- // Phase parameter identification (private helpers) //---------------------------------------------------------------------- /** * @brief Identifies which parameters represent phase angles. * * Scans the THEORY block to detect parameters used as phases in * standard functions (TFieldCos, bessel, etc.). Phase parameters * are constrained to [-360°, +360°] during fitting. */ void GetPhaseParams(); /** * @brief Extracts parameter numbers from a FUNCTIONS block entry. * * Parses "funX" references in theory lines to find all parameters * used in the function definition. * * @param funStr Function identifier string (e.g., "fun1", "fun23") * @return Vector of parameter numbers (1-indexed) used in the function */ PIntVector GetParFromFun(const TString funStr); /** * @brief Extracts parameter numbers from a map reference. * * Parses "mapX" references to find mapped parameters across all runs. * Maps allow different runs to use different parameters for the same * theoretical component. * * @param mapStr Map identifier string (e.g., "map1", "map5") * @return Vector of parameter numbers (1-indexed) referenced by the map */ PIntVector GetParFromMap(const TString mapStr); //---------------------------------------------------------------------- // Command validation and execution (private methods) //---------------------------------------------------------------------- /** * @brief Validates COMMANDS block syntax and builds execution queue. * * Parses all command lines, checks for syntax errors, extracts parameters, * and populates fCmdList for sequential execution. * * @return true if all commands are valid, false on syntax errors */ Bool_t CheckCommands(); /** * @brief Transfers MSR parameters to Minuit2 parameter state. * * Initializes fMnUserParams with values, errors, and bounds from the * MSR file's PARAMETERS block. * * @return true if parameters set successfully */ Bool_t SetParameters(); /** * @brief Executes CONTOURS command (2D error contours). * * Calculates confidence regions in 2D parameter space by evaluating * χ² on a grid around the minimum. * * @return true if contour calculation succeeded */ Bool_t ExecuteContours(); /** * @brief Executes FIT_RANGE command (optimal time-window search). * * Scans fit quality vs. fit start time to find the optimal first-good-bin. * Useful for determining when background subtraction is adequate. * * @param lineNo Command line number in MSR file * @return true if range scan succeeded */ Bool_t ExecuteFitRange(UInt_t lineNo); /** * @brief Executes FIX command (freeze parameters). * * Prevents specified parameters from varying during subsequent minimization. * * @param lineNo Command line number in MSR file * @return true if parameters fixed successfully */ Bool_t ExecuteFix(UInt_t lineNo); /** * @brief Executes HESSE command (calculate error matrix). * * Computes the covariance matrix by evaluating second derivatives at * the current minimum. Provides symmetric (parabolic) parameter errors. * * @return true if Hessian calculation succeeded */ Bool_t ExecuteHesse(); /** * @brief Executes MIGRAD command (gradient descent minimization). * * Runs Minuit2's MIGRAD algorithm, the recommended robust minimizer * using first derivatives and approximate Hessian updates. * * @return true if MIGRAD converged to a valid minimum */ Bool_t ExecuteMigrad(); /** * @brief Executes MINIMIZE command (automatic algorithm selection). * * Lets Minuit2 choose the best minimization strategy. Usually equivalent * to MIGRAD for well-behaved problems. * * @return true if minimization converged */ Bool_t ExecuteMinimize(); /** * @brief Executes MINOS command (asymmetric error analysis). * * Computes accurate asymmetric confidence intervals by scanning χ² * along each parameter axis. Slower but more accurate than HESSE. * * @return true if MINOS analysis completed */ Bool_t ExecuteMinos(); /** * @brief Executes PLOT command (visualize scan/contour results). * * Displays scan or contour data from previous SCAN/CONTOURS commands. * * @return true if plot generated successfully */ Bool_t ExecutePlot(); /** * @brief Executes PRINT command (set verbosity level). * * Controls Minuit2 output detail: 0=minimal, 1=normal, 2=debug. * * @param lineNo Command line number in MSR file * @return true if print level set successfully */ Bool_t ExecutePrintLevel(UInt_t lineNo); /** * @brief Executes RELEASE command (unfreeze parameters). * * Allows previously fixed parameters to vary in subsequent fits. * * @param lineNo Command line number in MSR file * @return true if parameters released successfully */ Bool_t ExecuteRelease(UInt_t lineNo); /** * @brief Executes RESTORE command (reload saved parameters). * * Restores parameter values from the last SAVE command. * * @return true if parameters restored successfully */ Bool_t ExecuteRestore(); /** * @brief Executes SCAN command (1D parameter space scan). * * Evaluates χ² along one or two parameter axes to visualize the * objective function landscape near the minimum. * * @return true if scan completed */ Bool_t ExecuteScan(); /** * @brief Executes SAVE command (store current parameters). * * Saves current parameter state for later RESTORE. Updates MSR file * statistics on first save (after final fit). * * @param first True if this is the first SAVE command in the session * @return true if parameters saved successfully */ Bool_t ExecuteSave(Bool_t first); /** * @brief Executes SIMPLEX command (non-gradient minimization). * * Runs the Nelder-Mead simplex algorithm. Robust for rough objective * functions but slow to converge. Often used before MIGRAD for difficult fits. * * @return true if SIMPLEX found a minimum */ Bool_t ExecuteSimplex(); /** * @brief Prepares sector χ² analysis data structures. * * Initializes sector time windows and allocates storage for sector results. * * @param param Current parameter values * @param error Current parameter errors */ void PrepareSector(PDoubleVector ¶m, PDoubleVector &error); /** * @brief Executes SECTOR command (time-dependent χ² analysis). * * Calculates χ² for progressively wider time windows to identify * optimal fit ranges and systematic time-dependent effects. * * @param fout Output stream for sector analysis results * @return true if sector analysis completed */ Bool_t ExecuteSector(std::ofstream &fout); //---------------------------------------------------------------------- // Utility functions (private) //---------------------------------------------------------------------- /** * @brief Returns current time in milliseconds. * * Used for timing fit commands and generating performance statistics. * * @return Timestamp in milliseconds since epoch */ Double_t MilliTime(); /** * @brief Rounds parameters for output with appropriate precision. * * Determines significant figures based on errors and formats parameters * for display in MSR file output. * * @param par Parameter values * @param err Parameter errors * @param ok Output flag: false if rounding failed * @return Rounded parameter values */ PDoubleVector ParamRound(const PDoubleVector &par, const PDoubleVector &err, Bool_t &ok); }; #endif // _PFITTER_H_