Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
LArMCParticleHelper.cc
Go to the documentation of this file.
1
10
11#include "Objects/CaloHit.h"
12#include "Objects/Cluster.h"
13#include "Objects/MCParticle.h"
14
15#include "Pandora/PdgTable.h"
16#include "Pandora/StatusCodes.h"
17
22
23#include <algorithm>
24#include <cstdlib>
25
26namespace lar_content
27{
28
29using namespace pandora;
30
32 m_minPrimaryGoodHits(15),
33 m_minHitsForGoodView(5),
34 m_minPrimaryGoodViews(2),
35 m_selectInputHits(true),
36 m_maxPhotonPropagation(2.5f),
37 m_minHitSharingFraction(0.9f),
38 m_foldBackHierarchy(true)
39{
40}
41
42//------------------------------------------------------------------------------------------------------------------------------------------
43//------------------------------------------------------------------------------------------------------------------------------------------
44
45bool LArMCParticleHelper::DoesPrimaryMeetCriteria(const MCParticle *const pMCParticle, std::function<bool(const MCParticle *const)> fCriteria)
46{
47 try
48 {
49 const MCParticle *const pPrimaryMCParticle = LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle);
50 return fCriteria(pPrimaryMCParticle);
51 }
52 catch (const StatusCodeException &)
53 {
54 }
55
56 return false;
57}
58
59//------------------------------------------------------------------------------------------------------------------------------------------
60
61bool LArMCParticleHelper::DoesLeadingMeetCriteria(const MCParticle *const pMCParticle, std::function<bool(const MCParticle *const)> fCriteria)
62{
63 try
64 {
65 const MCParticle *const pLeadingMCParticle = LArMCParticleHelper::GetLeadingMCParticle(pMCParticle);
66 return fCriteria(pLeadingMCParticle);
67 }
68 catch (const StatusCodeException &)
69 {
70 }
71
72 return false;
73}
74
75//------------------------------------------------------------------------------------------------------------------------------------------
76
78{
79 const MCParticle *const pParentMCParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle));
80 return (LArMCParticleHelper::IsPrimary(pMCParticle) && LArMCParticleHelper::IsNeutrino(pParentMCParticle));
81}
82
83//------------------------------------------------------------------------------------------------------------------------------------------
84
86{
87 const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
88 return (LArMCParticleHelper::IsPrimary(pMCParticle) && (nuance == 2001));
89}
90
91//------------------------------------------------------------------------------------------------------------------------------------------
92
93bool LArMCParticleHelper::IsBeamParticle(const MCParticle *const pMCParticle)
94{
95 const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
96 return (LArMCParticleHelper::IsPrimary(pMCParticle) && ((nuance == 2000) || (nuance == 2001)));
97}
98
99//------------------------------------------------------------------------------------------------------------------------------------------
100
102{
103 // ATTN: Only the parent triggered beam particle has nuance code 2001
105 return (LArMCParticleHelper::IsLeading(pMCParticle) && (parentNuance == 2001 || parentNuance == 2000));
106}
107
108//------------------------------------------------------------------------------------------------------------------------------------------
109
110bool LArMCParticleHelper::IsCosmicRay(const MCParticle *const pMCParticle)
111{
112 const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
113 return (LArMCParticleHelper::IsPrimary(pMCParticle) &&
114 ((nuance == 3000) || ((nuance == 0) && !LArMCParticleHelper::IsBeamNeutrinoFinalState(pMCParticle))));
115}
116
117//------------------------------------------------------------------------------------------------------------------------------------------
118
119unsigned int LArMCParticleHelper::GetNuanceCode(const MCParticle *const pMCParticle)
120{
121 const LArMCParticle *const pLArMCParticle(dynamic_cast<const LArMCParticle *>(pMCParticle));
122 if (pLArMCParticle)
123 return pLArMCParticle->GetNuanceCode();
124
125 std::cout << "LArMCParticleHelper::GetNuanceCode - Error: Can't cast to LArMCParticle" << std::endl;
126 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
127}
128
129//------------------------------------------------------------------------------------------------------------------------------------------
130
131bool LArMCParticleHelper::IsNeutrino(const MCParticle *const pMCParticle)
132{
133 const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
134 if ((nuance == 0) || (nuance == 2000) || (nuance == 2001) || (nuance == 3000))
135 return false;
136
137 const int absoluteParticleId(std::abs(pMCParticle->GetParticleId()));
138 return ((NU_E == absoluteParticleId) || (NU_MU == absoluteParticleId) || (NU_TAU == absoluteParticleId));
139}
140
141//------------------------------------------------------------------------------------------------------------------------------------------
142
144{
145 try
146 {
147 return (LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle) == pMCParticle);
148 }
149 catch (const StatusCodeException &)
150 {
151 }
152
153 return false;
154}
155
156//------------------------------------------------------------------------------------------------------------------------------------------
157
159{
160 try
161 {
162 return (LArMCParticleHelper::GetLeadingMCParticle(pMCParticle) == pMCParticle);
163 }
164 catch (const StatusCodeException &)
165 {
166 }
167
168 return false;
169}
170
171//------------------------------------------------------------------------------------------------------------------------------------------
172
174{
175 const MCParticle *pParentMCParticle = pMCParticle;
176 int tier(0);
177
178 while (pParentMCParticle->GetParentList().empty() == false)
179 {
180 if (1 != pParentMCParticle->GetParentList().size())
181 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
182
183 pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
184 ++tier;
185 }
186
187 return tier;
188}
189
190//------------------------------------------------------------------------------------------------------------------------------------------
191
192bool LArMCParticleHelper::IsVisible(const MCParticle *const pMCParticle)
193{
194 const int absoluteParticleId(std::abs(pMCParticle->GetParticleId()));
195
196 if ((E_MINUS == absoluteParticleId) || (MU_MINUS == absoluteParticleId) || (PI_PLUS == absoluteParticleId) || (K_PLUS == absoluteParticleId) ||
197 (SIGMA_MINUS == absoluteParticleId) || (SIGMA_PLUS == absoluteParticleId) || (HYPERON_MINUS == absoluteParticleId) ||
198 (PROTON == absoluteParticleId) || (PHOTON == absoluteParticleId) || (NEUTRON == absoluteParticleId))
199 return true;
200
201 return false;
202}
203
204//------------------------------------------------------------------------------------------------------------------------------------------
205
206void LArMCParticleHelper::GetTrueNeutrinos(const MCParticleList *const pMCParticleList, MCParticleVector &trueNeutrinos)
207{
208 for (const MCParticle *const pMCParticle : *pMCParticleList)
209 {
210 if (LArMCParticleHelper::IsNeutrino(pMCParticle))
211 trueNeutrinos.push_back(pMCParticle);
212 }
213
214 std::sort(trueNeutrinos.begin(), trueNeutrinos.end(), LArMCParticleHelper::SortByMomentum);
215}
216
217//------------------------------------------------------------------------------------------------------------------------------------------
218
219void LArMCParticleHelper::GetTrueTestBeamParticles(const MCParticleList *const pMCParticleList, MCParticleVector &trueTestBeamParticles)
220{
221 for (const MCParticle *const pMCParticle : *pMCParticleList)
222 {
224 trueTestBeamParticles.push_back(pMCParticle);
225 }
226
227 std::sort(trueTestBeamParticles.begin(), trueTestBeamParticles.end(), LArMCParticleHelper::SortByMomentum);
228}
229
230//------------------------------------------------------------------------------------------------------------------------------------------
231
233{
234 const MCParticle *pParentMCParticle = pMCParticle;
235
236 while (pParentMCParticle->GetParentList().empty() == false)
237 {
238 if (1 != pParentMCParticle->GetParentList().size())
239 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
240
241 pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
242 }
243
244 return pParentMCParticle;
245}
246
247//------------------------------------------------------------------------------------------------------------------------------------------
248
250{
251 for (const MCParticle *pDaughterMCParticle : pMCParticle->GetDaughterList())
252 {
253 if (std::find(descendentMCParticleList.begin(), descendentMCParticleList.end(), pDaughterMCParticle) == descendentMCParticleList.end())
254 {
255 descendentMCParticleList.emplace_back(pDaughterMCParticle);
256 LArMCParticleHelper::GetAllDescendentMCParticles(pDaughterMCParticle, descendentMCParticleList);
257 }
258 }
259}
260
261//------------------------------------------------------------------------------------------------------------------------------------------
262
263void LArMCParticleHelper::GetAllDescendentMCParticles(const MCParticle *const pMCParticle, MCParticleList &descendentTrackParticles,
264 MCParticleList &leadingShowerParticles, MCParticleList &leadingNeutrons)
265{
266 for (const MCParticle *pDaughterMCParticle : pMCParticle->GetDaughterList())
267 {
268 if (std::find(descendentTrackParticles.begin(), descendentTrackParticles.end(), pDaughterMCParticle) == descendentTrackParticles.end())
269 {
270 const int pdg{std::abs(pDaughterMCParticle->GetParticleId())};
271 if (pdg == E_MINUS || pdg == PHOTON)
272 {
273 leadingShowerParticles.emplace_back(pDaughterMCParticle);
274 }
275 else if (pdg == NEUTRON)
276 {
277 leadingNeutrons.emplace_back(pDaughterMCParticle);
278 }
279 else
280 {
281 descendentTrackParticles.emplace_back(pDaughterMCParticle);
282 LArMCParticleHelper::GetAllDescendentMCParticles(pDaughterMCParticle, descendentTrackParticles, leadingShowerParticles, leadingNeutrons);
283 }
284 }
285 }
286}
287
288//------------------------------------------------------------------------------------------------------------------------------------------
289
291{
292 const MCParticleList &parentMCParticleList = pMCParticle->GetParentList();
293 if (parentMCParticleList.empty())
294 return;
295 if (parentMCParticleList.size() != 1)
296 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
297
298 const MCParticle *pParentMCParticle = *parentMCParticleList.begin();
299 if (std::find(ancestorMCParticleList.begin(), ancestorMCParticleList.end(), pParentMCParticle) == ancestorMCParticleList.end())
300 {
301 ancestorMCParticleList.push_back(pParentMCParticle);
302 LArMCParticleHelper::GetAllAncestorMCParticles(pParentMCParticle, ancestorMCParticleList);
303 }
304}
305
306//------------------------------------------------------------------------------------------------------------------------------------------
307
308void LArMCParticleHelper::GetPrimaryMCParticleList(const MCParticleList *const pMCParticleList, MCParticleVector &mcPrimaryVector)
309{
310 for (const MCParticle *const pMCParticle : *pMCParticleList)
311 {
312 if (LArMCParticleHelper::IsPrimary(pMCParticle))
313 mcPrimaryVector.push_back(pMCParticle);
314 }
315
316 std::sort(mcPrimaryVector.begin(), mcPrimaryVector.end(), LArMCParticleHelper::SortByMomentum);
317}
318
319//------------------------------------------------------------------------------------------------------------------------------------------
320
321void LArMCParticleHelper::GetLeadingMCParticleList(const MCParticleList *const pMCParticleList, MCParticleVector &mcLeadingVector)
322{
323 for (const MCParticle *const pMCParticle : *pMCParticleList)
324 {
326
327 if ((isBeamParticle && LArMCParticleHelper::IsLeading(pMCParticle)) || (!isBeamParticle && LArMCParticleHelper::IsPrimary(pMCParticle)))
328 {
329 mcLeadingVector.push_back(pMCParticle);
330 }
331 }
332
333 std::sort(mcLeadingVector.begin(), mcLeadingVector.end(), LArMCParticleHelper::SortByMomentum);
334}
335
336//------------------------------------------------------------------------------------------------------------------------------------------
337
339{
341 {
342 visibleParticleList.emplace_back(pRoot);
343 }
344 else
345 {
346 for (const MCParticle *const pMCParticle : pRoot->GetDaughterList())
347 LArMCParticleHelper::GetFirstVisibleMCParticles(pMCParticle, visibleParticleList);
348 }
349}
350
351//------------------------------------------------------------------------------------------------------------------------------------------
352
354{
355 // Navigate upward through MC daughter/parent links - collect this particle and all its parents
356 MCParticleVector mcVector;
357
358 const MCParticle *pParentMCParticle = pMCParticle;
359 mcVector.push_back(pParentMCParticle);
360
361 while (!pParentMCParticle->GetParentList().empty())
362 {
363 if (1 != pParentMCParticle->GetParentList().size())
364 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
365
366 pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
367 mcVector.push_back(pParentMCParticle);
368 }
369
370 // Navigate downward through MC parent/daughter links - return the first long-lived charged particle
371 for (MCParticleVector::const_reverse_iterator iter = mcVector.rbegin(), iterEnd = mcVector.rend(); iter != iterEnd; ++iter)
372 {
373 const MCParticle *const pNextParticle = *iter;
374
375 if (LArMCParticleHelper::IsVisible(pNextParticle))
376 return pNextParticle;
377 }
378
379 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
380}
381
382//------------------------------------------------------------------------------------------------------------------------------------------
383
384const MCParticle *LArMCParticleHelper::GetLeadingMCParticle(const MCParticle *const pMCParticle, const int hierarchyTierLimit)
385{
386 // ATTN: If not beam particle return primary particle
388
389 if (!isBeamParticle)
391
392 // Navigate upward through MC daughter/parent links - collect this particle and all its parents
393 MCParticleVector mcVector;
394
395 const MCParticle *pParentMCParticle = pMCParticle;
396 mcVector.push_back(pParentMCParticle);
397
398 while (!pParentMCParticle->GetParentList().empty())
399 {
400 if (1 != pParentMCParticle->GetParentList().size())
401 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
402
403 pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
404 mcVector.push_back(pParentMCParticle);
405 }
406
407 int hierarchyTier(0);
408 const MCParticle *pLeadingMCParticle(nullptr);
409
410 // Navigate downward through MC parent/daughter links - return the first long-lived charged particle
411 for (MCParticleVector::const_reverse_iterator iter = mcVector.rbegin(), iterEnd = mcVector.rend(); iter != iterEnd; ++iter)
412 {
413 const MCParticle *const pNextParticle = *iter;
414
415 // ATTN: Squash any invisible particles (e.g. pizero)
416 if (!LArMCParticleHelper::IsVisible(pNextParticle))
417 continue;
418
419 if (hierarchyTier <= hierarchyTierLimit)
420 pLeadingMCParticle = pNextParticle;
421
422 hierarchyTier++;
423 }
424
425 if (!pLeadingMCParticle)
426 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
427
428 return pLeadingMCParticle;
429}
430
431//------------------------------------------------------------------------------------------------------------------------------------------
432
433void LArMCParticleHelper::GetMCPrimaryMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcPrimaryMap)
434{
435 for (const MCParticle *const pMCParticle : *pMCParticleList)
436 {
437 try
438 {
439 const MCParticle *const pPrimaryMCParticle = LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle);
440 mcPrimaryMap[pMCParticle] = pPrimaryMCParticle;
441 }
442 catch (const StatusCodeException &)
443 {
444 }
445 }
446}
447
448//------------------------------------------------------------------------------------------------------------------------------------------
449
450void LArMCParticleHelper::GetMCLeadingMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcLeadingMap)
451{
452 for (const MCParticle *const pMCParticle : *pMCParticleList)
453 {
454 try
455 {
456 const MCParticle *const pLeadingMCParticle = LArMCParticleHelper::GetLeadingMCParticle(pMCParticle);
457 mcLeadingMap[pMCParticle] = pLeadingMCParticle;
458 }
459 catch (const StatusCodeException &)
460 {
461 }
462 }
463}
464
465//------------------------------------------------------------------------------------------------------------------------------------------
466
467void LArMCParticleHelper::GetMCToSelfMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcToSelfMap)
468{
469 for (const MCParticle *const pMCParticle : *pMCParticleList)
470 {
471 mcToSelfMap[pMCParticle] = pMCParticle;
472 }
473}
474
475//------------------------------------------------------------------------------------------------------------------------------------------
476
478{
479 ClusterList clusterList;
480 LArPfoHelper::GetTwoDClusterList(pPfo, clusterList);
481 return MCParticleHelper::GetMainMCParticle(&clusterList);
482}
483
484//------------------------------------------------------------------------------------------------------------------------------------------
485
486bool LArMCParticleHelper::SortByMomentum(const MCParticle *const pLhs, const MCParticle *const pRhs)
487{
488 // Sort by momentum (prefer higher momentum)
489 const float momentumLhs(pLhs->GetMomentum().GetMagnitudeSquared());
490 const float momentumRhs(pRhs->GetMomentum().GetMagnitudeSquared());
491
492 if (std::fabs(momentumLhs - momentumRhs) > std::numeric_limits<float>::epsilon())
493 return (momentumLhs > momentumRhs);
494
495 // Sort by energy (prefer lighter particles)
496 if (std::fabs(pLhs->GetEnergy() - pRhs->GetEnergy()) > std::numeric_limits<float>::epsilon())
497 return (pLhs->GetEnergy() < pRhs->GetEnergy());
498
499 // Sort by PDG code (prefer smaller numbers)
500 if (pLhs->GetParticleId() != pRhs->GetParticleId())
501 return (pLhs->GetParticleId() < pRhs->GetParticleId());
502
503 // Sort by vertex position (tie-breaker)
504 const float positionLhs(pLhs->GetVertex().GetMagnitudeSquared());
505 const float positionRhs(pRhs->GetVertex().GetMagnitudeSquared());
506
507 return (positionLhs < positionRhs);
508}
509
510//------------------------------------------------------------------------------------------------------------------------------------------
511
512void LArMCParticleHelper::GetMCParticleToCaloHitMatches(const CaloHitList *const pCaloHitList, const MCRelationMap &mcToTargetMCMap,
513 CaloHitToMCMap &hitToMCMap, MCContributionMap &mcToTrueHitListMap)
514{
515 for (const CaloHit *const pCaloHit : *pCaloHitList)
516 {
517 try
518 {
519 const MCParticle *const pHitParticle(MCParticleHelper::GetMainMCParticle(pCaloHit));
520 const MCParticle *pTargetParticle(pHitParticle);
521
522 // ATTN Do not map back to target if mc to primary mc map or mc to self map not provided
523 if (!mcToTargetMCMap.empty())
524 {
525 MCRelationMap::const_iterator mcIter = mcToTargetMCMap.find(pHitParticle);
526
527 if (mcToTargetMCMap.end() == mcIter)
528 continue;
529
530 pTargetParticle = mcIter->second;
531 }
532
533 mcToTrueHitListMap[pTargetParticle].push_back(pCaloHit);
534 hitToMCMap[pCaloHit] = pTargetParticle;
535 }
536 catch (StatusCodeException &statusCodeException)
537 {
538 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
539 throw statusCodeException;
540 }
541 }
542}
543
544//------------------------------------------------------------------------------------------------------------------------------------------
545
547 const PrimaryParameters &parameters, std::function<bool(const MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
548{
549 // Obtain map: [mc particle -> target mc particle]
551 parameters.m_foldBackHierarchy ? LArMCParticleHelper::GetMCPrimaryMap(pMCParticleList, mcToTargetMCMap)
552 : LArMCParticleHelper::GetMCToSelfMap(pMCParticleList, mcToTargetMCMap);
553
554 // Remove non-reconstructable hits, e.g. those downstream of a neutron
555 // Unless selectInputHits == false
556 CaloHitList selectedCaloHitList;
557 LArMCParticleHelper::SelectCaloHits(pCaloHitList, mcToTargetMCMap, selectedCaloHitList, parameters.m_selectInputHits, parameters.m_maxPhotonPropagation);
558
559 // Obtain maps: [hit -> target mc particle], [target mc particle -> list of hits]
560 CaloHitToMCMap trueHitToTargetMCMap;
561 MCContributionMap targetMCToTrueHitListMap;
562 LArMCParticleHelper::GetMCParticleToCaloHitMatches(&selectedCaloHitList, mcToTargetMCMap, trueHitToTargetMCMap, targetMCToTrueHitListMap);
563
564 // Obtain vector: target mc particles
565 MCParticleVector targetMCVector;
566 if (parameters.m_foldBackHierarchy)
567 {
568 LArMCParticleHelper::GetPrimaryMCParticleList(pMCParticleList, targetMCVector);
569 }
570 else
571 {
572 std::copy(pMCParticleList->begin(), pMCParticleList->end(), std::back_inserter(targetMCVector));
573 }
574
575 // Select MCParticles matching criteria
576 MCParticleVector candidateTargets;
577 LArMCParticleHelper::SelectParticlesMatchingCriteria(targetMCVector, fCriteria, candidateTargets, parameters, false);
578
579 // Ensure the MCParticles have enough "good" hits to be reconstructed
580 LArMCParticleHelper::SelectParticlesByHitCount(candidateTargets, targetMCToTrueHitListMap, mcToTargetMCMap, parameters, selectedMCParticlesToHitsMap);
581}
582
583//------------------------------------------------------------------------------------------------------------------------------------------
584
586 const PrimaryParameters &parameters, std::function<bool(const MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
587{
588 // Obtain map: [mc particle -> target mc particle]
590 parameters.m_foldBackHierarchy ? LArMCParticleHelper::GetMCLeadingMap(pMCParticleList, mcToTargetMCMap)
591 : LArMCParticleHelper::GetMCToSelfMap(pMCParticleList, mcToTargetMCMap);
592
593 // Remove non-reconstructable hits, e.g. those downstream of a neutron
594 // Unless selectInputHits == false
595 CaloHitList selectedCaloHitList;
596 LArMCParticleHelper::SelectCaloHits(pCaloHitList, mcToTargetMCMap, selectedCaloHitList, parameters.m_selectInputHits, parameters.m_maxPhotonPropagation);
597
598 // Obtain maps: [hit -> target mc particle], [target mc particle -> list of hits]
599 CaloHitToMCMap trueHitToTargetMCMap;
600 MCContributionMap targetMCToTrueHitListMap;
601 LArMCParticleHelper::GetMCParticleToCaloHitMatches(&selectedCaloHitList, mcToTargetMCMap, trueHitToTargetMCMap, targetMCToTrueHitListMap);
602
603 // Obtain vector: target mc particles
604 MCParticleVector targetMCVector;
605 if (parameters.m_foldBackHierarchy)
606 {
607 LArMCParticleHelper::GetLeadingMCParticleList(pMCParticleList, targetMCVector);
608 }
609 else
610 {
611 std::copy(pMCParticleList->begin(), pMCParticleList->end(), std::back_inserter(targetMCVector));
612 }
613
614 // Select MCParticles matching criteria
615 MCParticleVector candidateTargets;
616 LArMCParticleHelper::SelectParticlesMatchingCriteria(targetMCVector, fCriteria, candidateTargets, parameters, true);
617
618 // Ensure the MCParticles have enough "good" hits to be reconstructed
619 LArMCParticleHelper::SelectParticlesByHitCount(candidateTargets, targetMCToTrueHitListMap, mcToTargetMCMap, parameters, selectedMCParticlesToHitsMap);
620
621 // ATTN: The parent particle must be in the hierarchy map, event if not reconstructable
622 for (const MCParticle *const pMCParticle : candidateTargets)
623 {
624 if (!LArMCParticleHelper::IsBeamParticle(pMCParticle))
625 continue;
626
627 const MCParticle *const pParentMCParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle));
628 if (selectedMCParticlesToHitsMap.find(pParentMCParticle) == selectedMCParticlesToHitsMap.end())
629 {
630 CaloHitList caloHitList;
631 selectedMCParticlesToHitsMap.insert(MCContributionMap::value_type(pParentMCParticle, caloHitList));
632 }
633 }
634}
635
636//------------------------------------------------------------------------------------------------------------------------------------------
637
638void LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(const PfoList &pfoList, const MCContributionMap &selectedMCParticleToHitsMap,
639 PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
640{
642 pfoList, MCContributionMapVector({selectedMCParticleToHitsMap}), pfoToReconstructable2DHitsMap, foldBackHierarchy);
643}
644
645//------------------------------------------------------------------------------------------------------------------------------------------
646
648 const MCContributionMap &selectedMCParticleToHitsMap, PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
649{
651 pfoList, MCContributionMapVector({selectedMCParticleToHitsMap}), pfoToReconstructable2DHitsMap, foldBackHierarchy);
652}
653
654//------------------------------------------------------------------------------------------------------------------------------------------
655
656void LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(const PfoList &pfoList, const MCContributionMapVector &selectedMCParticleToHitsMaps,
657 PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
658{
659 for (const ParticleFlowObject *const pPfo : pfoList)
660 {
661 CaloHitList pfoHitList;
662 LArMCParticleHelper::CollectReconstructable2DHits(pPfo, selectedMCParticleToHitsMaps, pfoHitList, foldBackHierarchy);
663
664 if (!pfoToReconstructable2DHitsMap.insert(PfoContributionMap::value_type(pPfo, pfoHitList)).second)
665 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
666 }
667}
668
669//------------------------------------------------------------------------------------------------------------------------------------------
670
672 const MCContributionMapVector &selectedMCParticleToHitsMaps, PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
673{
674 for (const ParticleFlowObject *const pPfo : pfoList)
675 {
676 CaloHitList pfoHitList;
677 LArMCParticleHelper::CollectReconstructableTestBeamHierarchy2DHits(pPfo, selectedMCParticleToHitsMaps, pfoHitList, foldBackHierarchy);
678
679 if (!pfoToReconstructable2DHitsMap.insert(PfoContributionMap::value_type(pPfo, pfoHitList)).second)
680 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
681 }
682}
683
684//------------------------------------------------------------------------------------------------------------------------------------------
685
687 const MCContributionMapVector &selectedMCParticleToHitsMaps, PfoToMCParticleHitSharingMap &pfoToMCParticleHitSharingMap,
688 MCParticleToPfoHitSharingMap &mcParticleToPfoHitSharingMap)
689{
690 PfoVector sortedPfos;
691 for (const auto &mapEntry : pfoToReconstructable2DHitsMap)
692 sortedPfos.push_back(mapEntry.first);
693 std::sort(sortedPfos.begin(), sortedPfos.end(), LArPfoHelper::SortByNHits);
694
695 for (const ParticleFlowObject *const pPfo : sortedPfos)
696 {
697 for (const MCContributionMap &mcParticleToHitsMap : selectedMCParticleToHitsMaps)
698 {
699 MCParticleVector sortedMCParticles;
700 for (const auto &mapEntry : mcParticleToHitsMap)
701 sortedMCParticles.push_back(mapEntry.first);
702 std::sort(sortedMCParticles.begin(), sortedMCParticles.end(), PointerLessThan<MCParticle>());
703
704 for (const MCParticle *const pMCParticle : sortedMCParticles)
705 {
706 // Add map entries for this Pfo & MCParticle if required
707 if (pfoToMCParticleHitSharingMap.find(pPfo) == pfoToMCParticleHitSharingMap.end())
708 if (!pfoToMCParticleHitSharingMap.insert(PfoToMCParticleHitSharingMap::value_type(pPfo, MCParticleToSharedHitsVector())).second)
709 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT); // ATTN maybe overkill
710
711 if (mcParticleToPfoHitSharingMap.find(pMCParticle) == mcParticleToPfoHitSharingMap.end())
712 if (!mcParticleToPfoHitSharingMap.insert(MCParticleToPfoHitSharingMap::value_type(pMCParticle, PfoToSharedHitsVector())).second)
713 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
714
715 // Check this Pfo & MCParticle pairing hasn't already been checked
716 MCParticleToSharedHitsVector &mcHitPairs(pfoToMCParticleHitSharingMap.at(pPfo));
717 PfoToSharedHitsVector &pfoHitPairs(mcParticleToPfoHitSharingMap.at(pMCParticle));
718
719 if (std::any_of(mcHitPairs.begin(), mcHitPairs.end(),
720 [&](const MCParticleCaloHitListPair &pair) { return (pair.first == pMCParticle); }))
721 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
722
723 if (std::any_of(pfoHitPairs.begin(), pfoHitPairs.end(), [&](const PfoCaloHitListPair &pair) { return (pair.first == pPfo); }))
724 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
725
726 // Add records to maps if there are any shared hits
727 const CaloHitList sharedHits(
728 LArMCParticleHelper::GetSharedHits(pfoToReconstructable2DHitsMap.at(pPfo), mcParticleToHitsMap.at(pMCParticle)));
729
730 if (!sharedHits.empty())
731 {
732 mcHitPairs.push_back(MCParticleCaloHitListPair(pMCParticle, sharedHits));
733 pfoHitPairs.push_back(PfoCaloHitListPair(pPfo, sharedHits));
734
735 std::sort(mcHitPairs.begin(), mcHitPairs.end(), [](const MCParticleCaloHitListPair &a, const MCParticleCaloHitListPair &b) -> bool {
736 return ((a.second.size() != b.second.size()) ? a.second.size() > b.second.size()
737 : LArMCParticleHelper::SortByMomentum(a.first, b.first));
738 });
739
740 std::sort(pfoHitPairs.begin(), pfoHitPairs.end(), [](const PfoCaloHitListPair &a, const PfoCaloHitListPair &b) -> bool {
741 return ((a.second.size() != b.second.size()) ? a.second.size() > b.second.size() : LArPfoHelper::SortByNHits(a.first, b.first));
742 });
743 }
744 }
745 }
746 }
747}
748
749//------------------------------------------------------------------------------------------------------------------------------------------
750
752 const MCContributionMap &selectedMCToHitsMap, ClusterContributionMap &clusterToReconstructable2DHitsMap)
753{
754 LArMCParticleHelper::GetClusterToReconstructable2DHitsMap(clusterList, MCContributionMapVector({selectedMCToHitsMap}), clusterToReconstructable2DHitsMap);
755}
756
757//------------------------------------------------------------------------------------------------------------------------------------------
758
760 const MCContributionMapVector &selectedMCToHitsMaps, ClusterContributionMap &clusterToReconstructable2DHitsMap)
761{
762 for (const Cluster *const pCluster : clusterList)
763 {
764 CaloHitList caloHitList;
765 LArMCParticleHelper::CollectReconstructable2DHits(pCluster, selectedMCToHitsMaps, caloHitList);
766
767 if (!clusterToReconstructable2DHitsMap.insert(ClusterContributionMap::value_type(pCluster, caloHitList)).second)
768 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
769 }
770}
771
772//------------------------------------------------------------------------------------------------------------------------------------------
773
775{
776 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
777 if (!pLArMCParticle)
778 return false;
779
780 switch (pLArMCParticle->GetProcess())
781 {
782 case MC_PROC_E_BREM:
783 case MC_PROC_MU_BREM:
784 case MC_PROC_HAD_BREM:
785 return true;
786 default:
787 return false;
788 }
789
790 return false;
791}
792
793//------------------------------------------------------------------------------------------------------------------------------------------
794
795bool LArMCParticleHelper::IsCapture(const MCParticle *const pMCParticle)
796{
797 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
798 if (!pLArMCParticle)
799 return false;
800
801 switch (pLArMCParticle->GetProcess())
802 {
808 return true;
809 default:
810 return false;
811 }
812
813 return false;
814}
815
816//------------------------------------------------------------------------------------------------------------------------------------------
817
818bool LArMCParticleHelper::IsDecay(const MCParticle *const pMCParticle)
819{
820 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
821 if (!pLArMCParticle)
822 return false;
823
824 switch (pLArMCParticle->GetProcess())
825 {
826 case MC_PROC_DECAY:
827 return true;
828 default:
829 return false;
830 }
831
832 return false;
833}
834
835//------------------------------------------------------------------------------------------------------------------------------------------
836
838{
839 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
840 if (!pLArMCParticle)
841 return false;
842
843 switch (pLArMCParticle->GetProcess())
844 {
848 case MC_PROC_RAYLEIGH:
849 return true;
850 default:
851 return false;
852 }
853
854 return false;
855}
856
857//------------------------------------------------------------------------------------------------------------------------------------------
858
860{
861 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
862 if (!pLArMCParticle)
863 return false;
864
865 switch (pLArMCParticle->GetProcess())
866 {
867 case MC_PROC_COMPT:
886 return true;
887 default:
888 return false;
889 }
890
891 return false;
892}
893
894//------------------------------------------------------------------------------------------------------------------------------------------
895
896bool LArMCParticleHelper::IsIonisation(const MCParticle *const pMCParticle)
897{
898 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
899 if (!pLArMCParticle)
900 return false;
901
902 switch (pLArMCParticle->GetProcess())
903 {
904 case MC_PROC_E_IONI:
905 case MC_PROC_MU_IONI:
906 case MC_PROC_HAD_IONI:
907 case MC_PROC_ION_IONI:
908 return true;
909 default:
910 return false;
911 }
912
913 return false;
914}
915
916//------------------------------------------------------------------------------------------------------------------------------------------
917
918bool LArMCParticleHelper::IsNuclear(const MCParticle *const pMCParticle)
919{
920 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
921 if (!pLArMCParticle)
922 return false;
923
924 switch (pLArMCParticle->GetProcess())
925 {
929 return true;
930 default:
931 return false;
932 }
933
934 return false;
935}
936
937//------------------------------------------------------------------------------------------------------------------------------------------
938
940{
941 const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
942 if (!pLArMCParticle)
943 return false;
944
945 switch (pLArMCParticle->GetProcess())
946 {
949 return true;
950 default:
951 return false;
952 }
953
954 return false;
955}
956
957//------------------------------------------------------------------------------------------------------------------------------------------
958
960{
961 CaloHitList sharedHits;
962
963 for (const CaloHit *const pCaloHit : hitListA)
964 {
965 if (std::find(hitListB.begin(), hitListB.end(), pCaloHit) != hitListB.end())
966 sharedHits.push_back(pCaloHit);
967 }
968
969 return sharedHits;
970}
971
972//------------------------------------------------------------------------------------------------------------------------------------------
973
974bool LArMCParticleHelper::AreTopologicallyContinuous(const MCParticle *const pMCParent, const MCParticle *const pMCChild, const float cosAngleTolerance)
975{
976 CartesianVector childDirection{pMCChild->GetEndpoint() - pMCChild->GetVertex()};
977 if (childDirection.GetMagnitude() < std::numeric_limits<float>::epsilon())
978 return true;
979 childDirection = childDirection.GetUnitVector();
980
981 const MCParticle *pMCUpstream{pMCParent};
982 while (true)
983 {
984 CartesianVector parentDirection{pMCUpstream->GetEndpoint() - pMCUpstream->GetVertex()};
985 if (parentDirection.GetMagnitude() > std::numeric_limits<float>::epsilon())
986 {
987 parentDirection = parentDirection.GetUnitVector();
988 return parentDirection.GetDotProduct(childDirection) >= cosAngleTolerance;
989 }
990 else
991 {
992 const MCParticleList &parentList{pMCUpstream->GetParentList()};
993 const size_t size{parentList.size()};
994 if (size == 1)
995 pMCUpstream = parentList.front();
996 else if (size == 0)
997 return true;
998 else
999 return false;
1000 }
1001 }
1002
1003 return false;
1004}
1005
1006// private
1007//------------------------------------------------------------------------------------------------------------------------------------------
1008
1010 const MCContributionMapVector &selectedMCParticleToHitsMaps, CaloHitList &reconstructableCaloHitList2D, const bool foldBackHierarchy)
1011{
1012
1013 PfoList pfoList;
1014
1015 // If foldBackHierarchy collect all 2D calo hits in pfo hierarchy
1016 // else collect hits directly belonging to pfo
1017 if (foldBackHierarchy)
1018 {
1020 }
1021 else
1022 {
1023 pfoList.push_back(pPfo);
1024 }
1025
1026 LArMCParticleHelper::CollectReconstructable2DHits(pfoList, selectedMCParticleToHitsMaps, reconstructableCaloHitList2D);
1027}
1028
1029//------------------------------------------------------------------------------------------------------------------------------------------
1030
1032 const MCContributionMapVector &selectedMCParticleToHitsMaps, CaloHitList &reconstructableCaloHitList2D, const bool foldBackHierarchy)
1033{
1034
1035 PfoList pfoList;
1036 // If foldBackHierarchy collect all 2D calo hits in pfo hierarchy
1037 // else collect hits directly belonging to pfo
1038 if (foldBackHierarchy)
1039 {
1040 // ATTN: Only collect downstream pfos for daughter test beam particles & cosmics
1041 if (pPfo->GetParentPfoList().empty() && LArPfoHelper::IsTestBeam(pPfo))
1042 {
1043 pfoList.push_back(pPfo);
1044 }
1045 else
1046 {
1048 }
1049 }
1050 else
1051 {
1052 pfoList.push_back(pPfo);
1053 }
1054
1055 LArMCParticleHelper::CollectReconstructable2DHits(pfoList, selectedMCParticleToHitsMaps, reconstructableCaloHitList2D);
1056}
1057
1058//------------------------------------------------------------------------------------------------------------------------------------------
1059
1061 const PfoList &pfoList, const MCContributionMapVector &selectedMCParticleToHitsMaps, CaloHitList &reconstructableCaloHitList2D)
1062{
1063 CaloHitList caloHitList2D;
1064 LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_U, caloHitList2D);
1065 LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_V, caloHitList2D);
1066 LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_W, caloHitList2D);
1067 LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_U, caloHitList2D); // TODO check isolated usage throughout
1068 LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_V, caloHitList2D);
1069 LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_W, caloHitList2D);
1070
1071 // Filter for only reconstructable hits
1072 for (const CaloHit *const pCaloHit : caloHitList2D)
1073 {
1074 bool isTargetHit(false);
1075 for (const MCContributionMap &mcParticleToHitsMap : selectedMCParticleToHitsMaps)
1076 {
1077 // ATTN This map is unordered, but this does not impact search for specific target hit
1078 for (const MCContributionMap::value_type &mapEntry : mcParticleToHitsMap)
1079 {
1080 if (std::find(mapEntry.second.begin(), mapEntry.second.end(), pCaloHit) != mapEntry.second.end())
1081 {
1082 isTargetHit = true;
1083 break;
1084 }
1085 }
1086 if (isTargetHit)
1087 break;
1088 }
1089
1090 if (isTargetHit)
1091 reconstructableCaloHitList2D.push_back(pCaloHit);
1092 }
1093}
1094
1095//------------------------------------------------------------------------------------------------------------------------------------------
1096
1098 const MCContributionMapVector &selectedMCToHitsMaps, pandora::CaloHitList &reconstructableCaloHitList2D)
1099{
1100 const CaloHitList &isolatedCaloHitList{pCluster->GetIsolatedCaloHitList()};
1101 CaloHitList caloHitList;
1102 pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
1103 for (const CaloHit *pCaloHit : isolatedCaloHitList)
1104 caloHitList.push_back(pCaloHit);
1105
1106 // Filter for only reconstructable hits
1107 for (const CaloHit *const pCaloHit : caloHitList)
1108 {
1109 bool isTargetHit{false};
1110 for (const MCContributionMap &mcParticleToHitsMap : selectedMCToHitsMaps)
1111 { // ATTN This map is unordered, but this does not impact search for specific target hit
1112 for (const MCContributionMap::value_type &mapEntry : mcParticleToHitsMap)
1113 {
1114 if (std::find(mapEntry.second.begin(), mapEntry.second.end(), pCaloHit) != mapEntry.second.end())
1115 {
1116 isTargetHit = true;
1117 break;
1118 }
1119 }
1120 if (isTargetHit)
1121 break;
1122 }
1123
1124 if (isTargetHit)
1125 reconstructableCaloHitList2D.push_back(pCaloHit);
1126 }
1127}
1128
1129//------------------------------------------------------------------------------------------------------------------------------------------
1130
1131void LArMCParticleHelper::SelectCaloHits(const CaloHitList *const pCaloHitList, const LArMCParticleHelper::MCRelationMap &mcToTargetMCMap,
1132 CaloHitList &selectedCaloHitList, const bool selectInputHits, const float maxPhotonPropagation)
1133{
1134 if (!selectInputHits)
1135 {
1136 selectedCaloHitList.insert(selectedCaloHitList.end(), pCaloHitList->begin(), pCaloHitList->end());
1137 return;
1138 }
1139
1140 for (const CaloHit *const pCaloHit : *pCaloHitList)
1141 {
1142 try
1143 {
1144 const MCParticle *const pHitParticle(MCParticleHelper::GetMainMCParticle(pCaloHit));
1145
1146 LArMCParticleHelper::MCRelationMap::const_iterator mcIter = mcToTargetMCMap.find(pHitParticle);
1147
1148 if (mcToTargetMCMap.end() == mcIter)
1149 continue;
1150
1151 // ATTN With folding on or off, still require primary particle to review hierarchy details
1152 const MCParticle *const pPrimaryParticle = LArMCParticleHelper::GetPrimaryMCParticle(pHitParticle);
1153
1154 if (PassMCParticleChecks(pPrimaryParticle, pPrimaryParticle, pHitParticle, maxPhotonPropagation))
1155 selectedCaloHitList.push_back(pCaloHit);
1156 }
1157 catch (const StatusCodeException &)
1158 {
1159 }
1160 }
1161}
1162
1163//------------------------------------------------------------------------------------------------------------------------------------------
1164
1165bool LArMCParticleHelper::IsDescendentOf(const MCParticle *const pMCParticle, const int pdg, const bool isChargeSensitive)
1166{
1167 const MCParticle *pCurrentParticle = pMCParticle;
1168 while (!pCurrentParticle->GetParentList().empty())
1169 {
1170 if (pCurrentParticle->GetParentList().size() > 1)
1171 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
1172
1173 const MCParticle *pParent = *(pCurrentParticle->GetParentList().begin());
1174 const bool found{isChargeSensitive ? pParent->GetParticleId() == pdg : std::abs(pParent->GetParticleId()) == std::abs(pdg)};
1175 if (found)
1176 return true;
1177 pCurrentParticle = pParent;
1178 }
1179
1180 return false;
1181}
1182
1183//------------------------------------------------------------------------------------------------------------------------------------------
1184
1186{
1187 const MCParticle *const pRoot{LArMCParticleHelper::GetParentMCParticle(pMCParticle)};
1188 MCParticleList queue;
1189 mcParticleList.emplace_back(pRoot);
1190 queue.emplace_back(pRoot);
1191
1192 while (!queue.empty())
1193 {
1194 const MCParticleList &daughters{queue.front()->GetDaughterList()};
1195 queue.pop_front();
1196 for (const MCParticle *pDaughter : daughters)
1197 {
1198 mcParticleList.emplace_back(pDaughter);
1199 queue.emplace_back(pDaughter);
1200 }
1201 }
1202}
1203
1204//------------------------------------------------------------------------------------------------------------------------------------------
1205
1206void LArMCParticleHelper::SelectParticlesByHitCount(const MCParticleVector &candidateTargets, const MCContributionMap &mcToTrueHitListMap,
1207 const MCRelationMap &mcToTargetMCMap, const PrimaryParameters &parameters, MCContributionMap &selectedMCParticlesToHitsMap)
1208{
1209 // Apply restrictions on the number of good hits associated with the MCParticles
1210 for (const MCParticle *const pMCTarget : candidateTargets)
1211 {
1212 MCContributionMap::const_iterator trueHitsIter = mcToTrueHitListMap.find(pMCTarget);
1213 if (mcToTrueHitListMap.end() == trueHitsIter)
1214 continue;
1215
1216 const CaloHitList &caloHitList(trueHitsIter->second);
1217
1218 // Remove shared hits where target particle deposits below threshold energy fraction
1219 CaloHitList goodCaloHitList;
1221 &caloHitList, mcToTargetMCMap, goodCaloHitList, parameters.m_selectInputHits, parameters.m_minHitSharingFraction);
1222
1223 if (goodCaloHitList.size() < parameters.m_minPrimaryGoodHits)
1224 continue;
1225
1226 unsigned int nGoodViews(0);
1227 if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_U, goodCaloHitList) >= parameters.m_minHitsForGoodView)
1228 ++nGoodViews;
1229
1230 if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_V, goodCaloHitList) >= parameters.m_minHitsForGoodView)
1231 ++nGoodViews;
1232
1233 if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_W, goodCaloHitList) >= parameters.m_minHitsForGoodView)
1234 ++nGoodViews;
1235
1236 if (nGoodViews < parameters.m_minPrimaryGoodViews)
1237 continue;
1238
1239 if (!selectedMCParticlesToHitsMap.insert(MCContributionMap::value_type(pMCTarget, caloHitList)).second)
1240 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
1241 }
1242}
1243
1244//------------------------------------------------------------------------------------------------------------------------------------------
1245
1246void LArMCParticleHelper::SelectGoodCaloHits(const CaloHitList *const pSelectedCaloHitList, const LArMCParticleHelper::MCRelationMap &mcToTargetMCMap,
1247 CaloHitList &selectedGoodCaloHitList, const bool selectInputHits, const float minHitSharingFraction)
1248{
1249 if (!selectInputHits)
1250 {
1251 selectedGoodCaloHitList.insert(selectedGoodCaloHitList.end(), pSelectedCaloHitList->begin(), pSelectedCaloHitList->end());
1252 return;
1253 }
1254
1255 for (const CaloHit *const pCaloHit : *pSelectedCaloHitList)
1256 {
1257 MCParticleVector mcParticleVector;
1258 for (const auto &mapEntry : pCaloHit->GetMCParticleWeightMap())
1259 mcParticleVector.push_back(mapEntry.first);
1260 std::sort(mcParticleVector.begin(), mcParticleVector.end(), PointerLessThan<MCParticle>());
1261
1262 MCParticleWeightMap targetWeightMap;
1263
1264 for (const MCParticle *const pMCParticle : mcParticleVector)
1265 {
1266 const float weight(pCaloHit->GetMCParticleWeightMap().at(pMCParticle));
1267 LArMCParticleHelper::MCRelationMap::const_iterator mcIter = mcToTargetMCMap.find(pMCParticle);
1268
1269 if (mcToTargetMCMap.end() != mcIter)
1270 targetWeightMap[mcIter->second] += weight;
1271 }
1272
1273 MCParticleVector mcTargetVector;
1274 for (const auto &mapEntry : targetWeightMap)
1275 mcTargetVector.push_back(mapEntry.first);
1276 std::sort(mcTargetVector.begin(), mcTargetVector.end(), PointerLessThan<MCParticle>());
1277
1278 const MCParticle *pBestTargetParticle(nullptr);
1279 float bestTargetWeight(0.f), targetWeightSum(0.f);
1280
1281 for (const MCParticle *const pTargetMCParticle : mcTargetVector)
1282 {
1283 const float targetWeight(targetWeightMap.at(pTargetMCParticle));
1284 targetWeightSum += targetWeight;
1285
1286 if (targetWeight > bestTargetWeight)
1287 {
1288 bestTargetWeight = targetWeight;
1289 pBestTargetParticle = pTargetMCParticle;
1290 }
1291 }
1292
1293 if (!pBestTargetParticle || (targetWeightSum < std::numeric_limits<float>::epsilon()) || ((bestTargetWeight / targetWeightSum) < minHitSharingFraction))
1294 continue;
1295
1296 selectedGoodCaloHitList.push_back(pCaloHit);
1297 }
1298}
1299
1300//------------------------------------------------------------------------------------------------------------------------------------------
1301
1303 std::function<bool(const MCParticle *const)> fCriteria, MCParticleVector &selectedParticles, const PrimaryParameters &parameters, const bool isTestBeam)
1304{
1305 for (const MCParticle *const pMCParticle : inputMCParticles)
1306 {
1307 if (parameters.m_foldBackHierarchy)
1308 {
1309 if (!fCriteria(pMCParticle))
1310 continue;
1311 }
1312 else
1313 {
1314 if (isTestBeam)
1315 {
1316 if (!LArMCParticleHelper::DoesLeadingMeetCriteria(pMCParticle, fCriteria))
1317 continue;
1318 }
1319 else
1320 {
1321 if (!LArMCParticleHelper::DoesPrimaryMeetCriteria(pMCParticle, fCriteria))
1322 continue;
1323 }
1324 }
1325 selectedParticles.push_back(pMCParticle);
1326 }
1327}
1328
1329//------------------------------------------------------------------------------------------------------------------------------------------
1330
1331bool LArMCParticleHelper::PassMCParticleChecks(const MCParticle *const pOriginalPrimary, const MCParticle *const pThisMCParticle,
1332 const MCParticle *const pHitMCParticle, const float maxPhotonPropagation)
1333{
1334 if (NEUTRON == std::abs(pThisMCParticle->GetParticleId()))
1335 return false;
1336
1337 if ((PHOTON == pThisMCParticle->GetParticleId()) && (PHOTON != pOriginalPrimary->GetParticleId()) &&
1338 (E_MINUS != std::abs(pOriginalPrimary->GetParticleId())))
1339 {
1340 if ((pThisMCParticle->GetEndpoint() - pThisMCParticle->GetVertex()).GetMagnitude() > maxPhotonPropagation)
1341 return false;
1342 }
1343
1344 if (pThisMCParticle == pHitMCParticle)
1345 return true;
1346
1347 for (const MCParticle *const pDaughterMCParticle : pThisMCParticle->GetDaughterList())
1348 {
1349 if (PassMCParticleChecks(pOriginalPrimary, pDaughterMCParticle, pHitMCParticle, maxPhotonPropagation))
1350 return true;
1351 }
1352
1353 return false;
1354}
1355
1356} // namespace lar_content
Header file for the calo hit class.
Header file for the cluster class.
Header file for the cluster helper class.
Header file for the lar monte carlo particle helper helper class.
Header file for the lar monitoring helper helper class.
Header file for the pfo helper class.
Header file for the mc particle class.
Header file for the mc particle helper class.
Header file defining status codes and relevant preprocessor macros.
@ NEUTRON
Definition Validation.h:213
bool m_foldBackHierarchy
whether to fold the hierarchy back to the primary (neutrino) or leading particles (test beam)
float m_minHitSharingFraction
the minimum Hit sharing fraction
float m_maxPhotonPropagation
the maximum photon propagation length
unsigned int m_minPrimaryGoodHits
the minimum number of primary good Hits
unsigned int m_minPrimaryGoodViews
the minimum number of primary good views
unsigned int m_minHitsForGoodView
the minimum number of Hits for a good view
static bool IsCosmicRay(const pandora::MCParticle *const pMCParticle)
Return true if passed a primary cosmic ray MCParticle.
static pandora::CaloHitList GetSharedHits(const pandora::CaloHitList &hitListA, const pandora::CaloHitList &hitListB)
Get the hits in the intersection of two hit lists.
static bool IsLeading(const pandora::MCParticle *const pMCParticle)
Whether a provided mc particle matches the implemented definition of being leading.
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
std::map< const pandora::ParticleFlowObject *, MCParticleToSharedHitsVector > PfoToMCParticleHitSharingMap
static bool IsInelasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an inelastic scattering process.
static void SelectReconstructableTestBeamHierarchyMCParticles(const pandora::MCParticleList *pMCParticleList, const pandora::CaloHitList *pCaloHitList, const PrimaryParameters &parameters, std::function< bool(const pandora::MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
Select target, reconstructable mc particles in the relevant hierarchy that match given criteria.
static void GetPfoMCParticleHitSharingMaps(const PfoContributionMap &pfoToReconstructable2DHitsMap, const MCContributionMapVector &selectedMCParticleToHitsMaps, PfoToMCParticleHitSharingMap &pfoToMCParticleHitSharingMap, MCParticleToPfoHitSharingMap &mcParticleToPfoHitSharingMap)
Get the mappings from Pfo -> pair (reconstructable MCparticles, number of reconstructable 2D hits sha...
static void GetAllAncestorMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &ancestorMCParticleList)
Get all ancestor mc particles.
static void GetPrimaryMCParticleList(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &mcPrimaryVector)
Get vector of primary MC particles from an input list of MC particles.
static void GetFirstVisibleMCParticles(const pandora::MCParticle *const pRoot, pandora::MCParticleList &visibleParticleList)
Get the first visible MC particles given a root particle. For example, given a neutrino this would re...
static bool IsPrimary(const pandora::MCParticle *const pMCParticle)
Whether a provided mc particle matches the implemented definition of being primary.
static void GetClusterToReconstructable2DHitsMap(const pandora::ClusterList &clusterList, const MCContributionMap &selectedMCToHitsMap, ClusterContributionMap &clusterToReconstructable2DHitsMap)
Get mapping from cluster to reconstructable 2D hits (=good hits belonging to a selected reconstructab...
static void GetAllDescendentMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &descendentMCParticleList)
Get all descendent mc particles.
static void SelectParticlesByHitCount(const pandora::MCParticleVector &candidateTargets, const MCContributionMap &mcToTrueHitListMap, const MCRelationMap &mcToTargetMCMap, const PrimaryParameters &parameters, MCContributionMap &selectedMCParticlesToHitsMap)
Filter an input vector of MCParticles to ensure they have sufficient good hits to be reconstructable.
static void GetMCLeadingMap(const pandora::MCParticleList *const pMCParticleList, MCRelationMap &mcLeadingMap)
Get mapping from individual mc particles (in a provided list) and their leading parent mc particles.
static const pandora::MCParticle * GetPrimaryMCParticle(const pandora::MCParticle *const pMCParticle)
Get the primary parent mc particle.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
static void CollectReconstructable2DHits(const pandora::ParticleFlowObject *const pPfo, const MCContributionMapVector &selectedMCParticleToHitsMaps, pandora::CaloHitList &reconstructableCaloHitList2D, const bool foldBackHierarchy)
For a given Pfo, collect the hits which are reconstructable (=good hits belonging to a selected recon...
static bool IsVisible(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is visible (i.e. long-lived charged particle)
static bool IsBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary beam MCParticle.
static bool IsDecay(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a decay process.
static bool IsCapture(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a capture process.
std::unordered_map< const pandora::ParticleFlowObject *, pandora::CaloHitList > PfoContributionMap
std::vector< MCContributionMap > MCContributionMapVector
std::vector< PfoCaloHitListPair > PfoToSharedHitsVector
static bool IsBremsstrahlung(const pandora::MCParticle *const pMCParticle)
static void SelectReconstructableMCParticles(const pandora::MCParticleList *pMCParticleList, const pandora::CaloHitList *pCaloHitList, const PrimaryParameters &parameters, std::function< bool(const pandora::MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
Select target, reconstructable mc particles that match given criteria.
std::unordered_map< const pandora::MCParticle *, pandora::CaloHitList > MCContributionMap
static const pandora::MCParticle * GetLeadingMCParticle(const pandora::MCParticle *const pMCParticle, const int hierarchyTierLimit=1)
Get the leading particle in the hierarchy, for use at ProtoDUNE.
static void GetMCToSelfMap(const pandora::MCParticleList *const pMCParticleList, MCRelationMap &mcToSelfMap)
Get mapping from individual mc particles (in a provided list) to themselves (to be used when not fold...
static bool IsTriggeredBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary triggered beam MCParticle.
static bool PassMCParticleChecks(const pandora::MCParticle *const pOriginalPrimary, const pandora::MCParticle *const pThisMCParticle, const pandora::MCParticle *const pHitMCParticle, const float maxPhotonPropagation)
Whether it is possible to navigate from a primary mc particle to a downstream mc particle without "pa...
static bool AreTopologicallyContinuous(const pandora::MCParticle *const pMCParent, const pandora::MCParticle *const pMCChild, const float cosAngleTolerance)
Determine if two MC particles are topologically continuous within a given tolerance....
static void GetLeadingMCParticleList(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &mcLeadingVector)
Get vector of leading MC particles from an input list of MC particles.
static void GetBreadthFirstHierarchyRepresentation(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &mcParticleList)
Retrieve a linearised representation of the MC particle hierarchy in breadth first order....
static bool IsDescendentOf(const pandora::MCParticle *const pMCParticle, const int pdg, const bool isChargeSensitive=false)
Determine if the MC particle is a descendent of a particle with the given PDG code.
static unsigned int GetNuanceCode(const pandora::MCParticle *const pMCParticle)
Get the nuance code of an MCParticle.
static void CollectReconstructableTestBeamHierarchy2DHits(const pandora::ParticleFlowObject *const pPfo, const MCContributionMapVector &selectedMCParticleToHitsMaps, pandora::CaloHitList &reconstructableCaloHitList2D, const bool foldBackHierarchy)
For a given Pfo, collect the hits which are reconstructable (=good hits belonging to a selected recon...
static const pandora::MCParticle * GetParentMCParticle(const pandora::MCParticle *const pMCParticle)
Get the parent mc particle.
std::pair< const pandora::ParticleFlowObject *, pandora::CaloHitList > PfoCaloHitListPair
static void GetPfoToReconstructable2DHitsMap(const pandora::PfoList &pfoList, const MCContributionMap &selectedMCParticleToHitsMap, PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
Get mapping from Pfo to reconstructable 2D hits (=good hits belonging to a selected reconstructable M...
static bool IsPairProduction(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a pair production process.
static void GetTrueTestBeamParticles(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &trueTestBeamParticles)
Get triggered test beam MC particles from an input MC particle list.
std::unordered_map< const pandora::CaloHit *, const pandora::MCParticle * > CaloHitToMCMap
static void GetMCParticleToCaloHitMatches(const pandora::CaloHitList *const pCaloHitList, const MCRelationMap &mcToTargetMCMap, CaloHitToMCMap &hitToMCMap, MCContributionMap &mcToTrueHitListMap)
Match calo hits to their parent particles.
static void SelectCaloHits(const pandora::CaloHitList *const pCaloHitList, const MCRelationMap &mcToTargetMCMap, pandora::CaloHitList &selectedCaloHitList, const bool selectInputHits, const float maxPhotonPropagation)
Select a subset of calo hits representing those that represent "reconstructable" regions of the event...
static bool IsNuclear(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a nuclear interaction process.
static bool DoesPrimaryMeetCriteria(const pandora::MCParticle *const pMCParticle, std::function< bool(const pandora::MCParticle *const)> fCriteria)
Returns true if passed particle whose primary meets the passed criteria.
std::unordered_map< const pandora::MCParticle *, const pandora::MCParticle * > MCRelationMap
std::vector< MCParticleCaloHitListPair > MCParticleToSharedHitsVector
static void GetMCPrimaryMap(const pandora::MCParticleList *const pMCParticleList, MCRelationMap &mcPrimaryMap)
Get mapping from individual mc particles (in a provided list) and their primary parent mc particles.
static void SelectParticlesMatchingCriteria(const pandora::MCParticleVector &inputMCParticles, std::function< bool(const pandora::MCParticle *const)> fCriteria, pandora::MCParticleVector &selectedParticles, const PrimaryParameters &parameters, const bool isTestBeam)
Select mc particles matching given criteria from an input list.
static const pandora::MCParticle * GetMainMCParticle(const pandora::ParticleFlowObject *const pPfo)
Find the mc particle making the largest contribution to 2D clusters in a specified pfo.
static bool DoesLeadingMeetCriteria(const pandora::MCParticle *const pMCParticle, std::function< bool(const pandora::MCParticle *const)> fCriteria)
Returns true if passed particle whose leading meets the passed criteria.
std::unordered_map< const pandora::Cluster *, pandora::CaloHitList > ClusterContributionMap
static bool IsIonisation(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from an ionisation process.
static bool IsElasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an elastic scattering process.
static int GetHierarchyTier(const pandora::MCParticle *const pMCParticle)
Determine the position in the hierarchy for the MCParticle.
static void SelectGoodCaloHits(const pandora::CaloHitList *const pSelectedCaloHitList, const MCRelationMap &mcToTargetMCMap, pandora::CaloHitList &selectedGoodCaloHitList, const bool selectInputHits, const float minHitSharingFraction)
Apply further selection criteria to end up with a collection of "good" calo hits that can be use to d...
static bool IsLeadingBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a leading beam MCParticle.
static void GetTrueNeutrinos(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &trueNeutrinos)
Get neutrino MC particles from an input MC particle list.
std::map< const pandora::MCParticle *, PfoToSharedHitsVector > MCParticleToPfoHitSharingMap
std::pair< const pandora::MCParticle *, pandora::CaloHitList > MCParticleCaloHitListPair
static bool IsBeamNeutrinoFinalState(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary neutrino final state MCParticle.
static void GetTestBeamHierarchyPfoToReconstructable2DHitsMap(const pandora::PfoList &pfoList, const MCContributionMap &selectedMCParticleToHitsMap, PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
Get mapping from Pfo in reconstructed test beam hierarchy to reconstructable 2D hits (=good hits belo...
LAr mc particle class.
int GetNuanceCode() const
Get the nuance code.
static unsigned int CountHitsByType(const pandora::HitType hitType, const pandora::CaloHitList &caloHitList)
Count the number of calo hits, in a provided list, of a specified type.
static bool IsTestBeam(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a test beam particle.
static void GetAllDownstreamPfos(const pandora::PfoList &inputPfoList, pandora::PfoList &outputPfoList)
Get a flat list of all pfos, recursively, of all daughters associated with those pfos in an input lis...
static void GetTwoDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 2D clusters from an input pfo.
static void GetIsolatedCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of isolated calo hits of a particular hit type from a list of pfos.
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
CaloHit class.
Definition CaloHit.h:26
CartesianVector class.
float GetMagnitudeSquared() const
Get the magnitude squared.
CartesianVector GetUnitVector() const
Get a unit vector in the direction of the cartesian vector.
float GetDotProduct(const CartesianVector &rhs) const
Get the dot product of the cartesian vector with a second cartesian vector.
Cluster class.
Definition Cluster.h:31
const OrderedCaloHitList & GetOrderedCaloHitList() const
Get the ordered calo hit list.
Definition Cluster.h:470
const CaloHitList & GetIsolatedCaloHitList() const
Get the isolated calo hit list.
Definition Cluster.h:477
static const MCParticle * GetMainMCParticle(const T *const pT)
Find the mc particle making the largest contribution to a specified calo hit, track or cluster.
MCParticle class.
Definition MCParticle.h:26
float GetEnergy() const
Get energy of mc particle, units GeV.
Definition MCParticle.h:243
const MCParticleList & GetDaughterList() const
Get list of daughters of mc particle.
Definition MCParticle.h:306
const CartesianVector & GetMomentum() const
Get momentum of mc particle, units GeV.
Definition MCParticle.h:250
const CartesianVector & GetEndpoint() const
Get the endpoint of the mc particle, units mm.
Definition MCParticle.h:264
const CartesianVector & GetVertex() const
Get the production vertex of the mc particle, units mm.
Definition MCParticle.h:257
const MCParticleList & GetParentList() const
Get list of parents of mc particle.
Definition MCParticle.h:299
int GetParticleId() const
Get the PDG code of the mc particle.
Definition MCParticle.h:285
void FillCaloHitList(CaloHitList &caloHitList) const
Fill a provided calo hit list with all the calo hits in the ordered calo hit list.
ParticleFlowObject class.
const PfoList & GetParentPfoList() const
Get the parent pfo list.
Enable ordering of pointers based on properties of target objects.
StatusCodeException class.
StatusCode GetStatusCode() const
Get status code.
@ MC_PROC_HAD_BERTINI_CAPTURE_AT_REST
@ MC_PROC_NEUTRON_INELASTIC
@ MC_PROC_ALPHA_INELASTIC
@ MC_PROC_DEUTERON_INELASTIC
@ MC_PROC_TRITON_INELASTIC
@ MC_PROC_ANTI_DEUTERON_INELASTIC
@ MC_PROC_PI_PLUS_INELASTIC
@ MC_PROC_ANTI_NEUTRON_INELASTIC
@ MC_PROC_ANTI_ALPHA_INELASTIC
@ MC_PROC_CHIPS_NUCLEAR_CAPTURE_AT_REST
@ MC_PROC_ANTI_TRITON_INELASTIC
@ MC_PROC_ELECTRON_NUCLEAR
@ MC_PROC_ANTI_PROTON_INELASTIC
@ MC_PROC_PI_MINUS_INELASTIC
@ MC_PROC_PROTON_INELASTIC
@ MC_PROC_PHOTON_INELASTIC
@ MC_PROC_MU_MINUS_CAPTURE_AT_REST
@ MC_PROC_HAD_FRITIOF_CAPTURE_AT_REST
@ MC_PROC_KAON_PLUS_INELASTIC
@ MC_PROC_LAMBDA_INELASTIC
@ MC_PROC_ANTI_HE3_INELASTIC
@ MC_PROC_KAON_MINUS_INELASTIC
MANAGED_CONTAINER< const MCParticle * > MCParticleList
std::unordered_map< const MCParticle *, float > MCParticleWeightMap
MANAGED_CONTAINER< const Cluster * > ClusterList
std::vector< const ParticleFlowObject * > PfoVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList
std::vector< const MCParticle * > MCParticleVector
MANAGED_CONTAINER< const ParticleFlowObject * > PfoList