BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
HistogramDefSet.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "HistogramDef.hh"
19#include "HistogramDefSet.hh"
20#include "RBDSException.hh"
21#include "SpectraParticles.hh"
22
23#include <map>
24#include <regex>
25#include <set>
26#include <stdexcept>
27#include <string>
28
29HistogramDefSet::HistogramDefSet(const std::string& branchNameIn,
30 const HistogramDef* baseDefinitionIn,
31 const std::set<ParticleSpec>& particlesSpecs,
32 const std::string& particleSpecificationIn,
33 const std::string& definitionLineIn):
34 branchName(branchNameIn),
35 dynamicallyStoreIons(false),
36 dynamicallyStoreParticles(particlesSpecs.empty()),
37 what(writewhat::all),
38 topN(1),
39 definitionLine(definitionLineIn),
40 samplerType(samplertype::plane)
41{
42 if (!baseDefinitionIn)
43 {throw std::invalid_argument("invalid histogram definition");}
44
45 baseDefinition = baseDefinitionIn->Clone();
46
47 if (!particlesSpecs.empty())
48 {
49 for (const auto& particleSpec : particlesSpecs)
50 {
51 HistogramDef* h = baseDefinitionIn->Clone();
52 std::string thisHistName = "Spectra_" + h->histName + "_";
53 if (particleSpec.first > 0) // prepend + character for positive values so we always have + or -
54 {thisHistName += "+";}
55 thisHistName += std::to_string(particleSpec.first);
56 h->histName = thisHistName;
57 std::string suffix;
58 switch (particleSpec.second)
59 {
60 case RBDS::SpectraParticles::primary:
61 {suffix = "_Primary"; break;}
62 case RBDS::SpectraParticles::secondary:
63 {suffix = "_Secondary"; break;}
64 default:
65 {break;}
66 }
67 h->histName += suffix;
68 h->selection = AddPDGFilterToSelection(particleSpec, h->selection, branchName);
69 definitions[particleSpec] = h;
70 definitionsV.push_back(h);
71 }
72 }
73 else
74 {
75 std::string spec = particleSpecificationIn;
76 std::transform(spec.begin(), spec.end(), spec.begin(), ::tolower);
77 spec = RemoveSubString(spec, "{");
78 spec = RemoveSubString(spec, "}");
79
80 if (spec.find("all") != std::string::npos || spec.find("ions") != std::string::npos)
81 {dynamicallyStoreIons = true;}
82 if (spec.find("all") != std::string::npos || spec.find("particles") != std::string::npos)
83 {dynamicallyStoreParticles = true;}
84
85 std::map<std::string, writewhat> keys = {{"all", writewhat::all},
86 {"particles", writewhat::particles},
87 {"ions", writewhat::ions}};
88
89 auto search = keys.find(spec);
90 if (search != keys.end())
91 {what = search->second;}
92 else
93 {
94 std::regex topNR("top(\\d+)(?:particles|ions)*");
95 std::smatch match;
96 if (std::regex_search(spec, match, topNR))
97 {
98 try
99 {topN = std::stoi(match[1]);}
100 catch (...)
101 {topN = 1;}
102 if (spec.find("particles") != std::string::npos)
103 {what = writewhat::topNParticles;}
104 else if (spec.find("ions") != std::string::npos)
105 {what = writewhat::topNIons;}
106 else
107 {what = writewhat::topN;}
108 }
109 else // this will happen if 'top' isn't in the specification or it generally doesn't match
110 {throw RBDSException("Invalid particle specifier \"" + particleSpecificationIn + "\"");}
111 }
112 }
113}
114
115HistogramDefSet::~HistogramDefSet()
116{
117 delete baseDefinition;
118 for (auto kv : definitions)
119 {delete kv.second;}
120}
121
122std::string HistogramDefSet::RemoveSubString(const std::string& stringIn,
123 const std::string& wordToRemove) const
124{
125 std::string result = stringIn;
126 while (result.find(wordToRemove) != std::string::npos)
127 {
128 size_t pos = result.find(wordToRemove);
129 result.erase(pos, wordToRemove.size());
130 }
131 return result;
132}
133
134void HistogramDefSet::ReplaceStringInVariable(const std::string& match,
135 const std::string& replacement)
136{
137 baseDefinition->ReplaceStringInVariable(match, replacement);
138 for (auto* def : definitionsV)
139 {def->ReplaceStringInVariable(match, replacement);}
140}
141
142std::ostream& operator<< (std::ostream &out, const HistogramDefSet& s)
143{
144 out << "Spectra: " << s.baseDefinition->histName;
145 if (!s.definitionLine.empty())
146 {out << ": \"" << s.definitionLine << "\"";}
147 out << "\n";
148 for (const auto* d : s.definitionsV)
149 {out << *d;}
150 return out;
151}
152
153std::string HistogramDefSet::AddPDGFilterToSelection(const ParticleSpec& particleSpec,
154 const std::string& selection,
155 const std::string& branchName)
156{
157 long long int pdgID = particleSpec.first;
158
159 if (pdgID == 0) // '0' is our code for total or really all particles in 1x histogram
160 {return selection;} // just return whatever selection is
161
162 RBDS::SpectraParticles flag = particleSpec.second;
163 std::string flagFilter;
164 switch (flag)
165 {
166 case RBDS::SpectraParticles::primary:
167 {flagFilter = "&&" + branchName + ".parentID==0"; break;}
168 case RBDS::SpectraParticles::secondary:
169 {flagFilter = "&&" + branchName + ".parentID>0"; break;}
170 default:
171 {break;}
172 }
173 std::string filter = branchName+".partID=="+std::to_string(pdgID) + flagFilter;
174
175 // input selection could be:
176 // 1
177 // samplerName.weight
178 // samplerName.variable*number/number
179 // samplerName.variable<value // Boolean expression
180 // variable*(Boolean)
181 // we need to put in the bonus Boolean if needed
182 // check if it has a Boolean expression already in it
183 std::string result;
184 std::regex boolOperator("&&|[<>!=]=|[<>]|\\|\\|");
185 std::smatch match;
186 if (std::regex_search(selection, match, boolOperator))
187 {// has boolean operator somewhere in it
188 std::string afterBool = match.suffix();
189 std::size_t bracketPos = afterBool.find(')');
190 result = selection; // copy it
191 if (bracketPos == std::string::npos) // no bracket found - so just Boolean condition on its own
192 {result += "&&" + filter;}
193 else
194 {result.insert(match.position()+ match.length() + bracketPos, "&&"+filter);}
195 }
196 else if (selection.empty() || selection == "1") // technically the selection shouldn't be empty, but just in case...
197 {result = filter;}
198 else
199 {result = selection + "*("+filter+")";}
200 return result;
201}
202
Specification for a set of histograms.
std::vector< HistogramDef * > definitionsV
Vector version for easy iteration.
std::string RemoveSubString(const std::string &stringIn, const std::string &wordToRemove) const
Remove a substring from a string.
std::string definitionLine
Original definition line purely for print out.
Common specification for a histogram.
void ReplaceStringInVariable(const std::string &match, const std::string &replacement)
Little utility function.
virtual HistogramDef * Clone() const =0
Copy this instance. Virtual to be overridden in derived classes.
General exception with possible name of object and message.