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)
57 if (outputFileNameIn.empty() && !inputFilePathIn.empty())
60 std::cout <<
"Using default output file name with \"" << defaultOutputFileSuffix <<
"\" suffix : " << ofn << std::endl;
63 {ofn = outputFileNameIn;}
69 branches[
"Event."].emplace_back(
"Histos");
70 branches[
"Run."].emplace_back(
"Histos");
75 const std::string& inputFilePathIn,
76 const std::string& outputFileNameIn,
77 const std::string& defaultOutputFileSuffix)
82 if (!inputFilePathIn.empty())
84 if (!outputFileNameIn.empty())
92 std::cout <<
"Using default output file name with \"" << defaultOutputFileSuffix <<
"\" suffix : " <<
optionsString.at(
"outputfilename") << std::endl;
103 for (
auto& histoDef : nameDefs.second)
108 for (
auto def : eventHistoDefSetsPerEntry)
117 alternateKeys[
"calculateopticalfunctions"] =
"calculateoptics";
118 alternateKeys[
"calculateopticalfunctionsfilename"] =
"opticsfilename";
147 histoDefs[name] = std::vector<HistogramDef*>();
150 branches[name] = std::vector<std::string>();
155 const std::string& inputFilePath,
156 const std::string& outputFileName,
157 const std::string& defaultOutputFileSuffix)
159 if (!instance && !fileName.empty())
160 {instance =
new Config(fileName, inputFilePath, outputFileName, defaultOutputFileSuffix);}
161 else if(instance && !fileName.empty())
163 std::cout <<
"Config::Instance> Instance present, delete and construct" << std::endl;
165 instance =
new Config(fileName, inputFilePath, outputFileName, defaultOutputFileSuffix);
167 else if (!instance && fileName.empty())
168 {instance =
new Config(inputFilePath, outputFileName, defaultOutputFileSuffix);}
173void Config::ParseInputFile()
176 std::ifstream f(fn.c_str());
179 {
throw RBDSException(
"Config::ParseInputFile>",
"could not open analysis configuration file \"" + fn +
"\"");}
186 std::regex comment(
"^\\#.*");
188 std::regex option(R
"(^\s*(\S+)\s+(\S+)\s*$)");
190 std::regex histogram(
"(?:simple)*histogram.*", std::regex_constants::icase);
192 std::regex spectra(
"(?:simple)*spectra(?:TE|rigidity|momentum)*(?:log)*(?:\\s+)", std::regex_constants::icase);
194 std::regex particleSet(
"(?:simple)*particleset", std::regex_constants::icase);
196 while (std::getline(f, line))
201 if (std::all_of(line.begin(), line.end(), isspace))
203 else if (std::regex_search(line, comment))
205 else if (std::regex_search(line, particleSet))
207 else if (std::regex_search(line, option))
209 else if (std::regex_search(line, histogram))
211 else if (std::regex_search(line, spectra))
218 e.AppendToMessage(
"\nProblem is on line " + std::to_string(
lineCounter) +
" of configuration file: " + fn +
"\n");
234 branches[
"Event."].emplace_back(
"Histos");
235 branches[
"Run."].emplace_back(
"Histos");
243 {eE = std::numeric_limits<double>::max();}
244 if (eS < 0 || eS > eE)
245 {
throw RBDSException(
"Invalid starting event number " + std::to_string(eS));}
256 if (copyLine.find(
"mergehistograms") != std::string::npos)
264 std::regex histNDim(
"^\\s*(?:Simple)*Histogram([1-3])D[a-zA-Z]*\\s+(.*)", std::regex_constants::icase);
268 if (std::regex_search(line, match, histNDim))
270 int nDim = std::stoi(match[1]);
282 std::vector<std::string> results;
283 std::regex wspace(
"\\s+");
285 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
286 std::sregex_token_iterator end;
287 for (; iter != end; ++iter)
289 std::string res = (*iter).str();
290 results.push_back(res);
293 if (results.size() < 7)
294 {
throw RBDSException(
"Too few columns in histogram definition.");}
295 if (results.size() > 7)
296 {
throw RBDSException(
"Too many columns in histogram definition.");}
298 std::string histName = results[2];
301 {
throw RBDSException(
"Duplicate histogram name \"" + histName +
"\" - histograms must have unique names.");}
306 ParseLog(results[0], xLog, yLog, zLog);
308 bool perEntry =
true;
311 std::string treeName = results[1];
316 std::string treeNameWithoutPoint = treeName;
317 treeNameWithoutPoint.pop_back();
318 treeNameWithoutPoint =
LowerCase(treeNameWithoutPoint);
319 optionsBool[
"perentry"+treeNameWithoutPoint] =
true;
322 std::string bins = results[3];
323 std::string binning = results[4];
324 std::string variable = results[5];
325 std::string selection = results[6];
330 ParseBins(bins, nDim,xBinning, yBinning, zBinning);
331 ParseBinning(binning, nDim, xBinning, yBinning, zBinning, xLog, yLog, zLog);
336 std::regex singleColon(
"\\w+(:{1})\\w+");
338 int nColons =
static_cast<int>(std::distance(std::sregex_iterator(variable.begin(),
341 std::sregex_iterator()));
342 if (nColons > nDim - 1)
344 std::string err =
"Error: Histogram \"" + histName +
"\" variable includes too many single\n";
345 err +=
"colons specifying more dimensions than the number of specified dimensions.\n";
346 err +=
"Declared dimensions: " + std::to_string(nDim) +
"\n";
347 err +=
"Number of dimensions in variables " + std::to_string(nColons + 1);
358 variable, selection, perEntry);
365 variable, selection, perEntry);
371 xBinning, yBinning, zBinning,
372 variable, selection, perEntry);
395 if (results.size() < 6)
396 {
throw RBDSException(
"Too few columns in spectra definition.");}
397 if (results.size() > 6)
398 {
throw RBDSException(
"Too many columns in spectra definition - check there's no extra whitespace");}
403 ParseLog(results[0], xLog, yLog, zLog);
405 bool perEntry =
true;
408 std::string variable =
".kineticEnergy";
410 {variable =
".energy";}
412 {variable =
".rigidity";}
416 std::string samplerName = results[1];
418 int nSpectraThisBranch = 0;
422 nSpectraThisBranch = search->second;
427 std::string histogramName = samplerName +
"_" + std::to_string(nSpectraThisBranch);
428 std::string selection = results[5];
433 ParseBins(results[2], 1, xBinning, yBinning, zBinning);
434 ParseBinning(results[3], 1, xBinning, yBinning, zBinning, xLog, yLog, zLog);
436 std::set<ParticleSpec> particles;
441 e.AppendToMessage(
"\nError in spectra particle definition.");
447 if (particles.empty() && !perEntry)
448 {
throw RBDSException(
"Simple spectra cannot be used with 'topN'- only works for specific particles");}
453 samplerName + variable,
454 selection, perEntry);
464 {eventHistoDefSetsPerEntry.push_back(result);}
474 if (results.size() < 2)
475 {
throw RBDSException(
"Too few columns in particle set definition.");}
476 if (results.size() > 2)
477 {
throw RBDSException(
"Too many columns in particle set definition - check there's no extra whitespace");}
479 std::string samplerName = results[1];
482 bool perEntry =
true;
487 {eventParticleSetSimpleBranches.push_back(samplerName);}
493 perEntry = res.find(
"simple") == std::string::npos;
497 const std::string& word)
const
501 return il.find(wl) != std::string::npos;
510 std::regex linLogWords(
"(Lin)|(Log)", std::regex_constants::icase);
511 std::sregex_token_iterator iter(definition.begin(), definition.end(), linLogWords);
512 std::sregex_token_iterator end;
513 std::vector<bool*> results = {&xLog, &yLog, &zLog};
515 for (; iter != end; ++iter, ++index)
517 std::string res =
LowerCase((*iter).str());
518 *(results[index]) = res ==
"log";
529 const std::string& var)
537 std::regex branchLeaf(
"(\\w+)\\.(\\w+)");
538 auto words_begin = std::sregex_iterator(var.begin(), var.end(), branchLeaf);
539 auto words_end = std::sregex_iterator();
540 for (std::sregex_iterator i = words_begin; i != words_end; ++i)
542 std::string targetBranch = (*i)[1];
548 const std::string& branchName)
551 if (std::find(v.begin(), v.end(), branchName) == v.end())
552 {v.push_back(branchName);}
557 std::cout <<
"Simple histogram set definitions for Event tree:" << std::endl;
559 {std::cout << *def << std::endl;}
560 std::cout <<
"PerEntry histogram set definitions for Event tree:" << std::endl;
561 for (
const auto* def : eventHistoDefSetsPerEntry)
562 {std::cout << *def << std::endl;}
567 const std::set<std::string>& allSNames)
571 for (
auto *hset: *hsetset)
573 std::string tempName = hset->branchName +
".";
574 if (allCNames.count(tempName) > 0)
576 hset->ReplaceStringInVariable(
"energy",
"totalEnergy");
577 hset->SetSamplerType(HistogramDefSet::samplertype::cylindrical);
579 else if (allSNames.count(tempName) > 0)
581 hset->ReplaceStringInVariable(
"energy",
"totalEnergy");
582 hset->SetSamplerType(HistogramDefSet::samplertype::spherical);
591 if (strcmp(&treeName.back(),
".") != 0)
596 std::string err =
"Invalid tree name \"" + treeName +
"\"\n";
597 err +=
"Tree names are one of: ";
599 {err +=
"\"" + n +
"\" ";}
616 std::regex number(
"([0-9e\\+]+)+", std::regex_constants::icase);
617 int* binValues[3] = {&xBinning.n, &yBinning.n, &zBinning.n};
618 auto words_begin = std::sregex_iterator(bins.begin(), bins.end(), number);
619 auto words_end = std::sregex_iterator();
621 for (std::sregex_iterator i = words_begin; i != words_end; ++i, ++counter)
622 {(*binValues[counter]) = std::stoi((*i).str());}
623 if (counter < nDim-1)
624 {
throw RBDSException(
"Too few binning dimensions specified (N dimensions = " + std::to_string(nDim) +
") \"" + bins +
"\"");}
637 std::string binningL = binning;
638 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'{'), binningL.end());
639 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'}'), binningL.end());
641 std::regex oneDim(
"([0-9eE.+-]+):([0-9eE.+-]+)");
643 std::regex commas(
",");
644 auto wordsBegin = std::sregex_token_iterator(binningL.begin(), binningL.end(), commas, -1);
645 auto wordsEnd = std::sregex_token_iterator();
647 std::vector<BinSpecification*> values = {&xBinning, &yBinning, &zBinning};
648 std::vector<bool> isLog = {xLog, yLog, zLog};
649 for (
auto i = wordsBegin; i != wordsEnd; ++i, ++counter)
651 std::string matchS = *i;
652 if (matchS.find(
".txt") != std::string::npos)
655 (*values[counter]).edges = binEdges;
656 (*values[counter]).n = (
int)binEdges->size() - 1;
657 (*values[counter]).low = binEdges->at(0);
658 (*values[counter]).high = binEdges->back();
659 (*values[counter]).edgesFileName = matchS;
663 auto rangeBegin = std::sregex_iterator(matchS.begin(), matchS.end(), oneDim);
664 auto rangeEnd = std::sregex_iterator();
665 int counterRange = 0;
666 for (
auto j = rangeBegin; j != rangeEnd; ++j, ++counterRange)
668 std::smatch matchR = *j;
671 (*values[counter]).low = std::stod(matchR[1]);
672 (*values[counter]).high = std::stod(matchR[2]);
674 catch (std::invalid_argument&)
675 {
throw RBDSException(
"Invalid binning number: \"" + matchS +
"\"");}
676 if ((*values[counter]).high <= (*values[counter]).low)
677 {
throw RBDSException(
"high bin edge is <= low bin edge \"" + binning +
"\"");}
680 std::vector<double> binEdges = RBDS::LogSpace((*values[counter]).low, (*values[counter]).high, (*values[counter]).n);
681 (*values[counter]).edges =
new std::vector<double>(binEdges);
682 (*values[counter]).isLogSpaced =
true;
689 {
throw RBDSException(
"Invalid binning specification: \"" + binning +
"\"");}
690 else if (counter < nDim)
692 std::string errString =
"Insufficient number of binning dimensions: \n"
693 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
694 + binning +
"\nDimension defined by \"low:high\" and comma separated";
697 else if (counter > nDim)
699 std::string errString =
"Too many binning dimension (i.e. commas) on line #"
701 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
702 + binning +
"\nDimension defined by \"low:high\" and comma separated";
709 std::vector<std::string> results;
710 std::regex wspace(
"\\s+");
712 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
713 std::sregex_token_iterator end;
714 for (; iter != end; ++iter)
716 std::string res = (*iter).str();
717 results.push_back(res);
728 std::vector<std::string> specialKeys = {
"top",
"particles",
"all",
"ions"};
729 for (
const auto& key : specialKeys)
731 if (wordLower.find(key) != std::string::npos)
732 {
return std::set<ParticleSpec>();}
737 std::regex inBrackets(
"^\\{(.+)\\}$");
739 auto firstSearch = std::regex_search(word, match, inBrackets);
741 {
throw RBDSException(
"Invalid particle definition - no braces");}
744 std::string numbers = match[1];
745 std::set<ParticleSpec> result;
746 std::regex commas(
",");
748 std::sregex_token_iterator iter(numbers.begin(), numbers.end(), commas, -1);
749 std::sregex_token_iterator end;
750 for (; iter != end; ++iter)
752 std::string res = (*iter).str();
753 std::regex selection(
"^([a-zA-Z]){1}(\\d+)");
754 std::smatch matchSelection;
755 if (std::regex_search(res, matchSelection, selection))
757 auto keySearch = RBDS::spectraParticlesKeys.find(matchSelection[1]);
758 RBDS::SpectraParticles which;
759 if (keySearch != RBDS::spectraParticlesKeys.end())
760 {which = keySearch->second;}
762 {
throw RBDSException(
"Invalid particle specifier \"" + matchSelection[1].str() +
"\"");}
765 long long int id = std::stoll(matchSelection[2].str());
766 result.insert(ParticleSpec(
id, which));
768 catch (
const std::exception& e)
771 else if (res.find(
"total") != std::string::npos)
772 {result.insert(ParticleSpec(0, RBDS::SpectraParticles::all));}
777 long long int id = std::stoll(res);
778 result.insert(ParticleSpec(
id, RBDS::SpectraParticles::all));
780 catch (
const std::exception& e)
789 std::string res = st;
790 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
797 std::regex setting(
"(\\w+)\\s+([\\-\\.\\/_\\w\\*]+)", std::regex_constants::icase);
799 if (std::regex_search(line, match, setting))
802 std::string value = match[2];
810 std::regex tfRegex(
"\\s*(true|false)\\s*", std::regex_constants::icase);
812 if (std::regex_search(value, tfMatch, tfRegex))
814 std::string flag = tfMatch[1];
816 std::regex tRegex(
"true", std::regex_constants::icase);
817 bool result = std::regex_search(flag, tMatch, tRegex);
831 {
throw RBDSException(
"Invalid option line \"" + line +
"\"");}
836 bool existsAlready = histogramNames.count(newHistName) > 0;
841 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)