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