BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
PerEntryHistogramSet.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2023.
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 "Event.hh"
20#include "HistogramDef.hh"
21#include "HistogramDefSet.hh"
22#include "PerEntryHistogram.hh"
23#include "PerEntryHistogramSet.hh"
24#include "SpectraParticles.hh"
25
26#include "BDSOutputROOTEventSampler.hh"
27#include "RBDSException.hh"
28
29#include <algorithm>
30#include <iterator>
31#include <map>
32#include <set>
33#include <string>
34#include <vector>
35
36//ClassImp(PerEntryHistogramSet)
37
38PerEntryHistogramSet::PerEntryHistogramSet(const HistogramDefSet* definitionIn,
39 Event* eventIn,
40 TChain* chainIn):
41 baseDefinition(definitionIn->baseDefinition),
42 event(eventIn),
43 chain(chainIn),
44 branchName(definitionIn->branchName),
45 dynamicallyStoreParticles(definitionIn->dynamicallyStoreParticles),
46 dynamicallyStoreIons(definitionIn->dynamicallyStoreIons),
47 nEntries(0),
48 what(definitionIn->what),
49 topN(definitionIn->topN),
50 sampler(nullptr)
51{
52 for (const auto& pSpecDef : definitionIn->definitions)
53 {
54 auto pSpec = pSpecDef.first;
55 auto def = pSpecDef.second;
56 PerEntryHistogram* hist = new PerEntryHistogram(def, chainIn);
57 histograms[pSpec] = hist;
58 histogramsByPDGID[pSpec.first] = hist;
59 allPerEntryHistograms.push_back(hist); // keep vector for quick iteration each Accumulate() call
60 if (pSpec.second == RBDS::SpectraParticles::all)
61 {
62 if (IsIon(pSpec.first))
63 {ions.insert(pSpec.first);}
64 else
65 {nonIons.insert(pSpec.first);}
66 }
67 }
68}
69
70void PerEntryHistogramSet::CreatePerEntryHistogram(long long int pdgID)
71{
72 allPDGIDs.insert(pdgID);
73 if (IsIon(pdgID))
74 {ions.insert(pdgID);}
75 else
76 {nonIons.insert(pdgID);}
77 // copy base definition
78 HistogramDef* def = baseDefinition->Clone();
79 def->histName = "Top" + std::to_string(topN) + "_Spectra_" + def->histName + "_" + std::to_string(pdgID);
80 def->selection = HistogramDefSet::AddPDGFilterToSelection(ParticleSpec(pdgID,RBDS::SpectraParticles::all),
81 def->selection,
82 branchName);
83
84 PerEntryHistogram* hist = new PerEntryHistogram(def, chain);
85 hist->AddNEmptyEntries(nEntries); // update to current number of events
86 histograms[ParticleSpec(pdgID, RBDS::SpectraParticles::all)] = hist;
87 histogramsByPDGID[pdgID] = hist;
88 allPerEntryHistograms.push_back(hist);
89}
90
91PerEntryHistogramSet::~PerEntryHistogramSet()
92{
93 delete baseDefinition;
94 for (auto kv : allPerEntryHistograms)
95 {delete kv;}
96}
97
99{
100 if (!sampler)
101 {
102 sampler = event->GetSampler(branchName + "."); // cache sampler
103 if (!sampler)
104 {throw RBDSException("Cannot find sampler \"" + branchName + "\" or Model tree was not stored");}
105 }
106}
107
109{
110 CheckSampler();
111
112 if (dynamicallyStoreParticles || dynamicallyStoreIons)
113 {
114 // for this event, form a set of pdgIDs and
115 // then ensure we have all prepare histograms
116 std::set<long long int> pdgIDSet(sampler->partID.begin(), sampler->partID.end());
117
118 // use vector because set cannot be appended to for set_difference
119 std::vector<long long int> missing;
120 std::set_difference(pdgIDSet.begin(), pdgIDSet.end(),
121 allPDGIDs.begin(), allPDGIDs.end(),
122 std::back_inserter(missing));
123 if (!missing.empty())
124 {
125 for (auto pdgID : missing)
126 {
127 bool isIon = IsIon(pdgID);
128 if ((isIon && dynamicallyStoreIons) || (!isIon && dynamicallyStoreParticles))
129 {CreatePerEntryHistogram(pdgID);}
130 }
131 }
132 }
133 nEntries += 1;
134 for (auto hist : allPerEntryHistograms)
135 {hist->AccumulateCurrentEntry(entryNumber);}
136}
137
139{
140 for (auto hist : allPerEntryHistograms)
141 {hist->Terminate();}
142}
143
144void PerEntryHistogramSet::Write(TDirectory* dir)
145{
146 if (what == HistogramDefSet::writewhat::all)
147 {
148 for (auto hist : allPerEntryHistograms)
149 {hist->Write(dir);}
150 }
151 else
152 {
153 // form a (sorted) vector of desired pdgIDs
154 std::vector<long long int> desiredPDGIDs;
155 switch (what)
156 {
157 case HistogramDefSet::writewhat::all:
158 {std::copy(allPDGIDs.begin(), allPDGIDs.end(), std::back_inserter(desiredPDGIDs)); break;}
159 case HistogramDefSet::writewhat::topN:
160 {desiredPDGIDs = TopN(topN); break;}
161 case HistogramDefSet::writewhat::ions:
162 {std::copy(ions.begin(), ions.end(), std::back_inserter(desiredPDGIDs)); break;}
163 case HistogramDefSet::writewhat::topNIons:
164 {desiredPDGIDs = TopNIons(topN); break;}
165 case HistogramDefSet::writewhat::particles:
166 {std::copy(nonIons.begin(), nonIons.end(), std::back_inserter(desiredPDGIDs)); break;}
167 case HistogramDefSet::writewhat::topNParticles:
168 {desiredPDGIDs = TopNNonIons(topN); break;}
169 }
170
171 for (auto pdgID : desiredPDGIDs)
172 {histogramsByPDGID.at(pdgID)->Write(dir);}
173 }
174}
175
176std::vector<long long int> PerEntryHistogramSet::TopUtility(const std::set<long long int>& s,
177 size_t n) const
178{
179 // map the pdg id to the total number (inc weight) of that particle histogrammed (per event)
180 std::map<long long int, double> integrals;
181 for (auto id : s)
182 {integrals[id] = histogramsByPDGID.at(id)->Integral();}
183
184 // reverse the mapping so the pdg ids are sorted by the integral, whilst tolerating
185 // multiple integrals of the same value (ie same rate)
186 std::multimap<double, long long int> sorted = BDS::flip_map(integrals);
187
188 // take advantage of a multimap being (by definition) ordered - therefore, the integrals
189 // are ordered low to high, so reverse iterate to get in decreasing order.
190 std::vector<long long int> topResult;
191 int i = 0;
192 int nInt = (int)n;
193 // reverse iterate up to the end of the result or n, whichever is smaller
194 for (auto it = sorted.rbegin(); it != sorted.rend() && i < nInt; it++, i++)
195 {topResult.push_back(it->second);}
196 return topResult;
197}
198
199std::vector<long long int> PerEntryHistogramSet::TopNNonIons(int n) const
200{
201 return TopUtility(nonIons, (size_t)n);
202}
203
204std::vector<long long int> PerEntryHistogramSet::TopNIons(int n) const
205{
206 return TopUtility(ions, (size_t)n);
207}
208
209std::vector<long long int> PerEntryHistogramSet::TopN(int n) const
210{
211 return TopUtility(allPDGIDs, (size_t)n);
212}
Event loader.
Definition: Event.hh:50
Specification for a set of histograms.
Common specification for a histogram.
Definition: HistogramDef.hh:34
virtual HistogramDef * Clone() const =0
Copy this instance. Virtual to be overridden in derived classes.
virtual void Write(TDirectory *dir=nullptr)
virtual void AccumulateCurrentEntry(long int entryNumber)
std::vector< long long int > TopN(int n) const
Get top part of set. Sorted in descending order of integral.
std::vector< long long int > TopNIons(int n) const
Get top part of set. Sorted in descending order of integral.
virtual void Terminate()
Terminate the accumulator and save the result to the result member variable.
std::vector< long long int > TopNNonIons(int n) const
Get top part of set. Sorted in descending order of integral.
std::vector< long long int > TopUtility(const std::set< long long int > &s, size_t n) const
Utility function to find top N in set s. Sorted in descending order of integral.
Holder for information to calculate per entry histograms.
virtual void Terminate()
Terminate the accumulator and save the result to the result member variable.
PerEntryHistogram()
Public constructor only for compatibility with ROOT - not intended for use.
virtual void Write(TDirectory *dir=nullptr)
virtual void AccumulateCurrentEntry(long int entryNumber)
void AddNEmptyEntries(unsigned long i)
General exception with possible name of object and message.
G4bool IsIon(const G4ParticleDefinition *particle)
Whether a particle is an ion. A proton is counted NOT as an ion.