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