ATLAS Offline Software
MergeMcEventCollTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "MergeMcEventCollTool.h"
6 
7 #include "AthenaKernel/errorcheck.h" // Handy definitions for error checking
11 
12 #include "GaudiKernel/PhysicalConstants.h"
13 using namespace Gaudi::Units;
14 
15 
16 #include <vector>
17 #include <string>
18 #include <cmath>
19 #include <stdexcept>
20 #include <array>
21 
22 typedef std::pair<int, int> IndexKey;
23 namespace {
24  IndexKey makekey(int signal_process_id, int event_number, int separator_hack=0) {
25  //std::size_t key(0);
26  //Check for Separtor GenEvents
27  if(signal_process_id==0 && event_number==-1) {
28  return std::make_pair(separator_hack, event_number);
29  }
30  return std::make_pair(signal_process_id, event_number);
31  }
32 
33  class GenEventSorter {
34  public:
35  typedef std::map<IndexKey, int> PileUpBackgroundMap;
36  GenEventSorter(const PileUpBackgroundMap& backgroundClassificationMap) : m_backgroundClassificationMap(backgroundClassificationMap) {}
37  bool operator() (const HepMC::GenEvent *pGenEvent1, const HepMC::GenEvent *pGenEvent2) {
38  const int signal_process_id1(HepMC::signal_process_id(pGenEvent1)), event_number1(pGenEvent1->event_number()), separator_hack1(HepMC::mpi(pGenEvent1));
39  const int signal_process_id2(HepMC::signal_process_id(pGenEvent2)), event_number2(pGenEvent2->event_number()), separator_hack2(HepMC::mpi(pGenEvent2));
40  const IndexKey key1(makekey(signal_process_id1, event_number1,separator_hack1));
41  const IndexKey key2(makekey(signal_process_id2, event_number2,separator_hack2));
42  const PileUpBackgroundMap::const_iterator event1=m_backgroundClassificationMap.find(key1);
43  const PileUpBackgroundMap::const_iterator event2=m_backgroundClassificationMap.find(key2);
44  if(event1==m_backgroundClassificationMap.end()) {
45  throw std::runtime_error("GenEventSorter::operator() : IndexKey 1 not found in backgroundClassificationMap");
46  }
47  if(event2==m_backgroundClassificationMap.end()) {
48  throw std::runtime_error("GenEventSorter::operator() : IndexKey 2 not found in backgroundClassificationMap");
49  }
50 
51  //Both events have the same 'type'
52  if(event1->second==event2->second) {
53  if (is_separator(signal_process_id1, event_number1)) {return true;} //separator GenEvents should go at the start of each classification
54  if (is_separator(signal_process_id2, event_number2)) {return false;}
55  //Both events are from the same dataset
56  if (signal_process_id1==signal_process_id2) {
57  return (event_number1<event_number2);
58  }
59  return (signal_process_id1<signal_process_id2);
60  }
61  return (event1->second<event2->second);
62 
63  }
64  private:
65  inline bool is_separator(int signal_process_id, int event_number) const { return (0==signal_process_id && -1==event_number); }
66  const PileUpBackgroundMap& m_backgroundClassificationMap;
67  };
68 } //anonymous namespace
69 
71  const std::string& name,
72  const IInterface *parent) :
74 {
75 }
76 
78  ATH_MSG_DEBUG( "Initializing" );
79  if (m_doSlimming) {
80  //set all m_saveTypes based on properties
85  }
86  else {
87  m_keepUnstable = true;
88  m_saveType[INTIME] = true;
89  m_saveType[OUTOFTIME] = true;
90  m_saveType[RESTOFMB] = true;
91  m_saveType[CAVERN] = true;
92  }
94 
95  return StatusCode::SUCCESS;
96 }
97 
98 StatusCode MergeMcEventCollTool::prepareEvent(const EventContext& /*ctx*/, unsigned int nInputEvents) {
99  //clear the background classification map
101  m_newevent=true;
102 
103  //Check we are getting at least one event
104  m_nInputMcEventColls = nInputEvents;
105  if (0 == m_nInputMcEventColls) {
106  msg(MSG::ERROR)
107  << "prepareEvent: TimedTruthList with key "
108  << m_truthCollInputKey.value()
109  << " is empty" << endmsg;
110  return StatusCode::RECOVERABLE;
111  }
112  ATH_MSG_DEBUG( "prepareEvent: there are " << m_nInputMcEventColls << " subevents in this event.");
113 
114  return StatusCode::SUCCESS;
115 }
116 
118  ATH_MSG_VERBOSE ( "processAllSubEvents()" );
119  if(!m_pMergeSvc) {
120  if (!(m_pMergeSvc.retrieve()).isSuccess()) {
121  ATH_MSG_FATAL ( "processAllSubEvents: Could not find PileUpMergeSvc" );
122  return StatusCode::FAILURE;
123  }
124  }
125 
126  //PRECONDITIONS
127  //first get the list of McEventCollections
129  TimedTruthList truthList;
130  if (!m_pMergeSvc->retrieveSubEvtsData(m_truthCollInputKey.value(), truthList).isSuccess() ) {
131  msg(MSG::ERROR)
132  << "execute: Can not find TimedTruthList with key "
133  << m_truthCollInputKey.value() << endmsg;
134  return StatusCode::RECOVERABLE;
135  }
136 
137  //clear the background classification map
139 
140  //Check we are getting at least one event
141  m_nInputMcEventColls=truthList.size();
142  if (0 == m_nInputMcEventColls) {
143  msg(MSG::ERROR)
144  << "execute: TimedTruthList with key "
145  << m_truthCollInputKey.value()
146  << " is empty" << endmsg;
147  return StatusCode::RECOVERABLE;
148  }
149  ATH_MSG_DEBUG( "execute: there are " << m_nInputMcEventColls << " subevents in this event.");
150  TimedTruthList::iterator timedTruthListIter(truthList.begin()), endOfTimedTruthList(truthList.end());
151  //loop over the McEventCollections (each one assumed to containing exactly one GenEvent) of the various input events
152  m_newevent=true;
153  while (timedTruthListIter != endOfTimedTruthList) {
154  const PileUpTimeEventIndex& currentPileUpTimeEventIndex(timedTruthListIter->first);
155  const McEventCollection *pBackgroundMcEvtColl(&*(timedTruthListIter->second));
156  if (!processEvent(pBackgroundMcEvtColl, currentPileUpTimeEventIndex.time(), currentPileUpTimeEventIndex.index(), static_cast<int>(currentPileUpTimeEventIndex.type())).isSuccess()) {
157  ATH_MSG_ERROR ("Failed to process McEventCollection." );
158  return StatusCode::FAILURE;
159  }
160  ++timedTruthListIter;
161  } //timed colls
162 
163  //Remove empty copies of GenEvents
165 
166  //Sort the GenEvents in the output McEventCollection according to background classification
167  std::sort(m_pOvrlMcEvColl->begin(), m_pOvrlMcEvColl->end(), GenEventSorter(m_backgroundClassificationMap));
168 
169  if(msgLvl(MSG::DEBUG)) {
170  ATH_MSG_DEBUG("Sorted McEventCollection OK.");
172  }
173 
174  if(m_pOvrlMcEvColl->at(0)->event_number()!=-2)
175  {
176  ATH_MSG_FATAL("Signal GenEvent is not first in the list! Something has gone wrong during the GenEvent sorting!");
177  return StatusCode::FAILURE;
178  }
179  //Restore original event number
180  m_pOvrlMcEvColl->at(0)->set_event_number(m_signal_event_number);
181 
182  return StatusCode::SUCCESS;
183 }
184 
186  SubEventIterator bSubEvents,
187  SubEventIterator eSubEvents)
188 {
189  ATH_MSG_VERBOSE ( "processBunchXing()" );
190  SubEventIterator iEvt(bSubEvents);
191  //loop over the McEventCollections (each one assumed to containing exactly one GenEvent) of the various input events
192  while (iEvt != eSubEvents) {
193  const McEventCollection *pMEC(NULL);
194  if (!m_pMergeSvc->retrieveSingleSubEvtData(m_truthCollInputKey.value(), pMEC,
195  bunchXing, iEvt).isSuccess()){
196  ATH_MSG_ERROR("McEventCollection not found for event key " << m_truthCollInputKey.value());
197  return StatusCode::FAILURE;
198  }
199 
200  if (!processEvent(pMEC,iEvt->time(),iEvt->index(), static_cast<int>(iEvt->type())).isSuccess()) {
201  ATH_MSG_ERROR ("processBunchXing: Failed to process McEventCollection." );
202  return StatusCode::FAILURE;
203  }
204  ++iEvt;
205  }
206  return StatusCode::SUCCESS;
207 }
208 
209 StatusCode MergeMcEventCollTool::mergeEvent(const EventContext& /*ctx*/) {
210  ATH_MSG_DEBUG( "mergeEvent" );
212  ATH_MSG_WARNING( "mergeEvent: Expected " << m_nInputMcEventColls << " subevents, but only saw " << m_nBkgEventsReadSoFar+1 << "! The job will probably crash now..." );
213  return StatusCode::FAILURE;
214  }
215 
216  //Remove empty copies of GenEvents
218 
219  if(m_backgroundClassificationMap.size()!=m_pOvrlMcEvColl->size()) {
220  ATH_MSG_WARNING( "There are " << m_pOvrlMcEvColl->size() << " GenEvents in the McEventCollection, but " << m_backgroundClassificationMap.size() << " entries in the classification map." );
221  }
222  //Sort the GenEvents in the output McEventCollection according to background classification
223 
224  std::sort(m_pOvrlMcEvColl->begin(), m_pOvrlMcEvColl->end(), GenEventSorter(m_backgroundClassificationMap));
225  ATH_MSG_DEBUG("Sorted McEventCollection OK.");
227 
228  if(m_pOvrlMcEvColl->at(0)->event_number()!=-2)
229  {
230  ATH_MSG_FATAL("Signal GenEvent is not first in the list! Something has gone wrong during the GenEvent sorting!");
231  return StatusCode::FAILURE;
232  }
233  //Restore original event number
234  m_pOvrlMcEvColl->at(0)->set_event_number(m_signal_event_number);
235 
236  return StatusCode::SUCCESS;
237 }
239  if (! m_pOvrlMcEvColl->empty()) {
240  ATH_MSG_INFO ( "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" );
241  ATH_MSG_INFO ( "INTIME("<<int(INTIME)<<"), OUTOFTIME("<<int(OUTOFTIME)<<"), RESTOFMB("<<int(RESTOFMB)<<"), CAVERN("<<int(CAVERN)<<"), NOPUTYPE("<<int(NOPUTYPE)<<")" );
242  ATH_MSG_INFO ( "Current OUTPUT GenEvent: " );
243  auto outputEventItr = m_pOvrlMcEvColl->cbegin();
244  while(outputEventItr!=m_pOvrlMcEvColl->cend()) {
245  const int signal_process_id(HepMC::signal_process_id((*outputEventItr))), event_number((*outputEventItr)->event_number()), separator_hack(HepMC::mpi((*outputEventItr)));
246  const IndexKey key(makekey(signal_process_id,event_number,separator_hack));
247  const PileUpBackgroundMap::const_iterator event(m_backgroundClassificationMap.find(key));
248  ATH_MSG_INFO ( "GenEvent #"<<event_number<<", signal_process_id="<<signal_process_id<<", category="<<event->second<<", number of Vertices="<<(*outputEventItr)->vertices_size() );
249  ++outputEventItr;
250  }
251  ATH_MSG_INFO ( "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" );
252  }
253  return;
254 }
255 
257  StatusCode sc(StatusCode::FAILURE);
258  //Assumes the first sub-event is the signal event
259  m_pOvrlMcEvColl = new McEventCollection(*pMcEvtColl);
260  m_signal_event_number = m_pOvrlMcEvColl->at(0)->event_number();
261  m_pOvrlMcEvColl->at(0)->set_event_number(-2); //Set this to zero for the purposes of sorting. (restore after sorting).
262 #ifdef HEPMC3
263  m_pOvrlMcEvColl->at(0)->add_attribute("BunchCrossingTime",std::make_shared<HepMC3::IntAttribute>(0));
264  m_pOvrlMcEvColl->at(0)->add_attribute("PileUpType",std::make_shared<HepMC3::IntAttribute>(0));
265 #endif
266  updateClassificationMap(HepMC::signal_process_id(m_pOvrlMcEvColl->at(0)), m_pOvrlMcEvColl->at(0)->event_number(), 0,- 1, true);
267  m_newevent=false; //Now the McEventCollection and classification map are not empty this should be set to false.
268  ATH_MSG_DEBUG( "execute: copied original event McEventCollection" );
269  const unsigned int nBackgroundMcEventCollections(m_nInputMcEventColls-1); // -1 for original event
270  // -> reserve enough space
271  unsigned int outCollSize(m_pOvrlMcEvColl->size());
272  if(!m_onlySaveSignalTruth) { outCollSize += nBackgroundMcEventCollections; }
273  outCollSize += NOPUTYPE-1; // Adding room for the spacers
274  m_pOvrlMcEvColl->resize(outCollSize);
275  if(!m_onlySaveSignalTruth) { ATH_MSG_DEBUG ( "Number of input SubEvents = " << m_nInputMcEventColls ); }
276  ATH_MSG_DEBUG ( "Total Size of Output McEventCollection = " << outCollSize );
277 
278  //now place the "separator" GenEvents. This is a hack used by clients to find/double-check where the GenEvents
279  //of a given type start in the overlay McEventCollection.
280 
281  // For example if intime and cavern saving is enabled i.e.
282  // Configurable Variable in code Example Value
283  // SaveInTimeMinBias m_saveType[INTIME] true
284  // SaveOutOfTimeMinBias m_saveType[OUTOFTIME] false
285  // SaveRestOfMinBias m_saveType[RESTOFMB] false
286  // SaveCavernBackground m_saveType[CAVERN] true
287  //If we have two input GenEvents the output collection would look like
288  //SIGNAL, INTIME0, INTIME1, SEPARATOR, SEPARATOR, SEPARATOR, CAVERN0, CAVERN1
289  unsigned int currentMcEventCollectionIndex(1);
290  ATH_MSG_DEBUG ( "Event Type: SIGNAL Starts at Position 0" );
291  for (int type(OUTOFTIME); type<NOPUTYPE; ++type) {
292  //if a type is enabled leave room to insert the events of that type, otherwise place separator immediately after
293  currentMcEventCollectionIndex += 1;
294  m_pOvrlMcEvColl->at(currentMcEventCollectionIndex-1) = HepMC::newGenEvent(0, -1); //pid 0 & event_number -1 flags this GenEvent as SEPARATOR
295  HepMC::set_mpi(m_pOvrlMcEvColl->at(currentMcEventCollectionIndex-1),type);
296  updateClassificationMap(0, -1, type, type, true);
297  ATH_MSG_DEBUG ( "Placing Separator for Type: "<<type<<" at Posistion: " << currentMcEventCollectionIndex-1 );
298  }
299  m_startingIndexForBackground=currentMcEventCollectionIndex;
300  m_nBkgEventsReadSoFar=0; //number of input events/eventcolls read so far. Used to build index of output GenEvent in ovrl McEvColl
301  sc = evtStore()->record(m_pOvrlMcEvColl, m_truthCollOutputKey);//**BIG TEST**//sc=StatusCode::SUCCESS;
302  ATH_MSG_DEBUG( "Starting loop on Background events ... " );
303 
304  return sc;
305 }
306 
308  const HepMC::GenEvent* currentBackgroundEvent = *(pMcEvtColl->begin());
309 #ifdef HEPMC3
310  if (currentBackgroundEvent->particles().size()!=1) return false;
311  if (currentBackgroundEvent->particles().at(0)->pdg_id()==999) return true;
312 #else
313  if (currentBackgroundEvent->particles_size()!=1) return false;
314  if ((*(currentBackgroundEvent->particles_begin()))->pdg_id()==999) return true;
315 #endif
316  return false;
317 }
318 
319 StatusCode MergeMcEventCollTool::processEvent(const McEventCollection *pMcEvtColl, const double currentEventTime, const int currentBkgEventIndex, int pileupType) {
320  ATH_MSG_VERBOSE ( "processEvent()" );
321  if(m_newevent) return processFirstSubEvent(pMcEvtColl);
322 
323  if (pMcEvtColl->empty() || m_onlySaveSignalTruth) {
325  return StatusCode::SUCCESS;
326  }
327  //GenEvt is there
328 
329  //Examine the properties of the GenEvent - if it looks like a TruthFiltered background event (contains a Geantino?!)
330  //then save the whole event as below, otherwise do the usual classification.
331  if(isTruthFiltertedMcEventCollection(pMcEvtColl)) {
332  if ( processTruthFilteredEvent(pMcEvtColl, currentEventTime, currentBkgEventIndex, pileupType).isSuccess() ) {
334  return StatusCode::SUCCESS;
335  }
336  else {
337  ATH_MSG_ERROR ("Failed to process a Truth Filtered GenEvent.");
338  }
339  }
340  else {
341  if ( processUnfilteredEvent(pMcEvtColl, currentEventTime, currentBkgEventIndex, pileupType).isSuccess() ) {
343  return StatusCode::SUCCESS;
344  }
345  else {
346  ATH_MSG_ERROR ("Failed to process an Unfiltered GenEvent.");
347  }
348  }
349  //If we make it here something has gone wrong.
351  return StatusCode::FAILURE;
352 }
353 
355 {
356  if (m_pOvrlMcEvColl->at(0)->heavy_ion()) return StatusCode::SUCCESS;
357  if (pMcEvtColl->at(0)->heavy_ion())
358  {
359 //It should be clarified if ne wants to get a copy or the content
360 #ifdef HEPMC3
361  HepMC::GenHeavyIonPtr hinew=std::make_shared<HepMC::GenHeavyIon>(*(pMcEvtColl->at(0)->heavy_ion()));
362  m_pOvrlMcEvColl->at(0)->set_heavy_ion(hinew);
363 #else
364  m_pOvrlMcEvColl->at(0)->set_heavy_ion(*(pMcEvtColl->at(0)->heavy_ion()));
365 #endif
366  }
367  return StatusCode::SUCCESS;
368 }
369 
370 StatusCode MergeMcEventCollTool::processTruthFilteredEvent(const McEventCollection *pMcEvtColl, const double currentEventTime, const int currentBkgEventIndex, int pileupType) {
371  //insert the GenEvent into the overlay McEventCollection.
372  ATH_MSG_VERBOSE ( "processTruthFilteredEvent(): Event Type: " << pileupType );
373  ATH_CHECK(this->saveHeavyIonInfo(pMcEvtColl));
374  m_pOvrlMcEvColl->at(m_startingIndexForBackground+m_nBkgEventsReadSoFar)=new HepMC::GenEvent(**(pMcEvtColl->begin()));
375  HepMC::GenEvent& currentBackgroundEvent(*(m_pOvrlMcEvColl->at(m_startingIndexForBackground+m_nBkgEventsReadSoFar)));
376  HepMC::fillBarcodesAttribute(&currentBackgroundEvent);
377 #ifdef HEPMC3
378  const int bunchCrossingTime=static_cast<int>(currentEventTime);
379  currentBackgroundEvent.add_attribute("BunchCrossingTime",std::make_shared<HepMC3::IntAttribute>(bunchCrossingTime));
380  currentBackgroundEvent.add_attribute("PileUpType",std::make_shared<HepMC3::IntAttribute>(pileupType));
381 #endif
382 
383  currentBackgroundEvent.set_event_number(currentBkgEventIndex);
384  puType currentGenEventClassification(RESTOFMB);
385  if ( std::abs(currentEventTime)<51.0 ) {
386  currentGenEventClassification = ( std::abs(currentEventTime)<1.0 ) ? INTIME : OUTOFTIME;
387  }
388  updateClassificationMap(HepMC::signal_process_id(currentBackgroundEvent),
389  currentBackgroundEvent.event_number(),
390  0, currentGenEventClassification, true);
391  return StatusCode::SUCCESS;
392 }
393 
394 StatusCode MergeMcEventCollTool::processUnfilteredEvent(const McEventCollection *pMcEvtColl, const double currentEventTime, const int currentBkgEventIndex, int pileupType) {
395  ATH_MSG_VERBOSE ( "processUnfilteredEvent() Event Type: " << pileupType );
396  ATH_CHECK(this->saveHeavyIonInfo(pMcEvtColl));
397  const HepMC::GenEvent& currentBackgroundEvent(**(pMcEvtColl->begin())); //background event
398  //handle the slimming case
399  HepMC::GenVertexPtr pCopyOfGenVertex{nullptr};
400  int spi = HepMC::signal_process_id(currentBackgroundEvent);
401 #ifdef HEPMC3
402  if ( HepMC::signal_process_vertex(&currentBackgroundEvent) ) pCopyOfGenVertex = std::make_shared<HepMC3::GenVertex> ( HepMC::signal_process_vertex(&currentBackgroundEvent)->data() );
403  //insert the GenEvent into the overlay McEventCollection.
404  //for configs with pile-up truth, also need to propagate barcodes to GenEvent
405  HepMC::GenEvent* evt = m_onlySaveSignalTruth ? new HepMC::GenEvent() : new HepMC::GenEvent(currentBackgroundEvent);
406  const int bunchCrossingTime=static_cast<int>(currentEventTime);
407  evt->add_attribute("BunchCrossingTime",std::make_shared<HepMC3::IntAttribute>(bunchCrossingTime));
408  evt->add_attribute("PileUpType",std::make_shared<HepMC3::IntAttribute>(pileupType));
409  //AV Not sure if one should add the vertex here
410  evt->set_event_number(currentBkgEventIndex);
411  evt->add_vertex(pCopyOfGenVertex);
412  HepMC::set_signal_process_vertex(evt,pCopyOfGenVertex);
415  updateClassificationMap(spi, currentBkgEventIndex, 0, RESTOFMB, true);
416 
417  unsigned int nCollisionVerticesFound(0);
418  //loop over vertices in Background GenEvent
419  ATH_MSG_VERBOSE( "Starting a vertex loop ... " );
420  auto currentVertexIter = currentBackgroundEvent.vertices().begin();
421  auto endOfCurrentListOfVertices = currentBackgroundEvent.vertices().end();
422 #else
423  if ( HepMC::signal_process_vertex(&currentBackgroundEvent) ) pCopyOfGenVertex = new HepMC::GenVertex ( *currentBackgroundEvent.signal_process_vertex() );
424  //insert the GenEvent into the overlay McEventCollection.
425  m_pOvrlMcEvColl->at(m_startingIndexForBackground+m_nBkgEventsReadSoFar) = new HepMC::GenEvent(spi, currentBkgEventIndex, pCopyOfGenVertex );
426  updateClassificationMap(spi, currentBkgEventIndex, 0, RESTOFMB, true);
427 
428  unsigned int nCollisionVerticesFound(0);
429  //loop over vertices in Background GenEvent
430  ATH_MSG_VERBOSE( "Starting a vertex loop ... " );
431  auto currentVertexIter = currentBackgroundEvent.vertices_begin();
432  auto endOfCurrentListOfVertices = currentBackgroundEvent.vertices_end();
433 #endif
434  for (; currentVertexIter != endOfCurrentListOfVertices; ++currentVertexIter) {
435  const auto& pCurrentVertex=*currentVertexIter;
436  HepMC::GenVertexPtr pCopyOfVertexForClassification[NOPUTYPE];
437  for (int type(INTIME); type<NOPUTYPE; ++type) pCopyOfVertexForClassification[type]=(HepMC::GenVertexPtr )nullptr;
438 
439  //check for collision vertices for in-time events
440  bool isCollisionVertex(false);
441  if(m_addBackgroundCollisionVertices && nCollisionVerticesFound<2 && currentEventTime==0.0) {
442  isCollisionVertex=isInitialCollisionVertex(pCurrentVertex);
443  if(isCollisionVertex) ++nCollisionVerticesFound;
444  }
445 
446  //loop over outgoing particles in the current GenVertex keeping those not classified as NOPUTYPE
447  ATH_MSG_VERBOSE( "Starting an outgoing particle loop ... " );
448  for (const HepMC::ConstGenParticlePtr& currentVertexParticle: *pCurrentVertex){
449  ATH_MSG_VERBOSE( "Found a particle at location " << std::hex << currentVertexParticle << std::dec << " with PDG ID = " << currentVertexParticle->pdg_id() );
450  HepMC::ConstGenVertexPtr pCurrentParticleProductionVertex = currentVertexParticle->production_vertex();
451  puType particleClassification(classifyVertex(currentVertexParticle, pCurrentParticleProductionVertex,currentEventTime));
452  //hack to keep the complete vertex information for the interaction vertices of in-time background events
453  if(isCollisionVertex && NOPUTYPE==particleClassification) {
454  particleClassification=INTIME;
455  }
456  //add particle to appropriate vertex
457  if (particleClassification<NOPUTYPE && m_saveType[particleClassification]) {
458  if (!pCopyOfVertexForClassification[particleClassification]) {
459  pCopyOfVertexForClassification[particleClassification] =HepMC::newGenVertexPtr(pCurrentVertex->position());
460  ATH_MSG_VERBOSE( "Added bkg vertex " << pCopyOfVertexForClassification[particleClassification] << " at position " << pCopyOfVertexForClassification[particleClassification] << " for pu type = " << particleClassification );
461  }
462 #ifdef HEPMC3
463  pCopyOfVertexForClassification[particleClassification]->add_particle_out(std::make_shared<HepMC3::GenParticle>(currentVertexParticle->data()));
464 #else
465  pCopyOfVertexForClassification[particleClassification]->add_particle_out( new HepMC::GenParticle(*currentVertexParticle) );
466 #endif
467  ATH_MSG_VERBOSE( "Added bkg particle at location " << std::hex << currentVertexParticle << std::dec << " with PDG ID = " << currentVertexParticle->pdg_id() );
468  }
469  } //particle loop
471  if (m_saveType[INTIME] && pCopyOfVertexForClassification[INTIME]) {
472 #ifdef HEPMC3
473  for (const auto& currentVertexParticle: pCurrentVertex->particles_in()) {
474  pCopyOfVertexForClassification[INTIME]->add_particle_in (std::make_shared<HepMC3::GenParticle>(currentVertexParticle->data()));
475  }
476 #else
477  HepMC::GenVertex::particles_in_const_iterator currentVertexParticleIter(pCurrentVertex->particles_in_const_begin());
478  const HepMC::GenVertex::particles_in_const_iterator endOfListOfParticlesFromCurrentVertex(pCurrentVertex->particles_in_const_end());
479  for (; currentVertexParticleIter != endOfListOfParticlesFromCurrentVertex; ++currentVertexParticleIter) {
480  pCopyOfVertexForClassification[INTIME]->add_particle_in ( new HepMC::GenParticle(**currentVertexParticleIter) );
481  }
482 #endif
483  }
484  //keep vertices with outgoing particles
485  for (int type(INTIME); type<NOPUTYPE; ++type) {
486  if (!pCopyOfVertexForClassification[type]) continue;
487  int n_particles_out=pCopyOfVertexForClassification[type]->particles_out_size();
488  if (m_saveType[type] && (n_particles_out > 0) ) {
489  updateClassificationMap(spi, currentBkgEventIndex, 0, type, false);
490  }
491  }
492  } //vertex loop
493 
494  return StatusCode::SUCCESS;
495 }
496 
498 //AV: The olde version was too generator specific.
499 #ifdef HEPMC3
500  for (const auto& pCurrentVertexParticle: pCurrentVertex->particles_in()) {
501 #else
502  auto currentVertexParticleIter = pCurrentVertex->particles_in_const_begin();
503  auto endOfListOfParticlesFromCurrentVertex = pCurrentVertex->particles_in_const_end();
504  for( ;currentVertexParticleIter != endOfListOfParticlesFromCurrentVertex; ++currentVertexParticleIter ) {
505  auto pCurrentVertexParticle = *currentVertexParticleIter;
506 #endif
507  if (MC::isBeam(pCurrentVertexParticle)) return true;
508  }
509  return false;
510 }
511 
512 MergeMcEventCollTool::puType MergeMcEventCollTool::classifyVertex(const HepMC::ConstGenParticlePtr& pCurrentVertexParticle, const HepMC::ConstGenVertexPtr& pCurrentParticleProductionVertex, double currentEventTime) {
513  //=======================================================================
514  //handle the slimming case
515  //=======================================================================
516  puType particleClassification(NOPUTYPE);
517  if ( pCurrentParticleProductionVertex ) {
518  //throw away unstable particles and particles outside eta cut
519  if ( m_keepUnstable || MC::isSimStable(pCurrentVertexParticle) ) {
521  if ( std::abs(pCurrentParticleProductionVertex->position().z()) < m_zRange ) {
522  const float xi((pCurrentParticleProductionVertex->position()).x());
523  const float yi((pCurrentParticleProductionVertex->position()).y());
524  if ( !m_doSlimming || ( (xi*xi + yi*yi < m_r2Range) && (pCurrentVertexParticle->momentum().perp() > m_ptMin) ) ) {
525  const double eta(pCurrentVertexParticle->momentum().pseudoRapidity());
526  if ( !m_doSlimming || (std::abs(eta) <= m_absEtaMax) ) {
527  const bool currentEventIsInTime((m_lowTimeToKeep<=currentEventTime) && (currentEventTime<=m_highTimeToKeep));
528  if ( currentEventIsInTime ) {
529  // cout << "the Time is " << currentEventTime << std::endl;
530  if ( 0.0==currentEventTime ) {
531  particleClassification=INTIME;
532  }
533  else if (std::abs(eta) <= m_absEtaMax_outOfTime) {
534  particleClassification=OUTOFTIME;
535  }
536  else {
537  particleClassification=RESTOFMB;
538  }
539  }
540  else {
541  particleClassification=RESTOFMB;
542  }
543  } // r2 && eta cut
544  } // ptmin cut
545  } // zrange cut
546  else {
547  // select cavern events
548  double mass(pCurrentVertexParticle->momentum().m());
549  if ( mass < 0.0 ) { mass = 0.0; }
550  const double kineticEnergy(pCurrentVertexParticle->momentum().e() - mass);
551  if ( !m_doSlimming || ( (kineticEnergy > m_minKinE) && (MC::charge(pCurrentVertexParticle->pdg_id()) != 0) ) ) {
552  particleClassification=CAVERN;
553  }
554  } // zrange cut
555  } // keep unstable
556  } // pCurrentParticleProductionVertex is not NULL
557  return particleClassification;
558 }
559 
561  int currentClassification=int(INTIME);
562  if (! m_pOvrlMcEvColl->empty()) {
564  while(outputEventItr!=m_pOvrlMcEvColl->end()) { //as end may change
565  const int signal_process_id(HepMC::signal_process_id((*outputEventItr))),event_number((*outputEventItr)->event_number());
566  //Check for separators
567  if(signal_process_id==0 && event_number==-1) {
568  ++outputEventItr;
569  ++currentClassification;
570  continue;
571  }
572  if((*outputEventItr)->vertices_empty()) {
573  //Delete empty GenEvent
574  outputEventItr=m_pOvrlMcEvColl->erase(outputEventItr);
575  ATH_MSG_VERBOSE( "compressOutputMcEventCollection() Removed Empty GenEvent #" << event_number << ", signal_process_id(" << signal_process_id << "), category = " << currentClassification);
576  continue;
577  }
578  ++outputEventItr;
579  }
580  }
581  return StatusCode::SUCCESS;
582 }
583 
584 void MergeMcEventCollTool::updateClassificationMap(int signal_process_id, int event_number, int separator_hack, int classification, bool firstUpdateForThisEvent=false)
585 {
586  if(m_newevent && !m_backgroundClassificationMap.empty()) {
587  ATH_MSG_ERROR( "updateClassidificationMap: GenEvent #" << event_number << ", signal_process_id(" << signal_process_id << "), category = " << classification );
588  ATH_MSG_ERROR ("Failed to clear background classification map! Size = "<< m_backgroundClassificationMap.size());
590  }
591  if(-1==classification && !m_newevent) {
592  ATH_MSG_ERROR( "updateClassidificationMap: GenEvent #" << event_number << ", signal_process_id(" << signal_process_id << "), category = " << classification );
593  ATH_MSG_FATAL ("Should only ever be one signal event in the background classification map! Bailing out.");
594  }
595  // Check for separators
596  IndexKey key(makekey(signal_process_id,event_number));
597  //Check for Separator GenEvents
598  if(signal_process_id==0 && event_number==-1) {
599  key=makekey(separator_hack,event_number);
600  }
601  ATH_MSG_VERBOSE( "updateClassidificationMap: GenEvent #" << event_number << ", signal_process_id(" << signal_process_id << "), category = " << classification << ", key = " << key);
604  if(firstUpdateForThisEvent) {
605  ATH_MSG_ERROR( "updateClassidificationMap: Repeated KEY! "<< key <<". Previous category = " << event->second );
606  }
607  else {
608  ATH_MSG_DEBUG( "updateClassidificationMap: Updating category for existing key "<< key <<". Previous category = " << event->second << ", new category = " << classification );
609  }
610  if(int(RESTOFMB)!=event->second) {
611  if(event->second<=classification) return;
612  }
613  }
614  m_backgroundClassificationMap[key]=classification;
615  return;
616 }
HepMC::GenVertexPtr
HepMC::GenVertex * GenVertexPtr
Definition: GenVertex.h:59
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
MergeMcEventCollTool::m_rRange
DoubleProperty m_rRange
Definition: MergeMcEventCollTool.h:93
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
python.handimod.spi
spi
Definition: handimod.py:532
IndexKey
std::pair< int, int > IndexKey
Definition: MergeMcEventCollTool.cxx:22
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
MergeMcEventCollTool::m_saveOutOfTimePileup
BooleanProperty m_saveOutOfTimePileup
Definition: MergeMcEventCollTool.h:103
MergeMcEventCollTool::m_truthCollOutputKey
StringProperty m_truthCollOutputKey
Definition: MergeMcEventCollTool.h:86
MergeMcEventCollTool::INTIME
@ INTIME
Definition: MergeMcEventCollTool.h:54
MergeMcEventCollTool::prepareEvent
virtual StatusCode prepareEvent(const EventContext &ctx, unsigned int nInputEvents) override final
called before the subevts loop.
Definition: MergeMcEventCollTool.cxx:98
MergeMcEventCollTool::m_saveInTimePileup
BooleanProperty m_saveInTimePileup
Definition: MergeMcEventCollTool.h:101
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
MergeMcEventCollTool::initialize
virtual StatusCode initialize() override final
Definition: MergeMcEventCollTool.cxx:77
MergeMcEventCollTool::printDetailsOfMergedMcEventCollection
void printDetailsOfMergedMcEventCollection() const
Definition: MergeMcEventCollTool.cxx:238
MergeMcEventCollTool::CAVERN
@ CAVERN
Definition: MergeMcEventCollTool.h:54
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
MergeMcEventCollTool::m_signal_event_number
int m_signal_event_number
Definition: MergeMcEventCollTool.h:127
HepMC::signal_process_id
int signal_process_id(const GenEvent &e)
Definition: GenEvent.h:513
MergeMcEventCollTool.h
MergeMcEventCollTool::classifyVertex
MergeMcEventCollTool::puType classifyVertex(const HepMC::ConstGenParticlePtr &pCurrentVertexParticle, const HepMC::ConstGenVertexPtr &pCurrentParticleProductionVertex, double currentEventTime)
Definition: MergeMcEventCollTool.cxx:512
MergeMcEventCollTool::processUnfilteredEvent
StatusCode processUnfilteredEvent(const McEventCollection *pMcEvtColl, const double currentEventTime, const int currentBkgEventIndex, int pileupType)
Definition: MergeMcEventCollTool.cxx:394
MergeMcEventCollTool::m_lowTimeToKeep
DoubleProperty m_lowTimeToKeep
Definition: MergeMcEventCollTool.h:90
McEventCollection
McEventCollection
Definition: GeneratorObjectsTPCnv.cxx:60
MergeMcEventCollTool::m_saveType
bool m_saveType[NOPUTYPE]
Definition: MergeMcEventCollTool.h:111
MergeMcEventCollTool::processFirstSubEvent
StatusCode processFirstSubEvent(const McEventCollection *pMcEvtColl)
Definition: MergeMcEventCollTool.cxx:256
HepMC::newGenEvent
GenEvent * newGenEvent(const int a, const int b)
Definition: GenEvent.h:502
MergeMcEventCollTool::processEvent
StatusCode processEvent(const McEventCollection *pMcEvtColl, const double currentEventTime, const int currentBkgEventIndex, int pileupType)
Definition: MergeMcEventCollTool.cxx:319
PileUpTimeEventIndex::index
index_type index() const
the index of the component event in PileUpEventInfo
Definition: PileUpTimeEventIndex.cxx:76
MergeMcEventCollTool::m_newevent
bool m_newevent
Definition: MergeMcEventCollTool.h:115
LArG4FSStartPointFilter.evt
evt
Definition: LArG4FSStartPointFilter.py:42
MergeMcEventCollTool::m_truthCollInputKey
StringProperty m_truthCollInputKey
Definition: MergeMcEventCollTool.h:85
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
MergeMcEventCollTool::puType
puType
Definition: MergeMcEventCollTool.h:54
HepMC::fillBarcodesAttribute
void fillBarcodesAttribute(GenEvent *)
Definition: GenEvent.h:504
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
MergeMcEventCollTool::m_startingIndexForBackground
unsigned int m_startingIndexForBackground
Definition: MergeMcEventCollTool.h:113
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
module_driven_slicing.key2
key2
Definition: module_driven_slicing.py:159
PileUpMergeSvc::TimedList::type
std::list< value_t > type
type of the collection of timed data object
Definition: PileUpMergeSvc.h:75
MergeMcEventCollTool::m_absEtaMax
DoubleProperty m_absEtaMax
Definition: MergeMcEventCollTool.h:88
MergeMcEventCollTool::m_pOvrlMcEvColl
McEventCollection * m_pOvrlMcEvColl
Definition: MergeMcEventCollTool.h:84
HepMC::set_signal_process_vertex
void set_signal_process_vertex(GenEvent *e, T v)
Definition: GenEvent.h:528
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
MergeMcEventCollTool::m_doSlimming
BooleanProperty m_doSlimming
Definition: MergeMcEventCollTool.h:109
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
McEventCollection.h
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
MergeMcEventCollTool::processAllSubEvents
virtual StatusCode processAllSubEvents(const EventContext &ctx) override final
return false if not interested in certain xing times (in ns) implemented by default in PileUpToolBase...
Definition: MergeMcEventCollTool.cxx:117
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
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
MergeMcEventCollTool::m_nInputMcEventColls
unsigned int m_nInputMcEventColls
Definition: MergeMcEventCollTool.h:117
MergeMcEventCollTool::m_nBkgEventsReadSoFar
unsigned int m_nBkgEventsReadSoFar
Definition: MergeMcEventCollTool.h:119
MergeMcEventCollTool::MergeMcEventCollTool
MergeMcEventCollTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: MergeMcEventCollTool.cxx:70
MergeMcEventCollTool::saveHeavyIonInfo
StatusCode saveHeavyIonInfo(const McEventCollection *pMcEvtColl)
Definition: MergeMcEventCollTool.cxx:354
test_pyathena.parent
parent
Definition: test_pyathena.py:15
MergeMcEventCollTool::OUTOFTIME
@ OUTOFTIME
Definition: MergeMcEventCollTool.h:54
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
MergeMcEventCollTool::updateClassificationMap
void updateClassificationMap(int signal_process_id, int event_number, int hack, int classification, bool firstUpdateForThisEvent)
Definition: MergeMcEventCollTool.cxx:584
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
PileUpToolBase
Definition: PileUpToolBase.h:18
MergeMcEventCollTool::m_highTimeToKeep
DoubleProperty m_highTimeToKeep
Definition: MergeMcEventCollTool.h:91
HepMC::ConstGenParticlePtr
const GenParticle * ConstGenParticlePtr
Definition: GenParticle.h:38
MergeMcEventCollTool::m_backgroundClassificationMap
PileUpBackgroundMap m_backgroundClassificationMap
Definition: MergeMcEventCollTool.h:78
MergeMcEventCollTool::mergeEvent
virtual StatusCode mergeEvent(const EventContext &ctx) override final
called at the end of the subevts loop.
Definition: MergeMcEventCollTool.cxx:209
MergeMcEventCollTool::m_addBackgroundCollisionVertices
BooleanProperty m_addBackgroundCollisionVertices
Definition: MergeMcEventCollTool.h:121
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
PileUpTimeEventIndex::time
time_type time() const
bunch xing time in ns
Definition: PileUpTimeEventIndex.cxx:71
errorcheck.h
Helpers for checking error return status codes and reporting errors.
charge
double charge(const T &p)
Definition: AtlasPID.h:494
MergeMcEventCollTool::NOPUTYPE
@ NOPUTYPE
Definition: MergeMcEventCollTool.h:54
MergeMcEventCollTool::m_minKinE
DoubleProperty m_minKinE
Definition: MergeMcEventCollTool.h:99
MergeMcEventCollTool::isInitialCollisionVertex
bool isInitialCollisionVertex(const HepMC::ConstGenVertexPtr &pCurrentVertex) const
Definition: MergeMcEventCollTool.cxx:497
MergeMcEventCollTool::m_saveCavernBackground
BooleanProperty m_saveCavernBackground
Definition: MergeMcEventCollTool.h:107
MergeMcEventCollTool::processBunchXing
virtual StatusCode processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) override final
called for each active bunch-crossing to process current SubEvents bunchXing is in ns
Definition: MergeMcEventCollTool.cxx:185
MergeMcEventCollTool::isTruthFiltertedMcEventCollection
bool isTruthFiltertedMcEventCollection(const McEventCollection *pMcEvtColl) const
Definition: MergeMcEventCollTool.cxx:307
MergeMcEventCollTool::m_saveRestOfPileup
BooleanProperty m_saveRestOfPileup
Definition: MergeMcEventCollTool.h:105
MergeMcEventCollTool::m_compressOutputCollection
BooleanProperty m_compressOutputCollection
Definition: MergeMcEventCollTool.h:123
MergeMcEventCollTool::m_keepUnstable
BooleanProperty m_keepUnstable
Definition: MergeMcEventCollTool.h:87
MergeMcEventCollTool::RESTOFMB
@ RESTOFMB
Definition: MergeMcEventCollTool.h:54
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
PileUpMergeSvc.h
the preferred mechanism to access information from the different event stores in a pileup job.
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
MC::isBeam
bool isBeam(const T &p)
Definition: HepMCHelpers.h:28
DEBUG
#define DEBUG
Definition: page_access.h:11
MergeMcEventCollTool::m_onlySaveSignalTruth
BooleanProperty m_onlySaveSignalTruth
Definition: MergeMcEventCollTool.h:125
MergeMcEventCollTool::m_pMergeSvc
ServiceHandle< PileUpMergeSvc > m_pMergeSvc
Definition: MergeMcEventCollTool.h:82
MergeMcEventCollTool::m_ptMin
DoubleProperty m_ptMin
Definition: MergeMcEventCollTool.h:98
HepMC::mpi
int mpi(const GenEvent &e)
Definition: GenEvent.h:507
SubEventIterator
std::vector< xAOD::EventInfo::SubEvent >::const_iterator SubEventIterator
Definition: IPileUpTool.h:22
HepMC::ConstGenVertexPtr
const HepMC::GenVertex * ConstGenVertexPtr
Definition: GenVertex.h:60
MC::isSimStable
bool isSimStable(const T &p)
Identify if the particle is considered stable at the post-detector-sim stage.
Definition: HepMCHelpers.h:39
MergeMcEventCollTool::m_zRange
DoubleProperty m_zRange
Definition: MergeMcEventCollTool.h:97
MergeMcEventCollTool::compressOutputMcEventCollection
StatusCode compressOutputMcEventCollection()
Definition: MergeMcEventCollTool.cxx:560
HepMC::set_signal_process_id
void set_signal_process_id(GenEvent *e, const int i)
Definition: GenEvent.h:519
PileUpTimeEventIndex
a struct encapsulating the identifier of a pile-up event
Definition: PileUpTimeEventIndex.h:12
MergeMcEventCollTool::processTruthFilteredEvent
StatusCode processTruthFilteredEvent(const McEventCollection *pMcEvtColl, const double currentEventTime, const int currentBkgEventIndex, int pileupType)
Definition: MergeMcEventCollTool.cxx:370
HepMC::set_mpi
void set_mpi(GenEvent *e, const int i)
Definition: GenEvent.h:522
PileUpTimeEventIndex::type
PileUpType type() const
the pileup type - minbias, cavern, beam halo, signal?
Definition: PileUpTimeEventIndex.cxx:81
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
MergeMcEventCollTool::m_r2Range
double m_r2Range
Definition: MergeMcEventCollTool.h:95
HepMCHelpers.h
GenParticle
@ GenParticle
Definition: TruthClasses.h:30
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
MergeMcEventCollTool::m_absEtaMax_outOfTime
DoubleProperty m_absEtaMax_outOfTime
Definition: MergeMcEventCollTool.h:89
HepMC::signal_process_vertex
GenVertex * signal_process_vertex(const GenEvent *e)
Definition: GenEvent.h:503
module_driven_slicing.key1
key1
Definition: module_driven_slicing.py:158