BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSPrimaryGeneratorFileSampler.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 "BDSBunchEventGenerator.hh"
20#include "BDSDebug.hh"
21#include "BDSException.hh"
22#include "BDSOutputLoaderSampler.hh"
23#include "BDSPrimaryGeneratorFileSampler.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#include "BDSWarning.hh"
32
33#include "G4Event.hh"
34#include "G4EventManager.hh"
35#include "G4LorentzVector.hh"
36#include "G4PrimaryParticle.hh"
37#include "G4PrimaryVertex.hh"
38
39#include "CLHEP/Units/SystemOfUnits.h"
40
41#include "globals.hh"
42
43#include <utility>
44
46 const G4String& fileNameIn,
48 G4bool loopFileIn,
49 G4bool removeUnstableWithoutDecayIn,
50 G4bool warnAboutSkippedParticlesIn):
51 BDSPrimaryGeneratorFile(loopFileIn, bunchIn),
52 reader(nullptr),
53 fileName(fileNameIn),
54 removeUnstableWithoutDecay(removeUnstableWithoutDecayIn),
55 warnAboutSkippedParticles(warnAboutSkippedParticlesIn)
56{
57 std::pair<G4String, G4String> ba = BDS::SplitOnColon(distrType); // before:after
58 samplerName = ba.second;
59 G4cout << __METHOD_NAME__ << "reading sampler named: \"" << samplerName << "\"" << G4endl;
60 referenceBeamMomentumOffset = bunch->ReferenceBeamMomentumOffset();
61 reader = new BDSOutputLoaderSampler(fileName, samplerName);
62 nEventsInFile = reader->NEventsInFile();
63 bunch->SetNEventsInFile(nEventsInFile);
64 bunch->SetNOriginalEvents(reader->NOriginalEvents());
65 G4cout << __METHOD_NAME__ << nEventsInFile << " events found in file" << G4endl;
66 if (!bunch)
67 {throw BDSException(__METHOD_NAME__, "must be constructed with a valid BDSBunchEventGenerator instance");}
69}
70
71BDSPrimaryGeneratorFileSampler::~BDSPrimaryGeneratorFileSampler()
72{
73 delete reader;
74}
75
77{
78 if (!reader)
79 {throw BDSException(__METHOD_NAME__, "no file reader available");}
80
81 currentVertices.clear();
82
83 // currentFileEventIndex is zero counting by nEventsInFile will be 1 greater
84 if (currentFileEventIndex >= nEventsInFile)
85 {
86 endOfFileReached = true;
87 G4cout << __METHOD_NAME__ << "End of file reached. ";
88
89 if (loopFile)
90 {
91 if (OKToLoopFile())
92 {
93 G4cout << "Returning to beginning of file for next event." << G4endl;
94 currentFileEventIndex = 0;
95 endOfFileReached = false;
96 }
97 else
98 {
99 BDS::Warning(__METHOD_NAME__, "file looping requested, but 0 events passed filters - ending.");
100 return;
101 }
102 }
103 else
104 {
105 G4cout << G4endl; // to flush output
106 return;
107 }
108 }
109
110 ReadSingleEvent(currentFileEventIndex, anEvent);
111}
112
114{
115 G4cout << "BDSROOTSamplerLoader::RecreateAdvanceToEvent> Advancing file to event: " << eventOffset << G4endl;
117 SkipEvents(eventOffset);
118}
119
121{
122 vertices.clear();
123 const auto sampler = reader->SamplerDataFloat(index);
124
125 int n = sampler->n;
126 for (int i = 0; i < n; i++)
127 {
128 G4int pdgID = (G4int)sampler->partID[i];
129 G4double xp = (G4double)sampler->xp[i];
130 G4double yp = (G4double)sampler->yp[i];
131 G4double zp = (G4double)sampler->zp[i];
132 G4double p = (G4double)sampler->p[i];
133 G4ThreeVector momentum = G4ThreeVector(xp,yp,zp) * p * CLHEP::GeV;
134 G4double x = (G4double)sampler->x[i] * CLHEP::m;
135 G4double y = (G4double)sampler->y[i] * CLHEP::m;
136 G4double T = (G4double)sampler->T[i] * CLHEP::s;
137 G4ThreeVector localPosition(x,y,0);
138 G4double weight = (G4double)sampler->weight[i];
139 auto g4prim = new G4PrimaryParticle(pdgID, momentum.x(), momentum.y(), momentum.z());
140 g4prim->SetWeight(weight);
141 vertices.emplace_back(DisplacedVertex{localPosition, T, g4prim});
142 }
143}
144
145void BDSPrimaryGeneratorFileSampler::ReadPrimaryParticlesDouble(G4long index)
146{
147 vertices.clear();
148 const auto sampler = reader->SamplerDataDouble(index);
149
150 int n = sampler->n;
151 for (int i = 0; i < n; i++)
152 {
153 G4int pdgID = (G4int)sampler->partID[i];
154 G4double xp = (G4double)sampler->xp[i];
155 G4double yp = (G4double)sampler->yp[i];
156 G4double zp = (G4double)sampler->zp[i];
157 G4double p = (G4double)sampler->p[i];
158 G4ThreeVector momentum = G4ThreeVector(xp,yp,zp) * p;
159 G4double x = (G4double)sampler->x[i] * CLHEP::m;
160 G4double y = (G4double)sampler->y[i] * CLHEP::m;
161 G4double T = (G4double)sampler->T[i] * CLHEP::s;
162 G4ThreeVector localPosition(x,y,0);
163 G4double weight = (G4double)sampler->weight[i];
164 auto g4prim = new G4PrimaryParticle(pdgID, momentum.x(), momentum.y(), momentum.z());
165 g4prim->SetWeight(weight);
166 vertices.emplace_back(DisplacedVertex{localPosition, T, g4prim});
167 }
168}
169
170void BDSPrimaryGeneratorFileSampler::ReadSingleEvent(G4long index, G4Event* anEvent)
171{
172 if (reader->DoublePrecision())
173 {ReadPrimaryParticlesDouble(index);}
174 else
176
177 G4int nParticlesSkipped = 0;
178 for (const auto& xyzVertex : vertices)
179 {
180 const auto vertex = xyzVertex.vertex;
181 // if the particle definition isn't found from the pdgcode in the construction
182 // of G4PrimaryParticle, it means the mass, charge, etc. will be wrong - don't
183 // stack this particle into the vertex.
184 // technically shouldn't happen as bdsim produced this output... but safety first
185 const G4ParticleDefinition* pd = vertex->GetParticleDefinition();
186 G4bool deleteIt = !pd;
187 if (pd && removeUnstableWithoutDecay)
188 {deleteIt = !(pd->GetPDGStable()) && !pd->GetDecayTable();}
189
190 if (deleteIt)
191 {
192 nParticlesSkipped++;
193 continue;
194 }
195
196 G4ThreeVector unitMomentum = vertex->GetMomentumDirection();
197 unitMomentum.transform(referenceBeamMomentumOffset);
198 G4double rp = unitMomentum.perp();
199
200 BDSParticleCoordsFull centralCoords = bunch->GetNextParticleLocal();
201 centralCoords.AddOffset(xyzVertex.xyz, xyzVertex.T); // add on the local offset from the sampler
202
203 BDSParticleCoordsFull local(centralCoords.x,
204 centralCoords.y,
205 centralCoords.z,
206 unitMomentum.x(),
207 unitMomentum.y(),
208 unitMomentum.z(),
209 centralCoords.T,
210 centralCoords.s,
211 vertex->GetTotalEnergy(),
212 vertex->GetWeight());
213
214 if (!bunch->AcceptParticle(local, rp, vertex->GetKineticEnergy(), vertex->GetPDGcode()))
215 {
216 nParticlesSkipped++;
217 continue;
218 }
219
220 BDSParticleCoordsFullGlobal fullCoordsGlobal = bunch->ApplyTransform(local);
221
222 auto g4vtx = new G4PrimaryVertex(fullCoordsGlobal.global.x,
223 fullCoordsGlobal.global.y,
224 fullCoordsGlobal.global.z,
225 fullCoordsGlobal.global.T);
226
227 // ensure it's in the world - not done in primary generator action for event generators
228 if (!VertexInsideWorld(fullCoordsGlobal.global.Position()))
229 {
230 delete g4vtx;
231 nParticlesSkipped++;
232 continue;
233 }
234
235 G4double brho = 0;
236 G4double charge = vertex->GetCharge();
237 G4double momentum = vertex->GetTotalMomentum();
238 if (BDS::IsFinite(charge)) // else leave as 0
239 {
240 brho = momentum / CLHEP::GeV / BDS::cOverGeV / charge;
241 brho *= CLHEP::tesla*CLHEP::m; // rigidity (in Geant4 units)
242 }
243 auto vertexInfo = new BDSPrimaryVertexInformation(fullCoordsGlobal,
244 vertex->GetTotalMomentum(),
245 vertex->GetCharge(),
246 brho,
247 vertex->GetMass(),
248 vertex->GetPDGcode());
249
250 // update momentum in case of a beam line transform
251 auto prim = new G4PrimaryParticle(*vertex);
252 prim->SetMomentumDirection(G4ThreeVector(fullCoordsGlobal.global.xp,
253 fullCoordsGlobal.global.yp,
254 fullCoordsGlobal.global.zp));
255 g4vtx->SetPrimary(prim);
256 g4vtx->SetUserInformation(vertexInfo);
257 currentVertices.push_back(g4vtx);
258 }
259
260 if (nParticlesSkipped > 0 && warnAboutSkippedParticles)
261 {G4cout << __METHOD_NAME__ << nParticlesSkipped << " particles skipped" << G4endl;}
262
263 if (currentVertices.empty())
264 {// no particles found that pass criteria... we can't simulate this event... abort and move on
265 nEventsSkipped++;
266 if (warnAboutSkippedParticles)
267 {G4cout << __METHOD_NAME__ << "no particles found in event number: " << currentFileEventIndex << " in the file" << G4endl;}
268 }
269 else
270 {
271 vertexGeneratedSuccessfully = true;
272 nEventsReadThatPassedFilters++;
273 }
274
275 // clear initially loaded ones
276 for (auto& v : vertices)
277 {delete v.vertex;}
278 vertices.clear();
279
280 currentFileEventIndex++;
281
282 for (auto* v : currentVertices)
283 {anEvent->AddPrimaryVertex(v);}
284 currentVertices.clear();
285}
286
288{
289 if (nEventsToSkip > 0)
290 {G4cout << __METHOD_NAME__ << "skipping " << nEventsToSkip << " into file." << G4endl;}
291 else
292 {return ;}
293 G4long distrFileLoopNTimes = bunch->DistrFileLoopNTimes();
294 G4long nAvailable = nEventsInFile * distrFileLoopNTimes;
295 if ((G4long)nEventsToSkip > nAvailable)
296 {
297 G4String msg = "number of events to skip (" + std::to_string(nEventsToSkip) + ") is greater than the number of events (";
298 msg += std::to_string(nEventsInFile);
299 if (distrFileLoopNTimes > 1)
300 {msg += " x " + std::to_string(distrFileLoopNTimes) + " loops of file";}
301 msg += ") in this file.";
302 throw BDSException("BDSBunchUserFile::RecreateAdvanceToEvent>", msg);
303 }
304 G4long nToSkipSinglePass = nEventsToSkip % nEventsInFile;
305 currentFileEventIndex = nToSkipSinglePass;
306}
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.
G4int eventGeneratorNEventsSkip
Cache of limit.
G4bool AcceptParticle(const BDSParticleCoordsFull &coords, G4double rpOriginal, G4double kineticEnergy, G4int pdgID)
G4int DistrFileLoopNTimes() const
Accessor.
BDSParticleCoordsFullGlobal ApplyTransform(const BDSParticleCoordsFull &localIn) const
Definition BDSBunch.cc:292
virtual BDSParticleCoordsFull GetNextParticleLocal()
Definition BDSBunch.cc:272
General exception with possible name of object and message.
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, G4double offsetT=0)
Apply an offset to the spatial and T coordinates only - assignment.
virtual void RecreateAdvanceToEvent(G4int eventOffset)
Advance to the correct event number in the file for recreation.
void ReadSingleEvent(G4long index, G4Event *anEvent)
Read sampler hits and put into primary vertices if they pass filters.
std::vector< DisplacedVertex > vertices
Used for transiently loading information.
BDSPrimaryGeneratorFileSampler()=delete
Do not require default constructor.
void ReadPrimaryParticlesFloat(G4long index)
Conversion from HepMC::GenEvent to G4Event.
virtual void GeneratePrimaryVertex(G4Event *anEvent)
Read the next non-empty sampler entry from the file.
Common interface for any primary generators that are file based.
void ThrowExceptionIfRecreateOffsetTooHigh(G4long eventOffset) const
G4bool VertexInsideWorld(const G4ThreeVector &pos) const
Utility function for derived classes to check a position is inside the world.
Full set of coordinates for association with primary vertex.
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())