BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSPrimaryGeneratorAction.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 "BDSBunch.hh"
19#include "BDSDebug.hh"
20#include "BDSEventInfo.hh"
21#include "BDSException.hh"
22#include "BDSExtent.hh"
23#include "BDSGlobalConstants.hh"
24#include "BDSIonDefinition.hh"
25#include "BDSOutputLoader.hh"
26#include "BDSParticleDefinition.hh"
27#include "BDSPhysicsUtilities.hh"
28#include "BDSPrimaryGeneratorAction.hh"
29#include "BDSPrimaryGeneratorFile.hh"
30#include "BDSPrimaryVertexInformation.hh"
31#include "BDSPTCOneTurnMap.hh"
32#include "BDSRunAction.hh"
33#include "BDSRandom.hh"
34#include "BDSUtilities.hh"
35#include "BDSWarning.hh"
36
37#include "parser/beam.h"
38
39#include "CLHEP/Random/Random.h"
40
41#include "globals.hh" // geant4 types / globals
42#include "G4Event.hh"
43#include "G4EventManager.hh"
44#include "G4HEPEvtInterface.hh"
45#include "G4IonTable.hh"
46#include "G4ParticleGun.hh"
47#include "G4ParticleDefinition.hh"
48#include "G4Run.hh"
49#include "G4RunManager.hh"
50
52 const GMAD::Beam& beam,
53 G4bool batchMode):
54 bunch(bunchIn),
55 recreateFile(nullptr),
56 eventOffset(0),
57 ionPrimary(false),
58 distrFileMatchLength(beam.distrFileMatchLength),
59 ionCached(false),
60 oneTurnMap(nullptr),
61 generatorFromFile(nullptr)
62{
63 if (!bunchIn)
64 {throw BDSException(__METHOD_NAME__, "valid BDSBunch required");}
66
67 particleGun = new G4ParticleGun(1); // 1-particle gun
68
71 useASCIISeedState = BDSGlobalConstants::Instance()->UseASCIISeedState();
72
73 if (recreate)
74 {
76 eventOffset = BDSGlobalConstants::Instance()->StartFromEvent();
78 }
79
80 particleGun->SetParticleMomentumDirection(G4ThreeVector(0.,0.,1.));
81 particleGun->SetParticlePosition(G4ThreeVector());
82 particleGun->SetParticleTime(0);
83
84 generatorFromFile = BDSPrimaryGeneratorFile::ConstructGenerator(beam, bunch, recreate, eventOffset, batchMode);
85}
86
87BDSPrimaryGeneratorAction::~BDSPrimaryGeneratorAction()
88{
89 delete particleGun;
90 delete recreateFile;
91 delete generatorFromFile;
92}
93
95{
96 G4int thisEventID = anEvent->GetEventID();
97
98 // update the bunch distribution for which event we're on for different bunch timings
99 bunch->CalculateBunchIndex(thisEventID);
100
101 if (recreate) // load seed state if recreating.
102 {
103 G4cout << __METHOD_NAME__ << "setting seed state from file" << G4endl;
104 BDSRandom::SetSeedState(recreateFile->SeedState(thisEventID + eventOffset));
105 bunch->CalculateBunchIndex(thisEventID + eventOffset); // correct bunch index
106 }
107
108 // save the seed state in a file to recover potentially unrecoverable events
110 {BDSRandom::WriteSeedState();}
111
114 {
115 G4String fileName = globals->SeedStateFileName();
116 BDSRandom::LoadSeedState(fileName);
117 }
118
119 // always save seed state in output
120 BDSEventInfo* eventInfo = new BDSEventInfo();
122 anEvent->SetUserInformation(eventInfo);
123 eventInfo->SetSeedStateAtStart(BDSRandom::GetSeedState());
124
125 // events from external file
126 if (generatorFromFile)
127 {
129 return; // nothing else to be done here
130 }
131
132 // update particle definition in the special case of an ion - can only be done here
133 // and not before due to Geant4 ion information availability only at run time
134 if (ionPrimary && !ionCached)
135 {
137 ionCached = true;
138 }
139
140 // generate set of coordinates - internally the bunch may try many times to generate
141 // coordinates with total energy above the rest mass and may throw an exception if it can't
143
144 // BDSBunch distributions based on files do not (as a principle) have the ability to filter
145 // the particles they load so the number of events to generate can be predicted exactly and
146 // there is no need to check on whether an event has been successfully generated here.
147 try
148 {coords = bunch->GetNextParticleValid();}
149 catch (const BDSException& exception)
150 {// we couldn't safely generate a particle -> abort
151 // could be because of user input file
152 anEvent->SetEventAborted();
153 G4cout << exception.what() << G4endl;
154 G4cout << "Aborting this event (#" << thisEventID << ")" << G4endl;
155 return;
156 }
157
158 if (oneTurnMap)
159 {
160 G4bool offsetSAndOnFirstTurn = bunch->UseCurvilinearTransform();
161 oneTurnMap->SetInitialPrimaryCoordinates(coords, offsetSAndOnFirstTurn);
162 }
163
164 particleGun->SetParticleDefinition(bunch->ParticleDefinition()->ParticleDefinition());
165
166 // always update the charge - ok for normal particles; fixes purposively specified ions.
167 particleGun->SetParticleCharge(bunch->ParticleDefinition()->Charge());
168
169 // check that kinetic energy is positive and finite anyway and abort if not.
170 // get the mass from the beamParticle as this takes into account any electrons
171 G4double EK = coords.local.totalEnergy - bunch->ParticleDefinition()->Mass();
172 if (EK <= 0)
173 {
174 G4cout << __METHOD_NAME__ << "Event #" << thisEventID
175 << " - Particle kinetic energy smaller than 0! "
176 << "This will not be tracked." << G4endl;
177 anEvent->SetEventAborted();
178 return;
179 }
180
181 // check the coordinates are valid
182 if (!worldExtent.Encompasses(coords.global))
183 {
184 G4cerr << __METHOD_NAME__ << "point: " << coords.global
185 << "mm lies outside the world volume with extent ("
186 << worldExtent << " - event aborted!" << G4endl << G4endl;
187 anEvent->SetEventAborted();
188 }
189
190#ifdef BDSDEBUG
191 G4cout << __METHOD_NAME__ << coords << G4endl;
192#endif
193
194 G4ThreeVector PartMomDir(coords.global.xp,coords.global.yp,coords.global.zp);
195 G4ThreeVector PartPosition(coords.global.x,coords.global.y,coords.global.z);
196
197 particleGun->SetParticlePosition(PartPosition);
198 particleGun->SetParticleEnergy(EK);
199 particleGun->SetParticleMomentumDirection(PartMomDir);
200 particleGun->SetParticleTime(coords.global.T);
201
202 particleGun->GeneratePrimaryVertex(anEvent);
203
204 // set the weight
205 auto vertex = anEvent->GetPrimaryVertex();
206 vertex->SetWeight(coords.local.weight);
207
208 // associate full set of coordinates with vertex for writing to output after event
209 vertex->SetUserInformation(new BDSPrimaryVertexInformation(coords, bunch->ParticleDefinition()));
210
211#ifdef BDSDEBUG
212 vertex->Print();
213#endif
214}
215
216
218{
219 G4bool distributionFinished = generatorFromFile->DistributionIsFinished(); // only happens if no looping
220 G4int nGenerateRequested = BDSGlobalConstants::Instance()->NGenerate();
221
222 G4bool generatedVertexOK = false;
223 if (!distributionFinished)
224 {generatedVertexOK = generatorFromFile->GeneratePrimaryVertexSafe(anEvent);}
225
226 // file finished (no more events) and we haven't generated a viable event
227 if (distributionFinished && !generatedVertexOK)
228 {
229 G4bool endRunNow = false;
231 {
232 endRunNow = true;
233 G4cout << __METHOD_NAME__ << "distribution file finished (matched in length): ending run." << G4endl;
234 if (generatorFromFile->NEventsReadThatPassedFilters() == 0)
235 {BDS::Warning(__METHOD_NAME__, "no events passed filters and were simulated.");}
236 }
237 else if (generatorFromFile->NEventsReadThatPassedFilters() < nGenerateRequested)
238 {// not matching the file length specifically but requested a certain number of events
239 // If the NEventsReadThatPassedFilters == nGenerateRequested then this won't happen as we won't
240 // try to generate another new event beyond this and the run will end naturally without intervention here.
241 endRunNow = true;
242 G4int currentEventIndex = G4RunManager::GetRunManager()->GetCurrentRun()->GetNumberOfEvent();
243 G4cerr << __METHOD_NAME__ << "unable to generate " << nGenerateRequested
244 << " events as fewer events passed the filters in the file." << G4endl;
245 G4cerr << __METHOD_NAME__ << currentEventIndex << " events generated" << G4endl;
246 }
247 // common bit to artificially abort the event and then end the run now
248 if (endRunNow)
249 {
250 anEvent->SetEventAborted();
251 G4EventManager::GetEventManager()->AbortCurrentEvent();
252 G4RunManager::GetRunManager()->AbortRun();
253 return; // don't generate anything - just return
254 }
255 }
256 else if (!generatedVertexOK) // file isn't finished, but we didn't successfully generate this event
257 {
258 anEvent->SetEventAborted();
259 G4EventManager::GetEventManager()->AbortCurrentEvent();
260 }
261}
The base class for bunch distribution generators.
Definition BDSBunch.hh:46
virtual void RecreateAdvanceToEvent(G4int eventOffset)
Definition BDSBunch.cc:279
virtual const BDSParticleDefinition * ParticleDefinition() const
Access the beam particle definition.
Definition BDSBunch.hh:95
void CalculateBunchIndex(G4int eventIndex)
Calculate which bunch index we should be at given an event index.
Definition BDSBunch.cc:214
G4int CurrentBunchIndex() const
Get the current bunch index for writing to output.
Definition BDSBunch.hh:147
G4bool BeamParticleIsAnIon() const
Access whether the beam particle is an ion or not.
Definition BDSBunch.hh:118
virtual void UpdateIonDefinition()
Definition BDSBunch.cc:388
virtual BDSParticleCoordsFullGlobal GetNextParticleValid(G4int maxTries=100)
Definition BDSBunch.cc:233
G4bool UseCurvilinearTransform() const
Access whether there's a finite S offset and therefore we're using a CL transform.
Definition BDSBunch.hh:108
Interface to store event information use G4 hooks.
void SetBunchIndex(int bunchIndexIn)
Setters.
void SetSeedStateAtStart(const G4String &seedStateAtStartIn)
Setters.
General exception with possible name of object and message.
const char * what() const noexcept override
Override message in std::exception.
G4bool Encompasses(const G4ThreeVector &point) const
Return whether the extent encompasses the point. True if point lies inside the extent.
Definition BDSExtent.cc:189
A class that holds global options and constants.
static BDSGlobalConstants * Instance()
Access method.
Loader of ROOT Event output for recreating events.
G4String SeedState(G4int eventNumber=0)
Access the seed state for a given event index in the file (0 counting).
void SetInitialPrimaryCoordinates(const BDSParticleCoordsFullGlobal &coords, G4bool offsetS0)
Load initial coordinates where the beam started and convert to PTC coordinates.
A set of particle coordinates in both local and global.
G4double Mass() const
Accessor.
G4double Charge() const
Accessor.
G4ParticleDefinition * ParticleDefinition() const
Accessor.
G4bool recreate
Whether to load seed state at start of event from rootevent file.
G4ParticleGun * particleGun
Geant4 particle gun that creates single particles.
G4int eventOffset
The offset in the file to read events from when setting the seed.
G4bool useASCIISeedState
Whether to use the ascii seed state each time.
G4bool ionPrimary
The primary particle will be an ion.
BDSPrimaryGeneratorAction(BDSBunch *bunchIn, const GMAD::Beam &beam, G4bool batchMode)
Bunch must have a valid particle definition (ie not nullptr).
G4bool distrFileMatchLength
Match external file length for event generator.
void GeneratePrimariesFromFile(G4Event *anEvent)
For a file-based event generator there are a few checks we have to do - put in a function to keep tid...
BDSExtent worldExtent
World extent that particle coordinates are checked against to ensure they're inside it.
BDSBunch * bunch
BDSIM particle generator.
virtual void GeneratePrimaries(G4Event *)
Main interface for Geant4. Prepare primary(ies) for the event.
BDSPTCOneTurnMap * oneTurnMap
Cached OTM for setting first turn primary coords.
G4bool writeASCIISeedState
Cache of whether to write seed state as ASCII per event.
BDSOutputLoader * recreateFile
Optional output handler for restoring seed state.
G4long NEventsReadThatPassedFilters() const
Accessor.
G4bool DistributionIsFinished() const
Report whether the distribution is finished generating.
G4bool GeneratePrimaryVertexSafe(G4Event *event)
Return false if not able to generate a primary vertex.
static BDSPrimaryGeneratorFile * ConstructGenerator(const GMAD::Beam &beam, BDSBunch *bunchIn, G4bool recreate, G4int eventOffset, G4bool batchMode)
Full set of coordinates for association with primary vertex.
Beam class.
Definition beam.h:43