diff --git a/src/classes/PMsr2Data.cpp b/src/classes/PMsr2Data.cpp index db5973f77..4bfa5d8cc 100644 --- a/src/classes/PMsr2Data.cpp +++ b/src/classes/PMsr2Data.cpp @@ -49,11 +49,26 @@ using namespace boost::algorithm; #include "PMsr2Data.h" +//------------------------------------------------------------- +// Constructor //------------------------------------------------------------- /** - *

Constructor + * \brief Constructor that initializes the msr2data handler. * - * \param ext extension/suffix of the msr-files to be processed + * Initializes all member variables and prepares the object for processing. + * Sets default values: + * - Run number digits: 4 (typical for standard run numbering) + * - Global/specific parameter counts: 0 + * - Header written flag: false + * - Run list file flag: false + * + * All handler pointers (SAX parser, startup handler, data handler, msr handler) + * are initialized to nullptr and will be created as needed during processing. + * + * \param ext File extension for data files (e.g., ".bin", ".root", ".mdu") + * This extension is used to locate corresponding data files for each run + * + * \note The extension should include the leading dot if required */ PMsr2Data::PMsr2Data(const std::string &ext) : fFileExtension(ext), fRunListFile(false), fNumGlobalParam(0), fNumSpecParam(0), fNumTempRunBlocks(0), fRunNumberDigits(4), fHeaderWritten(false) { @@ -65,9 +80,15 @@ PMsr2Data::PMsr2Data(const std::string &ext) : fFileExtension(ext), fRunListFile fMsrHandler = nullptr; } +//------------------------------------------------------------- +// Destructor //------------------------------------------------------------- /** - *

Destructor + * \brief Destructor that cleans up resources. + * + * Clears all vectors and resets iterators. The unique_ptr members + * (fRunListFileStream, fSaxParser, fStartupHandler, fDataHandler, fMsrHandler) + * are automatically cleaned up through their destructors. */ PMsr2Data::~PMsr2Data() { @@ -76,21 +97,36 @@ PMsr2Data::~PMsr2Data() fIndVar.clear(); } +//------------------------------------------------------------- +// DetermineRunNumberDigits //------------------------------------------------------------- /** - *

Determines the number of digits used for the run number in the data file name from the first msr-file that is processed - * If the specified run number is the first one of the list of runs and it cannot be opened, then the rest of the given runs is checked - * until an existing msr-file is found + * \brief Determines the number of digits used for run number formatting. * - *

return: - * - 0 if the number has been determined and set successfully - * - -1 in case the msr-file cannot be read - * - -2 if the msr-file-number does not match the data-file-number - * - -3 if the msr-file does not contain a RUN block + * Analyzes the first processable msr-file to determine how many digits are + * used for run number formatting in data file names. This ensures consistent + * zero-padding when generating new msr-files from templates. * - * \param runNo run number of an msr-file - * \param normalMode false for global mode + * The algorithm: + * 1. Attempts to open the msr-file for the specified run number + * 2. If in global mode and file not found, tries the "+global" variant + * 3. If first run fails, iterates through the run list to find an existing file + * 4. Searches the RUN block for the run number in the data file path + * 5. Counts leading zeros to determine the digit width * + * Example: If the data file is "run_0042.bin", this determines 4 digits. + * + * \param runNo Run number to analyze + * \param normalMode true for normal mode, false for global fitting mode + * + * \return + * - 0 if the number of digits was successfully determined + * - -1 if no msr-file could be opened + * - -2 if msr-file run number doesn't match data file run number + * - -3 if the msr-file contains no RUN block + * + * \note The determined digit count is stored in fRunNumberDigits + * \note In global mode, also checks for files with "+global" suffix */ int PMsr2Data::DetermineRunNumberDigits(unsigned int runNo, bool normalMode) const { @@ -177,13 +213,27 @@ int PMsr2Data::DetermineRunNumberDigits(unsigned int runNo, bool normalMode) con return -3; } +//------------------------------------------------------------- +// CheckRunNumbersInRange //------------------------------------------------------------- /** - *

Checks if all given run numbers are in the range covered by the number of digits used in the data file name + * \brief Validates that all run numbers fit within the determined digit width. * - *

return: - * - 0 if everything is fine - * - -1 if a given run number is too big + * Checks if all run numbers in the run vector can be represented with the + * number of digits determined from the data file naming convention. This + * prevents formatting errors when generating file names. + * + * The check has been loosened since 2023 to accommodate LEM run numbers + * exceeding 9999 by allowing one extra digit beyond the determined width. + * + * Maximum allowed run number = 10^(fRunNumberDigits+1) - 1 + * + * \return + * - 0 if all run numbers are within the acceptable range + * - -1 if any run number exceeds the maximum + * + * \note Since 2023, uses fRunNumberDigits+1 instead of fRunNumberDigits + * to handle larger run numbers at facilities like LEM */ int PMsr2Data::CheckRunNumbersInRange() const { @@ -201,13 +251,18 @@ int PMsr2Data::CheckRunNumbersInRange() const return 0; } +//------------------------------------------------------------- +// GetPresentRun //------------------------------------------------------------- /** - *

Determines the current run number + * \brief Returns the current run number being processed. * - *

return: - * - current run number - * - 0 if all runs have been processed already + * Retrieves the run number pointed to by the internal iterator. + * Used to track progress through the run list during processing. + * + * \return + * - Current run number if processing is ongoing + * - 0 if all runs have been processed (iterator at end) */ unsigned int PMsr2Data::GetPresentRun() const { @@ -217,15 +272,20 @@ unsigned int PMsr2Data::GetPresentRun() const return 0; } +//------------------------------------------------------------- +// SetRunNumbers (single run) //------------------------------------------------------------- /** - *

Initialization of the internal list of runs using a single run number + * \brief Sets a single run number for processing. * - *

return: + * Clears any existing run list and initializes with a single run number. + * The internal iterator is reset to point to the beginning. + * + * \param runNo Run number to process (must be >= 1) + * + * \return * - 0 if the run number is valid - * - 1 otherwise - * - * \param runNo run number + * - 1 if the run number is invalid (< 1) */ int PMsr2Data::SetRunNumbers(unsigned int runNo) { @@ -239,16 +299,24 @@ int PMsr2Data::SetRunNumbers(unsigned int runNo) return 0; } +//------------------------------------------------------------- +// SetRunNumbers (range) //------------------------------------------------------------- /** - *

Initialization of the internal list of runs using first and last run numbers + * \brief Sets a range of run numbers for processing. * - *

return: - * - 0 if the run numbers are valid - * - 1 otherwise + * Clears any existing run list and populates it with all run numbers + * from runNoStart to runNoEnd (inclusive). Handles both ascending + * and descending ranges automatically. * - * \param runNoStart first run number - * \param runNoEnd last run number + * \param runNoStart First run number in the range (must be >= 1) + * \param runNoEnd Last run number in the range (must be >= 1) + * + * \return + * - 0 if both run numbers are valid + * - 1 if either run number is invalid (< 1) + * + * \note If runNoStart > runNoEnd, the range is generated in descending order */ int PMsr2Data::SetRunNumbers(unsigned int runNoStart, unsigned int runNoEnd) { @@ -268,16 +336,21 @@ int PMsr2Data::SetRunNumbers(unsigned int runNoStart, unsigned int runNoEnd) return 0; } +//------------------------------------------------------------- +// SetRunNumbers (explicit vector) //------------------------------------------------------------- /** - *

Initialization of the internal list of runs using explicitly specified run numbers + * \brief Sets run numbers from an explicit vector. * - *

return: + * Clears any existing run list and copies the provided vector of run numbers. + * All run numbers in the vector must be valid (>= 1). + * + * \param runListVector Vector containing run numbers to process + * + * \return * - -1 if the vector is empty * - 0 if all run numbers are valid - * - 1 otherwise - * - * \param runListVector vector containing the run numbers to be processed + * - 1 if any run number is invalid (< 1) */ int PMsr2Data::SetRunNumbers(const std::vector &runListVector) { @@ -295,16 +368,34 @@ int PMsr2Data::SetRunNumbers(const std::vector &runListVector) return 0; } +//------------------------------------------------------------- +// SetRunNumbers (from file) //------------------------------------------------------------- /** - *

Initialization of the internal list of runs using a run list file + * \brief Sets run numbers from a run list file. * - *

return: + * Reads run numbers from a text file with the following format: + * - First line: "RUN" followed by optional independent variable names + * - Subsequent lines: run number followed by corresponding variable values + * - Comments start with '#' and are ignored + * - Empty lines are skipped + * + * Example run list file: + * \verbatim + * RUN FIELD TEMP + * 1234 0.5 295.0 + * 1235 1.0 295.0 # This is a comment + * 1236 1.5 295.0 + * \endverbatim + * + * \param runListFile Path to run list file + * + * \return * - -1 if the run list file cannot be opened * - 0 if all run numbers are valid - * - 1 otherwise + * - 1 if any run number is invalid (< 1) or file format is incorrect * - * \param runListFile name of run list file + * \note Sets fRunListFile flag to true and opens stream for reading variables */ int PMsr2Data::SetRunNumbers(const std::string &runListFile) { @@ -366,13 +457,27 @@ int PMsr2Data::SetRunNumbers(const std::string &runListFile) return 0; } +//------------------------------------------------------------- +// ParseXmlStartupFile //------------------------------------------------------------- /** - *

Parse the musrfit startup xml file + * \brief Parses the musrfit XML startup file for configuration. * - *

return: - * - 0 if everything went fine - * - return value of the parseXmlFile function otherwise + * Creates a SAX parser and startup handler to read the musrfit_startup.xml + * configuration file. This file contains paths, templates, and other settings + * needed for msr2data operation. + * + * The parseXmlFile function is used instead of ParseFile to avoid + * environment-specific issues encountered with direct parsing. + * + * \return + * - 0 if parsing succeeded + * - Non-zero error code from parseXmlFile if parsing failed + * + * \note Outputs a warning to stderr if parsing fails + * + * \see PStartupHandler for XML configuration details + * \see parseXmlFile for the parsing implementation */ int PMsr2Data::ParseXmlStartupFile() { @@ -392,15 +497,22 @@ int PMsr2Data::ParseXmlStartupFile() return status; } +//------------------------------------------------------------- +// ReadMsrFile //------------------------------------------------------------- /** - *

Read in a msr-file into the default structure + * \brief Reads and parses an msr-file. * - *

return: - * - PMUSR_SUCCESS if everything is OK - * - return value of the ReadMsrFile-method otherwise + * Creates a new PMsrHandler and uses it to read and parse the specified + * msr-file into the internal data structure. * - * \param infile name of the msr-file to be read + * \param infile Path to the msr-file to read + * + * \return + * - PMUSR_SUCCESS if reading and parsing succeeded + * - Error code from PMsrHandler::ReadMsrFile otherwise + * + * \see PMsrHandler::ReadMsrFile for parsing details */ int PMsr2Data::ReadMsrFile(const std::string &infile) const { @@ -423,14 +535,23 @@ int PMsr2Data::ReadMsrFile(const std::string &infile) const return status; } +//------------------------------------------------------------- +// GetSingleRunMsrFile //------------------------------------------------------------- /** - *

Read in the single run msr-file corresponding to the position in the run-vector - * into a secondary msr-handler different from the class member + * \brief Retrieves msr-file handler for a single-run fit file. * - *

return: - * - pointer to the secondary msr-handler or 0 in case of an error + * Reads the "-OneRunFit" variant of the msr-file for the current run. + * This is used when extracting individual run results from global fits. * + * The file name format: "-OneRunFit.msr" + * + * \return + * - Pointer to newly created PMsrHandler on success + * - nullptr if file cannot be read or parsed + * + * \note Caller is responsible for deleting the returned handler + * \note Different from the class member fMsrHandler */ PMsrHandler* PMsr2Data::GetSingleRunMsrFile() const { @@ -457,13 +578,23 @@ PMsrHandler* PMsr2Data::GetSingleRunMsrFile() const return singleRunMsrFile; } +//------------------------------------------------------------- +// ReadRunDataFile //------------------------------------------------------------- /** - *

Read in a run data-file + * \brief Reads the run data file for the current run. * - *

return: - * - 0 if everything is OK - * - 1 otherwise + * Creates a PRunDataHandler and reads the experimental data file + * associated with the current msr-file. Uses data paths from the + * startup handler if available, otherwise uses defaults. + * + * \return + * - 0 if all data was successfully read + * - 1 if some data files could not be read (with warning) + * + * \note Outputs a warning to stderr if data is unavailable but continues processing + * + * \see PRunDataHandler for data file reading details */ int PMsr2Data::ReadRunDataFile() { @@ -2457,13 +2588,23 @@ int PMsr2Data::WriteOutput(const std::string &outfile, const std::vectorWrite formatted output to column-formatted ASCII output file + * \brief Writes a formatted numeric value to output stream. * - * \param outFile output file stream to the ASCII file - * \param value number to be written to the ASCII file - * \param width column width of the ASCII file + * Formats the value for column-aligned ASCII output with automatic + * selection of scientific notation for very large or very small numbers. + * + * Formatting rules: + * - Scientific notation if |value| >= 1e6 or (|value| < 1e-4 and value != 0) + * - Fixed-point notation otherwise + * - Left-aligned in field of specified width + * + * \param outFile Output file stream + * \param value Numeric value to write + * \param width Column width for formatting */ void PMsr2Data::WriteValue(std::fstream &outFile, const double &value, const unsigned int &width) const { @@ -2474,16 +2615,32 @@ void PMsr2Data::WriteValue(std::fstream &outFile, const double &value, const uns outFile << std::setw(width) << std::left << value; } +//------------------------------------------------------------- +// WriteValue (value with error) //------------------------------------------------------------- /** - *

Write a value to the outFile stream. The string length is determined on its error. - * E.g. 17.0023 +- 0.0018, or 73212.081 +- 0.033, etc. + * \brief Writes a value with error-based precision formatting. * - * \param outFile output stream object - * \param value to be written to stream outFile - * \param errValue error of the value. needed to determine the needed accuracy - * \param width field width for outFile for formatted output - * \param db true for db-file output, false for dat-file output. Needed to have at least on space between numbers for dat-file output + * Formats output with precision determined by the error value, ensuring + * significant digits are preserved appropriately. The precision is calculated + * based on the first significant digit of the error. + * + * Examples: + * - value=17.0023 ± errValue=0.0018 → formatted with 4 decimal places + * - value=73212.081 ± errValue=0.033 → formatted with 2 decimal places + * + * Formatting rules: + * - Precision based on error's first significant digit + * - Scientific notation if |value| >= 1e6 or (|value| < 1e-4 and value != 0) + * - Extra space added after value in ASCII mode for readability + * + * \param outFile Output file stream + * \param value Numeric value to write + * \param errValue Error/uncertainty value (determines precision) + * \param width Field width for formatted output + * \param db true for DB format, false for ASCII format (adds extra space) + * + * \see GetFirstSignificantDigit for precision calculation */ void PMsr2Data::WriteValue(std::fstream &outFile, const double &value, const double &errValue, const unsigned int &width, const bool &db) const { @@ -2509,14 +2666,28 @@ void PMsr2Data::WriteValue(std::fstream &outFile, const double &value, const dou } } +//------------------------------------------------------------- +// GetFirstSignificantDigit //------------------------------------------------------------- /** - *

Determines the first significant digit of the provided number value. - * E.g. for value=2.03 it will return 1, for value=0.00023 it will return 4, etc. + * \brief Determines the position of the first significant digit. * - * \param value for which the first significant digit needs to be determined. + * Calculates how many decimal places are needed to reach the first + * significant digit by repeatedly multiplying by 10 until the value + * is >= 1.0. This is used for precision control in output formatting. * - * \return first significant digit of the provided number value + * Examples: + * - value = 2.03 → returns 1 (first significant digit in tenths place) + * - value = 0.00023 → returns 4 (first significant digit in ten-thousandths) + * - value = 0.5 → returns 1 + * + * \param value Value to analyze (typically an error/uncertainty) + * + * \return + * - Position of first significant digit (1-19) + * - 6 if no significant digit found after 20 iterations (default precision) + * + * \note Maximum 20 iterations to prevent infinite loops */ int PMsr2Data::GetFirstSignificantDigit(const double &value) const { @@ -2538,15 +2709,26 @@ int PMsr2Data::GetFirstSignificantDigit(const double &value) const return prec+1; } +//------------------------------------------------------------- +// InParameterList //------------------------------------------------------------- /** - *

Checks paramValue is found in the paramList. If paramList - * is empty, ALL paramValues will be accepted, i.e. return true. + * \brief Checks if a parameter index should be included in output. * - * \param paramValue paramValue to be checked - * \param paramList parameter list + * Determines whether a given parameter should be written to the output + * file based on the user-specified parameter list. If the parameter list + * is empty, all parameters are included by default. * - * \return true if the paramValue if found in paramList, or true if paramList is empty. + * \param paramValue Zero-based parameter index to check + * \param paramList Vector of one-based parameter numbers to output + * (empty vector means output all parameters) + * + * \return + * - true if paramValue should be included in output + * - true if paramList is empty (output all parameters) + * - false if paramValue is not in the list + * + * \note paramValue is zero-based while paramList contains one-based indices */ bool PMsr2Data::InParameterList(const unsigned int ¶mValue, const std::vector ¶mList) const { diff --git a/src/include/PMsr2Data.h b/src/include/PMsr2Data.h index ec41b8f28..21efbc8ae 100644 --- a/src/include/PMsr2Data.h +++ b/src/include/PMsr2Data.h @@ -45,57 +45,273 @@ //------------------------------------------------------------- /** - *

Class providing the necessary utilities for msr2data: - * generate new msr-files from a template, collect fit parameters from msr-files and write them to DB or plain ASCII files + * \brief Utility class for msr2data: template-based msr-file generation and parameter extraction. + * + * PMsr2Data provides comprehensive functionality for the msr2data tool, which is used to: + * - Generate new msr-files from templates by substituting run numbers + * - Extract fit parameters from analyzed msr-files + * - Write collected parameters to database (DB) or plain ASCII files + * - Support both single-run and global (multi-run) fitting workflows + * + * Key Features: + * - Template-based msr-file generation with automatic run number substitution + * - Flexible run number specification (single, range, list file, explicit list) + * - Parameter extraction from fitted msr-files + * - Multiple output formats (DB format, ASCII tables) + * - Global fitting support for combined multi-run analysis + * - XML-based configuration via startup files + * + * Implementation Note: + * This class uses std::string and standard C++ string handling exclusively + * (rather than ROOT's TString) to demonstrate modern C++ practices, though + * this occasionally requires conversions when interfacing with PMusr classes. + * + * Typical Workflow: + * 1. Create PMsr2Data object with file extension + * 2. Parse XML startup file for configuration + * 3. Set run numbers (single, range, or list) + * 4. Generate msr-files from template or extract parameters from fitted files + * 5. Write output to DB or ASCII format + * + * \see PStartupHandler for XML configuration parsing + * \see PRunDataHandler for run data management + * \see PMsrHandler for msr-file parsing and manipulation */ class PMsr2Data { public: - PMsr2Data(const std::string&); // File extension + //----------------------------------------------------------------------- + /** + * \brief Constructor that initializes the msr2data handler. + * + * \param fileExtension File extension for data files (e.g., "bin", "root", "mdu") + */ + PMsr2Data(const std::string& fileExtension); + + //----------------------------------------------------------------------- + /** + * \brief Destructor that cleans up resources. + */ ~PMsr2Data(); - int SetRunNumbers(unsigned int); // single run given - int SetRunNumbers(unsigned int, unsigned int); // run list specified through first and last run number - int SetRunNumbers(const std::string&); // run list file given - int SetRunNumbers(const std::vector&); // explicit run list specified using [ ] + //----------------------------------------------------------------------- + /** + * \brief Sets a single run number for processing. + * + * \param runNumber Single run number to process + * \return 0 on success, non-zero on error + */ + int SetRunNumbers(unsigned int runNumber); + + //----------------------------------------------------------------------- + /** + * \brief Sets a range of run numbers (from first to last, inclusive). + * + * \param firstRun First run number in the range + * \param lastRun Last run number in the range + * \return 0 on success, non-zero on error + */ + int SetRunNumbers(unsigned int firstRun, unsigned int lastRun); + + //----------------------------------------------------------------------- + /** + * \brief Sets run numbers from a run list file. + * + * Reads run numbers from a text file, one run number per line. + * + * \param runListFileName Path to file containing run numbers + * \return 0 on success, non-zero on error + */ + int SetRunNumbers(const std::string& runListFileName); + + //----------------------------------------------------------------------- + /** + * \brief Sets run numbers from an explicit vector. + * + * \param runVector Vector of run numbers to process + * \return 0 on success, non-zero on error + */ + int SetRunNumbers(const std::vector& runVector); + + //----------------------------------------------------------------------- + /** + * \brief Gets the current run number being processed. + * + * \return Current run number from the internal iterator + */ unsigned int GetPresentRun() const; - int DetermineRunNumberDigits(unsigned int, bool) const; + //----------------------------------------------------------------------- + /** + * \brief Determines the number of digits needed for run number formatting. + * + * Analyzes run numbers to determine zero-padding requirements for + * consistent file naming. + * + * \param maxRunNumber Maximum run number to consider + * \param templateFile Whether processing a template file + * \return Number of digits needed for run number formatting + */ + int DetermineRunNumberDigits(unsigned int maxRunNumber, bool templateFile) const; + + //----------------------------------------------------------------------- + /** + * \brief Validates that all run numbers are within acceptable ranges. + * + * \return 0 if all run numbers are valid, non-zero otherwise + */ int CheckRunNumbersInRange() const; + //----------------------------------------------------------------------- + /** + * \brief Parses the XML startup file for configuration. + * + * Reads and processes the msr2data XML startup file containing + * paths, templates, and other configuration settings. + * + * \return 0 on success, non-zero on parsing errors + */ int ParseXmlStartupFile(); - int ReadMsrFile(const std::string&) const; + + //----------------------------------------------------------------------- + /** + * \brief Reads and parses an msr-file. + * + * \param msrFileName Path to the msr-file to read + * \return 0 on success, non-zero on read/parse errors + */ + int ReadMsrFile(const std::string& msrFileName) const; + + //----------------------------------------------------------------------- + /** + * \brief Reads the run data file for the current run. + * + * \return 0 on success, non-zero on read errors + */ int ReadRunDataFile(); - bool PrepareNewInputFile(unsigned int, bool) const; // template - bool PrepareGlobalInputFile(unsigned int, const std::string&, unsigned int) const; // generate msr-input file for a global fit + //----------------------------------------------------------------------- + /** + * \brief Generates a new msr-file from a template. + * + * Creates an msr-file by substituting run number placeholders in the + * template with actual run numbers. + * + * \param templateNumber Template identifier number + * \param sorted Whether to generate sorted output + * \return true on success, false on failure + */ + bool PrepareNewInputFile(unsigned int templateNumber, bool sorted) const; - int WriteOutput(const std::string&, const std::vector&, bool, unsigned int, bool global = false, unsigned int counter = 0) const; + //----------------------------------------------------------------------- + /** + * \brief Generates an msr-file for global (multi-run) fitting. + * + * Creates a combined msr-file for global fits across multiple runs. + * + * \param templateNumber Template identifier number + * \param globalOutputFile Path to output global msr-file + * \param runListSize Number of runs in the global fit + * \return true on success, false on failure + */ + bool PrepareGlobalInputFile(unsigned int templateNumber, const std::string& globalOutputFile, unsigned int runListSize) const; + + //----------------------------------------------------------------------- + /** + * \brief Writes extracted parameters to output file. + * + * Outputs fit parameters in either DB format or ASCII table format. + * + * \param outputFileName Output file path + * \param parameters Vector of parameter indices to output + * \param dbFormat Whether to use DB format (true) or ASCII (false) + * \param precision Number of significant digits for output + * \param global Whether this is global fit output + * \param counter Counter for global fit indexing + * \return 0 on success, non-zero on write errors + */ + int WriteOutput(const std::string& outputFileName, const std::vector& parameters, bool dbFormat, unsigned int precision, bool global = false, unsigned int counter = 0) const; private: - bool PrepareNewSortedInputFile(unsigned int) const; // template + //----------------------------------------------------------------------- + /** + * \brief Generates a sorted msr-file from a template. + * + * Internal helper for creating sorted msr-files with proper histogram ordering. + * + * \param templateNumber Template identifier number + * \return true on success, false on failure + */ + bool PrepareNewSortedInputFile(unsigned int templateNumber) const; + + //----------------------------------------------------------------------- + /** + * \brief Retrieves msr-file handler for a single run. + * + * \return Pointer to PMsrHandler for the current run + */ PMsrHandler* GetSingleRunMsrFile() const; + //----------------------------------------------------------------------- + /** + * \brief Writes a single numeric value to output stream. + * + * \param outFile Output file stream + * \param value Value to write + * \param width Field width for formatting + */ void WriteValue(std::fstream &outFile, const double &value, const unsigned int &width) const; - void WriteValue(std::fstream &outFile, const double &value, const double &errValue, const unsigned int &width, const bool &db) const; - int GetFirstSignificantDigit(const double &value) const; - bool InParameterList(const unsigned int ¶mValue, const std::vector&) const; - std::string fFileExtension; - std::vector fRunVector; - mutable std::vector::const_iterator fRunVectorIter; - bool fRunListFile; - std::vector fIndVar; - std::unique_ptr fRunListFileStream; - std::unique_ptr fSaxParser; - std::unique_ptr fStartupHandler; - mutable std::unique_ptr fDataHandler; - mutable std::unique_ptr fMsrHandler; - mutable unsigned int fNumGlobalParam; - mutable unsigned int fNumSpecParam; - mutable unsigned int fNumTempRunBlocks; - mutable unsigned int fRunNumberDigits; - mutable bool fHeaderWritten; + //----------------------------------------------------------------------- + /** + * \brief Writes a value with its error to output stream. + * + * Formats output based on DB or ASCII mode. + * + * \param outFile Output file stream + * \param value Value to write + * \param errValue Error/uncertainty value + * \param width Field width for formatting + * \param db Whether to use DB format (true) or ASCII (false) + */ + void WriteValue(std::fstream &outFile, const double &value, const double &errValue, const unsigned int &width, const bool &db) const; + + //----------------------------------------------------------------------- + /** + * \brief Determines the first significant digit position of a value. + * + * Used for intelligent formatting and precision control. + * + * \param value Value to analyze + * \return Position of first significant digit + */ + int GetFirstSignificantDigit(const double &value) const; + + //----------------------------------------------------------------------- + /** + * \brief Checks if a parameter is in the output parameter list. + * + * \param paramValue Parameter index to check + * \param paramList List of parameters to output + * \return true if parameter should be output, false otherwise + */ + bool InParameterList(const unsigned int ¶mValue, const std::vector& paramList) const; + + std::string fFileExtension; ///< File extension for data files (e.g., "bin", "root") + std::vector fRunVector; ///< Vector of run numbers to process + mutable std::vector::const_iterator fRunVectorIter; ///< Iterator for current position in run vector + bool fRunListFile; ///< Flag indicating if run list is from a file + std::vector fIndVar; ///< Independent variables for output + std::unique_ptr fRunListFileStream; ///< Stream for reading run list file + std::unique_ptr fSaxParser; ///< XML SAX parser for startup file + std::unique_ptr fStartupHandler; ///< Handler for XML startup file configuration + mutable std::unique_ptr fDataHandler; ///< Handler for run data files + mutable std::unique_ptr fMsrHandler; ///< Handler for msr-file parsing and generation + mutable unsigned int fNumGlobalParam; ///< Number of global parameters in fit + mutable unsigned int fNumSpecParam; ///< Number of spectrum-specific parameters + mutable unsigned int fNumTempRunBlocks; ///< Number of temporary run blocks + mutable unsigned int fRunNumberDigits; ///< Number of digits for run number formatting + mutable bool fHeaderWritten; ///< Flag tracking if output header has been written };