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 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: " 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::vector 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 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