BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSHepMC3Reader.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#ifdef USE_HEPMC3
20
21#include "BDSBunchEventGenerator.hh"
22#include "BDSDebug.hh"
23#include "BDSEventGeneratorFileType.hh"
24#include "BDSException.hh"
25#include "BDSHepMC3Reader.hh"
26#include "BDSParticleCoords.hh"
27#include "BDSParticleCoordsFull.hh"
28#include "BDSParticleCoordsFullGlobal.hh"
29#include "BDSPhysicalConstants.hh"
30#include "BDSPrimaryVertexInformation.hh"
31#include "BDSPrimaryVertexInformationV.hh"
32#include "BDSUtilities.hh"
33
34#include "G4Event.hh"
35#include "G4LorentzVector.hh"
36#include "G4PrimaryParticle.hh"
37#include "G4PrimaryVertex.hh"
38#include "G4RunManager.hh"
39#include "G4TransportationManager.hh"
40#include "G4VSolid.hh"
41
42#include "HepMC3/Attribute.h"
43#include "HepMC3/GenParticle.h"
44#include "HepMC3/GenVertex.h"
45#include "HepMC3/Reader.h"
46#include "HepMC3/ReaderAscii.h"
47#include "HepMC3/ReaderAsciiHepMC2.h"
48#include "HepMC3/ReaderHEPEVT.h"
49#include "HepMC3/ReaderLHEF.h"
50#ifdef USE_HEPMC3_ROOTIO
51#include "HepMC3/ReaderRoot.h"
52#include "HepMC3/ReaderRootTree.h"
53#endif
54
55#include "CLHEP/Units/SystemOfUnits.h"
56
57#include "globals.hh"
58
59#include <utility>
60
61
62BDSHepMC3Reader::BDSHepMC3Reader(const G4String& distrType,
63 const G4String& fileNameIn,
65 G4bool removeUnstableWithoutDecayIn,
66 G4bool warnAboutSkippedParticlesIn):
67 hepmcEvent(nullptr),
68 reader(nullptr),
69 fileName(fileNameIn),
70 bunch(bunchIn),
71 removeUnstableWithoutDecay(removeUnstableWithoutDecayIn),
72 warnAboutSkippedParticles(warnAboutSkippedParticlesIn),
73 worldSolid(nullptr)
74{
75 std::pair<G4String, G4String> ba = BDS::SplitOnColon(distrType); // before:after
76 fileType = BDS::DetermineEventGeneratorFileType(ba.second);
77 G4cout << __METHOD_NAME__ << "event generator file format to be " << fileType.ToString() << G4endl;
78 referenceBeamMomentumOffset = bunch->ReferenceBeamMomentumOffset();
79 OpenFile();
80}
81
82BDSHepMC3Reader::~BDSHepMC3Reader()
83{
84 delete hepmcEvent;
85 delete reader;
86}
87
88void BDSHepMC3Reader::GeneratePrimaryVertex(G4Event* anEvent)
89{
90 if (!reader)
91 {throw BDSException(__METHOD_NAME__, "no file reader available");}
92
94 HepMC2G4(hepmcEvent, anEvent);
95}
96
98{
99 G4cout << "BDSHepMC3Reader::RecreateAdvanceToEvent> Advancing file to event: " << eventOffset << G4endl;
100 for (G4int i = 0; i < eventOffset; i++)
101 {ReadSingleEvent();}
102}
103
105{
106 G4cout << __METHOD_NAME__ << "Opening file: " << fileName << G4endl;
107 switch (fileType.underlying())
108 {
109 case BDSEventGeneratorFileType::hepmc2:
110 {reader = new HepMC3::ReaderAsciiHepMC2(fileName); break;}
111 case BDSEventGeneratorFileType::hepmc3:
112 {reader = new HepMC3::ReaderAscii(fileName); break;}
113 case BDSEventGeneratorFileType::hpe:
114 {reader = new HepMC3::ReaderHEPEVT(fileName); break;}
115#ifdef USE_HEPMC3_ROOTIO
116 case BDSEventGeneratorFileType::root:
117 {reader = new HepMC3::ReaderRoot(fileName); break;}
118 case BDSEventGeneratorFileType::treeroot:
119 {reader = new HepMC3::ReaderRootTree(fileName); break;}
120#else
121 case BDSEventGeneratorFileType::root:
122 case BDSEventGeneratorFileType::treeroot:
123 {
124 throw BDSException(__METHOD_NAME__, "HEPMC3 installation not compiled with ROOT support so can't load root file.");
125 break;
126 }
127#endif
128 case BDSEventGeneratorFileType::lhef:
129 {reader = new HepMC3::ReaderLHEF(fileName); break;}
130 default:
131 {break;}
132 }
133}
134
136{
137 if (reader)
138 {reader->close();}
139 delete reader;
140}
141
143{
144 delete hepmcEvent;
145 hepmcEvent = new HepMC3::GenEvent();
146
147 bool readEventOK = reader->read_event(*hepmcEvent);
148 if (!readEventOK)
149 {throw BDSException(__METHOD_NAME__, "problem with event generator file \"" + fileName + "\"");}
150 if (reader->failed()) // code for end of the file
151 {
152 G4cout << __METHOD_NAME__ << "End of file reached. Return to beginning of file for next event." << G4endl;
153 CloseFile();
154 OpenFile();
155 delete hepmcEvent;
156 hepmcEvent = new HepMC3::GenEvent();
157 readEventOK = reader->read_event(*hepmcEvent);
158 if (!readEventOK)
159 {throw BDSException(__METHOD_NAME__, "cannot read file \"" + fileName + "\".");}
160 }
161}
162
163void BDSHepMC3Reader::HepMC2G4(const HepMC3::GenEvent* hepmcevt,
164 G4Event* g4event)
165{
166 BDSParticleCoordsFull centralCoords = bunch->GetNextParticleLocal();
167 // do the transform for the reference particle (if any transform) and use that
168 BDSParticleCoordsFullGlobal centralCoordsGlobal = bunch->ApplyTransform(centralCoords);
169 G4PrimaryVertex* g4vtx = new G4PrimaryVertex(centralCoordsGlobal.global.x,
170 centralCoordsGlobal.global.y,
171 centralCoordsGlobal.global.z,
172 centralCoordsGlobal.global.T);
173
174 double overallWeight = 1.0;
175 if (!(hepmcevt->weights().empty()))
176 {overallWeight = hepmcevt->weight();}
177 std::vector<BDSPrimaryVertexInformation> vertexInfos;
178 G4int nParticlesSkipped = 0;
179 for (const auto& particlePtr : hepmcevt->particles())
180 {
181 const HepMC3::GenParticle* particle = particlePtr.get();
182 if (!particle->children().empty())
183 {continue;} // this particle is not at the end of the tree - ignore
184
185 int pdgcode = particle->pdg_id();
186 const HepMC3::FourVector& fv = particle->momentum();
187 G4LorentzVector p(fv.px(), fv.py(), fv.pz(), fv.e());
188 G4double px = p.x() * CLHEP::GeV;
189 G4double py = p.y() * CLHEP::GeV;
190 G4double pz = p.z() * CLHEP::GeV;
191 G4ThreeVector originalUnitMomentum(px,py,pz);
192 originalUnitMomentum = originalUnitMomentum.unit();
193 G4double rp = std::hypot(originalUnitMomentum.x(), originalUnitMomentum.y());
194
195 // apply any reference coordinate offsets. Copy the vector first.
196 G4ThreeVector unitMomentum = originalUnitMomentum;
197 unitMomentum.transform(referenceBeamMomentumOffset);
198 // it's ok that this G4PrimaryParticle doesn't have the correct momentum direction as we only use it for
199 // total energy and checking - it's direction is updated later based on unitMomentum with a beam line transform.
200 G4PrimaryParticle* g4prim = new G4PrimaryParticle(pdgcode, px, py, pz);
201
202 // if the particle definition isn't found from the pdgcode in the construction
203 // of G4PrimaryParticle, it means the mass, charge, etc will be wrong - don't
204 // stack this particle into the vertex.
205 const G4ParticleDefinition* pd = g4prim->GetParticleDefinition();
206 G4bool deleteIt = !pd;
207 if (pd && removeUnstableWithoutDecay)
208 {deleteIt = !(pd->GetPDGStable()) && !pd->GetDecayTable();}
209
210 if (deleteIt)
211 {
212#ifdef BDSDEBUG
213 G4cout << __METHOD_NAME__ << "skipping particle with PDG ID: " << pdgcode << G4endl;
214#endif
215 delete g4prim;
216 nParticlesSkipped++;
217 continue;
218 }
219
220 BDSParticleCoordsFull local(centralCoords.x,
221 centralCoords.y,
222 centralCoords.z,
223 unitMomentum.x(),
224 unitMomentum.y(),
225 unitMomentum.z(),
226 centralCoords.T,
227 centralCoords.s,
228 g4prim->GetTotalEnergy(),
229 overallWeight);
230
231 if (!bunch->AcceptParticle(local, rp, g4prim->GetKineticEnergy(), pdgcode))
232 {
233 delete g4prim;
234 nParticlesSkipped++;
235 continue;
236 }
237
238 BDSParticleCoordsFullGlobal fullCoords = bunch->ApplyTransform(local);
239 // ensure it's in the world - not done in primary generator action for event generators
240 if (!VertexInsideWorld(fullCoords.global.Position()))
241 {
242 delete g4prim;
243 nParticlesSkipped++;
244 continue;
245 }
246
247 G4double brho = 0;
248 G4double charge = g4prim->GetCharge();
249 G4double momentum = g4prim->GetTotalMomentum();
250 if (BDS::IsFinite(charge)) // else leave as 0
251 {
252 brho = momentum / CLHEP::GeV / BDS::cOverGeV / charge;
253 brho *= CLHEP::tesla*CLHEP::m; // rigidity (in Geant4 units)
254 }
255 BDSPrimaryVertexInformation vertexInfo(fullCoords,
256 g4prim->GetTotalMomentum(),
257 g4prim->GetCharge(),
258 brho,
259 g4prim->GetMass(),
260 pdgcode);
261 vertexInfos.emplace_back(vertexInfo);
262
263 // update momentum in case of a beam line transform
264 g4prim->SetMomentumDirection(G4ThreeVector(fullCoords.global.xp,
265 fullCoords.global.yp,
266 fullCoords.global.zp));
267 g4vtx->SetPrimary(g4prim);
268 }
269
270 if (nParticlesSkipped > 0 && warnAboutSkippedParticles)
271 {G4cout << __METHOD_NAME__ << nParticlesSkipped << " particles skipped" << G4endl;}
272 g4vtx->SetUserInformation(new BDSPrimaryVertexInformationV(vertexInfos));
273
274 g4event->AddPrimaryVertex(g4vtx);
275}
276
277G4bool BDSHepMC3Reader::VertexInsideWorld(const G4ThreeVector& pos) const
278{
279 if (!worldSolid)
280 {// cache the world solid
281 G4Navigator* navigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
282 G4VPhysicalVolume* world = navigator->GetWorldVolume();
283 worldSolid = world->GetLogicalVolume()->GetSolid();
284 }
285 EInside qinside = worldSolid->Inside(pos);
286 return qinside == kInside;
287}
288
289#else
290// insert empty function to avoid no symbols warning
291void _SymbolToPreventWarningHEPMC3Reader(){;}
292#endif
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
BDSHepMC3Reader()=delete
Do not require default constructor.
virtual void RecreateAdvanceToEvent(G4int eventOffset)
Advance to the correct event number in the file for recreation.
void OpenFile()
Construct the member "reader" and open the file for reading.
void ReadSingleEvent()
Clear the hepmcEvent object, reallocate and read a single event and fill that member.
void HepMC2G4(const HepMC3::GenEvent *hepmcevt, G4Event *g4event)
Conversion from HepMC::GenEvent to G4Event.
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.
Full set of coordinates for association with primary vertex. Vector version.
Full set of coordinates for association with primary vertex.
type underlying() const
return underlying value (can be used in switch statement)
std::pair< G4String, G4String > SplitOnColon(const G4String &formatAndPath)
static const G4double cOverGeV
speed of light / 1 GeV, used for scaling in brho calculation
BDSEventGeneratorFileType DetermineEventGeneratorFileType(G4String distrType)
Function that gives corresponding enum value for string (case-insensitive).
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())