EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
eASTHepMC3Interface.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file eASTHepMC3Interface.cc
1 // ********************************************************************
2 //
3 // eASTHepMC3Interface.cc
4 // HepMC3 interface
5 //
6 // History
7 // June 23rd, 2021 : first empty class definition - Makoto Asai (SLAC)
8 //
9 // ********************************************************************
10 
11 #include "eASTHepMC3Interface.hh"
12 
13 #include "G4Event.hh"
14 #include "G4PrimaryParticle.hh"
15 #include "G4PrimaryVertex.hh"
16 #include "G4GenericMessenger.hh"
17 #include "G4SystemOfUnits.hh"
18 
19 // The newer ReaderFactory is header-only and can be used for older versions
20 // This file is copied verbatim from https://gitlab.cern.ch/hepmc/HepMC3
21 // Copyright (C) 2014-2020 The HepMC collaboration, licensed under GPL3
22 #include <HepMC3/Version.h>
23 #if HEPMC3_VERSION_CODE < 3002004
24 #include <HepMC_3_2_4_ReaderFactory.h>
25 #else
26 #include <HepMC3/ReaderFactory.h>
27 #endif
28 
29 #include <HepMC3/GenEvent.h>
30 #include <HepMC3/GenVertex.h>
31 #include <HepMC3/GenParticle.h>
32 
33 
34 #include "G4AutoLock.hh"
35 namespace { G4Mutex myHepMC3Mutex = G4MUTEX_INITIALIZER; }
36 
40 {
41  G4AutoLock mlock(&myHepMC3Mutex);
42  if(instance==nullptr && !instantiated)
43  { instance = new eASTHepMC3Interface(); }
44  return instance;
45 }
46 
48 {
49  messenger = new G4GenericMessenger(this,"/eAST/generator/HepMC3/",
50  "HepMC3 interface commands");
51 
52  auto& fileCmd = messenger->DeclareMethod("openFile",
53  &eASTHepMC3Interface::OpenFile, "Open the HepMC3 input file");
54  fileCmd.SetParameterName("fileName",false);
55  fileCmd.SetToBeBroadcasted(false);
56 
57  auto& vtxCmd = messenger->DeclareMethodWithUnit("vertex","mm",
59  "Set vertex position");
60  vtxCmd.SetParameterName("position",false);
61  vtxCmd.SetToBeBroadcasted(false);
62 
63  auto& timeCmd = messenger->DeclareMethodWithUnit("time0","s",
65  "Set t0 (start time at the primary vertex)");
66  timeCmd.SetParameterName("t0",false);
67  timeCmd.SetToBeBroadcasted(false);
68 
69  auto& verCmd = messenger->DeclareMethod("verbose",
70  &eASTHepMC3Interface::SetVerbose,"Verbose level");
71  verCmd.SetParameterName("verboseLevel",true);
72  verCmd.SetDefaultValue("0");
73  verCmd.SetToBeBroadcasted(false);
74 
75  instantiated = true;
76 }
77 
79 {
80  G4AutoLock mlock(&myHepMC3Mutex);
81  delete messenger;
82  instance = nullptr;
83 }
84 
85 G4bool eASTHepMC3Interface::OpenFile(G4String fName)
86 {
87  fileName = fName;
88  if(verboseLevel>0){
89  G4cout << "eASTHepMC3Interface - opening " << fileName << G4endl;
90  }
91 
92  // Make a new reader for every file.
93  // Note: This supports a variety of formats (versions 1, 2, 3, HepEct, Root)
94  // and sources (files, streams, urls, ...)
96 
97  if ( !HepMC3Reader || HepMC3Reader->failed() ) {
98  G4Exception("eASTHepMC3Interface::GeneratePrimaryVertex","Event0201",
99  FatalException, "eASTHepMC3Interface:: cannot open input.");
100  }
101  // if ( !HepMC3Reader || HepMC3Reader->failed() ) return false;
102 
103  if(verboseLevel>0){
104  G4cout << "eASTHepMC3Interface - " << fileName << " is open." << G4endl;
105  }
106 
107  return true;
108 }
109 
111 {
112  G4AutoLock mlock(&myHepMC3Mutex);
113 
114  //read the event
115  HepMC3::GenEvent hepevt(HepMC3::Units::GEV,HepMC3::Units::MM);
116 
117  if (HepMC3Reader->failed()){
118  // Todo: Don't know if there's a correct exceptionCode
119  G4Exception("eASTHepMC3Interface::GeneratePrimaryVertex","Event0201",
120  FatalException, "eASTHepMC3Interface:: cannot open input.");
121  }
122  if ( !HepMC3Reader->read_event(hepevt) ) return; // reached eof
123 
124  // The root vertex is the default primary vertex
125  // There can be multiple, unconnected graphs in the event.
126  // In all cases I've seen, that is done for technical reasons,
127  // the record still only has one event, i.e. they all share the same primary vertex
128  auto pos = hepevt.event_pos();
129  auto* g4vtx = new G4PrimaryVertex(pos.x()*mm, pos.y()*mm, pos.z()*mm, 0);
130 
131  // loop over particles
132  // allowed statuses: 1 - final, 2 - decayed hadron/lepton
133  // decay daughters will be enrolled by their mothers.
134  // topological ordering in HepMC guarantees that mothers are
135  // seen first, so only need to keep track of already created ones
136  // to either ignore or reuse
137  // using the std::map created_daughters;
138  created_daughters.clear();
139 
140  // better safe than sorry, detect faulty double-counting
141  bool safetycheck=true;
142  std::set<int> used;
143 
144  for(auto hep_p : hepevt.particles()) {
145 
146  auto status = hep_p->status();
147  if ( status != 1 && status != 2 ) continue;
148 
149  // already created?
150  auto id = hep_p->id();
151  auto finditer=created_daughters.find( id );
152  G4PrimaryParticle* g4prim;
153  if ( finditer != created_daughters.end() ){
154  g4prim = finditer->second;
155  } else {
156  // doesn't exist already -> need to create
157  // that also means it belongs to the primary vertex
158  g4prim = MakeParticle ( hep_p, safetycheck, used );
159  g4vtx->SetPrimary(g4prim);
160  }
161 
162  if ( hep_p->status() == 1 ){ // final
163  // Nothing else to do, but should look for sanity
164  if ( hep_p->children().size() !=0 ){
165  // This should never happen
166  G4Exception("eASTHepMC3Interface::GeneratePrimaryVertex","HepmcStatus",
167  FatalException, "eASTHepMC3Interface:: status 1 but children.");
168  }
169  continue;
170  }
171 
172 
173  if ( hep_p->status() == 2 ){ // decayed, has daugthers
174  if ( hep_p->children().size() ==0 ){
175  // This should never happen
176  G4Exception("eASTHepMC3Interface::GeneratePrimaryVertex","HepmcStatus",
177  FatalException, "eASTHepMC3Interface:: status 2 but no children.");
178  }
179  // Now register daughters
180  for ( auto hep_d : hep_p->children()) {
181  auto id_d = hep_d->id();
182  auto finditer_d=created_daughters.find( id_d );
183  if ( finditer_d != created_daughters.end() ){
184  // This should never happen
185  G4cout << " PROBLEM: This primary with id = " << hep_d->id()
186  << ", mother id = " << hep_p->id()
187  << ", pid = " << hep_d->pid()
188  << ", status = " << hep_d->status()
189  << " and 4-momentum = " << hep_d->momentum().px() << " " << hep_d->momentum().py() << " , " << hep_d->momentum().pz() << " , " << hep_d->momentum().e()
190  << G4endl;
191  G4cout << " PROBLEM: already there with: " << G4endl;
192  finditer_d->second->Print();
193 
194  G4Exception("eASTHepMC3Interface::GeneratePrimaryVertex","Daughter",
195  FatalException, "eASTHepMC3Interface:: found daughter out of order.");
196  }
197  if ( hep_p->status() == 2 || hep_p->status() == 1 ){
198  auto g4daughter = MakeParticle ( hep_d, safetycheck, used );
199  g4prim->SetDaughter(g4daughter);
200  // and register
201  created_daughters[id_d] = g4daughter;
202  }
203  }
204  } // end of status == 1
205  }//particle loop
206 
207  // clean the HepMC objects
208  hepevt.clear();
209 
210  // set the primary vertex to G4Event
211  g4event->AddPrimaryVertex(g4vtx);
212 }
213 
214 G4PrimaryParticle* eASTHepMC3Interface::MakeParticle ( const HepMC3::ConstGenParticlePtr hep_p,
215  const bool safetycheck, std::set<int>& used){
216  // Shouldn't see a particle more than once
217  if ( safetycheck ){
218  auto id = hep_p->id();
219  if ( used.count ( id ) ){ // contains() is c++20...
220  G4Exception("eASTHepMC3Interface::MakeParticle","Particle",
221  FatalException, "eASTHepMC3Interface:: Double-counting particles.");
222  } else {
223  used.insert( id );
224  }
225  }
226  auto p = hep_p->momentum();
227  auto* g4prim = new G4PrimaryParticle(hep_p->pid(), p.x()*GeV, p.y()*GeV, p.z()*GeV);
228  g4prim->SetPolarization(0, 0, 0);
229 
230  if ( verboseLevel > 1) {
231  G4cout << " Made primary with pid = " << hep_p->pid()
232  << ", status = " << hep_p->status()
233  << " and 4-momentum = " << p.px() << " " << p.py() << " , " << p.pz() << " , " << p.e()
234  << G4endl;
235  }
236 
237  return g4prim;
238 }
239