BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
EventAnalysis.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 "BDSOutputROOTEventBeam.hh"
19#include "BDSOutputROOTEventHistograms.hh"
20#include "BDSOutputROOTEventLoss.hh"
21#include "BDSOutputROOTEventTrajectory.hh"
22#include "Config.hh"
23#include "Event.hh"
24#include "EventAnalysis.hh"
25#include "HistogramMeanFromFile.hh"
26#include "PerEntryHistogramSet.hh"
27#include "PerEntryHistogramSetPlane.hh"
28#include "PerEntryHistogramSetC.hh"
29#include "PerEntryHistogramSetS.hh"
30#include "RBDSException.hh"
31#include "SamplerAnalysis.hh"
32#include "rebdsim.hh"
33
34#include "TChain.h"
35#include "TDirectory.h"
36#include "TFile.h"
37
38#include <cmath>
39#include <iomanip>
40#include <iostream>
41#include <string>
42#include <vector>
43
44ClassImp(EventAnalysis)
45
47 Analysis("Event.", nullptr, "EventHistogramsMerged"),
48 event(nullptr),
49 printOut(false),
50 printModulo(1),
51 processSamplers(false),
52 emittanceOnTheFly(false),
53 eventStart(0),
54 eventEnd(-1),
55 nEventsToProcess(0)
56{;}
57
59 TChain* chainIn,
60 bool perEntryAnalysis,
61 bool processSamplersIn,
62 bool debugIn,
63 bool printOutIn,
64 double printModuloFraction,
65 bool emittanceOnTheFlyIn,
66 long int eventStartIn,
67 long int eventEndIn,
68 const std::string& primaryParticleName):
69 Analysis("Event.", chainIn, "EventHistogramsMerged", perEntryAnalysis, debugIn),
70 event(eventIn),
71 printOut(printOutIn),
72 printModulo(1),
73 processSamplers(processSamplersIn),
74 emittanceOnTheFly(emittanceOnTheFlyIn),
75 eventStart(eventStartIn),
76 eventEnd(eventEndIn),
77 nEventsToProcess(eventEndIn - eventStartIn)
78{
79 // check we get this right for print out normalisation
80 if (eventEndIn == -1)
81 {nEventsToProcess = (long int)chainIn->GetEntries();}
82
84 {// Create sampler analyses if needed
85 // Analyse the primary sampler in the optics too.
86 SamplerAnalysis* sa = nullptr;
87 SamplerAnalysis* pa = nullptr;
88 if (event->UsePrimaries())
89 {
91 samplerAnalyses.push_back(sa);
92 pa = sa;
93 }
94
95 for (const auto& sampler : event->Samplers)
96 {
97 sa = new SamplerAnalysis(sampler, debug);
98 samplerAnalyses.push_back(sa);
99 }
100 if (!event->UsePrimaries())
101 {
102 if (!samplerAnalyses.empty())
103 {pa = samplerAnalyses[0];}
104 }
105
106 chain->GetEntry(0);
107 if (!primaryParticleName.empty())
108 {SamplerAnalysis::UpdateMass(primaryParticleName);}
109 else if (pa)
111 else
112 {throw RBDSException("No samplers and no particle name - unable to calculate optics without mass of particle");}
113 }
114
115 SetPrintModuloFraction(printModuloFraction);
116}
117
119{
120 std::cout << "Analysis on \"" << treeName << "\" beginning" << std::endl;
122 {
123 // ensure new histograms are added to file
124 // crucial for draw command to work as it identifies the histograms by name
125 TH1::AddDirectory(kTRUE);
126 TH2::AddDirectory(kTRUE);
127 TH3::AddDirectory(kTRUE);
128 BDSBH4DBase::AddDirectory(kTRUE);
130 PreparePerEntryHistogramSets();
131 Process();
132 }
134 Terminate();
135 std::cout << "Analysis on \"" << treeName << "\" complete" << std::endl;
136}
137
139{
140 printModulo = (int)std::ceil((double)nEventsToProcess * fraction);
141 if (printModulo <= 0)
142 {printModulo = 1;}
143}
144
145EventAnalysis::~EventAnalysis() noexcept
146{
147 for (auto& sa : samplerAnalyses)
148 {delete sa;}
149 for (auto& hs : perEntryHistogramSets)
150 {delete hs;}
151}
152
154{
155 Initialise();
156
157 if (debug)
158 {std::cout << __METHOD_NAME__ << "Entries: " << chain->GetEntries() << " " << std::endl;}
159
160 // loop over events
161 if (eventEnd < 0)
162 {eventEnd = entries;}
163 if (eventEnd > entries)
164 {
165 std::cerr << "EventEnd " << eventEnd << " > entries (" << entries
166 << ") in file(s) -> curtailing to # of entries!" << std::endl;
168 }
169 bool firstLoop = true;
170 for (auto i = (Long64_t)eventStart; i < (Long64_t)eventEnd; ++i)
171 {
172 if (firstLoop) // ensure samplers setup for spectra before we load data
173 {CheckSpectraBranches();}
174
175 event->Flush();
176 Int_t bytesLoaded = chain->GetEntry(i);
177 if (debug)
178 {std::cout << __METHOD_NAME__ << i << ": " << bytesLoaded << " bytes loaded" << std::endl;}
179 // event analysis feedback
180 if (i % printModulo == 0 && printOut)
181 {
182 std::cout << "\rEvent #" << std::setw(8) << i << " of " << entries;
183 if (!debug)
184 {std::cout.flush();}
185 else
186 {std::cout << std::endl;}
187 }
188
189 // merge histograms stored per event in the output
190 if (firstLoop)
192 else
194
195 // per event histograms
197 AccumulatePerEntryHistogramSets(i);
198
199 UserProcess();
200
201 if (debug && processSamplers)
202 {
203 std::cout << __METHOD_NAME__ << "Vector lengths" << std::endl;
204 std::cout << __METHOD_NAME__ << "primaries=" << event->Primary->n << std::endl;
205 std::cout << __METHOD_NAME__ << "eloss=" << event->Eloss->n << std::endl;
206 std::cout << __METHOD_NAME__ << "nprimary=" << event->PrimaryFirstHit->n << std::endl;
207 std::cout << __METHOD_NAME__ << "nlast=" << event->PrimaryLastHit->n << std::endl;
208 std::cout << __METHOD_NAME__ << "ntunnel=" << event->TunnelHit->n << std::endl;
209 std::cout << __METHOD_NAME__ << "ntrajectory=" << event->Trajectory->n << std::endl;
210 }
211
212 if (processSamplers)
213 {ProcessSamplers(firstLoop);}
214 if (firstLoop)
215 {firstLoop = false;} // set to false on first pass of loop
216 }
217 std::cout << "\rSampler analysis complete " << std::endl;
218}
219
220void EventAnalysis::CheckSpectraBranches()
221{
222 for (auto s : perEntryHistogramSets)
223 {s->CheckSampler();}
224}
225
227{
229 TerminatePerEntryHistogramSets();
230
231 if (processSamplers)
232 {
233 //vector of emittance values and errors: emitt_x, emitt_y, err_emitt_x, err_emitt_y
234 std::vector<double> emittance = {0,0,0,0};
235 for (auto& samplerAnalysis : samplerAnalyses)
236 {
237 emittance = samplerAnalysis->Terminate(emittance, !emittanceOnTheFly);
238 opticalFunctions.push_back(samplerAnalysis->GetOpticalFunctions());
239 }
240 }
241}
242
244{
246
247 auto setDefinitions = Config::Instance()->EventHistogramSetDefinitionsSimple();
248 for (auto definition : setDefinitions)
249 {FillHistogram(definition);}
250}
251
252void EventAnalysis::Write(TFile* outputFile)
253{
254 // Write rebdsim histograms:
255 Analysis::Write(outputFile);
256
257 // histogram sets done in this derived class because they only apply to the Event tree
258 std::string peSetsDirName = "PerEntryHistogramSets";
259 std::string siSetsDirName = "SimpleHistogramSets";
260 std::string cleanedName = treeName;
261 TDirectory* treeDir = outputFile->GetDirectory(cleanedName.c_str());
262 TDirectory* peSetsDir = treeDir->mkdir(peSetsDirName.c_str());
263 TDirectory* siSetsDir = treeDir->mkdir(siSetsDirName.c_str());
264
265 // per entry histogram sets
266 peSetsDir->cd();
267 for (auto s : perEntryHistogramSets)
268 {s->Write(peSetsDir);}
269 outputFile->cd("/");
270
271 // simple histogram sets
272 siSetsDir->cd();
273 for (const auto& set : simpleSetHistogramOutputs)
274 {
275 for (auto h : set.second)
276 {
277 siSetsDir->Add(h);
278 h->Write();
279 }
280 }
281 outputFile->cd("/");
282
283 // We don't need to write out the optics tree if we didn't process samplers
284 // as there's no possibility of optical data.
285 if (!processSamplers)
286 {return;}
287
288 outputFile->cd("/");
289
290 std::vector<double> xOpticsPoint;
291 std::vector<double> yOpticsPoint;
292 std::vector<double> lOpticsPoint;
293 xOpticsPoint.resize(25);
294 yOpticsPoint.resize(25);
295 lOpticsPoint.resize(25);
296
297 // write optical functions
298 TTree* opticsTree = new TTree("Optics","Optics");
299 opticsTree->Branch("Emitt_x", &(xOpticsPoint[0]), "Emitt_x/D");
300 opticsTree->Branch("Emitt_y", &(yOpticsPoint[0]), "Emitt_y/D");
301 opticsTree->Branch("Alpha_x", &(xOpticsPoint[1]), "Alpha_x/D");
302 opticsTree->Branch("Alpha_y", &(yOpticsPoint[1]), "Alpha_y/D");
303 opticsTree->Branch("Beta_x", &(xOpticsPoint[2]), "Beta_x/D");
304 opticsTree->Branch("Beta_y", &(yOpticsPoint[2]), "Beta_y/D");
305 opticsTree->Branch("Gamma_x", &(xOpticsPoint[3]), "Gamma_x/D");
306 opticsTree->Branch("Gamma_y", &(yOpticsPoint[3]), "Gamma_y/D");
307 opticsTree->Branch("Disp_x", &(xOpticsPoint[4]), "Disp_x/D");
308 opticsTree->Branch("Disp_y", &(yOpticsPoint[4]), "Disp_y/D");
309 opticsTree->Branch("Disp_xp", &(xOpticsPoint[5]), "Disp_xp/D");
310 opticsTree->Branch("Disp_yp", &(yOpticsPoint[5]), "Disp_yp/D");
311 opticsTree->Branch("Mean_x", &(xOpticsPoint[6]), "Mean_x/D");
312 opticsTree->Branch("Mean_y", &(yOpticsPoint[6]), "Mean_y/D");
313 opticsTree->Branch("Mean_xp", &(xOpticsPoint[7]), "Mean_xp/D");
314 opticsTree->Branch("Mean_yp", &(yOpticsPoint[7]), "Mean_yp/D");
315 opticsTree->Branch("Sigma_x", &(xOpticsPoint[8]), "Sigma_x/D");
316 opticsTree->Branch("Sigma_y", &(yOpticsPoint[8]), "Sigma_y/D");
317 opticsTree->Branch("Sigma_xp",&(xOpticsPoint[9]), "Sigma_xp/D");
318 opticsTree->Branch("Sigma_yp",&(yOpticsPoint[9]), "Sigma_yp/D");
319 opticsTree->Branch("S" ,&(xOpticsPoint[10]),"S/D");
320 opticsTree->Branch("Npart" ,&(xOpticsPoint[11]),"Npart/D");
321
322 opticsTree->Branch("Sigma_Emitt_x", &(xOpticsPoint[12]), "Sigma_Emitt_x/D");
323 opticsTree->Branch("Sigma_Emitt_y", &(yOpticsPoint[12]), "Sigma_Emitt_y/D");
324 opticsTree->Branch("Sigma_Alpha_x", &(xOpticsPoint[13]), "Sigma_Alpha_x/D");
325 opticsTree->Branch("Sigma_Alpha_y", &(yOpticsPoint[13]), "Sigma_Alpha_y/D");
326 opticsTree->Branch("Sigma_Beta_x", &(xOpticsPoint[14]), "Sigma_Beta_x/D");
327 opticsTree->Branch("Sigma_Beta_y", &(yOpticsPoint[14]), "Sigma_Beta_y/D");
328 opticsTree->Branch("Sigma_Gamma_x", &(xOpticsPoint[15]), "Sigma_Gamma_x/D");
329 opticsTree->Branch("Sigma_Gamma_y", &(yOpticsPoint[15]), "Sigma_Gamma_y/D");
330 opticsTree->Branch("Sigma_Disp_x", &(xOpticsPoint[16]), "Sigma_Disp_x/D");
331 opticsTree->Branch("Sigma_Disp_y", &(yOpticsPoint[16]), "Sigma_Disp_y/D");
332 opticsTree->Branch("Sigma_Disp_xp", &(xOpticsPoint[17]), "Sigma_Disp_xp/D");
333 opticsTree->Branch("Sigma_Disp_yp", &(yOpticsPoint[17]), "Sigma_Disp_yp/D");
334 opticsTree->Branch("Sigma_Mean_x", &(xOpticsPoint[18]), "Sigma_Mean_x/D");
335 opticsTree->Branch("Sigma_Mean_y", &(yOpticsPoint[18]), "Sigma_Mean_y/D");
336 opticsTree->Branch("Sigma_Mean_xp", &(xOpticsPoint[19]), "Sigma_Mean_xp/D");
337 opticsTree->Branch("Sigma_Mean_yp", &(yOpticsPoint[19]), "Sigma_Mean_yp/D");
338 opticsTree->Branch("Sigma_Sigma_x", &(xOpticsPoint[20]), "Sigma_Sigma_x/D");
339 opticsTree->Branch("Sigma_Sigma_y", &(yOpticsPoint[20]), "Sigma_Sigma_y/D");
340 opticsTree->Branch("Sigma_Sigma_xp",&(xOpticsPoint[21]), "Sigma_Sigma_xp/D");
341 opticsTree->Branch("Sigma_Sigma_yp",&(yOpticsPoint[21]), "Sigma_Sigma_yp/D");
342
343 opticsTree->Branch("Mean_E", &(lOpticsPoint[6]), "Mean_E/D");
344 opticsTree->Branch("Mean_t", &(lOpticsPoint[7]), "Mean_t/D");
345 opticsTree->Branch("Sigma_E", &(lOpticsPoint[8]), "Sigma_E/D");
346 opticsTree->Branch("Sigma_t", &(lOpticsPoint[9]), "Sigma_t/D");
347 opticsTree->Branch("Sigma_Mean_E", &(lOpticsPoint[18]), "Sigma_Mean_E/D");
348 opticsTree->Branch("Sigma_Mean_t", &(lOpticsPoint[19]), "Sigma_Mean_t/D");
349 opticsTree->Branch("Sigma_Sigma_E", &(lOpticsPoint[20]), "Sigma_Sigma_E/D");
350 opticsTree->Branch("Sigma_Sigma_t", &(lOpticsPoint[21]), "Sigma_Sigma_t/D");
351
352 opticsTree->Branch("xyCorrelationCoefficent", &(xOpticsPoint[24]), "xyCorrelationCoefficent/D");
353
354 for(const auto& entry : opticalFunctions)
355 {
356 xOpticsPoint = entry[0];
357 yOpticsPoint = entry[1];
358 lOpticsPoint = entry[2];
359 opticsTree->Fill();
360 }
361 opticsTree->Write();
362}
363
365{
366 if (processSamplers)
367 {
368 for (auto s : samplerAnalyses)
369 {s->Process(firstTime);}
370 }
371}
372
374{
375 if (processSamplers)
376 {
377 for (auto s : samplerAnalyses)
378 {s->Initialise();}
379 }
380}
381
382void EventAnalysis::PreparePerEntryHistogramSets()
383{
384 auto c = Config::Instance();
385 if (c)
386 {
387 auto setDefinitions = c->EventHistogramSetDefinitionsPerEntry();
388 for (const auto& def : setDefinitions)
390 }
391}
392
394 Event* eventIn,
395 TChain* chainIn) const
396{
397 if (!definitionIn)
398 {return nullptr;}
399
400 PerEntryHistogramSet* result = nullptr;
401 switch (definitionIn->samplerType)
402 {
403 case HistogramDefSet::samplertype::plane:
404 {result = new PerEntryHistogramSetPlane(definitionIn, eventIn, chainIn); break;}
405 case HistogramDefSet::samplertype::cylindrical:
406 {result = new PerEntryHistogramSetC(definitionIn, eventIn, chainIn); break;}
407 case HistogramDefSet::samplertype::spherical:
408 {result = new PerEntryHistogramSetS(definitionIn, eventIn, chainIn); break;}
409 default:
410 {break;}
411 }
412 return result;
413}
414
415void EventAnalysis::AccumulatePerEntryHistogramSets(long int entryNumber)
416{
417 for (auto& peSet : perEntryHistogramSets)
418 {peSet->AccumulateCurrentEntry(entryNumber);}
419}
420
421void EventAnalysis::TerminatePerEntryHistogramSets()
422{
423 for (auto& peSet : perEntryHistogramSets)
424 {peSet->Terminate();}
425}
426
428{
429 std::vector<TH1*> outputHistograms;
430 for (auto def : definition->definitionsV)
431 {Analysis::FillHistogram(def, &outputHistograms);}
432 simpleSetHistogramOutputs[definition] = outputHistograms;
433}
Base class for any TTree analysis.
Definition Analysis.hh:43
virtual void Terminate()
Definition Analysis.cc:122
virtual void SimpleHistograms()
Process histogram definitions from configuration instance.
Definition Analysis.cc:85
void PreparePerEntryHistograms()
Create structures necessary for per entry histograms.
Definition Analysis.cc:99
long int entries
Number of entries in the chain.
Definition Analysis.hh:98
bool debug
Whether debug print out is used or not.
Definition Analysis.hh:97
HistogramMeanFromFile * histoSum
Merge of per event stored histograms.
Definition Analysis.hh:96
void AccumulatePerEntryHistograms(long int entryNumber)
Accumulate means and variances for per entry histograms.
Definition Analysis.cc:110
virtual void Write(TFile *outputFile)
Write rebdsim histograms.
Definition Analysis.cc:130
virtual void UserProcess()
Virtual function for user to overload and use. Does nothing by default.
Definition Analysis.cc:82
bool perEntry
Whether to analyse each entry in the tree in a for loop or not.
Definition Analysis.hh:99
void FillHistogram(HistogramDef *definition, std::vector< TH1 * > *outputHistograms=nullptr)
Create an individual histogram based on a definition.
Definition Analysis.cc:165
static Config * Instance(const std::string &fileName="", const std::string &inputFilePath="", const std::string &outputFileName="", const std::string &defaultOutputFileSuffix="_ana")
Singleton accessor.
Definition Config.cc:153
Event level analysis.
std::vector< PerEntryHistogramSet * > perEntryHistogramSets
Cache of all per entry histogram sets.
void FillHistogram(HistogramDefSet *definition)
Fill a set of simple histograms across all events.
void Initialise()
Initialise each sampler analysis object in samplerAnalysis.
bool printOut
Whether to print out at all per-event.
Event * event
Event object that data loaded from the file will be loaded into.
bool processSamplers
Whether to process samplers.
long int eventEnd
Event index to end analysis at.
virtual void Process()
Operate on each entry in the event tree.
virtual void SimpleHistograms()
Process histogram definitions from configuration instance.
int printModulo
Cache of print modulo fraction.
PerEntryHistogramSet * ConstructPerEntryHistogramSet(const HistogramDefSet *definitionIn, Event *eventIn, TChain *chainIn) const
std::vector< std::vector< std::vector< double > > > opticalFunctions
Optical functions from all samplers.
void ProcessSamplers(bool firstTime=false)
Process each sampler analysis object.
std::vector< SamplerAnalysis * > samplerAnalyses
Holder for sampler analysis objects.
virtual void Execute()
std::map< HistogramDefSet *, std::vector< TH1 * > > simpleSetHistogramOutputs
Map of simple histograms created per histogram set for writing out.
virtual void Write(TFile *outputFileName)
Write analysis including optical functions to an output file.
long int nEventsToProcess
Difference between start and stop.
virtual void Terminate()
Terminate each individual sampler analysis and append optical functions.
bool emittanceOnTheFly
Whether to calculate emittance fresh at each sampler.
long int eventStart
Event index to start analysis from.
void SetPrintModuloFraction(double fraction)
Set how often to print out information about the event.
Event loader.
Definition Event.hh:49
BDSOutputROOTEventSampler< double > * GetPrimaries()
Accessor.
Definition Event.hh:60
BDSOutputROOTEventHistograms * Histos
Local variable ROOT data is mapped to.
Definition Event.hh:145
bool UsePrimaries() const
Whether there is primary data in the output file.
Definition Event.hh:105
Specification for a set of histograms.
std::vector< HistogramDef * > definitionsV
Vector version for easy iteration.
Accumulator to merge pre-made per-entry histograms.
void Accumulate(BDSOutputROOTEventHistograms *hNew)
Histogram over a set of integers not number line.
Histogram over a set of integers not number line.
Histogram over a set of integers not number line.
Histogram over a set of integers not number line.
General exception with possible name of object and message.
Analysis routines for an individual sampler.
static void UpdateMass(SamplerAnalysis *s)
Set primary particle mass for optical functions from sampler data.