BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSROOTSamplerReader.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2022.
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 "BDSBunchEventGenerator.hh"
20#include "BDSDebug.hh"
21#include "BDSException.hh"
22#include "BDSOutputLoaderSampler.hh"
23#include "BDSROOTSamplerReader.hh"
24#include "BDSParticleCoords.hh"
25#include "BDSParticleCoordsFull.hh"
26#include "BDSParticleCoordsFullGlobal.hh"
27#include "BDSPhysicalConstants.hh"
28#include "BDSPrimaryVertexInformation.hh"
29#include "BDSPrimaryVertexInformationV.hh"
30#include "BDSUtilities.hh"
31
32#include "G4Event.hh"
33#include "G4LorentzVector.hh"
34#include "G4PrimaryParticle.hh"
35#include "G4PrimaryVertex.hh"
36#include "G4RunManager.hh"
37#include "G4TransportationManager.hh"
38#include "G4VSolid.hh"
39
40#include "CLHEP/Units/SystemOfUnits.h"
41
42#include "globals.hh"
43
44#include <utility>
45
47 const G4String& fileNameIn,
49 G4bool removeUnstableWithoutDecayIn,
50 G4bool warnAboutSkippedParticlesIn):
51 currentFileEventIndex(0),
52 nEventsInFile(0),
53 reader(nullptr),
54 fileName(fileNameIn),
55 bunch(bunchIn),
56 removeUnstableWithoutDecay(removeUnstableWithoutDecayIn),
57 warnAboutSkippedParticles(warnAboutSkippedParticlesIn),
58 worldSolid(nullptr),
59 anyParticlesFoundAtAll(false)
60{
61 std::pair<G4String, G4String> ba = BDS::SplitOnColon(distrType); // before:after
62 samplerName = ba.second;
63 G4cout << __METHOD_NAME__ << "reading sampler named: \"" << samplerName << "\"" << G4endl;
64 referenceBeamMomentumOffset = bunch->ReferenceBeamMomentumOffset();
65 reader = new BDSOutputLoaderSampler(fileName, samplerName);
66 nEventsInFile = reader->NEventsInFile();
67}
68
69BDSROOTSamplerReader::~BDSROOTSamplerReader()
70{
71 delete reader;
72}
73
75{
76 if (!reader)
77 {throw BDSException(__METHOD_NAME__, "no file reader available");}
78
79 G4int nParticles = 0;
80 currentVertices.clear();
81 while (nParticles < 1)
82 {
83 if (currentFileEventIndex > nEventsInFile)
84 {
85 G4cout << __METHOD_NAME__ << "End of file reached. Return to beginning of file for next event." << G4endl;
86 currentFileEventIndex = 0;
87 }
88 ReadSingleEvent(currentFileEventIndex);
89 nParticles = (G4int)currentVertices.size();
90 if (nParticles > 0)
92 currentFileEventIndex++;
93 if ((nParticles < 1) && (currentFileEventIndex > nEventsInFile) && !anyParticlesFoundAtAll)
94 {throw BDSException(__METHOD_NAME__, "no events in file provide any suitable particles from the sampler "+samplerName);}
95 }
96 for (auto* v : currentVertices)
97 {anEvent->AddPrimaryVertex(v);}
98 currentVertices.clear();
99}
100
102{
103 G4cout << "BDSROOTSamplerLoader::RecreateAdvanceToEvent> Advancing file to event: " << eventOffset << G4endl;
104 for (G4int i = 0; i < eventOffset; i++)
105 {
106 G4Event* event = new G4Event();
108 delete event;
109 }
110}
111
112void BDSROOTSamplerReader::ReadPrimaryParticlesFloat(G4long index)
113{
114 vertices.clear();
115 const auto sampler = reader->SamplerDataFloat(index);
116
117 int n = sampler->n;
118 for (int i = 0; i < n; i++)
119 {
120 G4int pdgID = (G4int)sampler->partID[i];
121 G4double xp = (G4double)sampler->xp[i];
122 G4double yp = (G4double)sampler->yp[i];
123 G4double zp = (G4double)sampler->zp[i];
124 G4double p = (G4double)sampler->p[i];
125 G4ThreeVector momentum = G4ThreeVector(xp,yp,zp) * p * CLHEP::GeV;
126 G4double x = (G4double)sampler->x[i] * CLHEP::m;
127 G4double y = (G4double)sampler->y[i] * CLHEP::m;
128 G4ThreeVector localPosition(x,y,0);
129 auto g4prim = new G4PrimaryParticle(pdgID, momentum.x(), momentum.y(), momentum.z());
130 vertices.emplace_back(DisplacedVertex{localPosition, g4prim});
131 }
132}
133
134void BDSROOTSamplerReader::ReadPrimaryParticlesDouble(G4long index)
135{
136 vertices.clear();
137 const auto sampler = reader->SamplerDataDouble(index);
138
139 int n = sampler->n;
140 for (int i = 0; i < n; i++)
141 {
142 G4int pdgID = (G4int)sampler->partID[i];
143 G4double xp = (G4double)sampler->xp[i];
144 G4double yp = (G4double)sampler->yp[i];
145 G4double zp = (G4double)sampler->zp[i];
146 G4double p = (G4double)sampler->p[i];
147 G4ThreeVector momentum = G4ThreeVector(xp,yp,zp) * p;
148 G4double x = (G4double)sampler->x[i] * CLHEP::m;
149 G4double y = (G4double)sampler->y[i] * CLHEP::m;
150 G4ThreeVector localPosition(x,y,0);
151 auto g4prim = new G4PrimaryParticle(pdgID, momentum.x(), momentum.y(), momentum.z());
152 vertices.emplace_back(DisplacedVertex{localPosition, g4prim});
153 }
154}
155
157{
158 if (reader->DoublePrecision())
159 {ReadPrimaryParticlesDouble(index);}
160 else
161 {ReadPrimaryParticlesFloat(index);}
162
163 double overallWeight = 1.0;
164 G4int nParticlesSkipped = 0;
165 for (const auto& xyzVertex : vertices)
166 {
167 const auto vertex = xyzVertex.vertex;
168 // if the particle definition isn't found from the pdgcode in the construction
169 // of G4PrimaryParticle, it means the mass, charge, etc will be wrong - don't
170 // stack this particle into the vertex.
171 // technically shouldn't happen as bdsim produced this output... but safety first
172 const G4ParticleDefinition* pd = vertex->GetParticleDefinition();
173 G4bool deleteIt = !pd;
174 if (pd && removeUnstableWithoutDecay)
175 {deleteIt = !(pd->GetPDGStable()) && !pd->GetDecayTable();}
176
177 if (deleteIt)
178 {
179#ifdef BDSDEBUG
180 G4cout << __METHOD_NAME__ << "skipping particle with PDG ID: " << pd->GetPDGEncoding() << G4endl;
181#endif
182 nParticlesSkipped++;
183 continue;
184 }
185
186 G4ThreeVector unitMomentum = vertex->GetMomentumDirection();
187 unitMomentum.transform(referenceBeamMomentumOffset);
188 G4double rp = unitMomentum.perp();
189
190 BDSParticleCoordsFull centralCoords = bunch->GetNextParticleLocal();
191 centralCoords.AddOffset(xyzVertex.xyz); // add on the local offset from the sampler
192
193 BDSParticleCoordsFull local(centralCoords.x,
194 centralCoords.y,
195 centralCoords.z,
196 unitMomentum.x(),
197 unitMomentum.y(),
198 unitMomentum.z(),
199 centralCoords.T,
200 centralCoords.s,
201 vertex->GetTotalEnergy(),
202 overallWeight);
203
204 if (!bunch->AcceptParticle(local, rp, vertex->GetKineticEnergy(), vertex->GetPDGcode()))
205 {
206 nParticlesSkipped++;
207 continue;
208 }
209
210 BDSParticleCoordsFullGlobal fullCoordsGlobal = bunch->ApplyTransform(local);
211
212 auto g4vtx = new G4PrimaryVertex(fullCoordsGlobal.global.x,
213 fullCoordsGlobal.global.y,
214 fullCoordsGlobal.global.z,
215 fullCoordsGlobal.global.T);
216
217 // ensure it's in the world - not done in primary generator action for event generators
218 if (!VertexInsideWorld(fullCoordsGlobal.global.Position()))
219 {
220 delete g4vtx;
221 nParticlesSkipped++;
222 continue;
223 }
224
225 G4double brho = 0;
226 G4double charge = vertex->GetCharge();
227 G4double momentum = vertex->GetTotalMomentum();
228 if (BDS::IsFinite(charge)) // else leave as 0
229 {
230 brho = momentum / CLHEP::GeV / BDS::cOverGeV / charge;
231 brho *= CLHEP::tesla*CLHEP::m; // rigidity (in Geant4 units)
232 }
233 auto vertexInfo = new BDSPrimaryVertexInformation(fullCoordsGlobal,
234 vertex->GetTotalMomentum(),
235 vertex->GetCharge(),
236 brho,
237 vertex->GetMass(),
238 vertex->GetPDGcode());
239
240 // update momentum in case of a beam line transform
241 auto prim = new G4PrimaryParticle(*vertex);
242 prim->SetMomentumDirection(G4ThreeVector(fullCoordsGlobal.global.xp,
243 fullCoordsGlobal.global.yp,
244 fullCoordsGlobal.global.zp));
245 g4vtx->SetPrimary(prim);
246 g4vtx->SetUserInformation(vertexInfo);
247 currentVertices.push_back(g4vtx);
248 }
249
250 if (nParticlesSkipped > 0 && warnAboutSkippedParticles)
251 {G4cout << __METHOD_NAME__ << nParticlesSkipped << " particles skipped" << G4endl;}
252
253 // clear initially loaded ones
254 for (auto& v : vertices)
255 {delete v.vertex;}
256 vertices.clear();
257}
258
259G4bool BDSROOTSamplerReader::VertexInsideWorld(const G4ThreeVector& pos) const
260{
261 if (!worldSolid)
262 {// cache the world solid
263 G4Navigator* navigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
264 G4VPhysicalVolume* world = navigator->GetWorldVolume();
265 worldSolid = world->GetLogicalVolume()->GetSolid();
266 }
267 EInside qinside = worldSolid->Inside(pos);
268 return qinside == kInside;
269}
A wrapper of BDSBunch to include a filter for the events loaded by an event generator.
G4RotationMatrix ReferenceBeamMomentumOffset() const
Get a rotation matrix according to Xp0 and Yp0.
G4bool AcceptParticle(const BDSParticleCoordsFull &coords, G4double rpOriginal, G4double kineticEnergy, G4int pdgID)
BDSParticleCoordsFullGlobal ApplyTransform(const BDSParticleCoordsFull &localIn) const
Definition: BDSBunch.cc:258
virtual BDSParticleCoordsFull GetNextParticleLocal()
Definition: BDSBunch.cc:244
General exception with possible name of object and message.
Definition: BDSException.hh:35
Loader of ROOT Event output for receating events.
A set of particle coordinates in both local and global.
A set of particle coordinates including energy and weight.
G4double s
TODO - remove this. Unused. S (global) is calculated from S0 + z.
void AddOffset(const G4ThreeVector &offset)
Apply an offset to the spatial coordinates only - assignment.
Full set of coordinates for association with primary vertex.
virtual void GeneratePrimaryVertex(G4Event *anEvent)
Read the next non-empty sampler entry from the file.
virtual void RecreateAdvanceToEvent(G4int eventOffset)
Advance to the correct event number in the file for recreation.
std::vector< DisplacedVertex > vertices
Used for transiently loading information.
void ReadSingleEvent(G4long index)
Clear the hepmcEvent object, reallocate and read a single event and fill that member.
virtual G4bool VertexInsideWorld(const G4ThreeVector &pos) const
Conversion from HepMC::GenEvent to G4Event.
BDSROOTSamplerReader()=delete
Do not require default constructor.
std::pair< G4String, G4String > SplitOnColon(const G4String &formatAndPath)
static const G4double cOverGeV
speed of light / 1 GeV, used for scaling in brho calculation
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())