ATLAS Offline Software
Loading...
Searching...
No Matches
xAODTruthCnvAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4#include "xAODTruthCnvAlg.h"
5
7#include "AthLinks/ElementLink.h"
8
9#include "GaudiKernel/MsgStream.h"
10#include "GaudiKernel/DataSvc.h"
11#include "GaudiKernel/PhysicalConstants.h"
14
18
22
26
30
33
36
40
42 // Separator defined by pid==0 and eventNumber==-1 as per
43 // https://twiki.cern.ch/twiki/bin/viewauth/AtlasComputing/PileupDigitization#Arrangement_of_Truth_Information
44 const int pid = HepMC::signal_process_id(genEvt);
45 const int eventNumber = genEvt->event_number();
46 return (pid==0 && eventNumber==-1);
47}
48
49using namespace std;
50
51namespace xAODMaker {
52
53
54 xAODTruthCnvAlg::xAODTruthCnvAlg( const string& name, ISvcLocator* svcLoc )
55 : AthReentrantAlgorithm( name, svcLoc )
56 , m_metaStore( "StoreGateSvc/MetaDataStore", name )
57 , m_firstBeginRun(true)
58 {
59 // leaving metadata alone for now--to be updated
60 declareProperty( "MetaObjectName", m_metaName = "TruthMetaData" );
61 declareProperty( "MetaDataStore", m_metaStore );
62 }
63
64
67 ATH_MSG_FATAL( "Contradictory xAOD truth pile-up setting: all pile-up AND in-time alone requested simultaneously. Check settings." );
68 return StatusCode::FAILURE;
69 }
70
71 if (m_writeMetaData) {
72 ATH_CHECK( m_meta.initialize (m_metaStore, m_metaName) );
73 }
74
75 // initialize handles
77
78 // only if doing full truth
79 ATH_CHECK(m_aodContainerKey.initialize());
86 }
87
88 ATH_CHECK(m_evtInfo.initialize());
89
90 ServiceHandle<IIncidentSvc> incSvc("IncidentSvc", name());
91 ATH_CHECK(incSvc.retrieve());
92 incSvc->addListener( this, "BeginRun", 10);
93
94 ATH_MSG_DEBUG("AODContainerName = " << m_aodContainerKey.key() );
95 ATH_MSG_DEBUG("xAOD TruthEventContainer name = " << m_xaodTruthEventContainerKey.key() );
96 ATH_MSG_DEBUG("xAOD TruthPileupEventContainer name = " << m_xaodTruthPUEventContainerKey.key() );
97 ATH_MSG_DEBUG("xAOD TruthParticleContainer name = " << m_xaodTruthParticleContainerKey.key() );
98 ATH_MSG_DEBUG("xAOD TruthVertexContainer name = " << m_xaodTruthVertexContainerKey.key() );
100 ATH_MSG_DEBUG("xAOD TruthLHEParticleContainer name = " << m_lheTruthParticleContainerKey.key() );
101 }
102
103 if (m_doAllPileUp) ATH_MSG_INFO( "All pile-up truth (including out-of-time) will be written" );
104 if (m_doInTimePileUp) ATH_MSG_INFO( "In-time pile-up truth (but not out-of-time) will be written" );
105 if (!m_doAllPileUp && !m_doInTimePileUp) ATH_MSG_INFO( "No pile-up truth will be written" );
106
107 return StatusCode::SUCCESS;
108 }
109
110
111 StatusCode xAODTruthCnvAlg::execute (const EventContext& ctx) const {
112
114 ATH_CHECK(truthLinkVec.record(std::make_unique<xAODTruthParticleLinkVector>()));
115
116 // Retrieve the HepMC truth:
118 // validity check is only really needed for serial running. Remove when MT is only way.
119 if (!mcColl.isValid()) {
120 ATH_MSG_ERROR("Could not retrieve HepMC with key:" << m_aodContainerKey.key());
121 return StatusCode::FAILURE;
122 } else {
123 ATH_MSG_DEBUG( "Retrieved HepMC with key: " << m_aodContainerKey.key() );
124 }
125
126 // **************************************************************
127 // Create the xAOD containers and their auxiliary stores:
128 // **************************************************************
129 // Signal event
131 ATH_CHECK(xTruthEventContainer.record(std::make_unique<xAOD::TruthEventContainer>(),
132 std::make_unique<xAOD::TruthEventAuxContainer>()));
133 ATH_MSG_DEBUG( "Recorded TruthEventContainer with key: " << m_xaodTruthEventContainerKey.key() );
134
135 // Pile-up events
136 SG::WriteHandle<xAOD::TruthPileupEventContainer> xTruthPileupEventContainer;
139 ATH_CHECK(xTruthPileupEventContainer.record(std::make_unique<xAOD::TruthPileupEventContainer>(),
140 std::make_unique<xAOD::TruthPileupEventAuxContainer>()));
141 ATH_MSG_DEBUG( "Recorded TruthPileupEventContainer with key: " << m_xaodTruthPUEventContainerKey.key() );
142 }
143
144 // Particles
146 ATH_CHECK(xTruthParticleContainer.record(std::make_unique<xAOD::TruthParticleContainer>(),
147 std::make_unique<xAOD::TruthParticleAuxContainer>()));
148 ATH_MSG_DEBUG( "Recorded TruthParticleContainer with key: " << m_xaodTruthParticleContainerKey.key() );
149 // Vertices
151 ATH_CHECK(xTruthVertexContainer.record(std::make_unique<xAOD::TruthVertexContainer>(),
152 std::make_unique<xAOD::TruthVertexAuxContainer>()));
153 ATH_MSG_DEBUG( "Recorded TruthVertexContainer with key: " << m_xaodTruthVertexContainerKey.key() );
154
155 // To keep track of whether we wrote an LHE event already or not
156 bool hadLHERecord = false;
157
158 // ***********************************************************************************
159 // Create the xAOD objects
160 // This consists of three parts:
161 // (1) For each Athena event, loop over the GenEvents and build TruthEvent collections
162 // In principle there can be more than one GenEvent per event
163 // (2) For each GenEvent, loop over the GenParticles. For each GenParticle:
164 // (a) Create a TruthParticle.
165 // (b) Call fillParticle
166 // (c) Add the TruthParticle to the TruthParticle container, and add
167 // an EL to this TruthParticle to the truthParticles in TruthEvent
168 // (call this EL eltp)
169 // (d) For the GenVertex * that's this particle's production vertex,
170 // (i) see if it is in tempMap. If not, add it.
171 // (ii) add a copy of eltp (the EL to this truth particle) to map[gv].second
172 // (e) For the GenVertex * that's this particle's decay vertex,
173 // (i) see if it is in tempMap. If not, add it.
174 // (ii) add a copy of eltp (the EL to this truth particle) to map[gv].first
175 // (3) Iterate over tempMap. For each GenVertex *:
176 // (a) Create a TruthVertex
177 // (b) Call fillVertex
178 // (c) Add the TruthVertex to the TruthTruth container, and add an EL to this TruthVertex
179 // to the truthVertices in TruthEvent. (call this EL eltv)
180 // (d) call tv->setIncomingParticles(mapiter.second.first) <- I think mapiter.second.first is the first of the pair
181 // (e) call tv->setOutgoingParticles(mapiter.second.second)
182 // (f) Iterate through the incomingParticles, and set the decay vertex EL as eltv.
183 // (g) Iterate through the outgoingParticles, and set the incoming vertex EL as eltv.
184 //
185 // Comment lines below follow this recipe
186 // ************************************************************************************
187
188 // (1) Build TruthEvents
189 ATH_MSG_DEBUG("Number of GenEvents in this Athena event = " << mcColl->size());
190 bool newAttributesPresent(false);
191 for (unsigned int cntr = 0; cntr < mcColl->size(); ++cntr) {
192 const HepMC::GenEvent* genEvt = (*mcColl)[cntr];
193 bool isSignalProcess(false);
194 if (cntr==0) {
195 isSignalProcess=true;
196 auto bunchCrossingTime = genEvt->attribute<HepMC3::IntAttribute>(HepMCStr::BunchCrossingTime);
197 if (bunchCrossingTime) {
198 newAttributesPresent = true;
199 ATH_MSG_VERBOSE("New attributes present.");
200 }
201 else {
202 ATH_MSG_VERBOSE("New attributes missing.");
203 }
204 }
205 if (cntr>0) {
206 // Handle pile-up events
207 if (!m_doInTimePileUp && !m_doAllPileUp) break;
208 isSignalProcess=false;
209 auto bunchCrossingTime = genEvt->attribute<HepMC3::IntAttribute>(HepMCStr::BunchCrossingTime);
210 if (bunchCrossingTime) {
211 // New approach based on checking the bunch crossing
212 // time directly.
213 if (m_doInTimePileUp && std::abs(bunchCrossingTime->value()) > 0) {
214 // Skip out-of-time pile-up events
215 continue;
216 }
217 }
218 else {
219 // Old approach based on McEventCollection structure. If
220 // in-time pileup only is requested, loop stops when the
221 // separator GenEvent between out-of-time and in-time is
222 // reached
223 if (m_doInTimePileUp && isSeparatorGenEvent(genEvt)) {
224 if (newAttributesPresent) {
225 // Old structure with new Attributes?! Check all
226 // GenEvents just in case.
227 ATH_MSG_VERBOSE("New-style, but seeing separator GenEvents");
228 continue;
229 }
230 // Old structure - stop at the first separator
231 // GenEvent.
232 break;
233 }
234 }
235 }
236
237 xAOD::TruthEvent* xTruthEvent = nullptr;
238 xAOD::TruthPileupEvent* xTruthPileupEvent = nullptr;
239
240
241 if (isSignalProcess) {
242 xTruthEvent = xTruthEventContainer->push_back( std::make_unique<xAOD::TruthEvent>() );
243 // Cross-section
244 auto crossSection = genEvt->cross_section();
245 xTruthEvent->setCrossSection(crossSection ? (float)crossSection->xsec() : -1);
246 xTruthEvent->setCrossSectionError(crossSection ? (float)crossSection->xsec_err() : -1);
247
248 if (m_writeMetaData) {
249 //The mcChannelNumber is used as a unique identifier for which truth meta data belongs to
250 uint32_t mcChannelNumber = 0;
252 if (evtInfo.isValid()) {
253 mcChannelNumber = evtInfo->mcChannelNumber();
254 if (mcChannelNumber==0) mcChannelNumber = evtInfo->runNumber();
255 }
256 else {
257 ATH_MSG_FATAL("Faied to retrieve EventInfo");
258 return StatusCode::FAILURE;
259 }
260
261 ATH_CHECK( m_meta.maybeWrite (mcChannelNumber, *genEvt, m_metaFields) );
262 }
263 // Event weights
264 vector<float> weights;
265 for (const double& w : genEvt->weights()) weights.push_back((float)(w));
266 //AV This to be decided. It is always a good idea to have a default weight 1.0.
267 //if (weights.empty()) weights.push_back(1.0);
268 xTruthEvent->setWeights(weights);
269
270 // Heavy ion info
271 auto const hiInfo = genEvt->heavy_ion();
272 if (hiInfo) {
273 /* Please note HepMC3 as well as more recent HePMC2 versions have more Hi parameters */
274 xTruthEvent->setHeavyIonParameter(hiInfo->Ncoll_hard, xAOD::TruthEvent::NCOLLHARD);
275 xTruthEvent->setHeavyIonParameter(hiInfo->Npart_proj, xAOD::TruthEvent::NPARTPROJ);
276 xTruthEvent->setHeavyIonParameter(hiInfo->Npart_targ, xAOD::TruthEvent::NPARTTARG);
277 xTruthEvent->setHeavyIonParameter(hiInfo->Ncoll, xAOD::TruthEvent::NCOLL);
278 xTruthEvent->setHeavyIonParameter(hiInfo->spectator_neutrons, xAOD::TruthEvent::SPECTATORNEUTRONS);
279 xTruthEvent->setHeavyIonParameter(hiInfo->spectator_protons, xAOD::TruthEvent::SPECTATORPROTONS);
280 xTruthEvent->setHeavyIonParameter(hiInfo->N_Nwounded_collisions, xAOD::TruthEvent::NNWOUNDEDCOLLISIONS);
281 xTruthEvent->setHeavyIonParameter(hiInfo->Nwounded_N_collisions, xAOD::TruthEvent::NWOUNDEDNCOLLISIONS);
282 xTruthEvent->setHeavyIonParameter(hiInfo->Nwounded_Nwounded_collisions, xAOD::TruthEvent::NWOUNDEDNWOUNDEDCOLLISIONS);
283 xTruthEvent->setHeavyIonParameter((float)hiInfo->impact_parameter, xAOD::TruthEvent::IMPACTPARAMETER);
284 xTruthEvent->setHeavyIonParameter((float)hiInfo->event_plane_angle, xAOD::TruthEvent::EVENTPLANEANGLE);
285 xTruthEvent->setHeavyIonParameter((float)hiInfo->eccentricity, xAOD::TruthEvent::ECCENTRICITY);
286 xTruthEvent->setHeavyIonParameter((float)hiInfo->sigma_inel_NN, xAOD::TruthEvent::SIGMAINELNN);
287 // This doesn't yet exist in our version of HepMC
288 // xTruthEvent->setHeavyIonParameter(hiInfo->centrality(),xAOD::TruthEvent::CENTRALITY);
289 }
290
291 // Parton density info
292 // This will exist 99% of the time, except for e.g. cosmic or particle gun simulation
293 auto const pdfInfo = genEvt->pdf_info();
294 if (pdfInfo) {
295 xTruthEvent->setPdfInfoParameter(pdfInfo->parton_id[0], xAOD::TruthEvent::PDGID1);
296 xTruthEvent->setPdfInfoParameter(pdfInfo->parton_id[1], xAOD::TruthEvent::PDGID2);
297 xTruthEvent->setPdfInfoParameter(pdfInfo->pdf_id[1], xAOD::TruthEvent::PDFID1);
298 xTruthEvent->setPdfInfoParameter(pdfInfo->pdf_id[1], xAOD::TruthEvent::PDFID2);
299
300 xTruthEvent->setPdfInfoParameter((float)pdfInfo->x[0], xAOD::TruthEvent::X1);
301 xTruthEvent->setPdfInfoParameter((float)pdfInfo->x[1], xAOD::TruthEvent::X2);
302 xTruthEvent->setPdfInfoParameter((float)pdfInfo->scale, xAOD::TruthEvent::Q);
303 xTruthEvent->setPdfInfoParameter((float)pdfInfo->xf[0], xAOD::TruthEvent::XF1);
304 xTruthEvent->setPdfInfoParameter((float)pdfInfo->xf[1], xAOD::TruthEvent::XF2);
305 }
306
307 // Handle LHE event record
308 auto lhe_record_attribute = genEvt->attribute<HepMC::ShortEventAttribute>(HepMCStr::LHERecord);
309
310 if (lhe_record_attribute && !hadLHERecord && !m_lheTruthParticleContainerKey.empty()){
311 hadLHERecord=true;
312 // The event had an LHE record, so let's record it. This will only happen once per event.
314 ATH_CHECK(xTruthLHEParticleContainer.record(std::make_unique<xAOD::TruthParticleContainer>(),
315 std::make_unique<xAOD::TruthParticleAuxContainer>()));
316 ATH_MSG_DEBUG( "Recorded TruthLHEParticleContainer with key: " << m_lheTruthParticleContainerKey.key() );
317 // The LHE record is stored in a struct with old-style LHE format, so we have to re-encode it
318 for (int nPart=0;nPart<lhe_record_attribute->NUP;++nPart) {
319 // Create TruthParticle
320 xAOD::TruthParticle* xTruthParticle = new xAOD::TruthParticle();
321 // Put particle into container;
322 xTruthLHEParticleContainer->push_back( xTruthParticle );
323 // Copy LHE info into the new particle; good description is in https://arxiv.org/abs/hep-ph/0609017
324 xTruthParticle->setPdgId( lhe_record_attribute->IDUP[nPart] );
325 xTruthParticle->setUid( nPart+1 );
326 xTruthParticle->setStatus( lhe_record_attribute->ISTUP[nPart] );
327 xTruthParticle->setPx( lhe_record_attribute->PUP[nPart][0] );
328 xTruthParticle->setPy( lhe_record_attribute->PUP[nPart][1] );
329 xTruthParticle->setPz( lhe_record_attribute->PUP[nPart][2] );
330 xTruthParticle->setE( lhe_record_attribute->PUP[nPart][3] );
331 xTruthParticle->setM( lhe_record_attribute->PUP[nPart][4] );
332 } // End of loop over particles
333 } // End of if we found the LHE record attribute
334 else if (hadLHERecord){
335 ATH_MSG_WARNING("Truth record appeared to have two LHE records; this should not be possible");
336 }
337 }else{//not isSignalProcess
338 xTruthPileupEvent = xTruthPileupEventContainer->push_back( std::make_unique<xAOD::TruthPileupEvent>() );
339 }
340
341 // (2) Build particles and vertices
342 // Map for building associations between particles and vertices
343 // The pair in the map is the (incomingParticles . outgoingParticles) of the given vertex
344 // If signal process vertex is a disconnected vertex (no incoming/outgoing particles), add it manually
345 VertexMap vertexMap;
346 VertexMap::iterator mapItr;
347 vector<HepMC::ConstGenVertexPtr> vertices;
348
349 // Check signal process vertex
350 // If this is a disconnected vertex, add it manually or won't be added from the loop over particles below.
351 auto disconnectedSignalProcessVtx = HepMC::signal_process_vertex(genEvt); // Get the signal process vertex
352 if (disconnectedSignalProcessVtx) {
353 if (disconnectedSignalProcessVtx->particles_in_size() == 0 && disconnectedSignalProcessVtx->particles_out_size() == 0 ) {
354 //This is a disconnected vertex, add it manually
355 vertices.push_back (std::move(disconnectedSignalProcessVtx));
356 }
357 } else {
358 ATH_MSG_WARNING("Signal process vertex pointer not valid in HepMC Collection for GenEvent #" << cntr << " / " << mcColl->size());
359 }
360
361 // Get the beam particles
362 pair<HepMC::ConstGenParticlePtr,HepMC::ConstGenParticlePtr> beamParticles;
363 bool genEvt_valid_beam_particles=false;
364 auto beamParticles_vec = genEvt->beams();
365 genEvt_valid_beam_particles=(beamParticles_vec.size()>1);
366 if (genEvt_valid_beam_particles){beamParticles.first=beamParticles_vec[0]; beamParticles.second=beamParticles_vec[1]; }
367 // We want to process particles in barcode order.
368 auto bcmapatt = genEvt->attribute<HepMC::GenEventBarcodes>(HepMCStr::barcodes); // FIXME barcode-based
369 if (!bcmapatt) {
370 ATH_MSG_ERROR("TruthParticleCnvTool.cxx: Event does not contain barcodes attribute");
371 return StatusCode::FAILURE;
372 }
373 std::map<int, HepMC3::ConstGenParticlePtr> bcmap = bcmapatt->barcode_to_particle_map();
374 xTruthParticleContainer->reserve(bcmap.size());
375 for (const auto &[genPartBarcode,part]: bcmap) {
376 int genPartUniqueID = HepMC::uniqueID(part);
377 // (a) create TruthParticle
378 xAOD::TruthParticle* xTruthParticle = new xAOD::TruthParticle();
379 // (b) Put particle into container;
380 xTruthParticleContainer->push_back( xTruthParticle );
381 fillParticle(xTruthParticle, part); // (c) Copy HepMC info into the new particle
382 // (d) Build Event<->Particle element link
383 const ElementLink<xAOD::TruthParticleContainer> eltp(*xTruthParticleContainer, xTruthParticleContainer->size()-1);
384 if (isSignalProcess) xTruthEvent->addTruthParticleLink(eltp);
385 if (!isSignalProcess) xTruthPileupEvent->addTruthParticleLink(eltp);
386
387 // Create link between HepMC and xAOD truth
388 if (isSignalProcess) truthLinkVec->push_back(new xAODTruthParticleLink(HepMcParticleLink(genPartUniqueID,0,HepMcParticleLink::IS_POSITION, HepMcParticleLink::IS_ID), eltp));
389 if (!isSignalProcess) truthLinkVec->push_back(new xAODTruthParticleLink(HepMcParticleLink(genPartUniqueID,genEvt->event_number(), HepMcParticleLink::IS_EVENTNUM, HepMcParticleLink::IS_ID), eltp));
390
391 // Is this one of the beam particles?
392 if (genEvt_valid_beam_particles) {
393 if (isSignalProcess) {
394 if (part == beamParticles.first) xTruthEvent->setBeamParticle1Link(eltp);
395 if (part == beamParticles.second) xTruthEvent->setBeamParticle2Link(eltp);
396 }
397 }
398 // (e) Particle's production vertex
399 auto productionVertex = part->production_vertex();
400 // Skip the dummy vertex that HepMC3 adds
401 // Can distinguish it from real vertices because it has
402 // a null event pointer.
403 if (productionVertex && productionVertex->parent_event() != nullptr) {
404 VertexParticles& parts = vertexMap[productionVertex];
405 if (parts.incoming.empty() && parts.outgoing.empty())
406 vertices.push_back (std::move(productionVertex));
407 parts.outgoingEL.push_back(eltp);
408 parts.outgoing.push_back(xTruthParticle);
409 }
410 //
411 // else maybe want to keep track that this is the production vertex
412 //
413 // (f) Particle's decay vertex
414 auto decayVertex = part->end_vertex();
415 if (decayVertex) {
416 VertexParticles& parts = vertexMap[decayVertex];
417 if (parts.incoming.empty() && parts.outgoing.empty())
418 vertices.push_back (std::move(decayVertex));
419 parts.incomingEL.push_back(eltp);
420 parts.incoming.push_back(xTruthParticle);
421 }
422
423 } // end of loop over particles
424
425 // (3) Loop over the map
426 auto signalProcessVtx = HepMC::signal_process_vertex(genEvt); // Get the signal process vertex
427 xTruthVertexContainer->reserve(vertices.size());
428 for (const auto& vertex : vertices) {
429 const auto& parts = vertexMap[vertex];
430 // (a) create TruthVertex
431 xAOD::TruthVertex* xTruthVertex = new xAOD::TruthVertex();
432 // (b) Put particle into container (so has store)
433 xTruthVertexContainer->push_back( xTruthVertex );
434 fillVertex(xTruthVertex, vertex); // (c) Copy HepMC info into the new vertex
435 // (d) Build Event<->Vertex element link
436 ElementLink<xAOD::TruthVertexContainer> eltv(*xTruthVertexContainer, xTruthVertexContainer->size()-1);
437 // Mark if this is the signal process vertex
438 if (vertex == signalProcessVtx && isSignalProcess) xTruthEvent->setSignalProcessVertexLink(eltv);
439 if (isSignalProcess) xTruthEvent->addTruthVertexLink(eltv);
440 if (!isSignalProcess) xTruthPileupEvent->addTruthVertexLink(eltv);
441 // (e) Assign incoming particles to the vertex, from the map
442 xTruthVertex->setIncomingParticleLinks( parts.incomingEL );
443 // (f) Assign outgoing particles to the vertex, from the map
444 xTruthVertex->setOutgoingParticleLinks( parts.outgoingEL );
445 // (g) Set Particle<->Vertex links for incoming particles
446 for (xAOD::TruthParticle* p : parts.incoming) p->setDecayVtxLink(eltv);
447 // (h) Set Particle<->Vertex links for incoming particles
448 for (xAOD::TruthParticle* p : parts.outgoing) p->setProdVtxLink(eltv);
449 } //end of loop over vertices
450
451 } // end of loop over McEventCollection
452
453
454 std::stable_sort(truthLinkVec->begin(), truthLinkVec->end(), SortTruthParticleLink());
455 ATH_MSG_VERBOSE("Summarizing truth link size: " << truthLinkVec->size() );
456
457 return StatusCode::SUCCESS;
458 }
459
460 void xAODTruthCnvAlg::handle(const Incident& incident) {
461 if (m_firstBeginRun && incident.type()==IncidentType::BeginRun) {
462 m_firstBeginRun = false;
463 ServiceHandle<StoreGateSvc> inputStore("StoreGateSvc/InputMetaDataStore", name());
464 if(inputStore.retrieve().isFailure()) {
465 ATH_MSG_ERROR("Failed to retrieve Input Metadata Store");
466 return;
467 }
468 const IOVMetaDataContainer* tagInfo{nullptr};
469 if(inputStore->retrieve(tagInfo,"/TagInfo").isFailure()) {
470 ATH_MSG_WARNING("Failed to retrieve /TagInfo metadata from the input store");
471 return;
472 }
473 if(tagInfo->payloadContainer()->size()>0) {
474 CondAttrListCollection* tagInfoPayload = tagInfo->payloadContainer()->at(0);
475 if(tagInfoPayload->size()>0) {
476 const CondAttrListCollection::AttributeList& al = tagInfoPayload->attributeList(0);
477 if (al.exists("lhefGenerator")){
478 m_metaFields.lhefGenerator = al["lhefGenerator"].data<std::string>();
479 }
480
481 if (al.exists("generators")){
482 m_metaFields.generators = al["generators"].data<std::string>();
483 }
484
485 if (al.exists("evgenProcess")){
486 m_metaFields.evgenProcess = al["evgenProcess"].data<std::string>();
487 }
488
489 if (al.exists("evgenTune")){
490 m_metaFields.evgenTune = al["evgenTune"].data<std::string>();
491 }
492
493 if (al.exists("hardPDF")){
494 m_metaFields.hardPDF = al["hardPDF"].data<std::string>();
495 }
496
497 if (al.exists("softPDF")){
498 m_metaFields.softPDF = al["softPDF"].data<std::string>();
499 }
500 }
501 }
502 else {
503 ATH_MSG_WARNING("Empty Tag Info metadata!");
504 }
505 }
506 }
507
508
509 // A helper to set up a TruthVertex (without filling the ELs)
511 // id was renamed to status in HepMC3.
512 tv->setStatus(HepMC::status(gv)); // For now convert the status back to the old scheme
513 tv->setUid(HepMC::uniqueID(gv)); // FIXME set xAOD::TruthVertex function name appropriately
514 tv->setX(gv->position().x());
515 tv->setY(gv->position().y());
516 tv->setZ(gv->position().z());
517 tv->setT(gv->position().t());
518 }
519
520
521 // A helper to set up a TruthParticle (without filling the ELs)
523 tp->setPdgId(gp->pdg_id());
524 tp->setUid(HepMC::uniqueID(gp)); // FIXME set xAOD::TruthParticle function name appropriately
525 tp->setStatus(HepMC::status(gp)); // For now convert the status back to the old scheme
526
527 auto pol = HepMC::polarization(gp);
528 if (pol.is_defined()) {
531 }
532
533 tp->setM(gp->generated_mass());
534 tp->setPx(gp->momentum().px());
535 tp->setPy(gp->momentum().py());
536 tp->setPz(gp->momentum().pz());
537 tp->setE(gp->momentum().e());
538 }
539
540
541 StatusCode
543 const std::string& metaName)
544 {
545 ATH_CHECK( metaStore.retrieve() );
546
547 auto md = std::make_unique<xAOD::TruthMetaDataContainer>();
548 m_tmd = md.get();
549
550 auto aux = std::make_unique<xAOD::TruthMetaDataAuxContainer>();
551 md->setStore( aux.get() );
552
553 // Record the trigger configuration metadata into it:
554 CHECK( metaStore->record( std::move (aux), metaName + "Aux." ) );
555 CHECK( metaStore->record( std::move (md), metaName ) );
556 return StatusCode::SUCCESS;
557 }
558
559
560 StatusCode
562 const HepMC::GenEvent& genEvt,
563 const MetadataFields& metaFields)
564 {
565 // This bit needs to be serialized.
567
568 //Inserting in a (unordered_)set returns an <iterator, boolean> pair, where the boolean
569 //is used to check if the key already exists (returns false in the case it exists)
570 if( m_existingMetaDataChan.insert(mcChannelNumber).second ) {
571 m_tmd->push_back (std::make_unique <xAOD::TruthMetaData>());
572 xAOD::TruthMetaData* md = m_tmd->back();
573
575 md->setMcChannelNumber(mcChannelNumber);
576 std::vector<std::string> orderedWeightNameVec;
577 if (!genEvt.run_info()) {
578 for (size_t i=0; i<genEvt.weights().size();i++) orderedWeightNameVec.push_back(std::to_string(i));
579 } else {
580 if (!genEvt.run_info()->weight_names().empty()) {
581 orderedWeightNameVec = genEvt.weight_names();
582 } else {
583 //AV This to be decided. It is always a good idea to have a default weight 1.0.
584 //orderedWeightNameVec.push_back("0");
585 }
586 }
587 md->setWeightNames(orderedWeightNameVec);
588
589 if(!metaFields.lhefGenerator.empty()) {
590 md->setLhefGenerator(metaFields.lhefGenerator);
591 }
592 if(!metaFields.generators.empty()) {
593 md->setGenerators(metaFields.generators);
594 }
595 if(!metaFields.evgenProcess.empty()) {
596 md->setEvgenProcess(metaFields.evgenProcess);
597 }
598 if(!metaFields.evgenTune.empty()) {
599 md->setEvgenTune(metaFields.evgenTune);
600 }
601 if(!metaFields.hardPDF.empty()) {
602 md->setHardPDF(metaFields.hardPDF);
603 }
604 if(!metaFields.softPDF.empty()) {
605 md->setSoftPDF(metaFields.softPDF);
606 }
607 }
608
609 return StatusCode::SUCCESS;
610 }
611
612
613
614} // namespace xAODMaker
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This file defines the class for a collection of AttributeLists where each one is associated with a ch...
Helpers for checking error return status codes and reporting errors.
#define CHECK(...)
Evaluate an expression and check for errors.
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
This class is a container for conditions data.
static Double_t al
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
size_t size() const
Number of registered mappings.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
An algorithm that can be simultaneously executed in multiple threads.
This class is a collection of AttributeLists where each one is associated with a channel number.
const AttributeList & attributeList(ChanNum chanNum) const
attribute list for a given channel number
size_type size() const
number of Chan/AttributeList pairs
coral::AttributeList AttributeList
std::map< int, ConstGenParticlePtr > barcode_to_particle_map() const
Definition GenEvent.h:248
This class is a container for conditions data.
const IOVPayloadContainer * payloadContainer() const
Access to payload container.
size_type size() const
size of payload vector
CondAttrListCollection * at(unsigned int i) const
Element access.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
std::mutex m_mutex
Mutex to control access to meta data writing.
std::lock_guard< std::mutex > lock_t
StatusCode maybeWrite(uint32_t mcChannelNumber, const HepMC::GenEvent &genEvt, const MetadataFields &metaFields)
std::unordered_set< uint32_t > m_existingMetaDataChan
Set for tracking the mc channels for which we already added meta data.
StatusCode initialize(ServiceHandle< StoreGateSvc > &metaStore, const std::string &metaName)
xAOD::TruthMetaDataContainer * m_tmd
The meta data container to be written out.
SG::WriteHandleKey< xAOD::TruthVertexContainer > m_xaodTruthVertexContainerKey
Gaudi::Property< bool > m_doAllPileUp
Pile-up options.
SG::WriteHandleKey< xAOD::TruthParticleContainer > m_lheTruthParticleContainerKey
SG::WriteHandleKey< xAODTruthParticleLinkVector > m_truthLinkContainerKey
SG::ReadHandleKey< McEventCollection > m_aodContainerKey
The key of the input AOD truth container.
static void fillVertex(xAOD::TruthVertex *tv, const HepMC::ConstGenVertexPtr &gv)
These functions do not set up ELs, just the other variables.
xAODTruthCnvAlg(const std::string &name, ISvcLocator *svcLoc)
Regular algorithm constructor.
SG::WriteHandleKey< xAOD::TruthParticleContainer > m_xaodTruthParticleContainerKey
Gaudi::Property< bool > m_writeMetaData
option to disable writing of metadata (e.g. if running a filter on xAOD in generators)
virtual StatusCode execute(const EventContext &ctx) const override
Function executing the algorithm.
std::map< HepMC::ConstGenVertexPtr, VertexParticles > VertexMap
Convenience handle for a map of vtx ptrs -> connected particles.
ServiceHandle< StoreGateSvc > m_metaStore
Connection to the metadata store.
SG::ReadHandleKey< xAOD::EventInfo > m_evtInfo
Event Info.
Gaudi::Property< bool > m_doInTimePileUp
virtual void handle(const Incident &incident) override
Incident handler.
static void fillParticle(xAOD::TruthParticle *tp, const HepMC::ConstGenParticlePtr &gp)
std::string m_metaName
SG key and name for meta data.
SG::WriteHandleKey< xAOD::TruthEventContainer > m_xaodTruthEventContainerKey
The key for the output xAOD truth containers.
SG::WriteHandleKey< xAOD::TruthPileupEventContainer > m_xaodTruthPUEventContainerKey
virtual StatusCode initialize() override
Function initialising the algorithm.
void addTruthVertexLink(const TruthVertexLink_t &vlink)
Add one truth vertex.
void addTruthParticleLink(const TruthParticleLink_t &plink)
Add one truth particle.
void setWeights(const std::vector< float > &weights)
Set the event weights.
void setSignalProcessVertexLink(const TruthVertexLink_t &link)
Set pointer to a vertex representing the primary beam interaction point.
void setCrossSectionError(float value)
Set the cross-section error.
void setCrossSection(float value)
Set the cross-section.
bool setHeavyIonParameter(int value, HIParam parameter)
Set an integer HI parameter.
bool setPdfInfoParameter(int value, PdfParam parameter)
Set an integer PDF info parameter.
@ NWOUNDEDNWOUNDEDCOLLISIONS
[int]
void setBeamParticle1Link(const TruthParticleLink_t &pcl1)
Set one incoming beam particle.
void setBeamParticle2Link(const TruthParticleLink_t &pcl2)
Set one incoming beam particle.
void setGenerators(const std::string &value)
void setLhefGenerator(const std::string &value)
void setEvgenTune(const std::string &value)
void setHardPDF(const std::string &value)
void setMcChannelNumber(uint32_t value)
void setSoftPDF(const std::string &value)
void setWeightNames(const std::vector< std::string > &value)
void setEvgenProcess(const std::string &value)
void setPy(float value)
Set the y component of the particle's momentum.
void setUid(int value)
Set unique ID.
void setM(float value)
Also store the mass.
void setE(float value)
Set the energy of the particle.
void setPz(float value)
Set the z component of the particle's momentum.
bool setPolarizationParameter(float value, PolParam parameter)
Set method for polarization parameter values.
void setStatus(int value)
Set status code.
void setPdgId(int pid)
Set PDG ID code.
void setPx(float value)
Set the x component of the particle's momentum.
@ polarizationPhi
Polarization in ( ).
@ polarizationTheta
Polarization in ( ).
void setStatus(int value)
Set the vertex status.
void setZ(float value)
Set the vertex's longitudinal distance from the origin.
void setUid(int value)
Set the vertex unique ID.
void setOutgoingParticleLinks(const TPLinks_t &links)
Set all the outgoing particles.
void setIncomingParticleLinks(const TPLinks_t &links)
Set all the incoming particles.
void setT(float value)
Set the vertex time.
void setX(float value)
Set the x displacement of the vertex.
void setY(float value)
Set the y displacement of the vertex.
const std::string BunchCrossingTime
const std::string barcodes
const std::string LHERecord
int signal_process_id(const GenEvent &evt)
Definition GenEvent.h:572
int uniqueID(const T &p)
ConstGenVertexPtr signal_process_vertex(const GenEvent *e)
Definition GenEvent.h:597
int status(const T &p)
Polarization polarization(const T &a)
HepMC3::ConstGenParticlePtr ConstGenParticlePtr
Definition GenParticle.h:20
HepMC3::ConstGenVertexPtr ConstGenVertexPtr
Definition GenVertex.h:24
HepMC3::GenEvent GenEvent
Definition GenEvent.h:39
STL namespace.
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TruthEvent_v1 TruthEvent
Typedef to implementation.
Definition TruthEvent.h:17
TruthParticle_v1 TruthParticle
Typedef to implementation.
TruthPileupEvent_v1 TruthPileupEvent
Typedef to implementation.
TruthMetaData_v1 TruthMetaData
Typedef to implementation.
Type for tracking particles connected to a single vertex.
bool isSeparatorGenEvent(const HepMC::GenEvent *genEvt)