ATLAS Offline Software
Loading...
Searching...
No Matches
CompactHardTruth.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
5*/
6
7// CompactHardTruth.cxx
8// Implementation file for class CompactHardTruth
9// Author: Frank Paige <paige@bnl.gov>
11
12// McParticleTests includes
14
15// STL includes
16#include <list>
17
18// FrameWork includes
19#include "Gaudi/Property.h"
20
21#include "AtlasHepMC/GenEvent.h"
27// Needed for FourVector
29
30namespace DerivationFramework {
31
33// Public methods:
35
36// Constructors
38CompactHardTruth::CompactHardTruth(const std::string& name, ISvcLocator* pSvcLocator)
39 : ::AthAlgorithm(name, pSvcLocator)
40 , m_mcEventsName("GEN_AOD")
41 , m_thinnedMcEventsName("GEN_AODTHIN")
42 , m_partonCut(10000.)
43 , m_hardCut(10000.)
44 , m_danglePtCut(0.)
45 , m_maxCount(0) {
46 //
47 // Property declaration
48 //
49 declareProperty("McEvent", m_mcEventsName, "input McEventCollection container name");
50 declareProperty("McEventOut", m_thinnedMcEventsName, "output McEventCollection container name");
51 declareProperty("ShowerMassCut", m_partonCut, "mass cut for thinning parton shower");
52 declareProperty("SoftMtCut", m_hardCut, "mt cut for underlying event showers");
53 declareProperty("DanglePtCut", m_danglePtCut, "maximum pt for dangling partons");
54
55 declareProperty("MaxCount", m_maxCount, "maximum number of events to print");
56}
57
58// Destructor
61
62// Athena Algorithm's Hooks
65 ATH_MSG_INFO("Initializing " << name() << "...");
66
67 m_evtCount = -1;
68 m_missCount = 0;
69 m_dangleFound = 0;
71 m_danglePtMax = 0;
72
75
76 // Print jobOption inputs
77 ATH_MSG_INFO("-------------------------------------------------");
78 ATH_MSG_INFO("jobOption McEvent " << m_mcEventsName);
79 ATH_MSG_INFO("jobOption McEventOut " << m_thinnedMcEventsName);
80 ATH_MSG_INFO("jobOption ShowerMassCut " << m_partonCut);
81 ATH_MSG_INFO("jobOption SoftMtCut " << m_hardCut);
82 ATH_MSG_INFO("jobOption MaxCount " << m_maxCount);
83 ATH_MSG_INFO("-------------------------------------------------");
84
85 return StatusCode::SUCCESS;
86}
87
89
90 ATH_MSG_INFO("Finalizing DerivationFramework::CompactHardTruth ");
91 ATH_MSG_INFO("Missing items limiting reclustering " << m_missCount);
92
93 ATH_MSG_INFO("Dangling partons pt cut: " << m_danglePtCut);
94 ATH_MSG_INFO("Dangling partons found: " << m_dangleFound);
95 ATH_MSG_INFO("Dangling partons removed: " << m_dangleRemoved);
96 ATH_MSG_INFO("Dangling partons max pt: " << m_danglePtMax);
97
98 ATH_MSG_INFO("CompactHardTruth total particles: " << m_thinParticles);
99 ATH_MSG_INFO("CompactHardTruth total vertices: " << m_thinVertices);
100
101 return StatusCode::SUCCESS;
102}
103
104StatusCode CompactHardTruth::execute(const EventContext& /*ctx*/) {
105
106 ++m_evtCount;
107 // if( m_evtCount%100 == 0 ){
108 ATH_MSG_INFO("Executing " << name() << " " << m_evtCount);
109 //}
110
111 // Normally doPrint is used to print the first m_maxCount events
112 // before and after thinning.
113 // doExtra adds extra intermediate event printouts.
114 // doDebug allows debug printout for a range of events.
115 const bool doPrint = m_evtCount < m_maxCount;
116 const bool doDebug = false;
117 const bool doExtra = false;
118 // doDebug = doPrint;
119 // doExtra = doPrint;
120
121 // Retrieve input data
122 const McEventCollection* mcEvts = nullptr;
123 if (!evtStore()->retrieve(mcEvts, m_mcEventsName).isSuccess() || nullptr == mcEvts) {
124 ATH_MSG_WARNING("could not retrieve mc collection at [" << m_mcEventsName << "]!");
125 return StatusCode::FAILURE;
126 }
127
128 if (mcEvts->empty()) {
129 ATH_MSG_WARNING("empty McEventCollection at [" << m_mcEventsName << "]");
130 return StatusCode::SUCCESS;
131 }
132
133 // Create output collection
134 McEventCollection* thinnedMcEvts = new McEventCollection;
135 if (!evtStore()->record(thinnedMcEvts, m_thinnedMcEventsName).isSuccess()) {
136 ATH_MSG_WARNING("Could not record thinned mc collection at [" << m_thinnedMcEventsName << "]!");
137 delete thinnedMcEvts;
138 thinnedMcEvts = nullptr;
139 return StatusCode::FAILURE;
140 }
141 if (evtStore()->setConst(thinnedMcEvts).isFailure()) { ATH_MSG_WARNING("Could not lock the McEventCollection at [" << m_thinnedMcEventsName << "] !!"); }
142
143 // Signal event is first (only?) event; front() is from DataVector
144 const HepMC::GenEvent* mcEvt = mcEvts->front();
145 const auto &wtCont = mcEvt->weights();
146 if (!wtCont.empty()) {
147 } else {
148 ATH_MSG_WARNING("Weights not found for mc collection [" << m_mcEventsName << "]");
149 }
150 int inEvent = mcEvt->event_number();
151 if (doDebug) ATH_MSG_DEBUG("FETCHED count/event " << m_evtCount << " " << inEvent);
152
154 // New event - copy of original
156
157 HepMC::GenEvent* thinEvt = new HepMC::GenEvent(*mcEvt);
158 int nEvent = thinEvt->event_number();
159 if (doPrint) ATH_MSG_DEBUG("New event number = " << nEvent);
160
161 if (doPrint) {
162 std::cout << "========== BEGIN EVENT BEFORE THINNING ==========" << std::endl;
163 HepMC::Print::line(std::cout, *thinEvt);
164 std::cout << "========== END EVENT BEFORE THINNING ==========" << std::endl;
165 }
166
168 // Containers for manipulating particles/vertices
170
171 // Hadronization vertex must have at least two incoming partons to
172 // conserve color. All outgoing must be hadrons; c.f. Pythia 2->1
173 // color reconnection vertices.
174 // Const iterators => must(?) save changes, then do them.
175 // Always remove particles from vertices, then delete.
176 // removePV: remove particle from vertex
177 // addinPV: add particle in to vertex
178 // addoutPV: add particle out from vertex
179 // removeV: remove vertex from event
180 // deleteP: delete particle after all passes
181 // deleteV: delete vertex after all passes
182 // HepMC ~GenVertex deletes particles, so remove them from ALL vertices
183
184 typedef std::pair<HepMC::GenVertexPtr, HepMC::GenParticlePtr> vpPair;
185 std::vector<vpPair> removePV;
186 std::vector<vpPair> addinPV;
187 std::vector<vpPair> addoutPV;
188 std::vector<HepMC::GenVertexPtr> removeV;
189
190 // Use list with sort/unique to insure no multiple deletion
191 std::list<HepMC::GenParticlePtr> deleteP;
192 std::list<HepMC::GenVertexPtr> deleteV;
193 std::list<HepMC::GenParticlePtr>::iterator dpItr;
194 std::list<HepMC::GenParticlePtr>::iterator dpItrE;
195 std::list<HepMC::GenVertexPtr>::iterator dvItr;
196 std::list<HepMC::GenVertexPtr>::iterator dvItrE;
197
199 // Find hadronization vertices
201
202 if (doDebug) ATH_MSG_DEBUG("Find hadronization vertices");
203
204 std::vector<HepMC::GenVertexPtr> hadVertices;
205
206 for (auto& hadv: thinEvt->vertices()) {
207 if (!hadv) continue;
208 if (hadv->particles_in().size() < 2) continue;
209 if (hadv->particles_out().size() < 1) continue;
210 // Check hadronization vertex
211 // isHad is true if at least one hadron
212 // q qbar -> pi is allowed, but q qbar -> W... is not
213 bool isHadVtx = true;
214 bool isHadOut = false;
215 for (const auto& inp: hadv->particles_in() ) {
216 if (!(MC::isParton(inp)|| MC::isDiquark(inp)) ) { isHadVtx = false; break;}
217 }
218 for (const auto& vp: hadv->particles_out()) {
219 if (MC::isParton(vp)|| MC::isDiquark(vp)) isHadVtx = false;
220 if (MC::isHadron(vp)) isHadOut = true;
221 }
222 isHadVtx = isHadVtx && isHadOut;
223 if (isHadVtx) hadVertices.push_back(hadv);
224 if (doDebug && isHadVtx) ATH_MSG_VERBOSE("Hadronization vertex " << hadv);
225 }
226
227 if (hadVertices.empty()) {
228 ATH_MSG_WARNING("No hadronization vertices for event " << nEvent);
229 ATH_MSG_WARNING("Exiting without changing event.");
230 thinnedMcEvts->push_back(thinEvt);
231 return StatusCode::SUCCESS;
232 }
233
235 // Remove all incoming partons from hadronization vertices
236 // Remove and delete all descendants
238
239 for (unsigned int iv = 0; iv < hadVertices.size(); ++iv) {
240 HepMC::GenVertexPtr ivtx = hadVertices[iv];
241 if (doDebug) ATH_MSG_DEBUG("Removing partons from hadVertex " << ivtx);
242 for (auto pin: ivtx->particles_in()) {
243 removePV.push_back(vpPair(ivtx, pin));
244 }
245 }
246 // Remove all descendant particles. Will remove empty vertices later.
247 // Might have parton decays of hadrons - hence delete sort/unique
248 for (unsigned int iv = 0; iv < hadVertices.size(); ++iv) {
249 HepMC::GenVertexPtr ivtx = hadVertices[iv];
250 auto descendants = HepMC::descendant_particles(ivtx);
251 for (auto pout: descendants) {
252 HepMC::GenVertexPtr vpar = pout->production_vertex();
253 if (vpar) removePV.push_back(vpPair(vpar, pout));
254 HepMC::GenVertexPtr vend = pout->end_vertex();
255 if (vend) removePV.push_back(vpPair(vend, pout));
256 deleteP.push_back(std::move(pout));
257 }
258 }
259
260 // Remove empty vertices
261 // Remove all particles from Geant vertices
262 // Remove and delete Geant vertices and particles
263 // All Geant particles should have Geant parent vertex
264
265 for (auto hadv:thinEvt->vertices()) {
266 // Empth vertices
267 if (hadv->particles_in().size() == 0 && hadv->particles_out().size() == 0) {
268 removeV.push_back(hadv);
269 deleteV.push_back(hadv);
270 }
271 // Geant vertices/particles
272 if (!HepMC::is_simulation_vertex(hadv)) continue;
273 for (auto pin: hadv->particles_in()) {
274 removePV.push_back(vpPair(hadv, pin));
275 if (HepMC::is_simulation_particle(pin)) { deleteP.push_back(std::move(pin)); }
276 }
277 for (auto pout: hadv->particles_out()) {
278 removePV.push_back(vpPair(hadv, pout));
279 if (HepMC::is_simulation_particle(pout)) { deleteP.push_back(std::move(pout)); }
280 }
281 removeV.push_back(hadv);
282 deleteV.push_back(std::move(hadv));
283 }
284
285 // Actually implement changes
286
287 for (unsigned int i = 0; i < removePV.size(); ++i) {
288 HepMC::GenVertexPtr v = removePV[i].first;
289 HepMC::GenParticlePtr p = removePV[i].second;
290 v->remove_particle_in(p);
291 v->remove_particle_out(std::move(p));
292 }
293
294 for (unsigned int i = 0; i < addoutPV.size(); ++i) {
295 HepMC::GenVertexPtr v = addoutPV[i].first;
296 HepMC::GenParticlePtr p = addoutPV[i].second;
297 v->add_particle_out(std::move(p));
298 }
299 for (unsigned int iv = 1; iv < hadVertices.size(); ++iv) {
300 HepMC::GenVertexPtr v = hadVertices[iv];
301 if (v->particles_in().size() != 0 || v->particles_out().size() != 0) {
302 ATH_MSG_WARNING("Removing vertex " << v << " for event " << nEvent
303 << " with in/out particles " << v->particles_in().size() << " " << v->particles_out().size());
304 }
305 thinEvt->remove_vertex(hadVertices[iv]);
306 }
307
309 // Cluster final partons
311
312 if (doDebug && doExtra) {
313 std::cout << "========== BEGIN EVENT BEFORE CLUSTER ==========" << std::endl;
314 HepMC::Print::line(std::cout, *thinEvt);
315 std::cout << "========== END EVENT BEFORE CLUSTER ==========" << std::endl;
316 }
317
318 // Possible cases:
319 // 1->1 branching: Drop earlier 1 and vertex.
320 // 2->1 connection: Drop 1 and vertex; leave 2 free
321 // Note momentum is conserved for these.
322 // Do not split 2->1 from initial 2->1->2 in Herwig.
323 // 1->2 branching: Set p1 = p2a+p2b, drop 2 and vertex.
324 // Add 1 to first vertex.
325
326 // Preserving color connections required merging vertices. Now no
327 // longer needed.
328
329 bool moreP = true;
330 using vpPair = std::pair<HepMC::GenVertexPtr, HepMC::GenParticlePtr>;
331 removePV.clear();
332 addinPV.clear();
333 addoutPV.clear();
334 removeV.clear();
335 deleteP.clear();
336 deleteV.clear();
337
338 using pkPair = std::pair<HepMC::GenParticlePtr, HepMC::FourVector>;
339 std::vector<pkPair> changePK;
340
341 if (doDebug) ATH_MSG_DEBUG("Start parton thinning");
342 while (moreP) {
343 if (doDebug) ATH_MSG_DEBUG("New parton pass " << inEvent << " " << thinEvt->particles_size() << " " << thinEvt->vertices_size());
344
345 moreP = false;
346 removePV.clear();
347 addinPV.clear();
348 addoutPV.clear();
349 removeV.clear();
350 changePK.clear();
351 // Find final partons
352 for (auto fp: thinEvt->particles() ) {
353 int iCase = 0;
354 if (!((MC::isParton(fp)|| MC::isDiquark(fp)) && fp->end_vertex() == nullptr)) continue;
355 if (doDebug) ATH_MSG_DEBUG("Starting final parton " << fp);
356 // Production/end vertices
357 HepMC::GenVertexPtr pvtx = fp->production_vertex();
358 if (!pvtx) {
359 ATH_MSG_WARNING("Missing production for final parton " << fp);
360 continue;
361 }
362 if (doDebug) ATH_MSG_DEBUG("Final parton " << pvtx << " " << fp);
364 // Case 1->1
366 // One-particle decay; use final particle
367 // ppvtx -> pp -> pvtx -> fp
368 if (pvtx->particles_in().size() == 1 && pvtx->particles_out().size() == 1) {
369 // Incoming particle to parent vertex
370 HepMC::GenParticlePtr pp = pvtx->particles_in().front();
371 if (!pp || pp->parent_event() == nullptr) {
372 ATH_MSG_DEBUG("1->1: missing pp for fp " << fp);
373 ++m_missCount;
374 continue;
375 }
376 // Its parent vertex
377 HepMC::GenVertexPtr ppvtx = pp->production_vertex();
378 if (!ppvtx || ppvtx->parent_event() == nullptr) {
379 ATH_MSG_DEBUG("1->1: missing ppvtx for fp " << fp);
380 ++m_missCount;
381 continue;
382 }
383 moreP = true;
384 iCase = 1;
385 removePV.push_back(vpPair(ppvtx, pp));
386 removePV.push_back(vpPair(pvtx, pp));
387 deleteP.push_back(pp);
388 removeV.push_back(pvtx);
389 deleteV.push_back(pvtx);
390 addoutPV.push_back(vpPair(ppvtx, fp));
391 if (doDebug) { ATH_MSG_DEBUG("1->1: ppvtx,pp,pvtx,fp,evtx " << ppvtx << " " << pp << " " << pvtx << " " << fp); }
392 }
394 // Case 2->1
396 // Color recombination. Momentum is conserved so just keep 2.
397 // Drop 1 and vertex.
398 // ppvtx1,ppvtx2 -> pp1,pp2 -> pvtx -> fp
399 // Recombination should not affect hard physics!
400 if (pvtx->particles_in().size() == 2 && pvtx->particles_out().size() == 1) {
401 // Incoming particles to parent vertex
402 HepMC::GenParticlePtr pp1 = pvtx->particles_in().front();
403 HepMC::GenParticlePtr pp2 = pvtx->particles_in().back();
404 // Check for 2->1->2 initial state interactions in Herwig++
405 // Initial partons have pt=0, use pt<0.001MeV
406 if (std::abs(pp1->momentum().perp()) < 1.e-3) continue;
407 if (std::abs(pp2->momentum().perp()) < 1.e-3) continue;
408 // Their parent vertices
409 HepMC::GenVertexPtr ppvtx1 = pp1->production_vertex();
410 HepMC::GenVertexPtr ppvtx2 = pp2->production_vertex();
411 if (!ppvtx1 || ppvtx1->parent_event() == nullptr) {
412 ATH_MSG_DEBUG("2->1: missing ppvtx1 for fp " << fp);
413 ++m_missCount;
414 continue;
415 }
416 if (!ppvtx2 || ppvtx2->parent_event() == nullptr) {
417 ATH_MSG_DEBUG("2->1: missing ppvtx2 for fp " << fp);
418 ++m_missCount;
419 continue;
420 }
421 moreP = true;
422 iCase = 2;
423 removePV.push_back(vpPair(pvtx, fp));
424 removePV.push_back(vpPair(pvtx, pp1));
425 removePV.push_back(vpPair(pvtx, pp2));
426 deleteP.push_back(fp);
427 removeV.push_back(pvtx);
428 deleteV.push_back(pvtx);
429 if (doDebug) {
430 ATH_MSG_DEBUG("2->1: ppvtx1,pp1,ppvtx2,pp2,pvtx,fp " << ppvtx1 << " " << pp1
431 << " " << ppvtx2 << " " << pp2 << " " << pvtx << " "<< fp);
432 }
433 }
435 // Case 1->2
437 // Parton branching. Momentum not conserved; 2 momenta correct
438 // Drop only if mass is below cut
439 // ppvtx -> pp -> pvtx -> pout1,pout2/fp
440 if (pvtx->particles_in().size() == 1 && pvtx->particles_out().size() == 2) {
441 HepMC::GenParticlePtr pout1 = pvtx->particles_out().front();
442 HepMC::GenParticlePtr pout2 = pvtx->particles_out().back();
443 // Require two final partons and avoid duplication
444 if (fp == pout1) {
445 if (!((MC::isParton(pout2)|| MC::isDiquark(pout2)) && pout2->end_vertex() == nullptr)) {
446 if (doDebug) ATH_MSG_DEBUG("1->2: not final " << pout2);
447 continue;
448 }
449 } else if (fp == pout2) {
450 if (!((MC::isParton(pout1)|| MC::isDiquark(pout1)) && pout1->end_vertex() == nullptr)) {
451 if (doDebug) ATH_MSG_DEBUG("1->2: not final " << pout1);
452 continue;
453 }
454 } else {
455 ATH_MSG_WARNING("1->2: No match found for branching " << fp << " " << pvtx << " " << pout1 << " " << pout2);
456 continue;
457 }
458 if (fp != pout1) continue;
459 // Incoming particle
460 HepMC::GenParticlePtr pp = pvtx->particles_in().front();
461 // Do not merge initial partons (pt<1MeV or m<-1MeV)
462 if (pout1->momentum().m() < -1.0 || pout1->momentum().perp() < 1.0) continue;
463 if (pout2->momentum().m() < -1.0 || pout2->momentum().perp() < 1.0) continue;
464 // Parton pair mass cut
465 HepMC::FourVector p12 = vtxOutMom(pvtx);
466 double m12 = p12.m();
467 if (m12 < 0) {
468 if (std::abs(m12) > 10. + 1.0e-5 * p12.e()) {
469 ATH_MSG_WARNING("Spacelike mass^2 for parton sum " << m12 << " " << pp << " " << pvtx << " " << pout1 << " " << pout2);
470 }
471 m12 = 0;
472 }
473 if (doDebug) ATH_MSG_DEBUG("1->2: parton pair mass " << m12);
474 // If mass > cut, keep pair
475 if (m12 > m_partonCut) {
476 if (doDebug) ATH_MSG_DEBUG("Keeping 1->2: parton mass " << m12);
477 continue;
478 }
479 // Associated vertices
480 HepMC::GenVertexPtr ppvtx = pp->production_vertex();
481 if (!ppvtx || ppvtx->parent_event() == nullptr) {
482 ATH_MSG_DEBUG("1->2: missing ppvtx for fp " << fp);
483 ++m_missCount;
484 continue;
485 }
486 // Merge branching
487 moreP = true;
488 iCase = 3;
489 if (doDebug) ATH_MSG_DEBUG("Merging 1->2: mass " << p12.m());
490 changePK.push_back(pkPair(pp, p12));
491 removePV.push_back(vpPair(pvtx, pp));
492 removePV.push_back(vpPair(pvtx, pout1));
493 removePV.push_back(vpPair(pvtx, pout2));
494 deleteP.push_back(pout1);
495 deleteP.push_back(pout2);
496 removeV.push_back(pvtx);
497 deleteV.push_back(pvtx);
498 if (doDebug) {
499 ATH_MSG_DEBUG("Merge 1->2: ppvtx,pp,pvtx,pout1,pout2,evtx " << ppvtx << " " << pp << " " << pvtx << " " << pout1 << " "
500 << pout2);
501 ATH_MSG_DEBUG("Merge 1->2: id " << pp->pdg_id() << " " << pout1->pdg_id() << " " << pout2->pdg_id());
502 }
503 } // end 1->2 case
505 // Incoming proton vertex
507 // Do nothing
508 if (pvtx->particles_in().size() == 1) {
509 // Incoming particle to parent vertex
510 HepMC::GenParticlePtr pp = pvtx->particles_in().front();
511 if (std::abs(pp->pdg_id()) == MC::PROTON) iCase = -1;
512 }
513 // Case not found
514 // Need test for 2->2 in underlying event
515 if (iCase == 0) {
516 if (doDebug) ATH_MSG_DEBUG("Case not found " << pvtx << " " << fp << " " << pvtx->particles_in().size() << " " << pvtx->particles_out().size());
517 }
518 } // end final parton loop
519
520 // Actually implement changes -- remove particles from vertices
521 // Parton ends free, so no addinPV
522 if (doDebug) ATH_MSG_DEBUG("Actually removing particles " << removePV.size());
523
524 for (unsigned int i = 0; i < removePV.size(); ++i) {
525 HepMC::GenVertexPtr v = removePV[i].first;
526 HepMC::GenParticlePtr p = removePV[i].second;
527 if (doDebug) ATH_MSG_VERBOSE("Removing v,p " << v << " " << p);
528 v->remove_particle_in(p);
529 v->remove_particle_out(std::move(p));
530 }
531
532 // Actually implement changes -- add particles to vertices
533 if (doDebug) ATH_MSG_DEBUG("Actually add particles in/out " << addinPV.size() << " " << addoutPV.size());
534 for (unsigned int i = 0; i < addoutPV.size(); ++i) {
535 HepMC::GenVertexPtr v = addoutPV[i].first;
536 HepMC::GenParticlePtr p = addoutPV[i].second;
537 if (doDebug) ATH_MSG_VERBOSE("Adding v,p " << v << " " << p);
538 v->add_particle_out(std::move(p));
539 }
540
541 // Actually implement changes -- change momenta
542 for (unsigned int i = 0; i < changePK.size(); ++i) {
543 HepMC::GenParticlePtr pp = changePK[i].first;
545 pp->set_momentum(changePK[i].second);
546 }
547
548 // Actually implement changes -- remove vertices
549 if (doDebug) ATH_MSG_DEBUG("Actually remove vertices " << removeV.size());
550 for (unsigned int i = 0; i < removeV.size(); ++i) {
551 int nv = thinEvt->vertices().size();
552 if (doDebug) { ATH_MSG_VERBOSE("Removing vertex " << removeV[i] << " " << nv << " " << thinEvt->vertices().size()); }
553 thinEvt->remove_vertex(removeV[i]);
554 }
555 if (doDebug) ATH_MSG_DEBUG("End while(moreP) pass " << moreP);
556
557 } // end moreP
558
560 // Strip soft underlying stuff
562
563 if (doDebug && doExtra) {
564 std::cout << "========== BEGIN EVENT BEFORE SOFT ==========" << std::endl;
565 HepMC::Print::line(std::cout, *thinEvt);
566 std::cout << "========== END EVENT BEFORE SOFT ==========" << std::endl;
567 }
568
569 // Have deleted all hadronization particles
570 // Find all particles connected to hard process(es) with m_T>10GeV
571 std::list<HepMC::GenParticlePtr> pNotHad;
572 std::list<HepMC::GenParticlePtr> pHard;
573 std::vector<HepMC::GenParticlePtr> beams=thinEvt->beams();
574 for (auto fp: thinEvt->particles()) {
575 HepMC::GenVertexPtr pvtx = fp->production_vertex();
576 if (!pvtx) continue;
577
578 double ep = fp->momentum().e();
579 double pzp = fp->momentum().pz();
580 double mtmax = (ep + pzp) * (ep - pzp);
581 auto ancestors = HepMC::ancestor_particles(fp);
582
583 for (auto gpar: ancestors) {
584 double e = gpar->momentum().e();
585 double pz = gpar->momentum().pz();
586 mtmax = std::max((e+pz)*(e-pz), mtmax);
587 }
588
589 // Keep hard particles and all ancestors
590 pNotHad.push_back(fp);
591 int ida = std::abs(fp->pdg_id());
592 bool keepid = (ida > 10 && ida < 20) || (ida > 1000000 && ida < 9000000);
593 if (mtmax > m_hardCut * m_hardCut || keepid) {
594 pHard.push_back(fp);
595 pHard.insert(pHard.end(),ancestors.begin(),ancestors.end());
596 }
597
598 // Also keep all descendants of interesting particles
599 // Include leptons to get photons in Sherpa with no Z parent
600 // All hard descendants would include soft initial radiation
601 // Will remove duplicates with list sort/unique
602 bool keepid2 = ( ida == 6) || (ida >= 11 && ida <= 16) || (ida >= 23 && ida <= 37) || (ida > 1000000 && ida < 9000000);
603 if (keepid2 && fp->end_vertex()) {
604 auto descendants = HepMC::descendant_particles(fp);
605 pHard.insert(pHard.end(),descendants.begin(),descendants.end());
606 }
607 }
608
609 // Sort/unique lists
610 pNotHad.sort();
611 pNotHad.unique();
612 pHard.sort();
613 pHard.unique();
614
615 // Dump information
616 if (doDebug) {
617 int nhard = 0;
618 for (auto ph: pHard) {
619 ++nhard;
620 ATH_MSG_DEBUG("Hard GenParticles " << ph );
621 }
622 if (doDebug) ATH_MSG_DEBUG("Hard GenParticles total " << nhard);
623 }
624
625 // Remove non-hadronization, non-hard GenParticles from vertices
626 // and delete them using lists constructed above.
627 // Any 1->1 vertices created will be removed below.
628 for (auto p: pNotHad) {
629 // Skip hard ones
630 bool isHard = false;
631 for (auto h: pHard) {
632 if (p == h) {
633 isHard = true;
634 break;
635 }
636 }
637 if (doDebug) ATH_MSG_DEBUG("Particle bc/isHard " << p << " " << isHard);
638 if (isHard) continue;
639 HepMC::GenVertexPtr pvtx = p->production_vertex();
640 if (pvtx) pvtx->remove_particle_out(p);
641 HepMC::GenVertexPtr evtx = p->end_vertex();
642 if (evtx) evtx->remove_particle_in(std::move(p));
643 }
644
646 // Remove and delete vertices with no remaining particles
648
649 removeV.clear();
650 deleteV.clear();
651
652 for (auto vtx: thinEvt->vertices()) {
653 if (vtx->particles_in().size() != 0) continue;
654 if (vtx->particles_out().size() != 0) continue;
655 removeV.push_back(vtx);
656 deleteV.push_back(std::move(vtx));
657 }
658 if (doDebug) ATH_MSG_DEBUG("Removing/deleting 0-particle vertices " << removeV.size() << " " << deleteV.size());
659 for (unsigned int i = 0; i < removeV.size(); ++i) {
660 if (doDebug) ATH_MSG_VERBOSE("Removing vertex " << removeV[i]);
661 thinEvt->remove_vertex(removeV[i]);
662 }
663
665 // Remove remaining 1-1 vertices
667
668 if (doDebug && doExtra) {
669 std::cout << "========== BEGIN EVENT BEFORE 1-BODY ==========" << std::endl;
670 HepMC::Print::line(std::cout, *thinEvt);
671 std::cout << "========== END EVENT BEFORE 1-BODY ==========" << std::endl;
672 }
673
674 // Not clear how to order sweep, so do it one at a time.
675 // Always keep child
676 // pvtx -> pin -> vtx11 -> pout -> evtx
677
678 bool moreV1 = true;
682
683 while (moreV1) {
684 moreV1 = false;
685 // Find next 1->1 vertex
686 for (auto v: thinEvt->vertices()) {
687 if (v->particles_in().size() != 1) continue;
688 if (v->particles_out().size() != 1) continue;
689 pin = *(v->particles_in().begin());
690 pout = *(v->particles_out().begin());
691 if (pin->pdg_id() != pout->pdg_id()) continue;
692 // Sherpa does 1-body decay of incoming protons :-(
693 if (pin == beams[0] || pin == beams[1]) continue;
694 HepMC::GenVertexPtr pvtx = pin->production_vertex();
695 if (!pvtx || pvtx->parent_event() == nullptr) {
696 ATH_MSG_DEBUG("1->1: missing pvtx for vertex " << v);
697 ++m_missCount;
698 continue;
699 }
700 moreV1 = true;
701 vtx11 = std::move(v);
702 if (doDebug) ATH_MSG_DEBUG("One-body " << pin << " " << vtx11 << " " << pout);
703 break;
704 }
705 if (moreV1) {
706 HepMC::GenVertexPtr pvtx = pin->production_vertex();
707 pvtx->remove_particle_in(pin);
708 pvtx->remove_particle_out(pin);
709 pvtx->add_particle_out(pout);
710 vtx11->remove_particle_in(pin);
711 vtx11->remove_particle_out(pin);
712 vtx11->remove_particle_in(pout);
713 vtx11->remove_particle_out(pout);
714 thinEvt->remove_vertex(vtx11);
715 if (doDebug) ATH_MSG_DEBUG("One-body new pvtx " << pvtx << " " << pvtx->particles_in().size() << " " << pvtx->particles_out().size());
716 }
717 }
719 // Remove dangling particles/vertices
721
722 // GEN_EVENT -> GEN_AOD conversion applies pt cut to partons, breaking
723 // tree structure. Result is "dangling" partons with 1 -> 0 vertices.
724 // FIXME!! Meanwhile discard these if pt < m_danglePtCut.
725
726 if (m_danglePtCut > 0) {
727
728 removePV.clear();
729 removeV.clear();
730 deleteP.clear();
731 deleteV.clear();
732
733 for (auto badv: thinEvt->vertices()) {
734 if (!badv) continue;
735 if (badv->particles_in().size() != 1 || badv->particles_out().size() != 0) continue;
736 auto pitr = badv->particles_in().begin();
737 HepMC::GenParticlePtr pp = *pitr;
738 if (pp->production_vertex()) continue;
739 double pt = pp->momentum().perp();
740 if (pt > m_danglePtMax) m_danglePtMax = pt;
742 if (pt > m_danglePtCut) continue;
743 if (doDebug) ATH_MSG_DEBUG("1->0: removing pp,badv,pt " << pp << " " << badv << " " << pt);
744 removePV.push_back(vpPair(badv, pp));
745 deleteP.push_back(std::move(pp));
746 removeV.push_back(badv);
747 deleteV.push_back(std::move(badv));
749 }
750 // Actually implement changes -- remove particles from vertices
751 for (unsigned int i = 0; i < removePV.size(); ++i) {
752 HepMC::GenVertexPtr v = removePV[i].first;
753 HepMC::GenParticlePtr p = removePV[i].second;
754 v->remove_particle_in(p);
755 v->remove_particle_out(std::move(p));
756 }
757 // Actually implement changes -- remove vertices
758 for (unsigned int i = 0; i < removeV.size(); ++i) {
759 thinEvt->remove_vertex(removeV[i]);
760 }
761 } // end m_danglePtCut
762
764 // Done - examine results
766
767 if (doPrint) {
768 std::cout << "========== BEGIN EVENT AFTER THINNING ==========" << std::endl;
769 HepMC::Print::line(std::cout, *thinEvt);
770 std::cout << "========== END EVENT AFTER THINNING ==========" << std::endl;
771 }
772
773 m_thinParticles += thinEvt->particles_size();
774 m_thinVertices += thinEvt->vertices_size();
775
777 // Save thinned event in output container
779
780 thinnedMcEvts->push_back(thinEvt);
781 return StatusCode::SUCCESS;
782}
783
785// Const methods:
787
788// Total cluster FourVectors
789
791 HepMC::FourVector ret(0.0,0.0,0.0,0.0);
792 for (auto p: v->particles_in()) ret+=p->momentum();
793 return ret;
794}
795
797 HepMC::FourVector ret(0.0,0.0,0.0,0.0);
798 for (auto p: v->particles_out()) ret+=p->momentum();
799 return ret;
800}
801
802} // namespace DerivationFramework
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
ATLAS-specific HepMC functions.
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Header file for AthHistogramAlgorithm.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const T * front() const
Access the first element in the collection as an rvalue.
bool empty() const noexcept
Returns true if the collection is empty.
virtual HepMC::FourVector vtxOutMom(HepMC::ConstGenVertexPtr)
virtual HepMC::FourVector vtxInMom(HepMC::ConstGenVertexPtr)
virtual StatusCode execute(const EventContext &ctx)
Execute method.
CompactHardTruth()
Default constructor:
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
THE reconstruction tool.
bool is_simulation_vertex(const T &v)
Method to establish if the vertex was created during simulation (TODO migrate to be based on status).
HepMC3::FourVector FourVector
HepMC3::GenParticlePtr GenParticlePtr
Definition GenParticle.h:19
HepMC3::GenVertexPtr GenVertexPtr
Definition GenVertex.h:23
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...
HepMC3::ConstGenVertexPtr ConstGenVertexPtr
Definition GenVertex.h:24
HepMC3::GenEvent GenEvent
Definition GenEvent.h:39
bool isParton(const T &p)
bool isDiquark(const T &p)
PDG rule 4 Diquarks have 4-digit numbers with nq1 >= nq2 and nq3 = 0 APID: states with top quarks are...
bool isHadron(const T &p)
static const int PROTON