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