BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSOutputROOTEventModel.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 "BDSOutputROOTEventModel.hh"
19
20#ifndef __ROOTBUILD__
21#include "BDSAcceleratorModel.hh"
22#include "BDSBeamline.hh"
23#include "BDSBeamlineElement.hh"
24#include "BDSBeamPipeInfo.hh"
25#include "BDSMagnet.hh"
26#include "BDSMagnetStrength.hh"
27#include "BDSPhysicalVolumeInfoRegistry.hh"
28#include "BDSSamplerRegistry.hh"
29
30#include "G4RotationMatrix.hh"
31#include "G4String.hh"
32#include "G4Types.hh"
33
34#include <algorithm>
35#include <iterator>
36#include <map>
37#include <set>
38#include <sstream>
39#include <string>
40#include <vector>
41#include <utility>
42#endif
43
45
47 n(0),
48 storeCollimatorInfo(false),
49 storeCavityInfo(false),
50 nCavities(0),
51 nCollimators(0)
52{
53 Flush();
54}
55
58
59int BDSOutputROOTEventModel::findNearestElement(const TVector3& point) const
60{
61 // we make a vector of pairs of the distance between the mid of each element
62 // and the specified point along with the index. We then sort this vector by
63 // the distance (first part of pair only). Could use a map as it's sorted but
64 // can't guarantee access with a double or float as a key due to binary representation.
65 std::vector<std::pair<float, int> > distanceAndIndex;
66 distanceAndIndex.reserve(midRefPos.size());
67 for (int i = 0; i < (int)midRefPos.size(); i++)
68 {distanceAndIndex.emplace_back(std::make_pair((midRefPos[i]-point).Mag(), i));}
69
70 struct customLess
71 {bool operator()(std::pair<float, int>& a, std::pair<float, int>& b) const {return a.first < b.first;};};
72 std::sort(distanceAndIndex.begin(), distanceAndIndex.end(), customLess());
73 return distanceAndIndex[0].second;
74}
75
77{
78 n = 0;
79 componentName.clear();
80 placementName.clear();
81 componentType.clear();
82 length.clear();
83 angle.clear();
84 staPos.clear();
85 midPos.clear();
86 endPos.clear();
87 staRot.clear();
88 midRot.clear();
89 endRot.clear();
90 staRefPos.clear();
91 midRefPos.clear();
92 endRefPos.clear();
93 staRefRot.clear();
94 midRefRot.clear();
95 endRefRot.clear();
96 tilt.clear();
97 offsetX.clear();
98 offsetY.clear();
99 staS.clear();
100 midS.clear();
101 endS.clear();
102 beamPipeType.clear();
103 beamPipeAper1.clear();
104 beamPipeAper2.clear();
105 beamPipeAper3.clear();
106 beamPipeAper4.clear();
107 material.clear();
108 k1.clear();
109 k2.clear();
110 k3.clear();
111 k4.clear();
112 k5.clear();
113 k6.clear();
114 k7.clear();
115 k8.clear();
116 k9.clear();
117 k10.clear();
118 k11.clear();
119 k12.clear();
120 k1s.clear();
121 k2s.clear();
122 k3s.clear();
123 k4s.clear();
124 k5s.clear();
125 k6s.clear();
126 k7s.clear();
127 k8s.clear();
128 k9s.clear();
129 k10s.clear();
130 k11s.clear();
131 k12s.clear();
132 ks.clear();
133 hkick.clear();
134 vkick.clear();
135 bField.clear();
136 eField.clear();
137 e1.clear();
138 e2.clear();
139 fint.clear();
140 fintx.clear();
141 fintk2.clear();
142 fintxk2.clear();
143 pvName.clear();
144 pvNameWPointer.clear();
145 midT.clear();
146 staP.clear();
147 staEk.clear();
148
149 storeCavityInfo = false;
150 cavityIndices.clear();
151 cavityIndicesByName.clear();
152 nCavities = 0;
153 cavityInfo.clear();
155 storeCollimatorInfo = false;
156 collimatorIndices.clear();
158 nCollimators = 0;
159 collimatorInfo.clear();
161 scoringMeshTranslation.clear();
162 scoringMeshRotation.clear();
163 scoringMeshName.clear();
164
165 materialIDToName.clear();
166 materialNameToID.clear();
167
168 samplerNamesUnique.clear();
169 samplerSPosition.clear();
170 samplerCNamesUnique.clear();
171 samplerSNamesUnique.clear();
172 samplerCRadius.clear();
173 samplerSRadius.clear();
174}
175
176#ifndef __ROOTBUILD__
178 G4bool storeCavityInfoIn):
179 n(0),
180 storeCollimatorInfo(storeCollimatorInfoIn),
181 storeCavityInfo(storeCavityInfoIn),
182 nCavities(0),
183 nCollimators(0)
184{;}
185
186TRotation BDSOutputROOTEventModel::ConvertToROOT(const G4RotationMatrix* rm) const
187{
188 TRotation rr = TRotation();
189 rr.SetToIdentity();
190 if (!rm)
191 {return rr;}
192
193 double rotAngle;
194 CLHEP::Hep3Vector axis;
195
196 rm->getAngleAxis(rotAngle, axis);
197 rr.Rotate(rotAngle, TVector3(axis.x(), axis.y(), axis.z()));
198 return rr;
199}
200
201TRotation BDSOutputROOTEventModel::ConvertToROOT(const G4RotationMatrix& rm) const
202{
203 return ConvertToROOT(&rm);
204}
205
206TVector3 BDSOutputROOTEventModel::ConvertToROOT(const G4ThreeVector& v) const
207{
208 return TVector3(v.x() / CLHEP::m, v.y() / CLHEP::m, v.z() / CLHEP::m);
209}
210
211void BDSOutputROOTEventModel::Fill(const std::vector<G4int>& collimatorIndicesIn,
212 const std::map<G4String, G4int>& collimatorIndicesByNameIn,
213 const std::vector<BDSOutputROOTEventCollimatorInfo>& collimatorInfoIn,
214 const std::vector<G4String>& collimatorBranchNamesIn,
215 const std::vector<G4int>& cavityIndicesIn,
216 const std::map<G4String, G4int>& cavityIndicesByNameIn,
217 const std::vector<BDSOutputROOTEventCavityInfo>& cavityInfoIn,
218 const std::vector<G4String>& cavityBranchNamesIn,
219 const std::map<G4String, G4Transform3D>* scorerMeshPlacements,
220 const std::map<short int, G4String>* materialIDToNameUnique,
221 G4bool storeTrajectory)
222{
224 for (const auto& nameSPos : sr->GetUniquePlaneNamesAndSPosition())
225 {
226 samplerNamesUnique.push_back(std::string(nameSPos.first) + ".");
227 samplerSPosition.push_back((double) nameSPos.second / CLHEP::m);
228 }
229 for (const auto& name : sr->GetUniqueNamesCylinder())
230 {samplerCNamesUnique.push_back(std::string(name) + ".");}
231 for (const auto& name : sr->GetUniqueNamesSphere())
232 {samplerSNamesUnique.push_back(std::string(name) + ".");}
233 samplerCRadius = sr->GetUniqueNameToRadiusCylinder();
234 samplerSRadius = sr->GetUniqueNameToRadiusSphere();
235
236 for (const auto& name : collimatorBranchNamesIn)
237 {collimatorBranchNamesUnique.push_back(std::string(name) + ".");}
238 for (const auto& name : cavityBranchNamesIn)
239 {cavityBranchNamesUnique.push_back(std::string(name) + ".");}
240
241 if (scorerMeshPlacements)
242 {
243 for (const auto& kv : *scorerMeshPlacements)
244 {
245 const G4String& name = kv.first;
246 scoringMeshTranslation[name] = ConvertToROOT(kv.second.getTranslation());
247 scoringMeshRotation[name] = ConvertToROOT(kv.second.getRotation());
248 scoringMeshName.emplace_back(name);
249 }
250 }
251
252 const BDSBeamline* beamline = BDSAcceleratorModel::Instance()->BeamlineMain();
253 if (!beamline)
254 {return;} // in case of generatePrimariesOnly there is no model - return
255
257 {
258 for (const auto value : collimatorIndicesIn)
259 {collimatorIndices.push_back((int)value);}
260
262
263 for (const auto& kv : collimatorIndicesByNameIn)
264 {collimatorIndicesByName[(std::string)kv.first] = (int)kv.second;}
265
266 collimatorInfo = collimatorInfoIn;
267 }
268
269 if (storeCavityInfo)
270 {
271 for (const auto value : cavityIndicesIn)
272 {cavityIndices.push_back((int)value);}
273
274 nCavities = (int)cavityIndices.size();
275
276 for (const auto& kv : cavityIndicesByNameIn)
277 {cavityIndicesByName[(std::string)kv.first] = (int)kv.second;}
278
279 cavityInfo = cavityInfoIn;
280 }
281
282 if (materialIDToNameUnique && storeTrajectory)
283 {
284 for (const auto& kv : *materialIDToNameUnique)
285 {
286 materialIDToName[kv.first] = (std::string)kv.second;
287 materialNameToID[(std::string)kv.second] = kv.first;
288 }
289 }
290
291 n = (int)beamline->size();
292
293 for (auto i = beamline->begin(); i != beamline->end(); ++i)
294 {
295 componentName.push_back((*i)->GetName());
296 placementName.push_back((*i)->GetPlacementName());
297 componentType.push_back((*i)->GetType());
298 length.push_back((float)((*i)->GetAcceleratorComponent()->GetArcLength() / CLHEP::m));
299 angle.push_back((float)((*i)->GetAcceleratorComponent()->GetAngle() / CLHEP::radian));
300 staPos.push_back(ConvertToROOT((*i)->GetPositionStart()));
301 midPos.push_back(ConvertToROOT((*i)->GetPositionMiddle()));
302 endPos.push_back(ConvertToROOT((*i)->GetPositionEnd()));
303 staRot.push_back(ConvertToROOT((*i)->GetRotationStart()));
304 midRot.push_back(ConvertToROOT((*i)->GetRotationMiddle()));
305 endRot.push_back(ConvertToROOT((*i)->GetRotationEnd()));
306 staRefPos.emplace_back(ConvertToROOT((*i)->GetReferencePositionStart()));
307 midRefPos.emplace_back(ConvertToROOT((*i)->GetReferencePositionMiddle()));
308 endRefPos.emplace_back(ConvertToROOT((*i)->GetReferencePositionEnd()));
309 staRefRot.push_back(ConvertToROOT((*i)->GetReferenceRotationStart()));
310 midRefRot.push_back(ConvertToROOT((*i)->GetReferenceRotationMiddle()));
311 endRefRot.push_back(ConvertToROOT((*i)->GetReferenceRotationEnd()));
312
313 // tilt and offset
314 BDSTiltOffset* to = (*i)->GetTiltOffset();
315 if (to)
316 {
317 tilt.push_back((float)(to->GetTilt() / CLHEP::rad));
318 offsetX.push_back((float)(to->GetXOffset() / CLHEP::m));
319 offsetY.push_back((float)(to->GetYOffset() / CLHEP::m));
320 }
321 else
322 {
323 tilt.push_back(0);
324 offsetX.push_back(0);
325 offsetY.push_back(0);
326 }
327
328 // S positions
329 staS.push_back((float)((*i)->GetSPositionStart() / CLHEP::m));
330 midS.push_back((float)((*i)->GetSPositionMiddle() / CLHEP::m));
331 endS.push_back((float)((*i)->GetSPositionEnd() / CLHEP::m));
332
333 // beam pipe
334 BDSBeamPipeInfo* beampipeinfo = (*i)->GetBeamPipeInfo();
335 beamPipeType.push_back(beampipeinfo ? beampipeinfo->beamPipeType.ToString() : "");
336 beamPipeAper1.push_back(beampipeinfo ? beampipeinfo->aper1 / CLHEP::m : 0);
337 beamPipeAper2.push_back(beampipeinfo ? beampipeinfo->aper2 / CLHEP::m : 0);
338 beamPipeAper3.push_back(beampipeinfo ? beampipeinfo->aper3 / CLHEP::m : 0);
339 beamPipeAper4.push_back(beampipeinfo ? beampipeinfo->aper4 / CLHEP::m : 0);
340
341 // associated material if any
342 const auto accComp = (*i)->GetAcceleratorComponent();
343 material.push_back(accComp->Material());
344
345 // helper shortcuts to all the member vectors
346 std::vector<std::vector<float>*> localNorm = {&k1,&k2,&k3,&k4,&k5,&k6,&k7,&k8,&k9,&k10,&k11,&k12};
347 std::vector<std::vector<float>*> localSkew = {&k1s,&k2s,&k3s,&k4s,&k5s,&k6s,&k7s,&k8s,&k9s,&k10s,&k11s,&k12s};
348
349 // helper lambda to avoid duplication
350 auto fillzero = [&]
351 {
352 for (int j = 0; j < (int)localNorm.size(); j++)
353 {localNorm[j]->push_back(0);}
354 for (int j = 0; j < (int)localSkew.size(); j++)
355 {localSkew[j]->push_back(0);}
356 ks.push_back(0);
357 hkick.push_back(0);
358 vkick.push_back(0);
359 bField.push_back(0);
360 eField.push_back(0);
361 e1.push_back(0);
362 e2.push_back(0);
363 hgap.push_back(0);
364 fint.push_back(0);
365 fintx.push_back(0);
366 fintk2.push_back(0);
367 fintxk2.push_back(0);
368 };
369
370 // do this bit first as we test for magnet strengths later and then do a 'continue' in the for loop
372 std::vector<std::string> localPVNames;
373 std::vector<std::string> localPVNamesWPointer;
374 if (setOfPVs)
375 {
376 auto name = [](G4VPhysicalVolume* pv){return pv->GetName();};
377 std::transform(setOfPVs->begin(), setOfPVs->end(), std::back_inserter(localPVNames), name);
378 auto fullName = [](G4VPhysicalVolume* pv)
379 {
380 std::stringstream ss;
381 ss << static_cast<const void*>(pv);
382 std::string addressName = ss.str();
383 return pv->GetName() + addressName;
384 };
385 std::transform(setOfPVs->begin(), setOfPVs->end(), std::back_inserter(localPVNamesWPointer), fullName);
386 }
387 // always push it back even if an empty vector
388 pvName.push_back(localPVNames);
389 pvNameWPointer.push_back(localPVNamesWPointer);
390
391 midT.push_back((float)(*i)->GetSynchronousTMiddle()/CLHEP::ns);
392 staP.push_back((float)(*i)->GetStartMomentum()/CLHEP::GeV);
393 staEk.push_back((float)(*i)->GetStartKineticEnergy()/CLHEP::GeV);
394
395 // fill magnet strength data
396 // NOTE - has a 'continue'
397 if (BDSMagnet* mag = dynamic_cast<BDSMagnet*>(accComp))
398 {
399 const BDSMagnetStrength* ms = mag->MagnetStrength();
400 if (!ms)
401 {
402 fillzero();
403 continue;
404 }
405 // assume localNorm and normComponents are same size
406 std::vector<G4double> normComponents = ms->NormalComponents();
407 for (int j = 0; j < (int)localNorm.size(); j++)
408 {localNorm[j]->push_back((float)normComponents[j]);}
409 std::vector<G4double> skewComponents = ms->SkewComponents();
410 for (int j = 0; j < (int)localSkew.size(); j++)
411 {localSkew[j]->push_back((float)skewComponents[j]);}
412
413 ks.push_back((float)((*ms)["ks"]/BDSMagnetStrength::Unit("ks")));
414 hkick.push_back( (float)((*ms)["hkick"]/BDSMagnetStrength::Unit("hkick")));
415 vkick.push_back( (float)((*ms)["vkick"]/BDSMagnetStrength::Unit("vkick")));
416 bField.push_back((float)((*ms)["field"]/BDSMagnetStrength::Unit("field")));
417 eField.push_back((float)((*ms)["efield"]/BDSMagnetStrength::Unit("efield")));
418 e1.push_back((float)((*ms)["e1"]/BDSMagnetStrength::Unit("e1")));
419 e2.push_back((float)((*ms)["e2"]/BDSMagnetStrength::Unit("e2")));
420 hgap.push_back((float)((*ms)["hgap"]/BDSMagnetStrength::Unit("hgap")));
421 fint.push_back((float)(*ms)["fint"]);
422 fintx.push_back((float)(*ms)["fintx"]);
423 fintk2.push_back((float)(*ms)["fintk2"]);
424 fintxk2.push_back((float)(*ms)["fintxk2"]);
425 }
426 else
427 {// not a magnet
428 fillzero();
429 }
430 }
431}
432#endif
const BDSBeamline * BeamlineMain() const
Accessor.
Holder class for all information required to describe a beam pipe model.
G4double aper3
Public member for direct access.
G4double aper1
Public member for direct access.
G4double aper4
Public member for direct access.
G4double aper2
Public member for direct access.
BDSBeamPipeType beamPipeType
Public member for direct access.
A vector of BDSBeamlineElement instances - a beamline.
BeamlineVector::size_type size() const
Get the number of elements.
iterator begin()
Iterator mechanics.
iterator end()
Iterator mechanics.
Efficient storage of magnet strengths.
std::vector< G4double > NormalComponents() const
Accessor for all normal components - k1 - k12.
std::vector< G4double > SkewComponents() const
Accessor for all skew components - k1 - k12.
static G4double Unit(const G4String &key)
Access a unit factor for a given key.
Abstract base class that implements features common to all magnets.
Definition BDSMagnet.hh:44
Information stored per model representing accelerator.
std::vector< BDSOutputROOTEventCollimatorInfo > collimatorInfo
Collimator information explicitly.
bool storeCollimatorInfo
Whether optional collimator information was stored.
std::vector< float > vkick
Vertical fractional momentum kick.
std::vector< float > eField
E field in V/m.
std::vector< std::string > collimatorBranchNamesUnique
Vector of all collimator branch names in event tree used to load data.
int nCollimators
Number of collimators in beam line.
int nCavities
Number of cavities in beam line.
virtual ~BDSOutputROOTEventModel()
Destructor.
int findNearestElement(const TVector3 &point) const
Find element index closest to point.
std::vector< float > bField
B field in T.
std::vector< float > hkick
Horizontal fractional momentum kick.
std::vector< std::string > material
Material associated with element if any.
std::vector< BDSOutputROOTEventCavityInfo > cavityInfo
cavity information explicitly.
void Flush()
Initialise all members.
virtual void Fill(const std::vector< G4int > &collimatorIndicesIn={}, const std::map< G4String, G4int > &collimatorIndicesByNameIn={}, const std::vector< BDSOutputROOTEventCollimatorInfo > &collimatorInfoIn={}, const std::vector< G4String > &collimatorBranchNamesIn={}, const std::vector< G4int > &cavityIndicesIn={}, const std::map< G4String, G4int > &cavityIndicesByNameIn={}, const std::vector< BDSOutputROOTEventCavityInfo > &cavityInfoIn={}, const std::vector< G4String > &cavityBranchNamesIn={}, const std::map< G4String, G4Transform3D > *scorerMeshPlacements=nullptr, const std::map< short int, G4String > *materialIDToNameUnique=nullptr, G4bool storeTrajectory=false)
Fill root output.
std::vector< std::string > cavityBranchNamesUnique
Vector of all cavity branch names in event tree used to load data.
BDSOutputROOTEventModel()
Default constructor.
std::map< std::string, int > collimatorIndicesByName
Similar cache but by name of collimator as built by BDSIM.
std::vector< float > ks
Solenoid strength.
bool storeCavityInfo
Whether optional cavity information was stored.
TRotation ConvertToROOT(const G4RotationMatrix *rm) const
Utility function.
std::map< std::string, int > cavityIndicesByName
Similar cache but by name of cavity as built by BDSIM.
const std::set< G4VPhysicalVolume * > * PVsForBeamlineElement(BDSBeamlineElement *element) const
Access a set of volumes registered for the placement of a beamline element.
static BDSPhysicalVolumeInfoRegistry * Instance()
Singleton accessor.
static BDSSamplerRegistry * Instance()
Accessor for registry.
A holder for any placement offsets and rotations for a BDSAcceleratorComponent.
G4double GetYOffset() const
Accessor.
G4double GetXOffset() const
Accessor.
G4double GetTilt() const
Accessor.