BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
DataLoader.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 "DataLoader.hh"
20#include "Beam.hh"
21#include "Event.hh"
22#include "FileMapper.hh"
23#include "ParticleData.hh"
24#include "Header.hh"
25#include "Model.hh"
26#include "Options.hh"
27#include "RBDSException.hh"
28#include "RebdsimTypes.hh"
29#include "Run.hh"
30
31#include "BDSDebug.hh"
32#include "BDSOutputROOTEventAperture.hh"
33#include "BDSOutputROOTEventCollimator.hh"
34#include "BDSOutputROOTEventSampler.hh"
35#include "BDSVersionData.hh"
36
37#include "TChain.h"
38#include "TFile.h"
39
40#include <algorithm>
41#include <cmath>
42#include <glob.h>
43#include <iostream>
44
45ClassImp(DataLoader)
46
47DataLoader::DataLoader(const std::string& fileName,
48 bool debugIn,
49 bool processSamplersIn,
50 bool allBranchesOnIn,
51 const RBDS::BranchMap* branchesToTurnOnIn,
52 bool backwardsCompatibleIn):
53 debug(debugIn),
54 processSamplers(processSamplersIn),
55 allBranchesOn(allBranchesOnIn),
56 branchesToTurnOn(branchesToTurnOnIn),
57 backwardsCompatible(backwardsCompatibleIn),
58 parChain(nullptr),
59 dataVersion(BDSIM_DATA_VERSION)
60{
61 CommonCtor(fileName);
62}
63
64DataLoader::~DataLoader()
65{
66 delete hea;
67 delete par;
68 delete bea;
69 delete opt;
70 delete mod;
71 delete evt;
72 delete run;
73
74 delete heaChain;
75 delete beaChain;
76 delete optChain;
77 delete modChain;
78 delete evtChain;
79 delete runChain;
80}
81
82void DataLoader::CommonCtor(const std::string& fileName)
83{
84 BuildInputFileList(fileName); // updates dataVersion
85
86 hea = new Header(debug);
87 par = new ParticleData(debug);
88 bea = new Beam(debug);
89 opt = new Options(debug);
90 mod = new Model(debug, dataVersion);
91 evt = new Event(debug, processSamplers, dataVersion);
92 run = new Run(debug, dataVersion);
93
94 heaChain = new TChain("Header", "Header");
95 if (dataVersion > 6)
96 {parChain = new TChain("ParticleData", "ParticleData");}
97 beaChain = new TChain("Beam", "Beam");
98 optChain = new TChain("Options", "Options");
99 modChain = new TChain("Model", "Model");
100 evtChain = new TChain("Event", "Event");
101 runChain = new TChain("Run", "Run");
102
105 ChainTrees();
106 SetBranchAddress(allBranchesOn, branchesToTurnOn);
107
108 if (dataVersion > 6)
109 {
110 parChain->GetEntry(0); // load particle data
111#ifdef __ROOTDOUBLE__
113#else
115 BDSOutputROOTEventCollimator::particleTable = par->particleData;
116 BDSOutputROOTEventAperture::particleTable = par->particleData;
117#endif
118 }
119}
120
121void DataLoader::BuildInputFileList(std::string inputPath)
122{
123 if (inputPath.empty())
124 {throw RBDSException("DataLoader::BuildInputFileList> no file specified");}
125
126 // wild card
127 std::vector<std::string> fileNamesTemp;
128 if (inputPath.find('*') != std::string::npos)
129 {
130 glob_t glob_result;
131 glob(inputPath.c_str(), GLOB_TILDE, nullptr, &glob_result);
132 for(unsigned int i = 0; i < glob_result.gl_pathc; ++i)
133 {fileNamesTemp.emplace_back(glob_result.gl_pathv[i]);}
134 globfree(&glob_result);
135 }
136 // single file
137 else if (inputPath.find(".root") != std::string::npos)
138 {fileNamesTemp.push_back(inputPath);}
139 // directory
140 else if (inputPath[inputPath.length()-1] == std::string("/"))
141 {
142 // find all files in directory
143 inputPath.append("/*.root");
144
145 glob_t glob_result;
146 glob(inputPath.c_str(), GLOB_TILDE, nullptr, &glob_result);
147 for (unsigned int i = 0; i < glob_result.gl_pathc; ++i)
148 {fileNamesTemp.emplace_back(glob_result.gl_pathv[i]);}
149 globfree(&glob_result);
150 }
151
152 // loop over files and check they're the right type
153 int* fileDataVersion = nullptr; // for backwards compatibility don't try
154 if (!backwardsCompatible)
155 {
156 fileDataVersion = new int();
157 (*fileDataVersion) = 0;
158 }
159 for (const auto& fn : fileNamesTemp)
160 {
161 if (backwardsCompatible)
162 {fileNames.push_back(fn);} // don't check if header -> old files don't have this
163 else if (RBDS::IsBDSIMOutputFile(fn, fileDataVersion))
164 {
165 int value = fileDataVersion ? *fileDataVersion : -1;
166 std::cout << "Loading> \"" << fn << "\" : data version " << value << std::endl;
167 fileNames.push_back(fn);
168 dataVersion = fileDataVersion ? std::min(dataVersion, *fileDataVersion) : dataVersion;
169 }
170 else
171 {std::cout << fn << " is not a BDSIM output file - skipping!" << std::endl;}
172 }
173 delete fileDataVersion;
174
175 if (fileNames.empty())
176 {throw RBDSException("DataLoader - No valid files found - check input file path / name");}
177}
178
180{
181 // open file - this is the first opening so test here if it's valid
182 TFile* f = new TFile(fileNames[0].c_str());
183 if (f->IsZombie())
184 {throw RBDSException(__METHOD_NAME__,"No such file \"" + fileNames[0] + "\"");}
185
186 TList* kl = f->GetListOfKeys();
187 for (int i = 0; i < kl->GetEntries(); ++i)
188 {treeNames.emplace_back(std::string(kl->At(i)->GetName()));}
189
190 f->Close();
191 delete f;
192
193 if (debug)
194 {
195 for (const auto& tr : treeNames)
196 {std::cout << "DataLoader::BuildTreeNameList> " << tr << std::endl;}
197 }
198}
199
201{
202 TFile* f = new TFile(fileNames[0].c_str());
203 if (f->IsZombie())
204 {throw RBDSException(__METHOD_NAME__, "No such file \"" + fileNames[0] + "\"");}
205
206 TTree* mt = (TTree*)f->Get("Model");
207 if (!mt)
208 {
209 f->Close();
210 delete f;
211 return;
212 }
213
214 if (mt->GetEntries() == 0)
215 {// no model tree was stored, so we don't know which branches are which type of samplers
216 // alternatively, inspect the branches of the event tree and get their class names.
217 TTree* et = (TTree*)f->Get("Event");
218 if (!et)
219 {
220 f->Close();
221 delete f;
222 throw RBDSException(__METHOD_NAME__, "No Event tree in file - likely a corrupted file.");
223 }
224 const std::set<std::string> samplerClasses = {"BDSOutputROOTEventSampler",
225 "BDSOutputROOTEventSampler<float>",
226 "BDSOutputROOTEventSampler<double>",
227 "BDSOutputROOTEventSamplerC",
228 "BDSOutputROOTEventSamplerS"};
229 std::map<std::string, std::vector<std::string>*> vectors = {
230 {"BDSOutputROOTEventSampler", &allSamplerNames},
231 {"BDSOutputROOTEventSampler<float>", &allSamplerNames},
232 {"BDSOutputROOTEventSampler<double>", &allSamplerNames},
233 {"BDSOutputROOTEventSamplerC", &allCSamplerNames},
234 {"BDSOutputROOTEventSamplerS", &allSSamplerNames},
235 };
236 TObjArray* branches = et->GetListOfBranches();
237 for (auto branch : *branches)
238 {
239 TBranch* b = (TBranch*)branch;
240 std::string branchClassName = std::string(b->GetClassName());
241 if (samplerClasses.count(branchClassName) != 0)
242 {vectors[branchClassName]->push_back(std::string(b->GetName()));}
243 else if (branchClassName == "BDSOutputROOTEventCollimator")
244 {collimatorNames.push_back(std::string(b->GetName()));}
245 }
246 f->Close();
247 delete f;
248 }
249 else
250 {
251 Model* modTemporary = new Model(false, dataVersion);
252 modTemporary->SetBranchAddress(mt);
253 mt->GetEntry(0);
254 allSamplerNames = modTemporary->SamplerNames();
255 allCSamplerNames = modTemporary->SamplerCNames();
256 allSSamplerNames = modTemporary->SamplerSNames();
257 // collimator names was only added in data version 4 - can leave as empty vector
258 if (dataVersion > 3)
259 {collimatorNames = modTemporary->CollimatorNames();}
260 f->Close();
261 delete f;
262 delete modTemporary;
263 }
264
265 allSamplerCNamesSet.insert(allCSamplerNames.begin(), allCSamplerNames.end());
266 allSamplerCAndSNames.insert(allCSamplerNames.begin(), allCSamplerNames.end());
267 allSamplerSNamesSet.insert(allSSamplerNames.begin(), allSSamplerNames.end());
268 allSamplerCAndSNames.insert(allSSamplerNames.begin(), allSSamplerNames.end());
269 if (processSamplers)
270 { // copy all sampler names to vector of samplers to analyse specifically
271 samplerNames = allSamplerNames;
272 samplerCNames = allCSamplerNames;
273 samplerSNames = allSSamplerNames;
274 }
275
276 if (debug)
277 {
278 std::cout << "All sampler names:" << std::endl;
279 for (const auto& n : allSamplerNames)
280 {std::cout << "DataLoader::BuildEventBranchNameList> Sampler : " << n << std::endl;}
281 for (const auto& n : allCSamplerNames)
282 {std::cout << "DataLoader::BuildEventBranchNameList> SamplerC : " << n << std::endl;}
283 for (const auto& n : allSSamplerNames)
284 {std::cout << "DataLoader::BuildEventBranchNameList> SamplerS : " << n << std::endl;}
285 for (const auto& n : collimatorNames)
286 {std::cout << "DataLoader::BuildEventBranchNameList> Collimator : " << n << std::endl;}
287 }
288}
289
291{
292 // loop over files and chain trees
293 if (dataVersion > 6)
294 {parChain->Add(fileNames[0].c_str());} // only require 1 copy
295 for (const auto& filename : fileNames)
296 {
297 heaChain->Add(filename.c_str());
298 beaChain->Add(filename.c_str());
299 optChain->Add(filename.c_str());
300 modChain->Add(filename.c_str());
301 evtChain->Add(filename.c_str());
302 runChain->Add(filename.c_str());
303 }
304}
305
307 const RBDS::BranchMap* bToTurnOn)
308{
309 if (dataVersion > 6)
310 {par->SetBranchAddress(parChain);}
311 hea->SetBranchAddress(heaChain);
312 bea->SetBranchAddress(beaChain, true); // true = always turn on all branches
313 mod->SetBranchAddress(modChain, true); // true = always turn on all branches
314 opt->SetBranchAddress(optChain, true); // true = always turn on all branches
315 // note we can't parse the :: properly in the options tree so we turn on by default
316
317 const RBDS::VectorString* evtBranches = nullptr;
318 if (bToTurnOn)
319 {
320 if (bToTurnOn->find("Event.") != bToTurnOn->end())
321 {evtBranches = &(*bToTurnOn).at("Event.");}
322 if (evtBranches) // technically could be nullptr
323 {
324 for (const auto& bName: *evtBranches)
325 {
326 if (std::find(allSamplerNames.begin(), allSamplerNames.end(), bName + ".") != allSamplerNames.end())
327 {samplerNames.push_back(bName + "."); continue;}
328 if (std::find(allCSamplerNames.begin(), allCSamplerNames.end(), bName + ".") != allCSamplerNames.end())
329 {samplerCNames.push_back(bName + "."); continue;}
330 if (std::find(allSSamplerNames.begin(), allSSamplerNames.end(), bName + ".") != allSSamplerNames.end())
331 {samplerSNames.push_back(bName + "."); continue;}
332 }
333 }
334 }
335 evt->SetBranchAddress(evtChain, &samplerNames, allOn, evtBranches, &collimatorNames, &samplerCNames, &samplerSNames);
336
337 const RBDS::VectorString* runBranches = nullptr;
338 if (bToTurnOn)
339 {
340 if (bToTurnOn->find("Run.") != bToTurnOn->end())
341 {runBranches = &(*bToTurnOn).at("Run.");}
342 }
343 run->SetBranchAddress(runChain, allOn, runBranches);
344}
Information stored per sampler per event.
Beam loader.
Definition Beam.hh:37
void SetBranchAddress(TTree *t, bool allBranchesOn=true, const RBDS::VectorString *branchesToTurnOn=nullptr)
Set the branch addresses to address the contents of the file.
Definition Beam.cc:44
Loader for a ROOT file using classes used to generate the file.
Definition DataLoader.hh:47
void SetBranchAddress(bool allOn=true, const RBDS::BranchMap *bToTurnOn=nullptr)
Map each chain to the member instance of each storage class in this class.
void BuildEventBranchNameList()
std::set< std::string > allSamplerCAndSNames
int dataVersion
Integer version of data loaded.
void CommonCtor(const std::string &fileName)
Definition DataLoader.cc:82
void BuildTreeNameList()
Open the first file in the file list and map the trees in it.
void BuildInputFileList(std::string inputPath)
Build up the input file list.
void ChainTrees()
Create a tree for each sampler and add all the files to it.
Event loader.
Definition Event.hh:50
void SetBranchAddress(TTree *t, const RBDS::VectorString *samplerNames=nullptr, bool allBranchesOn=false, const RBDS::VectorString *branchesToTurnOn=nullptr, const RBDS::VectorString *collimatorNamesIn=nullptr, const RBDS::VectorString *samplerCNamesIn=nullptr, const RBDS::VectorString *samplerSNamesIn=nullptr)
Definition Event.cc:206
Header loader.
Definition Header.hh:34
void SetBranchAddress(TTree *t)
Set the branch addresses to address the contents of the file.
Definition Header.cc:41
Model loader.
Definition Model.hh:36
std::vector< std::string > CollimatorNames() const
Access all the sampler branch names from the model.
Definition Model.cc:91
void SetBranchAddress(TTree *t, bool allBranchesOn=true, const RBDS::VectorString *branchesToTurnOn=nullptr)
Set the branch addresses to address the contents of the file.
Definition Model.cc:50
std::vector< std::string > SamplerNames() const
Access all the unique sampler names from the model.
Definition Model.cc:73
Options loader.
Definition Options.hh:36
void SetBranchAddress(TTree *t, bool allBranchesOn=true, const RBDS::VectorString *branchesToTurnOn=nullptr)
Set the branch addresses to address the contents of the file.
Definition Options.cc:43
Particle Data loader.
void SetBranchAddress(TTree *t)
Set the branch addresses to address the contents of the file.
BDSOutputROOTParticleData * particleData
Member that ROOT can map file data to locally.
General exception with possible name of object and message.
Class to overlay a run from a ROOT file with.
Definition Run.hh:36
void SetBranchAddress(TTree *t, bool allBranchesOn=true, const RBDS::VectorString *branchesToTurnOn=nullptr)
Map the ROOT file to members in this class.
Definition Run.cc:67
bool IsBDSIMOutputFile(TFile *file, int *dataVersion=nullptr)
Definition FileMapper.cc:66