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 - 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 "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 CheckSampler();
101
102 if (dynamicallyStoreParticles || dynamicallyStoreIons)
103 {
104 // for this event, form a set of pdgIDs and
105 // then ensure we have all prepare histograms
106 std::set<long long int> pdgIDSet;
107 GetPDGIDSetFromSampler(pdgIDSet);
108
109 // use vector because set cannot be appended to for set_difference
110 std::vector<long long int> missing;
111 std::set_difference(pdgIDSet.begin(), pdgIDSet.end(),
112 allPDGIDs.begin(), allPDGIDs.end(),
113 std::back_inserter(missing));
114 if (!missing.empty())
115 {
116 for (auto pdgID : missing)
117 {
118 bool isIon = IsIon(pdgID);
119 if ((isIon && dynamicallyStoreIons) || (!isIon && dynamicallyStoreParticles))
120 {CreatePerEntryHistogram(pdgID);}
121 }
122 }
123 }
124 nEntries += 1;
125 for (auto hist : allPerEntryHistograms)
126 {hist->AccumulateCurrentEntry(entryNumber);}
127}
128
130{
131 for (auto hist : allPerEntryHistograms)
132 {hist->Terminate();}
133}
134
135void PerEntryHistogramSet::Write(TDirectory* dir)
136{
137 if (what == HistogramDefSet::writewhat::all)
138 {
139 for (auto hist : allPerEntryHistograms)
140 {hist->Write(dir);}
141 }
142 else
143 {
144 // form a (sorted) vector of desired pdgIDs
145 std::vector<long long int> desiredPDGIDs;
146 switch (what)
147 {
148 case HistogramDefSet::writewhat::all:
149 {std::copy(allPDGIDs.begin(), allPDGIDs.end(), std::back_inserter(desiredPDGIDs)); break;}
150 case HistogramDefSet::writewhat::topN:
151 {desiredPDGIDs = TopN(topN); break;}
152 case HistogramDefSet::writewhat::ions:
153 {std::copy(ions.begin(), ions.end(), std::back_inserter(desiredPDGIDs)); break;}
154 case HistogramDefSet::writewhat::topNIons:
155 {desiredPDGIDs = TopNIons(topN); break;}
156 case HistogramDefSet::writewhat::particles:
157 {std::copy(nonIons.begin(), nonIons.end(), std::back_inserter(desiredPDGIDs)); break;}
158 case HistogramDefSet::writewhat::topNParticles:
159 {desiredPDGIDs = TopNNonIons(topN); break;}
160 }
161
162 for (auto pdgID : desiredPDGIDs)
163 {histogramsByPDGID.at(pdgID)->Write(dir);}
164 }
165}
166
167std::vector<long long int> PerEntryHistogramSet::TopUtility(const std::set<long long int>& s,
168 size_t n) const
169{
170 // map the pdg id to the total number (inc weight) of that particle histogrammed (per event)
171 std::map<long long int, double> integrals;
172 for (auto id : s)
173 {integrals[id] = histogramsByPDGID.at(id)->Integral();}
174
175 // reverse the mapping so the pdg ids are sorted by the integral, whilst tolerating
176 // multiple integrals of the same value (ie same rate)
177 std::multimap<double, long long int> sorted = BDS::flip_map(integrals);
178
179 // take advantage of a multimap being (by definition) ordered - therefore, the integrals
180 // are ordered low to high, so reverse iterate to get in decreasing order.
181 std::vector<long long int> topResult;
182 int i = 0;
183 int nInt = (int)n;
184 // reverse iterate up to the end of the result or n, whichever is smaller
185 for (auto it = sorted.rbegin(); it != sorted.rend() && i < nInt; it++, i++)
186 {topResult.push_back(it->second);}
187 return topResult;
188}
189
190std::vector<long long int> PerEntryHistogramSet::TopNNonIons(int n) const
191{
192 return TopUtility(nonIons, (size_t)n);
193}
194
195std::vector<long long int> PerEntryHistogramSet::TopNIons(int n) const
196{
197 return TopUtility(ions, (size_t)n);
198}
199
200std::vector<long long int> PerEntryHistogramSet::TopN(int n) const
201{
202 return TopUtility(allPDGIDs, (size_t)n);
203}
Event loader.
Definition Event.hh:50
Specification for a set of histograms.
Common specification for a histogram.
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 GetPDGIDSetFromSampler(std::set< long long int > &setIn) const =0
virtual void CheckSampler()=0
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)
G4bool IsIon(const G4ParticleDefinition *particle)
Whether a particle is an ion. A proton is counted NOT as an ion.