BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSOutputStructures.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 "BDSAcceleratorModel.hh"
19#include "BDSBeamline.hh"
20#include "BDSBeamlineElement.hh"
21#include "BDSDebug.hh"
22#include "BDSHitEnergyDeposition.hh"
23#include "BDSEventInfo.hh"
24#include "BDSGlobalConstants.hh"
25#include "BDSOutputStructures.hh"
26#include "BDSOutputROOTEventAperture.hh"
27#include "BDSOutputROOTEventBeam.hh"
28#include "BDSOutputROOTEventCollimator.hh"
29#include "BDSOutputROOTEventCoords.hh"
30#include "BDSOutputROOTEventHeader.hh"
31#include "BDSOutputROOTEventHistograms.hh"
32#include "BDSOutputROOTEventInfo.hh"
33#include "BDSOutputROOTEventLoss.hh"
34#include "BDSOutputROOTEventLossWorld.hh"
35#include "BDSOutputROOTEventModel.hh"
36#include "BDSOutputROOTEventOptions.hh"
37#include "BDSOutputROOTEventRunInfo.hh"
38#include "BDSOutputROOTEventSampler.hh"
39#include "BDSOutputROOTEventSamplerC.hh"
40#include "BDSOutputROOTEventSamplerS.hh"
41#include "BDSOutputROOTEventTrajectory.hh"
42#include "BDSOutputROOTParticleData.hh"
43#include "BDSHitSampler.hh"
44#include "BDSSamplerRegistry.hh"
45#include "BDSTrajectoryPoint.hh"
46
47#include "globals.hh"
48#include "G4Material.hh"
49#include "G4MaterialTable.hh"
50
51#include "CLHEP/Units/SystemOfUnits.h"
52
53#include <algorithm>
54#include <map>
55#include <string>
56#include <vector>
57#include <utility>
58
60 nCollimators(0),
61 nCavities(0),
62 localSamplersInitialised(false),
63 localCollimatorsInitialised(false)
64{
65 G4bool storeCollimatorInfo = globals->StoreCollimatorInfo();
66 G4bool storeCavityInfo = globals->StoreCavityInfo();
67 G4bool storeTurn = globals->StoreELossTurn();
68 G4bool storeLinks = globals->StoreELossLinks();
69 G4bool storeLocal = globals->StoreELossLocal();
70 G4bool storeGlobal = globals->StoreELossGlobal();
71 G4bool storeTime = globals->StoreELossTime();
72 G4bool storeStepLength = globals->StoreELossStepLength();
73 G4bool storePreStepKineticEnergy = globals->StoreELossPreStepKineticEnergy();
74 G4bool storeModelID = globals->StoreELossModelID();
75 G4bool storeELPhysics = globals->StoreELossPhysicsProcesses();
76 // store the model id if either modelID requested or store links
77 storeModelID = storeModelID || storeLinks;
78
79 particleDataOutput = new BDSOutputROOTParticleData();
80 headerOutput = new BDSOutputROOTEventHeader();
81 beamOutput = new BDSOutputROOTEventBeam();
82 optionsOutput = new BDSOutputROOTEventOptions();
83 modelOutput = new BDSOutputROOTEventModel(storeCollimatorInfo, storeCavityInfo);
84
85 eLoss = new BDSOutputROOTEventLoss(storeTurn, storeLinks, storeModelID, storeLocal,
86 storeGlobal, storeTime, storeStepLength,
87 storePreStepKineticEnergy, storeELPhysics);
88 eLossVacuum = new BDSOutputROOTEventLoss(storeTurn, storeLinks, storeModelID, storeLocal,
89 storeGlobal, storeTime, storeStepLength,
90 storePreStepKineticEnergy, storeELPhysics);
91 eLossTunnel = new BDSOutputROOTEventLoss(storeTurn, storeLinks, storeModelID, storeLocal,
92 storeGlobal, storeTime, storeStepLength,
93 storePreStepKineticEnergy, storeELPhysics);
94 eLossWorld = new BDSOutputROOTEventLossWorld();
95 eLossWorldExit = new BDSOutputROOTEventLossWorld();
96 eLossWorldContents = new BDSOutputROOTEventLossWorld();
97
98 pFirstHit = new BDSOutputROOTEventLoss(true, true, true, true, true, true, false, true, true);
99 pLastHit = new BDSOutputROOTEventLoss(true, true, true, true, true, true, false, true, true);
100
101 apertureImpacts = new BDSOutputROOTEventAperture();
102
103 traj = new BDSOutputROOTEventTrajectory();
104 evtHistos = new BDSOutputROOTEventHistograms();
105 evtInfo = new BDSOutputROOTEventInfo();
106 runHistos = new BDSOutputROOTEventHistograms();
107 runInfo = new BDSOutputROOTEventRunInfo();
108
109#ifndef __ROOTDOUBLE__
110 primary = new BDSOutputROOTEventSampler<float>("Primary");
111#else
112 primary = new BDSOutputROOTEventSampler<double>("Primary");
113#endif
114 primaryGlobal = new BDSOutputROOTEventCoords();
115}
116
117BDSOutputStructures::~BDSOutputStructures()
118{
119 delete particleDataOutput;
120 delete headerOutput;
121 delete beamOutput;
122 delete optionsOutput;
123 delete modelOutput;
124 delete primaryGlobal;
125 delete eLoss;
126 delete eLossVacuum;
127 delete eLossTunnel;
128 delete eLossWorld;
129 delete eLossWorldExit;
130 delete eLossWorldContents;
131 delete pFirstHit;
132 delete pLastHit;
133 delete apertureImpacts;
134 delete traj;
135 delete evtHistos;
136 delete evtInfo;
137 delete runHistos;
138 delete runInfo;
139 for (auto sampler : samplerTrees)
140 {delete sampler;}
141 for (auto sampler : samplerCTrees)
142 {delete sampler;}
143 for (auto sampler : samplerSTrees)
144 {delete sampler;}
145 for (auto collimator : collimators)
146 {delete collimator;}
147 delete primary;
148}
149
150G4int BDSOutputStructures::Create1DHistogram(G4String name, G4String title,
151 G4int nbins, G4double xmin, G4double xmax)
152{
153 G4int result = evtHistos->Create1DHistogram(name, title, nbins, xmin, xmax);
154 // index from runHistos will be the same as used only through interfaces in this class
155 runHistos->Create1DHistogram(name, title, nbins, xmin, xmax);
156 return result;
157}
158
159G4int BDSOutputStructures::Create1DHistogram(G4String name, G4String title,
160 std::vector<double>& edges)
161{
162 G4int result = evtHistos->Create1DHistogram(name,title,edges);
163 runHistos->Create1DHistogram(name,title,edges);
164 return result;
165}
166
167G4int BDSOutputStructures::Create3DHistogram(G4String name, G4String title,
168 G4int nBinsX, G4double xMin, G4double xMax,
169 G4int nBinsY, G4double yMin, G4double yMax,
170 G4int nBinsZ, G4double zMin, G4double zMax)
171{
172 G4int result = evtHistos->Create3DHistogram(name, title,
173 nBinsX, xMin, xMax,
174 nBinsY, yMin, yMax,
175 nBinsZ, zMin, zMax);
176 // index from runHistos will be the same as used only through interfaces in this class
177 runHistos->Create3DHistogram(name, title,
178 nBinsX, xMin, xMax,
179 nBinsY, yMin, yMax,
180 nBinsZ, zMin, zMax);
181 return result;
182}
183
184G4int BDSOutputStructures::Create4DHistogram(const G4String& name,
185 const G4String& title,
186 const G4String& eScale,
187 const std::vector<double>& eBinsEdges,
188 G4int nBinsX, G4double xMin, G4double xMax,
189 G4int nBinsY, G4double yMin, G4double yMax,
190 G4int nBinsZ, G4double zMin, G4double zMax,
191 G4int nBinsE, G4double eMin, G4double eMax)
192{
193 G4int result = evtHistos->Create4DHistogram(name, title, eScale, eBinsEdges,
194 nBinsX, xMin, xMax,
195 nBinsY, yMin, yMax,
196 nBinsZ, zMin, zMax,
197 nBinsE, eMin, eMax);
198
199 runHistos->Create4DHistogram(name, title, eScale, eBinsEdges,
200 nBinsX, xMin, xMax,
201 nBinsY, yMin, yMax,
202 nBinsZ, zMin, zMax,
203 nBinsE, eMin, eMax);
204 return result;
205}
206
208{
210 {
211 auto samplerRegistry = BDSSamplerRegistry::Instance();
212 const auto sNames = samplerRegistry->GetUniqueNamesPlane();
213#ifdef USE_SIXTRACKLINK
214 // TODO hardcoded because of sixtrack dynamic buildup
215 // Sixtrack does lazy initialisation for collimators in link to Geant4 so we don't know
216 // a priori how many link elements there'll be. If we allow it to be dynamically built up
217 // we risk the vector expanding and moving in memory, therefore breaking all the && (address
218 // of pointer) links of TTree::SetBranchAddress in the output. Therefore, we reserve a size
219 // of 300 in the hope that this is less than the LHC 120 collimators for both beams. Ideally,
220 // the sixtrack interface should be rewritten so we know at construction time how many will
221 // be built.
222 samplerTrees.reserve(300);
223#else
224 samplerTrees.reserve(sNames.size());
225#endif
227 for (const auto& samplerName : sNames)
228 {
229#ifndef __ROOTDOUBLE__
231#else
233#endif
234 samplerTrees.push_back(res);
235 samplerNames.push_back(samplerName);
236 }
237 const auto planeIDs = samplerRegistry->GetSamplerIDsPlane();
238 G4int i = 0;
239 for (const auto& ID : planeIDs)
240 {samplerIDToIndexPlane[ID] = i; i++;}
241
242 // cylindrical samplers
243 const auto scNames = samplerRegistry->GetUniqueNamesCylinder();
244 samplerCTrees.reserve(scNames.size());
245 for (const auto& samplerName : scNames)
246 {
247 samplerCTrees.emplace_back(new BDSOutputROOTEventSamplerC(samplerName));
248 samplerCNames.emplace_back(samplerName);
249 }
250 const auto cylinderIDs = samplerRegistry->GetSamplerIDsCylinder();
251 i = 0;
252 for (const auto& ID : cylinderIDs)
253 {samplerIDToIndexCylinder[ID] = i; i++;}
254
255 // spherical samplers
256 const auto ssNames = samplerRegistry->GetUniqueNamesSphere();
257 samplerSTrees.reserve(ssNames.size());
258 for (const auto& samplerName : ssNames)
259 {
260 samplerSTrees.emplace_back(new BDSOutputROOTEventSamplerS(samplerName));
261 samplerSNames.emplace_back(samplerName);
262 }
263 const auto sphereIDs = samplerRegistry->GetSamplerIDsSphere();
264 i = 0;
265 for (const auto& ID : sphereIDs)
266 {samplerIDToIndexSphere[ID] = i; i++;}
267 }
268}
269
271{
272 materialToID.clear();
273 materialIDToNameUnique.clear();
274
275 const auto materialTable = G4Material::GetMaterialTable(); // should be an std::vector<G4Material*>*
276
277 // It's completely permitted to use degenerate material names as the geometry is constructed by
278 // pointer. We need a way to sort the materials for a given input irrespective of pointer or memory
279 // location so the result is the same for multiple runs of bdsim.
280
281 // Use a pair of <name, density>. A c++ map will be internally sorted by keys and the various
282 // comparison operators are defined by pairs in <utility>. Once sorted, by a map, we then loop
283 // over that map and generate integer IDs for each material.
284
285 // This may seem overkill as we ensure in BDSMaterials we don't make materials with
286 // degenerate names and ultimately, we can't define degenerate materials in GMAD so
287 // this shouldn't happen. But, if someone turns off preprocessGDML and they have degenerate
288 // material names in multiple GDML files or a repeated definition of the same material
289 // in multiple GDML files, we will end up with different G4Material instances but still
290 // need a way to distinguish them withouth using the pointer.
291
292 std::map<std::pair<G4String, G4double>, G4Material*> sortingMap;
293 std::map<G4String, int> nameCount;
294 std::map<G4Material*, G4String> matToUniqueName;
295
296 for (const auto& mat : *materialTable)
297 {
298 G4String matName = mat->GetName();
299 G4String matNameUnique = matName;
300
301 auto search = nameCount.find(matName);
302 if (search != nameCount.end())
303 {
304 search->second += 1;
305 matNameUnique = matName + std::to_string(search->second);
306 matToUniqueName[mat] = matNameUnique;
307 }
308 else
309 {
310 nameCount[matName] = 0;
311 matToUniqueName[mat] = matName;
312 }
313 sortingMap[std::make_pair(matNameUnique, mat->GetDensity())] = mat;
314 }
315
316 short int i = 0;
317 for (const auto& kv : sortingMap)
318 {
319 materialToID[kv.second] = i;
320 materialIDToNameUnique[i] = matToUniqueName[kv.second];
321 i++;
322 }
323}
324
326{
327 G4int result = 0;
328 auto samplerRegistry = BDSSamplerRegistry::Instance();
329 for (auto const& samplerName : samplerRegistry->GetUniqueNames())
330 {// only put it in if it doesn't exist already
331 if (std::find(samplerNames.begin(), samplerNames.end(), samplerName) == samplerNames.end())
332 {
333 result++;
334#ifndef __ROOTDOUBLE__
336#else
338#endif
339 samplerTrees.push_back(res);
340 samplerNames.push_back(samplerName);
341 }
342 }
343
344 const auto planeNames = samplerRegistry->GetUniqueNamesPlane();
345 const auto planeIDs = samplerRegistry->GetSamplerIDsPlane();
346 for (size_t i = 0; i < planeIDs.size(); ++i)
347 {
348 auto nameIterator = std::find(samplerNames.begin(), samplerNames.end(), planeNames.at(i));
349 if (nameIterator != samplerNames.end())
350 {samplerIDToIndexPlane[planeIDs.at(i)] = (G4int)std::distance(samplerNames.begin(), nameIterator);}
351 }
353 return result;
354}
355
357{
358 const G4String collimatorPrefix = "COLL_";
359 const BDSBeamline* flatBeamline = BDSAcceleratorModel::Instance()->BeamlineMain();
360 if (flatBeamline)
361 {collimatorIndices = flatBeamline->GetIndicesOfCollimators();}
362 nCollimators = (G4int)collimatorIndices.size();
363
364 for (auto index : collimatorIndices)
365 {
366 // prepare output structure name
367 const BDSBeamlineElement* el = flatBeamline->at(index);
368 // use the 'placement' name for a unique name (with copy number included)
369 G4String collimatorName = collimatorPrefix + el->GetPlacementName();
370 collimatorNames.push_back(collimatorName);
371 collimatorIndicesByName[el->GetName()] = index;
373
375 info.Fill(el);
376 collimatorInfo.push_back(info);
377
378 // cache difference in apertures for efficient interpolation and avoid
379 // repeated calculation. not required in info for output though.
380 G4double xDiff = info.xSizeOut - info.xSizeIn;
381 G4double yDiff = info.ySizeOut - info.ySizeIn;
382 collimatorDifferences.emplace_back(xDiff, yDiff); // construct in place
383 }
384}
385
387{
388 const G4String cavityPrefix = "CAV_";
389 const BDSBeamline* flatBeamline = BDSAcceleratorModel::Instance()->BeamlineMain();
390 if (flatBeamline)
391 {
392 std::vector<G4int> pillboxIndices = flatBeamline->GetIndicesOfElementsOfType("cavity_pillbox");
393 std::vector<G4int> rectIndices = flatBeamline->GetIndicesOfElementsOfType("cavity_rectangular");
394 std::vector<G4int> ellipticalIndices = flatBeamline->GetIndicesOfElementsOfType("cavity_elliptical");
395 cavityIndices = pillboxIndices;
396 cavityIndices.insert(std::end(cavityIndices), std::begin(rectIndices), std::end(rectIndices));
397 cavityIndices.insert(std::end(cavityIndices), std::begin(ellipticalIndices), std::end(ellipticalIndices));
398 nCavities = (G4int) cavityIndices.size();
399 }
400 for (auto index : cavityIndices)
401 {
402 // prepare output structure name
403 const BDSBeamlineElement* el = flatBeamline->at(index);
404 // use the 'placement' name for a unique name (with copy number included)
405 G4String cavityName = cavityPrefix + el->GetPlacementName();
406 cavityNames.push_back(cavityName);
407 cavityIndicesByName[el->GetName()] = index;
409
411 info.Fill(el);
412 cavityInfo.push_back(info);
413 }
414}
415
417{
419 {
421 for (int i = 0; i < (int)collimatorIndices.size(); i++)
422 {collimators.push_back(new BDSOutputROOTEventCollimator());}
423 }
424}
425
430
435
440
445
450
452{
453 primary->Flush();
454 for (auto sampler : samplerTrees)
455 {sampler->Flush();}
456 for (auto sampler : samplerCTrees)
457 {sampler->Flush();}
458 for (auto sampler : samplerSTrees)
459 {sampler->Flush();}
460 for (auto collimator : collimators)
461 {collimator->Flush();}
462 primaryGlobal->Flush();
463 eLoss->Flush();
464 eLossVacuum->Flush();
465 eLossTunnel->Flush();
466 eLossWorld->Flush();
467 eLossWorldExit->Flush();
468 eLossWorldContents->Flush();
469 pFirstHit->Flush();
470 pLastHit->Flush();
471 apertureImpacts->Flush();
472 traj->Flush();
473 evtHistos->Flush();
474 evtInfo->Flush();
475}
476
const BDSBeamline * BeamlineMain() const
Accessor.
A class that holds a fully constructed BDSAcceleratorComponent as well as any information relevant to...
G4String GetPlacementName() const
Accessor.
G4String GetName() const
Accessor.
A vector of BDSBeamlineElement instances - a beamline.
const BDSBeamlineElement * at(int iElement) const
Return a reference to the element at i.
std::vector< G4int > GetIndicesOfElementsOfType(const G4String &type) const
Return vector of indices for this beam line where element of type name 'type' is found.
std::vector< G4int > GetIndicesOfCollimators() const
Return indices in order of ecol, rcol, jcol and crystalcol elements.
A class that holds global options and constants.
Data stored for energy deposition hits per event.
Class to store all beam options for a BDSIM run.
Data stored for each cavity in the model.
Data stored for each collimator in the model.
Data stored for each collimator per event.
Information about the software and the file.
Holder for a set of histograms to be stored.
virtual void Flush()
Flush the contents.
Information pertaining to an individual event.
Data stored for world hits per event.
Data stored for energy deposition hits per event.
Information stored per model representing accelerator.
void Flush()
Initialise all members.
Class to store all options for a BDSIM run.
Information pertaining to a run.
Information stored per cylindrical sampler per event.
Information stored per spherical sampler per event.
Information stored per sampler per event.
virtual void Flush()
Clean Sampler.
Structure to record a trajectory.
virtual void Flush()
add comment to avoid warning (no need to make persistent, see issue #191)
Geant4 particle data for particles used in simulation.
virtual void Flush()
Clear maps.
void InitialiseCollimators()
Construct collimators.
BDSOutputROOTEventModel * modelOutput
Model output.
G4int Create1DHistogram(G4String name, G4String title, G4int nbins, G4double xmin, G4double xmax)
Create histograms for both evtHistos and runHistos. Return index from evtHistos.
std::vector< G4String > collimatorNames
Names of collimators in output structures.
std::vector< BDSOutputROOTEventCollimator * > collimators
Collimator output structures.
G4int nCavities
Number of cavities in beam line.
std::vector< std::string > samplerNames
Sampler names to use.
BDSOutputROOTEventSampler< double > * primary
Primary sampler structure.
BDSOutputROOTEventRunInfo * runInfo
Run information.
void InitialiseMaterialMap()
Construct a map of material pointer to integer ID and name.
void ClearStructuresOptions()
Clear the local options structure.
std::vector< G4String > cavityNames
Names of cavities in output structures.
BDSOutputROOTEventHistograms * runHistos
Run level histograms.
BDSOutputROOTEventLossWorld * eLossWorldExit
World exit hits.
std::vector< G4int > cavityIndices
Indices in beam line that are cavities.
void ClearStructuresRunLevel()
Clear the local structures in this class in preparation for a new run.
BDSOutputStructures()=delete
Unused default constructors.
void InitialiseSamplers()
Construct samplers.
void ClearStructuresBeam()
Clear the local beam structure.
std::vector< BDSOutputROOTEventCavityInfo > cavityInfo
Cavity parameters.
std::map< G4String, G4int > collimatorIndicesByName
Indices mapped to their name.
BDSOutputROOTEventLossWorld * eLossWorldContents
Externally supplied world contents hits.
G4int nCollimators
Number of collimators in beam line.
std::vector< BDSOutputROOTEventSampler< double > * > samplerTrees
Sampler structures.
std::vector< std::pair< G4double, G4double > > collimatorDifferences
void ClearStructuresModel()
Clear the local model structure.
void ClearStructuresHeader()
Clear the local header structure.
G4int Create4DHistogram(const G4String &name, const G4String &title, const G4String &eScale, const std::vector< double > &eBinsEdges, G4int nBinsX, G4double xMin, G4double xMax, G4int nBinsY, G4double yMin, G4double yMax, G4int nBinsZ, G4double zMin, G4double zMax, G4int nBinsE, G4double eMin, G4double eMax)
Create histograms for both evtHistos and runHistos. Return index from evtHistos.
BDSOutputROOTEventHeader * headerOutput
Information about the file.
BDSOutputROOTEventLossWorld * eLossWorld
World energy deposition.
BDSOutputROOTEventLoss * eLossVacuum
General energy deposition.
std::vector< G4int > collimatorIndices
Indices in beam line that are collimators.
BDSOutputROOTEventInfo * evtInfo
Event information.
BDSOutputROOTEventLoss * pLastHit
Primary loss point.
BDSOutputROOTEventHistograms * evtHistos
Event level histograms.
BDSOutputROOTEventLoss * eLossTunnel
Tunnel energy deposition.
G4int UpdateSamplerStructures()
Interface to allow setting up samplers later for dynamic geometry construction a la SixTrack....
G4int Create3DHistogram(G4String name, G4String title, G4int nBinsX, G4double xMin, G4double xMax, G4int nBinsY, G4double yMin, G4double yMax, G4int nBinsZ, G4double zMin, G4double zMax)
Create histograms for both evtHistos and runHistos. Return index from evtHistos.
void ClearStructuresEventLevel()
Clear the local structures in this class in preparation for a new event.
BDSOutputROOTEventLoss * pFirstHit
Primary hit point.
BDSOutputROOTEventTrajectory * traj
Trajectories.
BDSOutputROOTEventBeam * beamOutput
Beam output.
BDSOutputROOTEventLoss * eLoss
General energy deposition.
std::vector< BDSOutputROOTEventCollimatorInfo > collimatorInfo
void PrepareCavityInformation()
Extract number of collimators and their names from beam line.
void ClearStructuresParticleData()
Clear the local particle data structure.
G4bool localCollimatorsInitialised
Whether we've setup the member vector of collimators. Similarly to localSamplersInitialised.
BDSOutputROOTEventAperture * apertureImpacts
Impacts on the aperture.
BDSOutputROOTParticleData * particleDataOutput
Geant4 information / particle tables.
BDSOutputROOTEventOptions * optionsOutput
Options output.
std::map< G4String, G4int > cavityIndicesByName
Indices mapped to their name.
static BDSSamplerRegistry * Instance()
Accessor for registry.