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