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."].push_back(
"Histos");
71 branches[
"Run."].push_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";
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 histogram(
"(?:simple)*histogram.*", std::regex_constants::icase);
189 std::regex spectra(
"(?:simple)*spectra(?:TE|rigidity)*(?:log)*(?:\\s+)", std::regex_constants::icase);
191 std::regex particleSet(
"(?:simple)*particleset", std::regex_constants::icase);
193 while (std::getline(f, line))
198 if (std::all_of(line.begin(), line.end(), isspace))
200 else if (std::regex_search(line, comment))
202 else if (std::regex_search(line, histogram))
204 else if (std::regex_search(line, spectra))
206 else if (std::regex_search(line, particleSet))
213 e.AppendToMessage(
"\nProblem is on line " + std::to_string(
lineCounter) +
" of configuration file: " + fn +
"\n");
229 branches[
"Event."].push_back(
"Histos");
230 branches[
"Run."].push_back(
"Histos");
238 {eE = std::numeric_limits<double>::max();}
239 if (eS < 0 || eS > eE)
240 {
throw RBDSException(
"Invalid starting event number " + std::to_string(eS));}
248 if (copyLine.find(
"mergehistograms") != std::string::npos)
256 std::regex histNDim(
"^\\s*(?:Simple)*Histogram([1-3])D[a-zA-Z]*\\s+(.*)", std::regex_constants::icase);
260 if (std::regex_search(line, match, histNDim))
262 int nDim = std::stoi(match[1]);
274 std::vector<std::string> results;
275 std::regex wspace(
"\\s+");
277 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
278 std::sregex_token_iterator end;
279 for (; iter != end; ++iter)
281 std::string res = (*iter).str();
282 results.push_back(res);
285 if (results.size() < 7)
286 {
throw RBDSException(
"Too few columns in histogram definition.");}
287 if (results.size() > 7)
288 {
throw RBDSException(
"Too many columns in histogram definition.");}
290 std::string histName = results[2];
293 {
throw RBDSException(
"Duplicate histogram name \"" + histName +
"\" - histograms must have unique names.");}
298 ParseLog(results[0], xLog, yLog, zLog);
300 bool perEntry =
true;
303 std::string treeName = results[1];
308 std::string treeNameWithoutPoint = treeName;
309 treeNameWithoutPoint.pop_back();
310 treeNameWithoutPoint =
LowerCase(treeNameWithoutPoint);
311 optionsBool[
"perentry"+treeNameWithoutPoint] =
true;
314 std::string bins = results[3];
315 std::string binning = results[4];
316 std::string variable = results[5];
317 std::string selection = results[6];
322 ParseBins(bins, nDim,xBinning, yBinning, zBinning);
323 ParseBinning(binning, nDim, xBinning, yBinning, zBinning, xLog, yLog, zLog);
328 std::regex singleColon(
"\\w+(:{1})\\w+");
330 int nColons =
static_cast<int>(std::distance(std::sregex_iterator(variable.begin(),
333 std::sregex_iterator()));
334 if (nColons > nDim - 1)
336 std::string err =
"Error: Histogram \"" + histName +
"\" variable includes too many single\n";
337 err +=
"colons specifying more dimensions than the number of specified dimensions.\n";
338 err +=
"Declared dimensions: " + std::to_string(nDim) +
"\n";
339 err +=
"Number of dimensions in variables " + std::to_string(nColons + 1);
350 variable, selection, perEntry);
357 variable, selection, perEntry);
363 xBinning, yBinning, zBinning,
364 variable, selection, perEntry);
387 if (results.size() < 6)
388 {
throw RBDSException(
"Too few columns in spectra definition.");}
389 if (results.size() > 6)
390 {
throw RBDSException(
"Too many columns in spectra definition - check there's no extra whitespace");}
395 ParseLog(results[0], xLog, yLog, zLog);
397 bool perEntry =
true;
400 std::string variable =
".kineticEnergy";
402 {variable =
".energy";}
404 {variable =
".rigidity";}
406 std::string samplerName = results[1];
408 int nSpectraThisBranch = 0;
412 nSpectraThisBranch = search->second;
417 std::string histogramName = samplerName +
"_" + std::to_string(nSpectraThisBranch);
418 std::string selection = results[5];
423 ParseBins(results[2], 1, xBinning, yBinning, zBinning);
424 ParseBinning(results[3], 1, xBinning, yBinning, zBinning, xLog, yLog, zLog);
426 std::set<ParticleSpec> particles;
431 e.AppendToMessage(
"\nError in spectra particle definition.");
437 if (particles.empty() && !perEntry)
438 {
throw RBDSException(
"Simple spectra cannot be used with 'topN'- only works for specific particles");}
442 samplerName + variable,
443 selection, perEntry);
452 {eventHistoDefSetsPerEntry.push_back(result);}
462 if (results.size() < 2)
463 {
throw RBDSException(
"Too few columns in particle set definition.");}
464 if (results.size() > 2)
465 {
throw RBDSException(
"Too many columns in particle set definition - check there's no extra whitespace");}
467 std::string samplerName = results[1];
470 bool perEntry =
true;
475 {eventParticleSetSimpleBranches.push_back(samplerName);}
481 perEntry = res.find(
"simple") == std::string::npos;
485 const std::string& word)
const
489 return il.find(wl) != std::string::npos;
498 std::regex linLogWords(
"(Lin)|(Log)", std::regex_constants::icase);
499 std::sregex_token_iterator iter(definition.begin(), definition.end(), linLogWords);
500 std::sregex_token_iterator end;
501 std::vector<bool*> results = {&xLog, &yLog, &zLog};
503 for (; iter != end; ++iter, ++index)
505 std::string res =
LowerCase((*iter).str());
506 *(results[index]) = res ==
"log";
517 const std::string& var)
525 std::regex branchLeaf(
"(\\w+)\\.(\\w+)");
526 auto words_begin = std::sregex_iterator(var.begin(), var.end(), branchLeaf);
527 auto words_end = std::sregex_iterator();
528 for (std::sregex_iterator i = words_begin; i != words_end; ++i)
530 std::string targetBranch = (*i)[1];
536 const std::string& branchName)
539 if (std::find(v.begin(), v.end(), branchName) == v.end())
540 {v.push_back(branchName);}
546 if (strcmp(&treeName.back(),
".") != 0)
551 std::string err =
"Invalid tree name \"" + treeName +
"\"\n";
552 err +=
"Tree names are one of: ";
554 {err +=
"\"" + n +
"\" ";}
571 std::regex number(
"([0-9e\\+]+)+", std::regex_constants::icase);
572 int* binValues[3] = {&xBinning.n, &yBinning.n, &zBinning.n};
573 auto words_begin = std::sregex_iterator(bins.begin(), bins.end(), number);
574 auto words_end = std::sregex_iterator();
576 for (std::sregex_iterator i = words_begin; i != words_end; ++i, ++counter)
577 {(*binValues[counter]) = std::stoi((*i).str());}
578 if (counter < nDim-1)
579 {
throw RBDSException(
"Too few binning dimensions specified (N dimensions = " + std::to_string(nDim) +
") \"" + bins +
"\"");}
592 std::string binningL = binning;
593 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'{'), binningL.end());
594 binningL.erase(std::remove(binningL.begin(), binningL.end(),
'}'), binningL.end());
596 std::regex oneDim(
"([0-9eE.+-]+):([0-9eE.+-]+)");
598 std::regex commas(
",");
599 auto wordsBegin = std::sregex_token_iterator(binningL.begin(), binningL.end(), commas, -1);
600 auto wordsEnd = std::sregex_token_iterator();
602 std::vector<BinSpecification*> values = {&xBinning, &yBinning, &zBinning};
603 std::vector<bool> isLog = {xLog, yLog, zLog};
604 for (
auto i = wordsBegin; i != wordsEnd; ++i, ++counter)
606 std::string matchS = *i;
607 if (matchS.find(
".txt") != std::string::npos)
610 (*values[counter]).edges = binEdges;
611 (*values[counter]).n = (
int)binEdges->size() - 1;
612 (*values[counter]).low = binEdges->at(0);
613 (*values[counter]).high = binEdges->back();
617 auto rangeBegin = std::sregex_iterator(matchS.begin(), matchS.end(), oneDim);
618 auto rangeEnd = std::sregex_iterator();
619 int counterRange = 0;
620 for (
auto j = rangeBegin; j != rangeEnd; ++j, ++counterRange)
622 std::smatch matchR = *j;
625 (*values[counter]).low = std::stod(matchR[1]);
626 (*values[counter]).high = std::stod(matchR[2]);
628 catch (std::invalid_argument&)
629 {
throw RBDSException(
"Invalid binning number: \"" + matchS +
"\"");}
630 if ((*values[counter]).high <= (*values[counter]).low)
631 {
throw RBDSException(
"high bin edge is <= low bin edge \"" + binning +
"\"");}
634 std::vector<double> binEdges = RBDS::LogSpace((*values[counter]).low, (*values[counter]).high, (*values[counter]).n);
635 (*values[counter]).edges =
new std::vector<double>(binEdges);
642 {
throw RBDSException(
"Invalid binning specification: \"" + binning +
"\"");}
643 else if (counter < nDim)
645 std::string errString =
"Insufficient number of binning dimensions: \n"
646 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
647 + binning +
"\nDimension defined by \"low:high\" and comma separated";
650 else if (counter > nDim)
652 std::string errString =
"Too many binning dimension (i.e. commas) on line #"
654 + std::to_string(nDim) +
" dimension histogram, but the following was specified:\n"
655 + binning +
"\nDimension defined by \"low:high\" and comma separated";
662 std::vector<std::string> results;
663 std::regex wspace(
"\\s+");
665 std::sregex_token_iterator iter(line.begin(), line.end(), wspace, -1);
666 std::sregex_token_iterator end;
667 for (; iter != end; ++iter)
669 std::string res = (*iter).str();
670 results.push_back(res);
678 std::vector<std::string> specialKeys = {
"top",
"particles",
"all",
"ions"};
679 for (
const auto& key : specialKeys)
681 if (wordLower.find(key) != std::string::npos)
682 {
return std::set<ParticleSpec>();}
687 std::regex inBrackets(
"^\\{(.+)\\}$");
689 auto firstSearch = std::regex_search(word, match, inBrackets);
691 {
throw RBDSException(
"Invalid particle definition - no braces");}
694 std::string numbers = match[1];
695 std::set<ParticleSpec> result;
696 std::regex commas(
",");
698 std::sregex_token_iterator iter(numbers.begin(), numbers.end(), commas, -1);
699 std::sregex_token_iterator end;
700 for (; iter != end; ++iter)
702 std::string res = (*iter).str();
703 std::regex selection(
"^([a-zA-Z]){1}(\\d+)");
704 std::smatch matchSelection;
705 if (std::regex_search(res, matchSelection, selection))
707 auto keySearch = RBDS::spectraParticlesKeys.find(matchSelection[1]);
708 RBDS::SpectraParticles which;
709 if (keySearch != RBDS::spectraParticlesKeys.end())
710 {which = keySearch->second;}
712 {
throw RBDSException(
"Invalid particle specifier \"" + matchSelection[1].str() +
"\"");}
715 long long int id = std::stoll(matchSelection[2].str());
716 result.insert(ParticleSpec(
id, which));
718 catch (
const std::exception& e)
725 long long int id = std::stoll(res);
726 result.insert(ParticleSpec(
id, RBDS::SpectraParticles::all));
728 catch (
const std::exception& e)
737 std::string res = st;
738 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
745 std::regex setting(
"(\\w+)\\s+([\\-\\.\\/_\\w\\*]+)", std::regex_constants::icase);
747 if (std::regex_search(line, match, setting))
750 std::string value = match[2];
758 std::regex tfRegex(
"\\s*(true|false)\\s*", std::regex_constants::icase);
760 if (std::regex_search(value, tfMatch, tfRegex))
762 std::string flag = tfMatch[1];
764 std::regex tRegex(
"true", std::regex_constants::icase);
765 bool result = std::regex_search(flag, tMatch, tRegex);
779 {
throw RBDSException(
"Invalid option line \"" + line +
"\"");}
784 bool existsAlready = histogramNames.count(newHistName) > 0;
789 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 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)