18#include "AnalysisUtilities.hh"
19#include "BinGeneration.hh"
20#include "BinLoader.hh"
21#include "BinSpecification.hh"
23#include "HistogramDefSet.hh"
24#include "HistogramDef1D.hh"
25#include "HistogramDef2D.hh"
26#include "HistogramDef3D.hh"
27#include "RBDSException.hh"
28#include "SpectraParticles.hh"
45Config* Config::instance =
nullptr;
47std::vector<std::string>
Config::treeNames = {
"Beam.",
"Options.",
"Model.",
"Run.",
"Event."};
50 const std::string& outputFileNameIn,
51 const std::string& defaultOutputFileSuffix)
56 if (outputFileNameIn.empty() && !inputFilePathIn.empty())
59 std::cout <<
"Using default output file name with \"" << defaultOutputFileSuffix <<
"\" suffix : " << ofn << std::endl;
62 {ofn = outputFileNameIn;}
68 branches[
"Event."].emplace_back(
"Histos");
69 branches[
"Run."].emplace_back(
"Histos");
74 const std::string& inputFilePathIn,
75 const std::string& outputFileNameIn,
76 const std::string& defaultOutputFileSuffix)
81 if (!inputFilePathIn.empty())
83 if (!outputFileNameIn.empty())
91 std::cout <<
"Using default output file name with \"" << defaultOutputFileSuffix <<
"\" suffix : " <<
optionsString.at(
"outputfilename") << std::endl;
102 for (
auto& histoDef : nameDefs.second)
107 for (
auto def : eventHistoDefSetsPerEntry)
116 alternateKeys[
"calculateopticalfunctions"] =
"calculateoptics";
117 alternateKeys[
"calculateopticalfunctionsfilename"] =
"opticsfilename";
146 histoDefs[name] = std::vector<HistogramDef*>();
149 branches[name] = std::vector<std::string>();
154 const std::string& inputFilePath,
155 const std::string& outputFileName,
156 const std::string& defaultOutputFileSuffix)
158 if (!instance && !fileName.empty())
159 {instance =
new Config(fileName, inputFilePath, outputFileName, defaultOutputFileSuffix);}
160 else if(instance && !fileName.empty())
162 std::cout <<
"Config::Instance> Instance present, delete and construct" << std::endl;
164 instance =
new Config(fileName, inputFilePath, outputFileName, defaultOutputFileSuffix);
166 else if (!instance && fileName.empty())
167 {instance =
new Config(inputFilePath, outputFileName, defaultOutputFileSuffix);}
172void Config::ParseInputFile()
175 std::ifstream f(fn.c_str());
178 {
throw RBDSException(
"Config::ParseInputFile>",
"could not open analysis configuration file \"" + fn +
"\"");}
185 std::regex comment(
"^\\#.*");
187 std::regex option(R
"(^\s*(\S+)\s+(\S+)\s*$)");
189 std::regex histogram(
"(?:simple)*histogram.*", std::regex_constants::icase);
191 std::regex spectra(
"(?:simple)*spectra(?:TE|rigidity|momentum)*(?:log)*(?:\\s+)", std::regex_constants::icase);
193 std::regex particleSet(
"(?:simple)*particleset", std::regex_constants::icase);
195 while (std::getline(f, line))
200 if (std::all_of(line.begin(), line.end(), isspace))
202 else if (std::regex_search(line, comment))
204 else if (std::regex_search(line, particleSet))
206 else if (std::regex_search(line, option))
208 else if (std::regex_search(line, histogram))
210 else if (std::regex_search(line, spectra))
217 e.AppendToMessage(
"\nProblem is on line " + std::to_string(
lineCounter) +
" of configuration file: " + fn +
"\n");
233 branches[
"Event."].emplace_back(
"Histos");
234 branches[
"Run."].emplace_back(
"Histos");
242 {eE = std::numeric_limits<double>::max();}
243 if (eS < 0 || eS > eE)
244 {
throw RBDSException(
"Invalid starting event number " + std::to_string(eS));}
255 if (copyLine.find(
"mergehistograms") != std::string::npos)
263 std::regex histNDim(
"^\\s*(?:Simple)*Histogram([1-3])D[a-zA-Z]*\\s+(.*)", std::regex_constants::icase);
267 if (std::regex_search(line, match, histNDim))
269 int nDim = std::stoi(match[1]);
281 std::vector<std::string> results;
282 std::regex wspace(
"\\s+");
284 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
285 std::sregex_token_iterator end;
286 for (; iter != end; ++iter)
288 std::string res = (*iter).str();
289 results.push_back(res);
292 if (results.size() < 7)
293 {
throw RBDSException(
"Too few columns in histogram definition.");}
294 if (results.size() > 7)
295 {
throw RBDSException(
"Too many columns in histogram definition.");}
297 std::string histName = results[2];
300 {
throw RBDSException(
"Duplicate histogram name \"" + histName +
"\" - histograms must have unique names.");}
305 ParseLog(results[0], xLog, yLog, zLog);
307 bool perEntry =
true;
310 std::string treeName = results[1];
315 std::string treeNameWithoutPoint = treeName;
316 treeNameWithoutPoint.pop_back();
317 treeNameWithoutPoint =
LowerCase(treeNameWithoutPoint);
318 optionsBool[
"perentry"+treeNameWithoutPoint] =
true;
321 std::string bins = results[3];
322 std::string binning = results[4];
323 std::string variable = results[5];
324 std::string selection = results[6];
329 ParseBins(bins, nDim,xBinning, yBinning, zBinning);
330 ParseBinning(binning, nDim, xBinning, yBinning, zBinning, xLog, yLog, zLog);
335 std::regex singleColon(
"\\w+(:{1})\\w+");
337 int nColons =
static_cast<int>(std::distance(std::sregex_iterator(variable.begin(),
340 std::sregex_iterator()));
341 if (nColons > nDim - 1)
343 std::string err =
"Error: Histogram \"" + histName +
"\" variable includes too many single\n";
344 err +=
"colons specifying more dimensions than the number of specified dimensions.\n";
345 err +=
"Declared dimensions: " + std::to_string(nDim) +
"\n";
346 err +=
"Number of dimensions in variables " + std::to_string(nColons + 1);
357 variable, selection, perEntry);
364 variable, selection, perEntry);
370 xBinning, yBinning, zBinning,
371 variable, selection, perEntry);
394 if (results.size() < 6)
395 {
throw RBDSException(
"Too few columns in spectra definition.");}
396 if (results.size() > 6)
397 {
throw RBDSException(
"Too many columns in spectra definition - check there's no extra whitespace");}
402 ParseLog(results[0], xLog, yLog, zLog);
404 bool perEntry =
true;
407 std::string variable =
".kineticEnergy";
409 {variable =
".energy";}
411 {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);
463 {eventHistoDefSetsPerEntry.push_back(result);}
473 if (results.size() < 2)
474 {
throw RBDSException(
"Too few columns in particle set definition.");}
475 if (results.size() > 2)
476 {
throw RBDSException(
"Too many columns in particle set definition - check there's no extra whitespace");}
478 std::string samplerName = results[1];
481 bool perEntry =
true;
486 {eventParticleSetSimpleBranches.push_back(samplerName);}
492 perEntry = res.find(
"simple") == std::string::npos;
496 const std::string& word)
const
500 return il.find(wl) != std::string::npos;
509 std::regex linLogWords(
"(Lin)|(Log)", std::regex_constants::icase);
510 std::sregex_token_iterator iter(definition.begin(), definition.end(), linLogWords);
511 std::sregex_token_iterator end;
512 std::vector<bool*> results = {&xLog, &yLog, &zLog};
514 for (; iter != end; ++iter, ++index)
516 std::string res =
LowerCase((*iter).str());
517 *(results[index]) = res ==
"log";
528 const std::string& var)
536 std::regex branchLeaf(
"(\\w+)\\.(\\w+)");
537 auto words_begin = std::sregex_iterator(var.begin(), var.end(), branchLeaf);
538 auto words_end = std::sregex_iterator();
539 for (std::sregex_iterator i = words_begin; i != words_end; ++i)
541 std::string targetBranch = (*i)[1];
547 const std::string& branchName)
550 if (std::find(v.begin(), v.end(), branchName) == v.end())
551 {v.push_back(branchName);}
556 std::cout <<
"Simple histogram set definitions for Event tree:" << std::endl;
558 {std::cout << *def << std::endl;}
559 std::cout <<
"PerEntry histogram set definitions for Event tree:" << std::endl;
560 for (
const auto* def : eventHistoDefSetsPerEntry)
561 {std::cout << *def << std::endl;}
566 const std::set<std::string>& allSNames)
570 for (
auto *hset: *hsetset)
572 std::string tempName = hset->branchName +
".";
573 if (allCNames.count(tempName) > 0)
575 hset->ReplaceStringInVariable(
"energy",
"totalEnergy");
576 hset->SetSamplerType(HistogramDefSet::samplertype::cylindrical);
578 else if (allSNames.count(tempName) > 0)
580 hset->ReplaceStringInVariable(
"energy",
"totalEnergy");
581 hset->SetSamplerType(HistogramDefSet::samplertype::spherical);
590 if (strcmp(&treeName.back(),
".") != 0)
595 std::string err =
"Invalid tree name \"" + treeName +
"\"\n";
596 err +=
"Tree names are one of: ";
598 {err +=
"\"" + n +
"\" ";}
615 std::regex number(
"([0-9e\\+]+)+", std::regex_constants::icase);
616 int* binValues[3] = {&xBinning.n, &yBinning.n, &zBinning.n};
617 auto words_begin = std::sregex_iterator(bins.begin(), bins.end(), number);
618 auto words_end = std::sregex_iterator();
620 for (std::sregex_iterator i = words_begin; i != words_end; ++i, ++counter)
621 {(*binValues[counter]) = std::stoi((*i).str());}
622 if (counter < nDim-1)
623 {
throw RBDSException(
"Too few binning dimensions specified (N dimensions = " + std::to_string(nDim) +
") \"" + bins +
"\"");}
636 std::string binningL = binning;
637 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'{'), binningL.end());
638 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'}'), binningL.end());
640 std::regex oneDim(
"([0-9eE.+-]+):([0-9eE.+-]+)");
642 std::regex commas(
",");
643 auto wordsBegin = std::sregex_token_iterator(binningL.begin(), binningL.end(), commas, -1);
644 auto wordsEnd = std::sregex_token_iterator();
646 std::vector<BinSpecification*> values = {&xBinning, &yBinning, &zBinning};
647 std::vector<bool> isLog = {xLog, yLog, zLog};
648 for (
auto i = wordsBegin; i != wordsEnd; ++i, ++counter)
650 std::string matchS = *i;
651 if (matchS.find(
".txt") != std::string::npos)
654 (*values[counter]).edges = binEdges;
655 (*values[counter]).n = (
int)binEdges->size() - 1;
656 (*values[counter]).low = binEdges->at(0);
657 (*values[counter]).high = binEdges->back();
658 (*values[counter]).edgesFileName = matchS;
662 auto rangeBegin = std::sregex_iterator(matchS.begin(), matchS.end(), oneDim);
663 auto rangeEnd = std::sregex_iterator();
664 for (
auto j = rangeBegin; j != rangeEnd; ++j)
666 std::smatch matchR = *j;
669 (*values[counter]).low = std::stod(matchR[1]);
670 (*values[counter]).high = std::stod(matchR[2]);
672 catch (std::invalid_argument&)
673 {
throw RBDSException(
"Invalid binning number: \"" + matchS +
"\"");}
674 if ((*values[counter]).high <= (*values[counter]).low)
675 {
throw RBDSException(
"high bin edge is <= low bin edge \"" + binning +
"\"");}
678 std::vector<double> binEdges = RBDS::LogSpace((*values[counter]).low, (*values[counter]).high, (*values[counter]).n);
679 (*values[counter]).edges =
new std::vector<double>(binEdges);
680 (*values[counter]).isLogSpaced =
true;
687 {
throw RBDSException(
"Invalid binning specification: \"" + binning +
"\"");}
688 else if (counter < nDim)
690 std::string errString =
"Insufficient number of binning dimensions: \n"
691 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
692 + binning +
"\nDimension defined by \"low:high\" and comma separated";
695 else if (counter > nDim)
697 std::string errString =
"Too many binning dimension (i.e. commas) on line #"
699 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
700 + binning +
"\nDimension defined by \"low:high\" and comma separated";
707 std::vector<std::string> results;
708 std::regex wspace(
"\\s+");
710 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
711 std::sregex_token_iterator end;
712 for (; iter != end; ++iter)
714 std::string res = (*iter).str();
715 results.push_back(res);
726 std::vector<std::string> specialKeys = {
"top",
"particles",
"all",
"ions"};
727 for (
const auto& key : specialKeys)
729 if (wordLower.find(key) != std::string::npos)
730 {
return std::set<ParticleSpec>();}
735 std::regex inBrackets(
"^\\{(.+)\\}$");
737 auto firstSearch = std::regex_search(word, match, inBrackets);
739 {
throw RBDSException(
"Invalid particle definition - no braces");}
742 std::string numbers = match[1];
743 std::set<ParticleSpec> result;
744 std::regex commas(
",");
746 std::sregex_token_iterator iter(numbers.begin(), numbers.end(), commas, -1);
747 std::sregex_token_iterator end;
748 for (; iter != end; ++iter)
750 std::string res = (*iter).str();
751 std::regex selection(
"^([a-zA-Z]){1}(\\d+)");
752 std::smatch matchSelection;
753 if (std::regex_search(res, matchSelection, selection))
755 auto keySearch = RBDS::spectraParticlesKeys.find(matchSelection[1]);
756 RBDS::SpectraParticles which;
757 if (keySearch != RBDS::spectraParticlesKeys.end())
758 {which = keySearch->second;}
760 {
throw RBDSException(
"Invalid particle specifier \"" + matchSelection[1].str() +
"\"");}
763 long long int id = std::stoll(matchSelection[2].str());
764 result.insert(ParticleSpec(
id, which));
766 catch (
const std::exception& e)
769 else if (res.find(
"total") != std::string::npos)
770 {result.insert(ParticleSpec(0, RBDS::SpectraParticles::all));}
775 long long int id = std::stoll(res);
776 result.insert(ParticleSpec(
id, RBDS::SpectraParticles::all));
778 catch (
const std::exception& e)
787 std::string res = st;
788 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
795 std::regex setting(
"(\\w+)\\s+([\\-\\.\\/_\\w\\*]+)", std::regex_constants::icase);
797 if (std::regex_search(line, match, setting))
800 std::string value = match[2];
808 std::regex tfRegex(
"\\s*(true|false)\\s*", std::regex_constants::icase);
810 if (std::regex_search(value, tfMatch, tfRegex))
812 std::string flag = tfMatch[1];
814 std::regex tRegex(
"true", std::regex_constants::icase);
815 bool result = std::regex_search(flag, tMatch, tRegex);
829 {
throw RBDSException(
"Invalid option line \"" + line +
"\"");}
834 bool existsAlready = histogramNames.count(newHistName) > 0;
839 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.
void FixCylindricalAndSphericalSamplerVariablesInSets(const std::set< std::string > &allCNames, const std::set< std::string > &allSNames)
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.
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)