1082 lines
49 KiB
C++
1082 lines
49 KiB
C++
/***************************************************************************
|
|
|
|
PStartupHandler.cpp
|
|
|
|
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. *
|
|
***************************************************************************/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#include <TObjArray.h>
|
|
#include <TObjString.h>
|
|
#include <TColor.h>
|
|
#include <TList.h>
|
|
#include <TXMLAttr.h>
|
|
|
|
#include "PStartupHandler.h"
|
|
|
|
ClassImpQ(PStartupHandler)
|
|
|
|
//--------------------------------------------------------------------------
|
|
// This function is a replacement for the ParseFile method of TSAXParser.
|
|
// It is needed because in certain environments ParseFile does not work but ParseBuffer does.
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Replacement for TSAXParser::ParseFile() that uses buffer-based parsing.
|
|
*
|
|
* This function provides a workaround for environments where the standard
|
|
* TSAXParser::ParseFile() method fails but ParseBuffer() works correctly.
|
|
* It reads the entire XML file into memory and then parses it as a buffer.
|
|
*
|
|
* <b>Algorithm:</b>
|
|
* -# Open XML file in binary mode, positioned at end to determine size
|
|
* -# Allocate buffer for entire file content
|
|
* -# Read file into buffer
|
|
* -# Close file
|
|
* -# Call saxParser->ParseBuffer() with buffer contents
|
|
* -# Free buffer memory
|
|
*
|
|
* <b>Memory Management:</b>
|
|
* The function allocates a buffer equal to the file size, which is freed
|
|
* after parsing completes. For very large XML files, this may consume
|
|
* significant memory temporarily.
|
|
*
|
|
* \param saxParser Pointer to an initialized TSAXParser object. The parser
|
|
* should have its signal slots connected to a handler object
|
|
* (e.g., PStartupHandler) before calling this function.
|
|
* \param startup_path_name Full filesystem path to the XML file to be parsed.
|
|
*
|
|
* \return Parse status code:
|
|
* - 0: Success (file parsed without errors)
|
|
* - 1: File could not be opened or read
|
|
* - Other: XML parse error code from TSAXParser::ParseBuffer()
|
|
*
|
|
* \see PStartupHandler for the XML content handler implementation
|
|
*/
|
|
int parseXmlFile(TSAXParser *saxParser, const char *startup_path_name)
|
|
{
|
|
int status;
|
|
std::fstream xmlFile;
|
|
unsigned int xmlSize = 0;
|
|
char *xmlBuffer = nullptr;
|
|
|
|
xmlFile.open(startup_path_name, std::ios::in | std::ios::ate); // open file for reading and go to the end of the file
|
|
if (xmlFile.is_open()) { // check if file has been opened successfully
|
|
xmlSize = xmlFile.tellg(); // get the position within the stream == size of the file (since we are at the end)
|
|
xmlFile.seekg(0, std::ios::beg); // go back to the beginning of the stream
|
|
xmlBuffer = new char[xmlSize]; // allocate buffer memory for the whole XML file
|
|
xmlFile.read(xmlBuffer, xmlSize); // read in the whole XML file into the buffer
|
|
xmlFile.close(); // close the XML file
|
|
}
|
|
if (!xmlBuffer) { // file has not been read into the buffer
|
|
status = 1;
|
|
} else {
|
|
status = saxParser->ParseBuffer(xmlBuffer, xmlSize); // parse buffer
|
|
delete[] xmlBuffer; // free the buffer memory
|
|
xmlBuffer = nullptr;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Constructor that locates and optionally resets the musrfit startup configuration.
|
|
*
|
|
* Searches for the musrfit_startup.xml configuration file in standard locations
|
|
* and initializes the handler. If no file is found, creates a default configuration.
|
|
*
|
|
* <b>Search Order:</b>
|
|
* -# Current working directory: \c ./musrfit_startup.xml
|
|
* -# User config directory: \c $HOME/.musrfit/musrfit_startup.xml
|
|
* -# MUSRFITPATH environment variable: \c $MUSRFITPATH/musrfit_startup.xml
|
|
* -# ROOT installation: \c $ROOTSYS/bin/musrfit_startup.xml (with warning)
|
|
*
|
|
* <b>File Creation:</b>
|
|
* If no startup file is found in any location, a default configuration is
|
|
* automatically created at \c $HOME/.musrfit/musrfit_startup.xml. This includes:
|
|
* - Standard PSI facility data paths
|
|
* - Run name templates for all PSI instruments
|
|
* - Default Fourier transform settings
|
|
* - Standard marker and color lists
|
|
*
|
|
* <b>Reset Mode:</b>
|
|
* When reset_startup_file=true and a file is found, the existing file is
|
|
* overwritten with default content. This is useful for:
|
|
* - Restoring corrupted configurations
|
|
* - Updating to new default settings after software updates
|
|
* - Resetting user customizations to defaults
|
|
*
|
|
* \param reset_startup_file If true, overwrites existing startup file with defaults.
|
|
* If false (default), uses existing file or creates new one.
|
|
*
|
|
* \note This constructor only locates the file. Actual XML parsing must be
|
|
* performed separately by connecting this handler to a TSAXParser and
|
|
* calling parseXmlFile().
|
|
*
|
|
* \see StartupFileFound(), GetStartupFilePath(), WriteDefaultStartupFile()
|
|
*/
|
|
PStartupHandler::PStartupHandler(bool reset_startup_file)
|
|
{
|
|
fStartupFileFound = false;
|
|
fStartupFilePath = "";
|
|
|
|
// get default path (for the moment only linux like)
|
|
Char_t *pmusrpath=nullptr;
|
|
Char_t *home=nullptr;
|
|
Char_t musrpath[128];
|
|
Char_t startup_path_name[128];
|
|
|
|
strncpy(musrpath, "", sizeof(musrpath));
|
|
|
|
// check if the startup file is found in the current directory
|
|
strcpy(startup_path_name, "./musrfit_startup.xml");
|
|
if (StartupFileExists(startup_path_name)) {
|
|
fStartupFileFound = true;
|
|
fStartupFilePath = TString(startup_path_name);
|
|
}
|
|
if (!fStartupFileFound) { // startup file not found in the current directory
|
|
// check if the startup file is found under $HOME/.musrfit
|
|
home = getenv("HOME");
|
|
if (home != nullptr) {
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s/.musrfit/musrfit_startup.xml", home);
|
|
if (StartupFileExists(startup_path_name)) {
|
|
fStartupFilePath = TString(startup_path_name);
|
|
fStartupFileFound = true;
|
|
}
|
|
}
|
|
}
|
|
if (!fStartupFileFound) { // startup file not found in $HOME/.musrfit
|
|
// check if the MUSRFITPATH system variable is set
|
|
pmusrpath = getenv("MUSRFITPATH");
|
|
if (pmusrpath != nullptr) {
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s/musrfit_startup.xml", pmusrpath);
|
|
if (StartupFileExists(startup_path_name)) {
|
|
fStartupFilePath = TString(startup_path_name);
|
|
fStartupFileFound = true;
|
|
}
|
|
}
|
|
}
|
|
if (!fStartupFileFound) { // MUSRFITPATH not set or empty, will try $ROOTSYS/bin
|
|
home = getenv("ROOTSYS");
|
|
if (home != nullptr) {
|
|
snprintf(musrpath, sizeof(musrpath), "%s/bin", home);
|
|
std::cerr << std::endl << "**WARNING** MUSRFITPATH environment variable not set will try " << musrpath << std::endl;
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s/musrfit_startup.xml", musrpath);
|
|
if (StartupFileExists(startup_path_name)) {
|
|
fStartupFilePath = TString(startup_path_name);
|
|
fStartupFileFound = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// musrfit_startup.xml found. Check if it should be rewritten
|
|
if (fStartupFileFound && reset_startup_file) {
|
|
std::cout << std::endl;
|
|
std::cout << ">> Will only reset the file: '" << fStartupFilePath.Data() << "'."<< std::endl;
|
|
std::cout << std::endl;
|
|
if (!WriteDefaultStartupFile(reset_startup_file)) {
|
|
std::cerr << std::endl << "**ERROR** couldn't re-write " << fStartupFilePath.Data() << "." << std::endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if musrfit_startup.xml is still not found, will create a default one
|
|
if (!fStartupFileFound) {
|
|
std::cout << std::endl << "**INFO** no musrfit_startup.xml file found, will write a default one." << std::endl;
|
|
if (!WriteDefaultStartupFile()) {
|
|
std::cerr << std::endl << "**ERROR** couldn't write default musrfit_startup.xml." << std::endl;
|
|
} else {
|
|
home = getenv("HOME");
|
|
if (home != nullptr) {
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s/.musrfit/musrfit_startup.xml", home);
|
|
if (StartupFileExists(startup_path_name)) {
|
|
fStartupFilePath = TString(startup_path_name);
|
|
fStartupFileFound = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Destructor
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Destructor that releases all allocated configuration data.
|
|
*
|
|
* Clears all configuration vectors to free memory:
|
|
* - fDataPathList: Data file search paths
|
|
* - fMarkerList: ROOT marker style codes
|
|
* - fColorList: ROOT color codes
|
|
* - fRunNameTemplate: Instrument run name patterns
|
|
*
|
|
* \note The Fourier defaults structure is a value type and is automatically
|
|
* cleaned up when the object is destroyed.
|
|
*/
|
|
PStartupHandler::~PStartupHandler()
|
|
{
|
|
// clean up
|
|
fDataPathList.clear();
|
|
fMarkerList.clear();
|
|
fColorList.clear();
|
|
fRunNameTemplate.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnStartDocument
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked at the start of XML document parsing.
|
|
*
|
|
* Initializes all configuration variables to default values before parsing
|
|
* begins. This ensures a clean state even if the same handler is reused.
|
|
*
|
|
* <b>Initialization:</b>
|
|
* - fKey = eEmpty (no active element)
|
|
* - Fourier defaults:
|
|
* - fFourierBlockPresent = false
|
|
* - fUnits = FOURIER_UNIT_GAUSS
|
|
* - fFourierPower = 0 (no zero-padding)
|
|
* - fApodization = FOURIER_APOD_NONE
|
|
* - fPlotTag = FOURIER_PLOT_REAL_AND_IMAG
|
|
* - fRangeForPhaseCorrection = [-1.0, -1.0] (auto)
|
|
* - fPlotRange = [-1.0, -1.0] (auto)
|
|
* - fPhaseIncrement = 1.0 degree
|
|
*
|
|
* \note This is a SAX parser callback connected via TQObject signals.
|
|
* It is automatically called by TSAXParser at document start.
|
|
*/
|
|
void PStartupHandler::OnStartDocument()
|
|
{
|
|
fKey = eEmpty;
|
|
|
|
// init fourier default variables
|
|
fFourierDefaults.fFourierBlockPresent = false;
|
|
fFourierDefaults.fUnits = FOURIER_UNIT_GAUSS;
|
|
fFourierDefaults.fFourierPower = 0;
|
|
fFourierDefaults.fApodization = FOURIER_APOD_NONE;
|
|
fFourierDefaults.fPlotTag = FOURIER_PLOT_REAL_AND_IMAG;
|
|
fFourierDefaults.fRangeForPhaseCorrection[0] = -1.0;
|
|
fFourierDefaults.fRangeForPhaseCorrection[1] = -1.0;
|
|
fFourierDefaults.fPlotRange[0] = -1.0;
|
|
fFourierDefaults.fPlotRange[1] = -1.0;
|
|
fFourierDefaults.fPhaseIncrement = 1.0;
|
|
|
|
fStartupOptions.writeExpectedChisq = false; // NOT defined in the XML, but initialized for later use!!
|
|
fStartupOptions.estimateN0 = false; // NOT defined in the XML, but initialized for later use!!
|
|
fStartupOptions.useDKS = false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnEndDocument
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked at the end of XML document parsing.
|
|
*
|
|
* Finalizes configuration by calling CheckLists() to ensure all required
|
|
* settings have values. If any list is empty after parsing, it will be
|
|
* populated with default values.
|
|
*
|
|
* \note This is a SAX parser callback connected via TQObject signals.
|
|
* It is automatically called by TSAXParser when parsing completes.
|
|
*
|
|
* \see CheckLists()
|
|
*/
|
|
void PStartupHandler::OnEndDocument()
|
|
{
|
|
// check if anything was set, and if not set some default stuff
|
|
CheckLists();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnStartElement
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when an XML start element tag is encountered.
|
|
*
|
|
* Identifies the element type and sets the parsing state (fKey) accordingly.
|
|
* This state is used by OnCharacters() to determine how to process element content.
|
|
*
|
|
* <b>Recognized Elements:</b>
|
|
* - \c data_path → eDataPath (data file search directory)
|
|
* - \c run_name_template → eRunNameTemplate (with inst attribute extraction)
|
|
* - \c marker → eMarker (ROOT marker style code)
|
|
* - \c color → eColor (RGB color specification)
|
|
* - \c units → eUnits (Fourier frequency units)
|
|
* - \c fourier_power → eFourierPower (zero-padding power)
|
|
* - \c apodization → eApodization (windowing function)
|
|
* - \c plot → ePlot (Fourier plot type)
|
|
* - \c phase → ePhase (Fourier phase value)
|
|
* - \c phase_increment → ePhaseIncrement (phase adjustment step)
|
|
*
|
|
* <b>Attribute Handling:</b>
|
|
* For \c run_name_template elements, extracts the \c inst attribute value
|
|
* and stores it in fCurrentInstrumentName for use when processing the
|
|
* element content.
|
|
*
|
|
* \param str XML element name (tag name without angle brackets)
|
|
* \param attributes TList of TXMLAttr objects containing element attributes
|
|
*
|
|
* \note Unrecognized elements leave fKey unchanged (typically eEmpty),
|
|
* causing their content to be ignored.
|
|
*/
|
|
void PStartupHandler::OnStartElement(const Char_t *str, const TList *attributes)
|
|
{
|
|
if (!strcmp(str, "data_path")) {
|
|
fKey = eDataPath;
|
|
} else if (!strcmp(str, "use_dks")) {
|
|
fKey = eUseDKS;
|
|
} else if (!strcmp(str, "run_name_template")) {
|
|
fKey = eRunNameTemplate;
|
|
TXMLAttr *attr;
|
|
TIter next(attributes);
|
|
while ((attr = (TXMLAttr*) next())) {
|
|
if (!strcmp(attr->GetName(), "inst")) {
|
|
fCurrentInstrumentName = attr->GetValue();
|
|
}
|
|
}
|
|
} else if (!strcmp(str, "marker")) {
|
|
fKey = eMarker;
|
|
} else if (!strcmp(str, "color")) {
|
|
fKey = eColor;
|
|
} else if (!strcmp(str, "units")) {
|
|
fKey = eUnits;
|
|
} else if (!strcmp(str, "fourier_power")) {
|
|
fKey = eFourierPower;
|
|
} else if (!strcmp(str, "apodization")) {
|
|
fKey = eApodization;
|
|
} else if (!strcmp(str, "plot")) {
|
|
fKey = ePlot;
|
|
} else if (!strcmp(str, "phase")) {
|
|
fKey = ePhase;
|
|
} else if (!strcmp(str, "phase_increment")) {
|
|
fKey = ePhaseIncrement;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnEndElement
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when an XML end element tag is encountered.
|
|
*
|
|
* Resets the parsing state (fKey) to eEmpty, indicating that any subsequent
|
|
* character data should be ignored until the next start element is found.
|
|
*
|
|
* \param str XML element name (unused, state is always reset to eEmpty)
|
|
*
|
|
* \note The element name parameter is not used because all elements reset
|
|
* to the same state. This simplifies handling of nested elements.
|
|
*/
|
|
void PStartupHandler::OnEndElement(const Char_t *str)
|
|
{
|
|
fKey = eEmpty;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnCharacters
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked with text content between XML element tags.
|
|
*
|
|
* Processes element content based on the current parsing state (fKey) set
|
|
* by OnStartElement(). Each element type has specific parsing logic and
|
|
* validation.
|
|
*
|
|
* <b>Element Processing:</b>
|
|
*
|
|
* - <b>eDataPath:</b> Adds path string directly to fDataPathList
|
|
*
|
|
* - <b>eRunNameTemplate:</b> Creates PRunNameTemplate with current instrument
|
|
* name and template string, adds to fRunNameTemplate
|
|
*
|
|
* - <b>eMarker:</b> Validates numeric string, converts to int, adds to fMarkerList
|
|
*
|
|
* - <b>eColor:</b> Parses "R,G,B" format (comma-separated integers 0-255),
|
|
* converts to ROOT color code via TColor::GetColor(), adds to fColorList
|
|
*
|
|
* - <b>eUnits:</b> Maps string to FOURIER_UNIT_* constant:
|
|
* - "gauss" → FOURIER_UNIT_GAUSS
|
|
* - "tesla" → FOURIER_UNIT_TESLA
|
|
* - "mhz" → FOURIER_UNIT_FREQ
|
|
* - "mc/s" → FOURIER_UNIT_CYCLES
|
|
*
|
|
* - <b>eFourierPower:</b> Validates integer 0-20, sets fFourierDefaults.fFourierPower
|
|
*
|
|
* - <b>eApodization:</b> Maps string to FOURIER_APOD_* constant:
|
|
* - "none" → FOURIER_APOD_NONE
|
|
* - "weak" → FOURIER_APOD_WEAK
|
|
* - "medium" → FOURIER_APOD_MEDIUM
|
|
* - "strong" → FOURIER_APOD_STRONG
|
|
*
|
|
* - <b>ePlot:</b> Maps string to FOURIER_PLOT_* constant:
|
|
* - "real" → FOURIER_PLOT_REAL
|
|
* - "imag" → FOURIER_PLOT_IMAG
|
|
* - "real_and_imag" → FOURIER_PLOT_REAL_AND_IMAG
|
|
* - "power" → FOURIER_PLOT_POWER
|
|
* - "phase" → FOURIER_PLOT_PHASE
|
|
*
|
|
* - <b>ePhase:</b> Validates float, adds to fFourierDefaults.fPhase vector
|
|
*
|
|
* - <b>ePhaseIncrement:</b> Validates float, sets fFourierDefaults.fPhaseIncrement
|
|
*
|
|
* \param str Text content between XML tags
|
|
*
|
|
* \note Invalid values generate warning messages to stderr but do not cause
|
|
* parsing to fail. The invalid value is simply ignored.
|
|
*/
|
|
void PStartupHandler::OnCharacters(const Char_t *str)
|
|
{
|
|
TObjArray *tokens;
|
|
TObjString *ostr;
|
|
TString tstr;
|
|
Int_t color, r, g, b, ival;
|
|
|
|
PRunNameTemplate tmpl;
|
|
switch (fKey) {
|
|
case eDataPath:
|
|
// check that str is a valid path
|
|
// add str to the path list
|
|
fDataPathList.push_back(str);
|
|
break;
|
|
case eUseDKS:
|
|
tstr = TString(str);
|
|
if (tstr.BeginsWith("y") || tstr.BeginsWith("Y"))
|
|
fStartupOptions.useDKS = true;
|
|
break;
|
|
case eRunNameTemplate:
|
|
tmpl.instrument = fCurrentInstrumentName;
|
|
tmpl.runNameTemplate = str;
|
|
fRunNameTemplate.push_back(tmpl);
|
|
fCurrentInstrumentName="???";
|
|
break;
|
|
case eMarker:
|
|
// check that str is a number
|
|
tstr = TString(str);
|
|
if (tstr.IsDigit()) {
|
|
// add converted str to the marker list
|
|
fMarkerList.push_back(tstr.Atoi());
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a number, will ignore it";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
case eColor:
|
|
// check that str is a rbg code
|
|
tstr = TString(str);
|
|
tokens = tstr.Tokenize(",");
|
|
// check that there any tokens
|
|
if (!tokens) {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it";
|
|
std::cerr << std::endl;
|
|
return;
|
|
}
|
|
// check there is the right number of tokens
|
|
if (tokens->GetEntries() != 3) {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it";
|
|
std::cerr << std::endl;
|
|
return;
|
|
}
|
|
// get r
|
|
ostr = dynamic_cast<TObjString*>(tokens->At(0));
|
|
tstr = ostr->GetString();
|
|
if (tstr.IsDigit()) {
|
|
r = tstr.Atoi();
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** r within the rgb code is not a number, will ignore it";
|
|
std::cerr << std::endl;
|
|
return;
|
|
}
|
|
// get g
|
|
ostr = dynamic_cast<TObjString*>(tokens->At(1));
|
|
tstr = ostr->GetString();
|
|
if (tstr.IsDigit()) {
|
|
g = tstr.Atoi();
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** g within the rgb code is not a number, will ignore it";
|
|
std::cerr << std::endl;
|
|
return;
|
|
}
|
|
// get b
|
|
ostr = dynamic_cast<TObjString*>(tokens->At(2));
|
|
tstr = ostr->GetString();
|
|
if (tstr.IsDigit()) {
|
|
b = tstr.Atoi();
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** b within the rgb code is not a number, will ignore it";
|
|
std::cerr << std::endl;
|
|
return;
|
|
}
|
|
// clean up tokens
|
|
if (tokens) {
|
|
delete tokens;
|
|
tokens = nullptr;
|
|
}
|
|
// generate the ROOT color code based on str
|
|
color = TColor::GetColor(r,g,b);
|
|
// add the color code to the color list
|
|
fColorList.push_back(color);
|
|
break;
|
|
case eUnits:
|
|
tstr = TString(str);
|
|
if (!tstr.CompareTo("gauss", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fUnits = FOURIER_UNIT_GAUSS;
|
|
} else if (!tstr.CompareTo("tesla", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fUnits = FOURIER_UNIT_TESLA;
|
|
} else if (!tstr.CompareTo("mhz", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fUnits = FOURIER_UNIT_FREQ;
|
|
} else if (!tstr.CompareTo("mc/s", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fUnits = FOURIER_UNIT_CYCLES;
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a valid unit, will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
case eFourierPower:
|
|
tstr = TString(str);
|
|
if (tstr.IsDigit()) {
|
|
ival = tstr.Atoi();
|
|
if ((ival >= 0) && (ival <= 20)) {
|
|
fFourierDefaults.fFourierPower = ival;
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** fourier power '" << str << "' is not a valid number (0..20), will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** fourier power '" << str << "' is not a valid number (0..20), will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
case eApodization:
|
|
tstr = TString(str);
|
|
if (!tstr.CompareTo("none", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fApodization = FOURIER_APOD_NONE;
|
|
} else if (!tstr.CompareTo("weak", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fApodization = FOURIER_APOD_WEAK;
|
|
} else if (!tstr.CompareTo("medium", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fApodization = FOURIER_APOD_MEDIUM;
|
|
} else if (!tstr.CompareTo("strong", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fApodization = FOURIER_APOD_STRONG;
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a valid apodization, will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
case ePlot:
|
|
tstr = TString(str);
|
|
if (!tstr.CompareTo("real", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fPlotTag = FOURIER_PLOT_REAL;
|
|
} else if (!tstr.CompareTo("imag", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fPlotTag = FOURIER_PLOT_IMAG;
|
|
} else if (!tstr.CompareTo("real_and_imag", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fPlotTag = FOURIER_PLOT_REAL_AND_IMAG;
|
|
} else if (!tstr.CompareTo("power", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fPlotTag = FOURIER_PLOT_POWER;
|
|
} else if (!tstr.CompareTo("phase", TString::kIgnoreCase)) {
|
|
fFourierDefaults.fPlotTag = FOURIER_PLOT_PHASE;
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a valid plot option, will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
case ePhase:
|
|
tstr = TString(str);
|
|
if (tstr.IsFloat()) {
|
|
fFourierDefaults.fPhase.push_back(tstr.Atof());
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a valid phase, will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
case ePhaseIncrement:
|
|
tstr = TString(str);
|
|
if (tstr.IsFloat()) {
|
|
fFourierDefaults.fPhaseIncrement = tstr.Atof();
|
|
} else {
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** '" << str << "' is not a valid phase increment, will ignore it.";
|
|
std::cerr << std::endl;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnComment
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when an XML comment is encountered.
|
|
*
|
|
* Currently does nothing. XML comments in the startup file are ignored.
|
|
*
|
|
* \param str Comment text content (without \<!-- and --\> delimiters)
|
|
*
|
|
* \note Comments in musrfit_startup.xml are for documentation purposes only
|
|
* and have no effect on configuration.
|
|
*/
|
|
void PStartupHandler::OnComment(const Char_t *str)
|
|
{
|
|
// nothing to be done for now
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnWarning
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when the XML parser generates a warning.
|
|
*
|
|
* Outputs the warning message to stderr with a "PStartupHandler **WARNING**"
|
|
* prefix. Warnings typically indicate non-fatal issues such as:
|
|
* - Deprecated XML constructs
|
|
* - Minor schema violations
|
|
* - Character encoding issues
|
|
*
|
|
* \param str Warning message from the XML parser
|
|
*
|
|
* \note Parsing continues after warnings; they do not cause failure.
|
|
*/
|
|
void PStartupHandler::OnWarning(const Char_t *str)
|
|
{
|
|
std::cerr << std::endl << "PStartupHandler **WARNING** " << str;
|
|
std::cerr << std::endl;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnError
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when the XML parser encounters an error.
|
|
*
|
|
* Outputs the error message to stderr with a "PStartupHandler **ERROR**"
|
|
* prefix. Errors indicate significant parsing problems such as:
|
|
* - Malformed XML syntax
|
|
* - Missing required elements
|
|
* - Invalid attribute values
|
|
*
|
|
* \param str Error message from the XML parser
|
|
*
|
|
* \note Depending on error severity, parsing may or may not continue.
|
|
* The configuration may be incomplete after errors.
|
|
*/
|
|
void PStartupHandler::OnError(const Char_t *str)
|
|
{
|
|
std::cerr << std::endl << "PStartupHandler **ERROR** " << str;
|
|
std::cerr << std::endl;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnFatalError
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when the XML parser encounters a fatal error.
|
|
*
|
|
* Outputs the error message to stderr with a "PStartupHandler **FATAL ERROR**"
|
|
* prefix. Fatal errors indicate unrecoverable parsing failures such as:
|
|
* - Document not well-formed (mismatched tags)
|
|
* - Invalid XML declaration
|
|
* - Character encoding that cannot be processed
|
|
*
|
|
* \param str Fatal error message from the XML parser
|
|
*
|
|
* \warning After a fatal error, parsing stops immediately and the configuration
|
|
* will be incomplete. CheckLists() will provide default values for
|
|
* missing settings when OnEndDocument() is called.
|
|
*/
|
|
void PStartupHandler::OnFatalError(const Char_t *str)
|
|
{
|
|
std::cerr << std::endl << "PStartupHandler **FATAL ERROR** " << str;
|
|
std::cerr << std::endl;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OnCdataBlock
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief SAX callback invoked when a CDATA section is encountered.
|
|
*
|
|
* Currently does nothing. CDATA sections in the startup file are not used.
|
|
* CDATA sections would typically be used for content containing special
|
|
* characters that would otherwise need escaping.
|
|
*
|
|
* \param str CDATA content (without \<![CDATA[ and ]]\> delimiters)
|
|
* \param len Length of the CDATA content in characters
|
|
*
|
|
* \note The musrfit_startup.xml format does not require CDATA sections
|
|
* as all content uses standard XML escaping where needed.
|
|
*/
|
|
void PStartupHandler::OnCdataBlock(const Char_t *str, Int_t len)
|
|
{
|
|
// nothing to be done for now
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CheckLists
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Validates configuration lists and populates empty ones with defaults.
|
|
*
|
|
* Called at the end of XML parsing (OnEndDocument) to ensure all required
|
|
* configuration lists have values. If any list is empty after parsing,
|
|
* it is populated with sensible defaults.
|
|
*
|
|
* <b>Default Data Paths:</b>
|
|
* Standard PSI facility data directories:
|
|
* - /mnt/data/nemu/his
|
|
* - /psi.ch/group/lmu/public/data/XXX/his/, where XXX=lem, alc, dolly, flame, gpd, gps, hal, ltf, or vms
|
|
*
|
|
* <b>Default Markers:</b>
|
|
* ROOT TMarker style codes for distinguishing multiple data sets:
|
|
* - 24 (open circle), 25 (open square), 26 (open triangle)
|
|
* - 27 (open diamond), 28 (open cross), 29 (full star)
|
|
* - 30 (open star), 20 (full circle), 21 (full square)
|
|
* - 22 (full triangle), 23 (full down triangle)
|
|
* - 2 (thin cross), 3 (thin star), 5 (thin x)
|
|
*
|
|
* <b>Default Colors:</b>
|
|
* Standard plotting colors (RGB → ROOT color code):
|
|
* - Black (0,0,0), Red (255,0,0), Green (0,255,0)
|
|
* - Blue (0,0,255), Magenta (255,0,255), Cyan (0,255,255)
|
|
* - Violet (156,0,255), Yellow-ish (99,101,49)
|
|
* - Dark Green (49,101,49), Orange (156,48,0)
|
|
*
|
|
* \note This method only populates empty lists. If a list has any entries
|
|
* from the XML file, no defaults are added.
|
|
*/
|
|
void PStartupHandler::CheckLists()
|
|
{
|
|
// check if anything was set, and if not set some default stuff
|
|
|
|
// check if any data path is given
|
|
if (fDataPathList.size() == 0) {
|
|
fDataPathList.push_back(TString("/mnt/data/nemu/his"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/lem/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/alc/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/dolly/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/flame/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/gpd/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/gps/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/hal/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/ltf/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/misc/his/"));
|
|
fDataPathList.push_back(TString("/psi.ch/group/lmu/public/data/vms/his/"));
|
|
}
|
|
|
|
// check if any markers are given
|
|
if (fMarkerList.size() == 0) {
|
|
fMarkerList.push_back(24); // open circle
|
|
fMarkerList.push_back(25); // open square
|
|
fMarkerList.push_back(26); // open triangle
|
|
fMarkerList.push_back(27); // open diamond
|
|
fMarkerList.push_back(28); // open cross
|
|
fMarkerList.push_back(29); // full star
|
|
fMarkerList.push_back(30); // open star
|
|
fMarkerList.push_back(20); // full circle
|
|
fMarkerList.push_back(21); // full square
|
|
fMarkerList.push_back(22); // full triangle
|
|
fMarkerList.push_back(23); // full down triangle
|
|
fMarkerList.push_back(2); // thin cross
|
|
fMarkerList.push_back(3); // thin star
|
|
fMarkerList.push_back(5); // thin cross 45° rotated
|
|
}
|
|
|
|
// check if any colors are given
|
|
if (fColorList.size() == 0) {
|
|
fColorList.push_back(TColor::GetColor(0, 0, 0)); // kBlack
|
|
fColorList.push_back(TColor::GetColor(255, 0, 0)); // kRed
|
|
fColorList.push_back(TColor::GetColor(0, 255, 0)); // kGreen
|
|
fColorList.push_back(TColor::GetColor(0, 0, 255)); // kBlue
|
|
fColorList.push_back(TColor::GetColor(255, 0, 255)); // kMagneta
|
|
fColorList.push_back(TColor::GetColor(0, 255, 255)); // kCyan
|
|
fColorList.push_back(TColor::GetColor(156, 0, 255)); // kViolette-3
|
|
fColorList.push_back(TColor::GetColor(99, 101, 49)); // kYellow-1
|
|
fColorList.push_back(TColor::GetColor(49, 101, 49)); // kGreen-1
|
|
fColorList.push_back(TColor::GetColor(156, 48, 0)); // kOrange-4
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// StartupFileExists
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Checks if a file exists and is readable at the specified path.
|
|
*
|
|
* Attempts to open the file for reading to verify its existence and
|
|
* accessibility. The file is immediately closed after the check.
|
|
*
|
|
* \param fln Full filesystem path to the file to check
|
|
*
|
|
* \return true if file exists and can be opened for reading,
|
|
* false if file does not exist or cannot be accessed
|
|
*
|
|
* \note This method uses std::ifstream for portability across platforms.
|
|
* It only checks readability, not write permissions.
|
|
*/
|
|
Bool_t PStartupHandler::StartupFileExists(Char_t *fln)
|
|
{
|
|
Bool_t result = false;
|
|
|
|
std::ifstream ifile(fln);
|
|
|
|
if (ifile.fail()) {
|
|
result = false;
|
|
} else {
|
|
result = true;
|
|
ifile.close();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// WriteDefaultStartupFile
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief Creates or overwrites a startup configuration file with default content.
|
|
*
|
|
* Writes a complete musrfit_startup.xml file containing comprehensive default
|
|
* settings for the musrfit package. This method is called when:
|
|
* - No startup file is found in any search location
|
|
* - User requests reset of existing configuration (reset_startup_file=true)
|
|
*
|
|
* <b>File Location:</b>
|
|
* - If reset_startup_file=true: Overwrites file at fStartupFilePath
|
|
* - If reset_startup_file=false: Creates new file at $HOME/.musrfit/musrfit_startup.xml
|
|
* (creates .musrfit directory if it doesn't exist)
|
|
*
|
|
* <b>Default Content Includes:</b>
|
|
*
|
|
* <b>Data Paths:</b>
|
|
* - PSI LEM, GPS, GPD, Dolly, Flame, HIFI, LTF, ALC data directories
|
|
* - Both local mount points and NFS paths
|
|
*
|
|
* <b>Run Name Templates:</b>
|
|
* - Templates for all PSI μSR instruments (GPS, GPD, Dolly, Flame, etc.)
|
|
* - Templates for various data formats (ROOT, binary, MDU)
|
|
* - Year and run number placeholder patterns
|
|
*
|
|
* <b>Fourier Settings:</b>
|
|
* - Units: Gauss
|
|
* - Fourier power: 0 (no zero-padding)
|
|
* - Apodization: none
|
|
* - Plot type: real_and_imag
|
|
* - Phase: 0.0 degrees
|
|
* - Phase increment: 1.0 degree
|
|
*
|
|
* <b>ROOT Settings:</b>
|
|
* - Marker list: 14 distinct marker styles
|
|
* - Color list: 10 distinct colors (RGB format)
|
|
*
|
|
* \param reset_startup_file If true, overwrites existing file at fStartupFilePath.
|
|
* If false, creates new file at $HOME/.musrfit/musrfit_startup.xml.
|
|
*
|
|
* \return true if file was successfully written, false on error:
|
|
* - $HOME environment variable not set
|
|
* - Cannot create .musrfit directory
|
|
* - Cannot open file for writing
|
|
*
|
|
* \see PStartupHandler() constructor, CheckLists()
|
|
*/
|
|
Bool_t PStartupHandler::WriteDefaultStartupFile(bool reset_startup_file)
|
|
{
|
|
Char_t startup_path_name[256];
|
|
if (reset_startup_file) { // reset the found
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s", fStartupFilePath.Data());
|
|
} else { // no musrfit_startup.xml found, hence write default under $HOME/.musrfit
|
|
// get home
|
|
Char_t *home = nullptr;
|
|
home = getenv("HOME");
|
|
if (home == nullptr) {
|
|
std::cerr << std::endl << "**ERROR** couldn't obtain $HOME." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// first check that $HOME/.musrfit exists and if NOT create it
|
|
struct stat info;
|
|
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s/.musrfit", home);
|
|
if (!stat(startup_path_name, &info)) {
|
|
if (!(info.st_mode & S_IFDIR))
|
|
return false;
|
|
} else {
|
|
if (mkdir(startup_path_name, 0777)) {
|
|
std::cerr << std::endl << "**ERROR** couldn't create '" << startup_path_name << "'" << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// set path-name for musrfit_startup.xml
|
|
snprintf(startup_path_name, sizeof(startup_path_name), "%s/.musrfit/musrfit_startup.xml", home);
|
|
}
|
|
|
|
std::ofstream fout(startup_path_name, std::ofstream::out);
|
|
if (!fout.is_open()) {
|
|
std::cerr << std::endl << "**ERROR** couldn't open '" << startup_path_name << "' for writing." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// write default musrfit_startup.xml
|
|
fout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
|
|
fout << "<musrfit xmlns=\"https://lmu.pages.psi.ch/musrfit-docu/\">" << std::endl;
|
|
fout << " <comment>" << std::endl;
|
|
fout << " Defines default settings for the musrfit package" << std::endl;
|
|
fout << " </comment>" << std::endl;
|
|
fout << " <!-- the use_dks flag is only for the GPU Fourier support, not the fitting -->" << std::endl;
|
|
fout << " <use_dks>no</use_dks>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/lem/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/alc/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/dolly/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/flame/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/gpd/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/gps/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/hal/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/ltf/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/misc/his</data_path>" << std::endl;
|
|
fout << " <data_path>/psi.ch/group/lmu/public/data/vms/his</data_path>" << std::endl;
|
|
fout << " <!-- MISC/PSI 1985 - 1990 -->" << std::endl;
|
|
fout << " <run_name_template inst=\"misc\">d%yyyy%/deltat_misc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <!-- ALC TD/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"alc\">d%yyyy%/deltat_zh_chem_%rrrr%.bin</run_name_template>" << std:: endl;
|
|
fout << " <run_name_template inst=\"alc\">d%yyyy%/deltat_tdc_alc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"alc\">d%yyyy%/tdc/deltat_tdc_alc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <!-- VMS/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"vms\">d%yyyy%/tdc/root/deltat_tdc_vms_%yyyy%_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <!-- Dolly/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/tdc/root/deltat_tdc_dolly_%yyyy%_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/pie1/deltat_flc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/pie3/deltat_flc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/deltat_flc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/deltat_pta_dolly_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/pta/deltat_pta_dolly_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/tdc/deltat_tdc_dolly_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"dolly\">d%yyyy%/tdc/mdu/deltat_tdc_dolly_%rrrr%.mdu</run_name_template>" << std::endl;
|
|
fout << " <!-- Flame/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"flame\">d%yyyy%/tdc/root/deltat_tdc_flame_%yyyy%_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"flame\">d%yyyy%/tdc/deltat_tdc_flame_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"flame\">d%yyyy%/tdc/mdu/deltat_tdc_flame_%yyyy%_%rrrr%.mdu</run_name_template>" << std::endl;
|
|
fout << " <!-- GPD/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/tdc/root/deltat_tdc_gpd_%yyyy%_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_mue1_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_fq_si_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_strobo_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_hp_ni_ht_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_hp_ni_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_ccr2_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_gpd_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_janis_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_janis_gpd_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/deltat_pta_gpd_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/pta/deltat_pta_gpd_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/tdc/deltat_tdc_gpd_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gpd\">d%yyyy%/tdc/mdu/deltat_tdc_gpd_%rrrr%.mdu</run_name_template>" << std::endl;
|
|
fout << " <!-- GPS/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/tdc/root/deltat_tdc_gps_%yyyy%_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_ccr_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_he3_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_stutt_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_ltf_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_flc_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_flc2_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_oven_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_oven2_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/deltat_pta_gps_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/tdc/deltat_tdc_gps_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"gps\">d%yyyy%/tdc/mdu/deltat_tdc_gps_%yyyy%_%rrrr%.mdu</run_name_template>" << std::endl;
|
|
fout << " <!-- HAL-9500/PSI == HIFI/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"hifi\">d%yyyy%/tdc/root/deltat_tdc_hifi_%yyyy%_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"hifi\">d%yyyy%/tdc/deltat_hifi_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"hifi\">d%yyyy%/tdc/tdc_hifi_%yyyy%_%rrrrr%.mdu</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"hifi\">d%yyyy%/tdc/root/deltat_tdc_hifi_%yyyy%_%rrrr%.mdu</run_name_template>" << std::endl;
|
|
fout << " <!-- LTF/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"ltf\">d%yyyy%/deltat_ltf_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"ltf\">d%yyyy%/deltat_ltf2_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"ltf\">d%yyyy%/deltat_pta_ltf_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"ltf\">d%yyyy%/pta/deltat_pta_ltf_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"ltf\">d%yyyy%/tdc/deltat_tdc_ltf_%rrrr%.bin</run_name_template>" << std::endl;
|
|
fout << " <!-- LEM/PSI -->" << std::endl;
|
|
fout << " <run_name_template inst=\"lem\">%yyyy%/lem%yy%_his_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"lem\">d%yyyy%/tdc/lem%yy%_his_%rrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"lem\">%yyyy%/lem%yy%_his_%rrrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <run_name_template inst=\"lem\">d%yyyy%/tdc/lem%yy%_his_%rrrrr%.root</run_name_template>" << std::endl;
|
|
fout << " <fourier_settings>" << std::endl;
|
|
fout << " <units>Gauss</units>" << std::endl;
|
|
fout << " <fourier_power>0</fourier_power>" << std::endl;
|
|
fout << " <apodization>none</apodization>" << std::endl;
|
|
fout << " <plot>real_and_imag</plot>" << std::endl;
|
|
fout << " <phase>0.0</phase>" << std::endl;
|
|
fout << " <phase_increment>1.0</phase_increment>" << std::endl;
|
|
fout << " </fourier_settings>" << std::endl;
|
|
fout << " <root_settings>" << std::endl;
|
|
fout << " <marker_list>" << std::endl;
|
|
fout << " <!-- Root marker numbers -->" << std::endl;
|
|
fout << " <marker>24</marker> <!-- open circle -->" << std::endl;
|
|
fout << " <marker>25</marker> <!-- open square -->" << std::endl;
|
|
fout << " <marker>26</marker> <!-- open triangle -->" << std::endl;
|
|
fout << " <marker>27</marker> <!-- open diamond -->" << std::endl;
|
|
fout << " <marker>28</marker> <!-- open cross -->" << std::endl;
|
|
fout << " <marker>29</marker> <!-- full star -->" << std::endl;
|
|
fout << " <marker>30</marker> <!-- open star -->" << std::endl;
|
|
fout << " <marker>20</marker> <!-- full circle -->" << std::endl;
|
|
fout << " <marker>21</marker> <!-- full square -->" << std::endl;
|
|
fout << " <marker>22</marker> <!-- full triangle -->" << std::endl;
|
|
fout << " <marker>23</marker> <!-- full triangle down -->" << std::endl;
|
|
fout << " <marker>2</marker> <!-- thin cross -->" << std::endl;
|
|
fout << " <marker>3</marker> <!-- thin star -->" << std::endl;
|
|
fout << " <marker>5</marker> <!-- thin x -->" << std::endl;
|
|
fout << " </marker_list>" << std::endl;
|
|
fout << " <color_list>" << std::endl;
|
|
fout << " <!-- Color as RGB coded string -->" << std::endl;
|
|
fout << " <color>0,0,0</color> <!-- kBlack -->" << std::endl;
|
|
fout << " <color>255,0,0</color> <!-- kRed -->" << std::endl;
|
|
fout << " <color>0,153,0</color> <!-- kGreen+2 -->" << std::endl;
|
|
fout << " <color>0,0,255</color> <!-- kBlue -->" << std::endl;
|
|
fout << " <color>255,0,255</color> <!-- kMagenta -->" << std::endl;
|
|
fout << " <color>0,255,255</color> <!-- kCyan -->" << std::endl;
|
|
fout << " <color>153,0,255</color> <!-- kViolet-3 -->" << std::endl;
|
|
fout << " <color>102,102,51</color> <!-- kYellow-1 -->" << std::endl;
|
|
fout << " <color>51,102,51</color> <!-- kGreen-1 -->" << std::endl;
|
|
fout << " <color>153,0,0</color> <!-- kRed+2 -->" << std::endl;
|
|
fout << " </color_list>" << std::endl;
|
|
fout << " </root_settings>" << std::endl;
|
|
fout << "</musrfit>" << std::endl;
|
|
|
|
fout.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// end
|
|
// -------------------------------------------------------------------------
|
|
|