19#include "AnalysisUtilities.hh"
20#include "BinGeneration.hh"
21#include "BinLoader.hh"
22#include "BinSpecification.hh"
24#include "HistogramDefSet.hh"
25#include "HistogramDef1D.hh"
26#include "HistogramDef2D.hh"
27#include "HistogramDef3D.hh"
28#include "RBDSException.hh"
29#include "SpectraParticles.hh"
46Config* Config::instance =
nullptr;
48std::vector<std::string>
Config::treeNames = {
"Beam.",
"Options.",
"Model.",
"Run.",
"Event."};
51 const std::string& outputFileNameIn,
52 const std::string& defaultOutputFileSuffix):
53 allBranchesActivated(false)
58 if (outputFileNameIn.empty() && !inputFilePathIn.empty())
61 std::cout <<
"Using default output file name with \"" << defaultOutputFileSuffix <<
"\" suffix : " << ofn << std::endl;
64 {ofn = outputFileNameIn;}
70 branches[
"Event."].emplace_back(
"Histos");
71 branches[
"Run."].emplace_back(
"Histos");
76 const std::string& inputFilePathIn,
77 const std::string& outputFileNameIn,
78 const std::string& defaultOutputFileSuffix):
79 allBranchesActivated(false)
84 if (!inputFilePathIn.empty())
86 if (!outputFileNameIn.empty())
94 std::cout <<
"Using default output file name with \"" << defaultOutputFileSuffix <<
"\" suffix : " <<
optionsString.at(
"outputfilename") << std::endl;
105 for (
auto& histoDef : nameDefs.second)
110 for (
auto def : eventHistoDefSetsPerEntry)
119 alternateKeys[
"calculateopticalfunctions"] =
"calculateoptics";
120 alternateKeys[
"calculateopticalfunctionsfilename"] =
"opticsfilename";
148 histoDefs[name] = std::vector<HistogramDef*>();
151 branches[name] = std::vector<std::string>();
156 const std::string& inputFilePath,
157 const std::string& outputFileName,
158 const std::string& defaultOutputFileSuffix)
160 if (!instance && !fileName.empty())
161 {instance =
new Config(fileName, inputFilePath, outputFileName, defaultOutputFileSuffix);}
162 else if(instance && !fileName.empty())
164 std::cout <<
"Config::Instance> Instance present, delete and construct" << std::endl;
166 instance =
new Config(fileName, inputFilePath, outputFileName, defaultOutputFileSuffix);
168 else if (!instance && fileName.empty())
169 {instance =
new Config(inputFilePath, outputFileName, defaultOutputFileSuffix);}
174void Config::ParseInputFile()
177 std::ifstream f(fn.c_str());
180 {
throw RBDSException(
"Config::ParseInputFile>",
"could not open analysis configuration file \"" + fn +
"\"");}
187 std::regex comment(
"^\\#.*");
189 std::regex option(R
"(^\s*(\S+)\s+(\S+)\s*$)");
191 std::regex histogram(
"(?:simple)*histogram.*", std::regex_constants::icase);
193 std::regex spectra(
"(?:simple)*spectra(?:TE|rigidity)*(?:log)*(?:\\s+)", std::regex_constants::icase);
195 std::regex particleSet(
"(?:simple)*particleset", std::regex_constants::icase);
197 while (std::getline(f, line))
202 if (std::all_of(line.begin(), line.end(), isspace))
204 else if (std::regex_search(line, comment))
206 else if (std::regex_search(line, particleSet))
208 else if (std::regex_search(line, option))
210 else if (std::regex_search(line, histogram))
212 else if (std::regex_search(line, spectra))
219 e.AppendToMessage(
"\nProblem is on line " + std::to_string(
lineCounter) +
" of configuration file: " + fn +
"\n");
235 branches[
"Event."].emplace_back(
"Histos");
236 branches[
"Run."].emplace_back(
"Histos");
244 {eE = std::numeric_limits<double>::max();}
245 if (eS < 0 || eS > eE)
246 {
throw RBDSException(
"Invalid starting event number " + std::to_string(eS));}
257 if (copyLine.find(
"mergehistograms") != std::string::npos)
265 std::regex histNDim(
"^\\s*(?:Simple)*Histogram([1-3])D[a-zA-Z]*\\s+(.*)", std::regex_constants::icase);
269 if (std::regex_search(line, match, histNDim))
271 int nDim = std::stoi(match[1]);
283 std::vector<std::string> results;
284 std::regex wspace(
"\\s+");
286 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
287 std::sregex_token_iterator end;
288 for (; iter != end; ++iter)
290 std::string res = (*iter).str();
291 results.push_back(res);
294 if (results.size() < 7)
295 {
throw RBDSException(
"Too few columns in histogram definition.");}
296 if (results.size() > 7)
297 {
throw RBDSException(
"Too many columns in histogram definition.");}
299 std::string histName = results[2];
302 {
throw RBDSException(
"Duplicate histogram name \"" + histName +
"\" - histograms must have unique names.");}
307 ParseLog(results[0], xLog, yLog, zLog);
309 bool perEntry =
true;
312 std::string treeName = results[1];
317 std::string treeNameWithoutPoint = treeName;
318 treeNameWithoutPoint.pop_back();
319 treeNameWithoutPoint =
LowerCase(treeNameWithoutPoint);
320 optionsBool[
"perentry"+treeNameWithoutPoint] =
true;
323 std::string bins = results[3];
324 std::string binning = results[4];
325 std::string variable = results[5];
326 std::string selection = results[6];
331 ParseBins(bins, nDim,xBinning, yBinning, zBinning);
332 ParseBinning(binning, nDim, xBinning, yBinning, zBinning, xLog, yLog, zLog);
337 std::regex singleColon(
"\\w+(:{1})\\w+");
339 int nColons =
static_cast<int>(std::distance(std::sregex_iterator(variable.begin(),
342 std::sregex_iterator()));
343 if (nColons > nDim - 1)
345 std::string err =
"Error: Histogram \"" + histName +
"\" variable includes too many single\n";
346 err +=
"colons specifying more dimensions than the number of specified dimensions.\n";
347 err +=
"Declared dimensions: " + std::to_string(nDim) +
"\n";
348 err +=
"Number of dimensions in variables " + std::to_string(nColons + 1);
359 variable, selection, perEntry);
366 variable, selection, perEntry);
372 xBinning, yBinning, zBinning,
373 variable, selection, perEntry);
396 if (results.size() < 6)
397 {
throw RBDSException(
"Too few columns in spectra definition.");}
398 if (results.size() > 6)
399 {
throw RBDSException(
"Too many columns in spectra definition - check there's no extra whitespace");}
404 ParseLog(results[0], xLog, yLog, zLog);
406 bool perEntry =
true;
409 std::string variable =
".kineticEnergy";
411 {variable =
".energy";}
413 {variable =
".rigidity";}
415 std::string samplerName = results[1];
417 int nSpectraThisBranch = 0;
421 nSpectraThisBranch = search->second;
426 std::string histogramName = samplerName +
"_" + std::to_string(nSpectraThisBranch);
427 std::string selection = results[5];
432 ParseBins(results[2], 1, xBinning, yBinning, zBinning);
433 ParseBinning(results[3], 1, xBinning, yBinning, zBinning, xLog, yLog, zLog);
435 std::set<ParticleSpec> particles;
440 e.AppendToMessage(
"\nError in spectra particle definition.");
446 if (particles.empty() && !perEntry)
447 {
throw RBDSException(
"Simple spectra cannot be used with 'topN'- only works for specific particles");}
452 samplerName + variable,
453 selection, perEntry);
462 {eventHistoDefSetsPerEntry.push_back(result);}
472 if (results.size() < 2)
473 {
throw RBDSException(
"Too few columns in particle set definition.");}
474 if (results.size() > 2)
475 {
throw RBDSException(
"Too many columns in particle set definition - check there's no extra whitespace");}
477 std::string samplerName = results[1];
480 bool perEntry =
true;
485 {eventParticleSetSimpleBranches.push_back(samplerName);}
491 perEntry = res.find(
"simple") == std::string::npos;
495 const std::string& word)
const
499 return il.find(wl) != std::string::npos;
508 std::regex linLogWords(
"(Lin)|(Log)", std::regex_constants::icase);
509 std::sregex_token_iterator iter(definition.begin(), definition.end(), linLogWords);
510 std::sregex_token_iterator end;
511 std::vector<bool*> results = {&xLog, &yLog, &zLog};
513 for (; iter != end; ++iter, ++index)
515 std::string res =
LowerCase((*iter).str());
516 *(results[index]) = res ==
"log";
527 const std::string& var)
535 std::regex branchLeaf(
"(\\w+)\\.(\\w+)");
536 auto words_begin = std::sregex_iterator(var.begin(), var.end(), branchLeaf);
537 auto words_end = std::sregex_iterator();
538 for (std::sregex_iterator i = words_begin; i != words_end; ++i)
540 std::string targetBranch = (*i)[1];
546 const std::string& branchName)
549 if (std::find(v.begin(), v.end(), branchName) == v.end())
550 {v.push_back(branchName);}
555 std::cout <<
"Simple histogram set definitions for Event tree:" << std::endl;
557 {std::cout << *def << std::endl;}
558 std::cout <<
"PerEntry histogram set definitions for Event tree:" << std::endl;
559 for (
const auto* def : eventHistoDefSetsPerEntry)
560 {std::cout << *def << std::endl;}
566 if (strcmp(&treeName.back(),
".") != 0)
571 std::string err =
"Invalid tree name \"" + treeName +
"\"\n";
572 err +=
"Tree names are one of: ";
574 {err +=
"\"" + n +
"\" ";}
591 std::regex number(
"([0-9e\\+]+)+", std::regex_constants::icase);
592 int* binValues[3] = {&xBinning.n, &yBinning.n, &zBinning.n};
593 auto words_begin = std::sregex_iterator(bins.begin(), bins.end(), number);
594 auto words_end = std::sregex_iterator();
596 for (std::sregex_iterator i = words_begin; i != words_end; ++i, ++counter)
597 {(*binValues[counter]) = std::stoi((*i).str());}
598 if (counter < nDim-1)
599 {
throw RBDSException(
"Too few binning dimensions specified (N dimensions = " + std::to_string(nDim) +
") \"" + bins +
"\"");}
612 std::string binningL = binning;
613 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'{'), binningL.end());
614 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'}'), binningL.end());
616 std::regex oneDim(
"([0-9eE.+-]+):([0-9eE.+-]+)");
618 std::regex commas(
",");
619 auto wordsBegin = std::sregex_token_iterator(binningL.begin(), binningL.end(), commas, -1);
620 auto wordsEnd = std::sregex_token_iterator();
622 std::vector<BinSpecification*> values = {&xBinning, &yBinning, &zBinning};
623 std::vector<bool> isLog = {xLog, yLog, zLog};
624 for (
auto i = wordsBegin; i != wordsEnd; ++i, ++counter)
626 std::string matchS = *i;
627 if (matchS.find(
".txt") != std::string::npos)
630 (*values[counter]).edges = binEdges;
631 (*values[counter]).n = (
int)binEdges->size() - 1;
632 (*values[counter]).low = binEdges->at(0);
633 (*values[counter]).high = binEdges->back();
634 (*values[counter]).edgesFileName = matchS;
638 auto rangeBegin = std::sregex_iterator(matchS.begin(), matchS.end(), oneDim);
639 auto rangeEnd = std::sregex_iterator();
640 int counterRange = 0;
641 for (
auto j = rangeBegin; j != rangeEnd; ++j, ++counterRange)
643 std::smatch matchR = *j;
646 (*values[counter]).low = std::stod(matchR[1]);
647 (*values[counter]).high = std::stod(matchR[2]);
649 catch (std::invalid_argument&)
650 {
throw RBDSException(
"Invalid binning number: \"" + matchS +
"\"");}
651 if ((*values[counter]).high <= (*values[counter]).low)
652 {
throw RBDSException(
"high bin edge is <= low bin edge \"" + binning +
"\"");}
655 std::vector<double> binEdges = RBDS::LogSpace((*values[counter]).low, (*values[counter]).high, (*values[counter]).n);
656 (*values[counter]).edges =
new std::vector<double>(binEdges);
657 (*values[counter]).isLogSpaced =
true;
664 {
throw RBDSException(
"Invalid binning specification: \"" + binning +
"\"");}
665 else if (counter < nDim)
667 std::string errString =
"Insufficient number of binning dimensions: \n"
668 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
669 + binning +
"\nDimension defined by \"low:high\" and comma separated";
672 else if (counter > nDim)
674 std::string errString =
"Too many binning dimension (i.e. commas) on line #"
676 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
677 + binning +
"\nDimension defined by \"low:high\" and comma separated";
684 std::vector<std::string> results;
685 std::regex wspace(
"\\s+");
687 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
688 std::sregex_token_iterator end;
689 for (; iter != end; ++iter)
691 std::string res = (*iter).str();
692 results.push_back(res);
703 std::vector<std::string> specialKeys = {
"top",
"particles",
"all",
"ions"};
704 for (
const auto& key : specialKeys)
706 if (wordLower.find(key) != std::string::npos)
707 {
return std::set<ParticleSpec>();}
712 std::regex inBrackets(
"^\\{(.+)\\}$");
714 auto firstSearch = std::regex_search(word, match, inBrackets);
716 {
throw RBDSException(
"Invalid particle definition - no braces");}
719 std::string numbers = match[1];
720 std::set<ParticleSpec> result;
721 std::regex commas(
",");
723 std::sregex_token_iterator iter(numbers.begin(), numbers.end(), commas, -1);
724 std::sregex_token_iterator end;
725 for (; iter != end; ++iter)
727 std::string res = (*iter).str();
728 std::regex selection(
"^([a-zA-Z]){1}(\\d+)");
729 std::smatch matchSelection;
730 if (std::regex_search(res, matchSelection, selection))
732 auto keySearch = RBDS::spectraParticlesKeys.find(matchSelection[1]);
733 RBDS::SpectraParticles which;
734 if (keySearch != RBDS::spectraParticlesKeys.end())
735 {which = keySearch->second;}
737 {
throw RBDSException(
"Invalid particle specifier \"" + matchSelection[1].str() +
"\"");}
740 long long int id = std::stoll(matchSelection[2].str());
741 result.insert(ParticleSpec(
id, which));
743 catch (
const std::exception& e)
746 else if (res.find(
"total") != std::string::npos)
747 {result.insert(ParticleSpec(0, RBDS::SpectraParticles::all));}
752 long long int id = std::stoll(res);
753 result.insert(ParticleSpec(
id, RBDS::SpectraParticles::all));
755 catch (
const std::exception& e)
764 std::string res = st;
765 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
772 std::regex setting(
"(\\w+)\\s+([\\-\\.\\/_\\w\\*]+)", std::regex_constants::icase);
774 if (std::regex_search(line, match, setting))
777 std::string value = match[2];
785 std::regex tfRegex(
"\\s*(true|false)\\s*", std::regex_constants::icase);
787 if (std::regex_search(value, tfMatch, tfRegex))
789 std::string flag = tfMatch[1];
791 std::regex tRegex(
"true", std::regex_constants::icase);
792 bool result = std::regex_search(flag, tMatch, tRegex);
806 {
throw RBDSException(
"Invalid option line \"" + line +
"\"");}
811 bool existsAlready = histogramNames.count(newHistName) > 0;
816 histogramNames.insert(newHistName);
Binning specification for a single dimension.
Configuration and configuration parser class.
std::map< std::string, std::vector< HistogramDef * > > histoDefs
void ParseSetting(const std::string &line)
Parse a settings line in input file and appropriate update member map.
void PrintHistogramSetDefinitions() const
void ParseHistogramLine(const std::string &line)
Parse a line beginning with histogram. Uses other functions if appropriately defined.
std::map< std::string, double > optionsNumber
Storage of options.
std::string LowerCase(const std::string &st) const
Return a lower case copy of a string.
void SetBranchToBeActivated(const std::string &treeName, const std::string &branchName)
Set a branch to be activated if not already.
void CheckValidTreeName(std::string &treeName) const
bool InvalidTreeName(const std::string &treeName) const
std::vector< std::string > eventParticleSetBranches
List of branches in event tree to produce ParticleSet objects on. (per event and simple).
std::map< std::string, int > spectraNames
static Config * Instance(const std::string &fileName="", const std::string &inputFilePath="", const std::string &outputFileName="", const std::string &defaultOutputFileSuffix="_ana")
Singleton accessor.
std::map< std::string, std::string > optionsString
Storage of options.
bool allBranchesActivated
Whether all branches will be activated - ie for optics.
Config()=delete
Private constructor for singleton pattern.
void ParseBinning(const std::string &binning, int nDim, BinSpecification &xBinning, BinSpecification &yBinning, BinSpecification &zBinning, bool xLog, bool yLog, bool zLog) const
std::vector< std::string > SplitOnWhiteSpace(const std::string &line) const
Return a vector of strings by splitting on whitespace.
std::set< ParticleSpec > ParseParticles(const std::string &word) const
Parser a list of particle PDG IDs into a set.
void ParseLog(const std::string &definition, bool &xLog, bool &yLog, bool &zLog) const
Parse whether each dimension is log or linear.
bool RegisterHistogramName(const std::string &newHistName)
std::vector< HistogramDefSet * > eventHistoDefSetsSimple
Sets of histogram definitions per particle. Only for event branch.
RBDS::BranchMap branches
Cache of which branches need to be activated for this analysis.
int lineCounter
Index of which line in the file we're on while parsing - for feedback.
std::map< std::string, std::string > alternateKeys
Private members first as required in accessors.
void UpdateRequiredBranches(const HistogramDef *def)
bool ContainsWordCI(const std::string &input, const std::string &word) const
Return true if 'input' contains 'word' - CI = case insensitive.
std::map< std::string, std::vector< HistogramDef * > > histoDefsSimple
Copy of definition used to identify only 'simple' histogram definitions. Doesn't own.
static std::vector< std::string > treeNames
Vector of permitted tree names.
void ParseParticleSetLine(const std::string &line)
Parse a particle set line.
void InitialiseOptions(const std::string &analysisFile)
void ParseSpectraLine(const std::string &line)
Parse a spectra definition line.
void ParseHistogram(const std::string &line, const int nDim)
Parse everything after the histogram declaration and check all parameters.
std::map< std::string, bool > optionsBool
Storage of options.
void ParsePerEntry(const std::string &name, bool &perEntry) const
void ParseBins(const std::string &bins, int nDim, BinSpecification &xBinning, BinSpecification &yBinning, BinSpecification &zBinning) const
std::map< std::string, std::vector< HistogramDef * > > histoDefsPerEntry
Copy of definition used to identify only 'per entry' histogram definitions. Doesn't own.
Specification for 1D histogram.
Specification for 2D histogram.
Specification for 3D Histogram.
Specification for a set of histograms.
Common specification for a histogram.
General exception with possible name of object and message.
std::vector< double > * LoadBins(const std::string &fileName)
Method to load a single column text file and return vector of values.
std::string DefaultOutputName(const std::string &inputFilePath, const std::string &suffix)