ATLAS Offline Software
xAODtoHepMCTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 #ifndef XAOD_STANDALONE
8 #endif
10 
12  : asg::AsgTool(name)
13 {
14 }
15 
17 {
18  ATH_MSG_INFO("Initializing xAODtoHepMCTool " << name() << "...");
19  ATH_MSG_INFO("SignalOnly = " << m_signalOnly);
20  m_evtCount = 0;
21  m_badSuggest = 0;
22  m_noProdVtx = 0;
23  m_badBeams = 0;
24  return StatusCode::SUCCESS;
25 }
26 
28 {
29  ATH_MSG_INFO("==============================================================");
30  ATH_MSG_INFO("========== xAOD -> HepMC Tool :: Run Summary ==========");
31  ATH_MSG_INFO("==============================================================");
32  if (m_badSuggest)
33  {
34  ATH_MSG_INFO("Number of suggest_barcode failures = " << m_badSuggest);
35  ATH_MSG_INFO(" ... check input particle/vertex barcodes.");
36  }
37  else
38  {
39  ATH_MSG_INFO("No suggest_barcode failures");
40  }
41  if (m_noProdVtx)
42  {
43  ATH_MSG_INFO("Number of events that have a missing production vertex = " << m_noProdVtx);
44  }
45  else
46  {
47  ATH_MSG_INFO("No missing production vertices");
48  }
49  if (m_badBeams)
50  {
51  ATH_MSG_INFO("Number events with improperly defined beamparticles = " << m_badBeams);
52  ATH_MSG_INFO("Inconsistencies with the beam particles storage in the event record!");
53  ATH_MSG_INFO("... check xAOD::TruthEvent record ...");
54  }
55  else
56  {
57  ATH_MSG_INFO("No events with undefined beams.");
58  }
59  ATH_MSG_INFO("==============================================================");
60  ATH_MSG_INFO("=================== End Run Summary ===================");
61  ATH_MSG_INFO("==============================================================");
62  return StatusCode::SUCCESS;
63 }
64 
65 std::vector<HepMC::GenEvent> xAODtoHepMCTool ::getHepMCEvents(const xAOD::TruthEventContainer *xTruthEventContainer, const xAOD::EventInfo *eventInfo) const
66 {
67  ++m_evtCount;
68  bool doPrint = m_evtCount < m_maxCount;
69  // CREATE HEPMC EVENT COLLECTION
70  std::vector<HepMC::GenEvent> mcEventCollection;
71  // Loop over xAOD truth container
72  // Signal event is always first, followed by pileup events
73  ATH_MSG_DEBUG("Start event loop");
74  for (const xAOD::TruthEvent *xAODEvent : *xTruthEventContainer)
75  {
76  if (doPrint)
77  ATH_MSG_DEBUG("XXX Printing xAOD Event");
78  if (doPrint)
79  printxAODEvent(xAODEvent, eventInfo);
80  // Create GenEvent for each xAOD truth event
81  ATH_MSG_DEBUG("Create new GenEvent");
82  HepMC::GenEvent&& hepmcEvent = createHepMCEvent(xAODEvent, eventInfo);
83  #ifdef HEPMC3
84  std::shared_ptr<HepMC3::GenRunInfo> runinfo = std::make_shared<HepMC3::GenRunInfo>(*(hepmcEvent.run_info().get()));
85  #endif
86  // Insert into McEventCollection
87  mcEventCollection.push_back(std::move(hepmcEvent));
88  #ifdef HEPMC3
89  mcEventCollection[mcEventCollection.size()-1].set_run_info(runinfo);
90  #endif
91  if (doPrint)
92  ATH_MSG_DEBUG("XXX Printing HepMC Event");
93  if (doPrint)
94  HepMC::Print::line(std::cout, hepmcEvent);
95  // Quit if signal only
96  if (m_signalOnly)
97  break;
98  }
99  return mcEventCollection;
100 }
101 
102 HepMC::GenEvent xAODtoHepMCTool::createHepMCEvent(const xAOD::TruthEvent *xEvt, const xAOD::EventInfo *eventInfo) const
103 {
104 
106  HepMC::GenEvent genEvt;
107  #ifdef HEPMC3
108  genEvt.set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
109  #endif
110 
111  long long int evtNum = eventInfo->eventNumber();
112  genEvt.set_event_number(evtNum);
113  ATH_MSG_DEBUG("Start createHepMCEvent for event " << evtNum);
114 
115  //Weights
116  #ifndef XAOD_STANDALONE
117  const std::vector<float> weights = xEvt->weights();
118  std::map<std::string, int> weightNameMap;
119  if (AthAnalysisHelper::retrieveMetadata("/Generation/Parameters","HepMCWeightNames", weightNameMap).isFailure()) {
120  ATH_MSG_DEBUG("Couldn't find meta-data for weight names.");
121  }
122  #ifdef HEPMC3
123  std::shared_ptr<HepMC3::GenRunInfo> runinfo = std::make_shared<HepMC3::GenRunInfo>();
124  genEvt.set_run_info(runinfo);
125  std::vector<std::string> wnames;
126  wnames.reserve(weights.size());
127  for (int idx = 0; idx < int(weights.size()); ++idx) {
128  for (const auto& it : weightNameMap) {
129  if (it.second == idx) {
130  wnames.push_back(it.first);
131  break;
132  }
133  }
134  }
135  genEvt.run_info()->set_weight_names(wnames);
136  for ( std::vector<float>::const_iterator wgt = weights.begin(); wgt != weights.end(); ++wgt ) {
137  genEvt.weights().push_back(*wgt);
138  }
139  #else
140  if (weightNameMap.size()) {
141  HepMC::WeightContainer& wc = genEvt.weights();
142  wc.clear();
143  for (int idx = 0; idx < int(weights.size()); ++idx) {
144  for (const auto& it : weightNameMap) {
145  if (it.second == idx) {
146  wc[ it.first ] = weights[idx];
147  break;
148  }
149  }
150  }
151  }
152  else {
153  for ( std::vector<float>::const_iterator wgt = weights.begin(); wgt != weights.end(); ++wgt ) {
154  genEvt.weights().push_back(*wgt);
155  }
156  }
157  #endif
158  #endif
159 
160  // PARTICLES AND VERTICES
161  // Map of existing vertices - needed for the tree linking
162  std::map<const xAOD::TruthVertex *, HepMC::GenVertexPtr> vertexMap;
163 
164  // Loop over all of the particles in the event, call particle builder
165  // Call suggest_barcode only after insertion!
166  for (auto tlink : xEvt->truthParticleLinks()) {
167  if (!tlink.isValid()) { continue; }
168  const xAOD::TruthParticle *xPart = *tlink;
169 
170  // sanity check
171  if (xPart == nullptr) {
172  ATH_MSG_WARNING("xAOD TruthParticle is equal to NULL. This should not happen!");
173  continue;
174  }
175 
176  if (!xPart->hasProdVtx() && !xPart->hasDecayVtx()) {
177  ATH_MSG_WARNING("xAOD particle with no vertices, uniqueID = " << HepMC::uniqueID(xPart));
178  continue;
179  }
180 
181  // skip particles which are Geant4 secondaries
182  if (HepMC::is_simulation_particle(xPart)) { continue; }
183 
184  // Create GenParticle
185  // presumably the GenEvent takes ownership of this, but creating a unique_ptr here as that will only happen if there's an associated vertex
186 #ifdef HEPMC3
187  auto hepmcParticle = createHepMCParticle(xPart);
188 #else
189  std::unique_ptr<HepMC::GenParticle> hepmcParticle(createHepMCParticle(xPart));
190 #endif
191  int bcpart = HepMC::barcode(xPart);
192 
193  // status HepMC::SPECIALSTATUS should be treated just as status 2
194  if (hepmcParticle->status() == HepMC::SPECIALSTATUS) {
195  hepmcParticle->set_status(2);
196  }
197 
198  // Get the production and decay vertices
199  if (xPart->hasProdVtx()) {
200  const xAOD::TruthVertex *xAODProdVtx = xPart->prodVtx();
201  // skip production vertices which are Geant4 secondaries
202  if (HepMC::is_simulation_vertex(xAODProdVtx)) { continue; }
203  bool prodVtxSeenBefore(false); // is this new?
204  auto hepmcProdVtx = vertexHelper(xAODProdVtx, vertexMap, prodVtxSeenBefore);
205  // Set the decay/production links
206 #ifdef HEPMC3
207  hepmcProdVtx->add_particle_out(hepmcParticle);
208 #else
209  hepmcProdVtx->add_particle_out(hepmcParticle.get());
210 #endif
211  // Insert into Event
212  if (!prodVtxSeenBefore) {
213  genEvt.add_vertex(hepmcProdVtx);
214  if (!HepMC::suggest_barcode(hepmcProdVtx, HepMC::barcode(xAODProdVtx))) {
215  ATH_MSG_WARNING("suggest_barcode failed for vertex " << HepMC::barcode(xAODProdVtx));
216  ++m_badSuggest;
217  }
218  }
219  if (!HepMC::suggest_barcode(hepmcParticle, bcpart)) {
220  ATH_MSG_VERBOSE("suggest_barcode failed for particle " << bcpart);
221  ++m_badSuggest;
222  }
223  bcpart = 0;
224  }
225  else {
226  ATH_MSG_VERBOSE("No production vertex found for particle " << HepMC::uniqueID(xPart));
227  }
228 
229  if (xPart->hasDecayVtx()) {
230  const xAOD::TruthVertex *xAODDecayVtx = xPart->decayVtx();
231  // skip decay vertices which are Geant4 secondaries
232  if (HepMC::is_simulation_vertex(xAODDecayVtx)) {
234 #ifndef HEPMC3
235  if (xPart->hasProdVtx()) { (void)hepmcParticle.release(); }
236 #endif
237  continue;
238  }
239  bool decayVtxSeenBefore(false); // is this new?
240  auto hepmcDecayVtx = vertexHelper(xAODDecayVtx, vertexMap, decayVtxSeenBefore);
241  // Set the decay/production links
242 #ifdef HEPMC3
243  hepmcDecayVtx->add_particle_in(hepmcParticle);
244 #else
245  hepmcDecayVtx->add_particle_in(hepmcParticle.get());
246 #endif
247  // Insert into Event
248  if (!decayVtxSeenBefore) {
249  genEvt.add_vertex(hepmcDecayVtx);
250  if (!HepMC::suggest_barcode(hepmcDecayVtx, HepMC::barcode(xAODDecayVtx))) {
251  ATH_MSG_WARNING("suggest_barcode failed for vertex "
252  << HepMC::barcode(xAODDecayVtx));
253  ++m_badSuggest;
254  }
255  }
256  if (bcpart != 0) {
257  if (!HepMC::suggest_barcode(hepmcParticle, bcpart)) {
258  ATH_MSG_DEBUG("suggest_barcode failed for particle " << bcpart);
259  ++m_badSuggest;
260  }
261  bcpart = 0;
262  }
263  }
264 #ifndef HEPMC3
265  (void)hepmcParticle.release();
266 #endif
267 
268  } // end of particle loop
269 
270  return genEvt;
271 }
272 
273 // Helper to check whether a vertex exists or not using a map;
274 // calls createHepMCVertex if not
276  std::map<const xAOD::TruthVertex *, HepMC::GenVertexPtr> &vertexMap,
277  bool &seenBefore) const
278 {
279 
280  HepMC::GenVertexPtr hepmcVertex;
282  vMapItr = vertexMap.find(xaodVertex);
283  // Vertex seen before?
284  if (vMapItr != vertexMap.end()) {
285  // YES: use the HepMC::Vertex already in the map
286  hepmcVertex = (*vMapItr).second;
287  seenBefore = true;
288  }
289  else {
290  // NO: create a new HepMC::Vertex
291  vertexMap[xaodVertex] = createHepMCVertex(xaodVertex);
292  hepmcVertex = vertexMap[xaodVertex];
293  seenBefore = false;
294  }
295  return hepmcVertex;
296 }
297 
298 // Create the HepMC GenParticle
299 // Call suggest_barcode after insertion!
301 {
302  ATH_MSG_VERBOSE("Creating GenParticle for uniqueID " << HepMC::uniqueID(particle));
303  const HepMC::FourVector fourVec(m_momFac * particle->px(), m_momFac * particle->py(), m_momFac * particle->pz(), m_momFac * particle->e());
304  auto hepmcParticle = HepMC::newGenParticlePtr(fourVec, particle->pdgId(), particle->status());
305  hepmcParticle->set_generated_mass(m_momFac * particle->m());
306  return hepmcParticle;
307 }
308 
309 // Create the HepMC GenVertex
310 // Call suggest_barcode after insertion!
312 {
313  ATH_MSG_VERBOSE("Creating GenVertex for uniqueID " << HepMC::uniqueID(vertex));
314  HepMC::FourVector prod_pos(m_lenFac * vertex->x(), m_lenFac * vertex->y(), m_lenFac * vertex->z(), m_lenFac * vertex->t());
315  auto genVertex = HepMC::newGenVertexPtr(prod_pos);
316  return genVertex;
317 }
318 
319 // Print xAODTruth Event. The printout is particle oriented, unlike the HepMC particle/vertex printout. Regenerated Geant (i.e. ones surving an interaction) and pileup particles (e.g. suppressed pileup barcodes), with barcode > 1000000 are omitted. Thus we output only the original particles created in Geant4.
320 
322 {
323 
324  std::vector<int> uidPars;
325  std::vector<int> uidKids;
326 
327  long long int evtNum = eventInfo->eventNumber();
328 
329  std::cout << "======================================================================================" << std::endl;
330  std::cout << "xAODTruth Event " << evtNum << std::endl;
331  std::cout << " UniqueID PDG Id Status px(GeV) py(GeV) pz(GeV) E(GeV) Parent: Decay" << std::endl;
332  std::cout << " -----------------------------------------------------------------------------------" << std::endl;
333 
334  int nPart = event->nTruthParticles();
335  for (int i = 0; i < nPart; ++i)
336  {
337  const xAOD::TruthParticle *part = event->truthParticle(i);
338  if (part == nullptr) continue;
339  if (HepMC::generations(part) > 0) continue;
340  int id = part->pdgId();
341  if (id != 25) continue;
342  int stat = part->status();
343  float px = part->px() / 1000.;
344  float py = part->py() / 1000.;
345  float pz = part->pz() / 1000.;
346  float e = part->e() / 1000.;
347  uidPars.clear();
348  uidKids.clear();
349 
350  if (part->hasProdVtx())
351  {
352  const xAOD::TruthVertex *pvtx = part->prodVtx();
353  if (pvtx)
354  uidPars.push_back(HepMC::uniqueID(pvtx));
355  }
356 
357  if (part->hasDecayVtx())
358  {
359  const xAOD::TruthVertex *dvtx = part->decayVtx();
360  if (dvtx)
361  uidKids.push_back(HepMC::uniqueID(dvtx));
362  }
363 
364  std::cout << std::setw(10) << HepMC::uniqueID(part) << std::setw(12) << id
365  << std::setw(8) << stat
366  << std::setprecision(2) << std::fixed
367  << std::setw(10) << px << std::setw(10) << py
368  << std::setw(10) << pz << std::setw(10) << e << " ";
369  std::cout << "P: ";
370  for (unsigned int k = 0; k < uidPars.size(); ++k)
371  {
372  std::cout << uidPars[k] << " ";
373  }
374  std::cout << " D: ";
375  for (unsigned int k = 0; k < uidKids.size(); ++k)
376  {
377  std::cout << uidKids[k] << " ";
378  }
379  std::cout << std::endl;
380  }
381  std::cout << "======================================================================================" << std::endl;
382 }
HepMC::GenVertexPtr
HepMC::GenVertex * GenVertexPtr
Definition: GenVertex.h:59
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
HepMC::suggest_barcode
bool suggest_barcode(T &p, int i)
Definition: GenEvent.h:548
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
xAODtoHepMCTool::m_signalOnly
Gaudi::Property< bool > m_signalOnly
Definition: xAODtoHepMCTool.h:49
xAODtoHepMCTool::xAODtoHepMCTool
xAODtoHepMCTool(const std::string &name)
Definition: xAODtoHepMCTool.cxx:11
test_pyathena.px
px
Definition: test_pyathena.py:18
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
xAOD::EventInfo_v1::eventNumber
uint64_t eventNumber() const
The current event's event number.
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
HepMC::GenParticlePtr
GenParticle * GenParticlePtr
Definition: GenParticle.h:37
skel.it
it
Definition: skel.GENtoEVGEN.py:423
asg
Definition: DataHandleTestTool.h:28
MM
@ MM
Definition: RegSelEnums.h:38
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
HepMC::Print::line
void line(std::ostream &os, const GenEvent &e)
Definition: GenEvent.h:554
DeMoUpdate.runinfo
def runinfo
Definition: DeMoUpdate.py:542
xAODtoHepMCTool::m_badBeams
int m_badBeams
Definition: xAODtoHepMCTool.h:60
xAODtoHepMCTool::printxAODEvent
void printxAODEvent(const xAOD::TruthEvent *event, const xAOD::EventInfo *eventInfo) const
Definition: xAODtoHepMCTool.cxx:321
xAODtoHepMCTool::m_evtCount
std::atomic< int > m_evtCount
Counters.
Definition: xAODtoHepMCTool.h:57
xAODtoHepMCTool::m_noProdVtx
int m_noProdVtx
Definition: xAODtoHepMCTool.h:59
xAODtoHepMCTool.h
xAODtoHepMCTool::m_maxCount
Gaudi::Property< int > m_maxCount
Definition: xAODtoHepMCTool.h:52
xAODtoHepMCTool::createHepMCEvent
HepMC::GenEvent createHepMCEvent(const xAOD::TruthEvent *xEvt, const xAOD::EventInfo *eventInfo) const
Definition: xAODtoHepMCTool.cxx:102
xAOD::TruthParticle_v1::hasDecayVtx
bool hasDecayVtx() const
Check for a decay vertex on this particle.
HepMC::SPECIALSTATUS
constexpr int SPECIALSTATUS
Constant that the meaning of which is currently lost, to be recovered...
Definition: MagicNumbers.h:41
xAODtoHepMCTool::finalize
StatusCode finalize() override
Definition: xAODtoHepMCTool.cxx:27
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
HepMC::is_simulation_particle
bool is_simulation_particle(const T &p)
Method to establish if a particle (or barcode) was created during the simulation (TODO update to be s...
Definition: MagicNumbers.h:299
HepMC::newGenVertexPtr
GenVertexPtr newGenVertexPtr(const HepMC::FourVector &pos=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), const int i=0)
Definition: GenVertex.h:64
lumiFormat.i
int i
Definition: lumiFormat.py:92
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
HepMC::barcode
int barcode(const T *p)
Definition: Barcode.h:16
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:41
xAODtoHepMCTool::m_lenFac
Gaudi::Property< float > m_lenFac
Definition: xAODtoHepMCTool.h:46
xAOD::TruthParticle_v1::hasProdVtx
bool hasProdVtx() const
Check for a production vertex on this particle.
Definition: TruthParticle_v1.cxx:74
HepMC::uniqueID
int uniqueID(const T &p)
Definition: MagicNumbers.h:113
Amg::pz
@ pz
Definition: GeoPrimitives.h:40
xAOD::TruthEvent_v1
Class describing a signal truth event in the MC record.
Definition: TruthEvent_v1.h:35
HepMC::is_simulation_vertex
bool is_simulation_vertex(const T &v)
Method to establish if the vertex was created during simulation (TODO migrate to be based on status).
Definition: MagicNumbers.h:305
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
beamspotman.stat
stat
Definition: beamspotman.py:266
xAOD::TruthParticle_v1::decayVtx
const TruthVertex_v1 * decayVtx() const
The decay vertex of this particle.
xAOD::TruthEvent_v1::weights
const std::vector< float > & weights() const
Const access to the weights vector.
xAOD::TruthParticle_v1::prodVtx
const TruthVertex_v1 * prodVtx() const
The production vertex of this particle.
Definition: TruthParticle_v1.cxx:80
xAOD::TruthVertex_v1
Class describing a truth vertex in the MC record.
Definition: TruthVertex_v1.h:41
xAODtoHepMCTool::createHepMCParticle
HepMC::GenParticlePtr createHepMCParticle(const xAOD::TruthParticle *) const
Definition: xAODtoHepMCTool.cxx:300
Amg::py
@ py
Definition: GeoPrimitives.h:39
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
MagicNumbers.h
xAOD::EventInfo_v1
Class describing the basic event information.
Definition: EventInfo_v1.h:43
AthAnalysisHelper.h
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
HepMC::newGenParticlePtr
GenParticlePtr newGenParticlePtr(const HepMC::FourVector &mom=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), int pid=0, int status=0)
Definition: GenParticle.h:39
xAODtoHepMCTool::initialize
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
Definition: xAODtoHepMCTool.cxx:16
xAODtoHepMCTool::vertexHelper
HepMC::GenVertexPtr vertexHelper(const xAOD::TruthVertex *, std::map< const xAOD::TruthVertex *, HepMC::GenVertexPtr > &, bool &) const
Definition: xAODtoHepMCTool.cxx:275
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
xAODtoHepMCTool::createHepMCVertex
HepMC::GenVertexPtr createHepMCVertex(const xAOD::TruthVertex *) const
Definition: xAODtoHepMCTool.cxx:311
xAODtoHepMCTool::getHepMCEvents
std::vector< HepMC::GenEvent > getHepMCEvents(const xAOD::TruthEventContainer *xTruthEventContainer, const xAOD::EventInfo *eventInfo) const override
Definition: xAODtoHepMCTool.cxx:65
xAODtoHepMCTool::m_momFac
Gaudi::Property< float > m_momFac
Input container key (job property)
Definition: xAODtoHepMCTool.h:43
xAOD::TruthEventBase_v1::truthParticleLinks
const TruthParticleLinks_t & truthParticleLinks() const
Get all the truth particles.
HepMC::generations
int generations(const T &p)
Method to return how many interactions a particle has undergone during simulation (TODO migrate to be...
Definition: MagicNumbers.h:302
xAODtoHepMCTool::m_badSuggest
std::atomic< int > m_badSuggest
Definition: xAODtoHepMCTool.h:58
fitman.k
k
Definition: fitman.py:528
AthAnalysisHelper::retrieveMetadata
static std::string retrieveMetadata(const std::string &folder, const std::string &key, const ServiceHandle< StoreGateSvc > &inputMetaStore)
method that always returns as a string you can use from, e.g, pyROOT with evt = ROOT....
Definition: AthAnalysisHelper.h:254