LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
LArMCParticleHelper.cc
Go to the documentation of this file.
1 
9 #include "Helpers/MCParticleHelper.h"
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 
26 namespace lar_content
27 {
28 
29 using 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 
45 bool 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 
61 bool 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 
77 bool LArMCParticleHelper::IsBeamNeutrinoFinalState(const MCParticle *const pMCParticle)
78 {
79  const MCParticle *const pParentMCParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle));
80  return (LArMCParticleHelper::IsPrimary(pMCParticle) && LArMCParticleHelper::IsNeutrino(pParentMCParticle));
81 }
82 
83 //------------------------------------------------------------------------------------------------------------------------------------------
84 
85 bool LArMCParticleHelper::IsTriggeredBeamParticle(const MCParticle *const pMCParticle)
86 {
87  const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
88  return (LArMCParticleHelper::IsPrimary(pMCParticle) && (nuance == 2001));
89 }
90 
91 //------------------------------------------------------------------------------------------------------------------------------------------
92 
93 bool 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 
101 bool LArMCParticleHelper::IsLeadingBeamParticle(const MCParticle *const pMCParticle)
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 
110 bool 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 
119 unsigned 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 
131 bool 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 
143 bool LArMCParticleHelper::IsPrimary(const pandora::MCParticle *const pMCParticle)
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 
158 bool LArMCParticleHelper::IsLeading(const pandora::MCParticle *const pMCParticle)
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 
173 int LArMCParticleHelper::GetHierarchyTier(const pandora::MCParticle *const pMCParticle)
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 
192 bool 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 
206 void 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 
219 void 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 
232 bool LArMCParticleHelper::GetTrueVertex(const MCParticleList *const pMCParticleList, CartesianVector &trueVertex)
233 {
234  MCParticleVector primaries;
235  LArMCParticleHelper::GetPrimaryMCParticleList(pMCParticleList, primaries);
236  if (!primaries.empty())
237  {
238  const MCParticle *primary{primaries.front()};
239  const MCParticleList &parents{primary->GetParentList()};
240  if (parents.size() == 1)
241  {
242  const MCParticle *trueNeutrino{parents.front()};
243  if (LArMCParticleHelper::IsNeutrino(trueNeutrino))
244  {
245  trueVertex = primaries.front()->GetVertex();
246  return true;
247  }
248  }
249  }
250 
251  return false;
252 }
253 
254 //------------------------------------------------------------------------------------------------------------------------------------------
255 
256 const MCParticle *LArMCParticleHelper::GetParentMCParticle(const MCParticle *const pMCParticle)
257 {
258  const MCParticle *pParentMCParticle = pMCParticle;
259 
260  while (pParentMCParticle->GetParentList().empty() == false)
261  {
262  if (1 != pParentMCParticle->GetParentList().size())
263  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
264 
265  pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
266  }
267 
268  return pParentMCParticle;
269 }
270 
271 //------------------------------------------------------------------------------------------------------------------------------------------
272 
273 void LArMCParticleHelper::GetAllDescendentMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &descendentMCParticleList)
274 {
275  for (const MCParticle *pDaughterMCParticle : pMCParticle->GetDaughterList())
276  {
277  if (std::find(descendentMCParticleList.begin(), descendentMCParticleList.end(), pDaughterMCParticle) == descendentMCParticleList.end())
278  {
279  descendentMCParticleList.emplace_back(pDaughterMCParticle);
280  LArMCParticleHelper::GetAllDescendentMCParticles(pDaughterMCParticle, descendentMCParticleList);
281  }
282  }
283 }
284 
285 //------------------------------------------------------------------------------------------------------------------------------------------
286 
287 void LArMCParticleHelper::GetAllDescendentMCParticles(const MCParticle *const pMCParticle, MCParticleList &descendentTrackParticles,
288  MCParticleList &leadingShowerParticles, MCParticleList &leadingNeutrons)
289 {
290  for (const MCParticle *pDaughterMCParticle : pMCParticle->GetDaughterList())
291  {
292  if (std::find(descendentTrackParticles.begin(), descendentTrackParticles.end(), pDaughterMCParticle) == descendentTrackParticles.end())
293  {
294  const int pdg{std::abs(pDaughterMCParticle->GetParticleId())};
295  if (pdg == E_MINUS || pdg == PHOTON)
296  {
297  leadingShowerParticles.emplace_back(pDaughterMCParticle);
298  }
299  else if (pdg == NEUTRON)
300  {
301  leadingNeutrons.emplace_back(pDaughterMCParticle);
302  }
303  else
304  {
305  descendentTrackParticles.emplace_back(pDaughterMCParticle);
306  LArMCParticleHelper::GetAllDescendentMCParticles(pDaughterMCParticle, descendentTrackParticles, leadingShowerParticles, leadingNeutrons);
307  }
308  }
309  }
310 }
311 
312 //------------------------------------------------------------------------------------------------------------------------------------------
313 
314 void LArMCParticleHelper::GetAllAncestorMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &ancestorMCParticleList)
315 {
316  const MCParticleList &parentMCParticleList = pMCParticle->GetParentList();
317  if (parentMCParticleList.empty())
318  return;
319  if (parentMCParticleList.size() != 1)
320  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
321 
322  const MCParticle *pParentMCParticle = *parentMCParticleList.begin();
323  if (std::find(ancestorMCParticleList.begin(), ancestorMCParticleList.end(), pParentMCParticle) == ancestorMCParticleList.end())
324  {
325  ancestorMCParticleList.push_back(pParentMCParticle);
326  LArMCParticleHelper::GetAllAncestorMCParticles(pParentMCParticle, ancestorMCParticleList);
327  }
328 }
329 
330 //------------------------------------------------------------------------------------------------------------------------------------------
331 
332 void LArMCParticleHelper::GetPrimaryMCParticleList(const MCParticleList *const pMCParticleList, MCParticleVector &mcPrimaryVector)
333 {
334  for (const MCParticle *const pMCParticle : *pMCParticleList)
335  {
336  if (LArMCParticleHelper::IsPrimary(pMCParticle))
337  mcPrimaryVector.push_back(pMCParticle);
338  }
339 
340  std::sort(mcPrimaryVector.begin(), mcPrimaryVector.end(), LArMCParticleHelper::SortByMomentum);
341 }
342 
343 //------------------------------------------------------------------------------------------------------------------------------------------
344 
345 void LArMCParticleHelper::GetLeadingMCParticleList(const MCParticleList *const pMCParticleList, MCParticleVector &mcLeadingVector)
346 {
347  for (const MCParticle *const pMCParticle : *pMCParticleList)
348  {
349  const bool isBeamParticle(LArMCParticleHelper::IsBeamParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle)));
350 
351  if ((isBeamParticle && LArMCParticleHelper::IsLeading(pMCParticle)) || (!isBeamParticle && LArMCParticleHelper::IsPrimary(pMCParticle)))
352  {
353  mcLeadingVector.push_back(pMCParticle);
354  }
355  }
356 
357  std::sort(mcLeadingVector.begin(), mcLeadingVector.end(), LArMCParticleHelper::SortByMomentum);
358 }
359 
360 //------------------------------------------------------------------------------------------------------------------------------------------
361 
362 void LArMCParticleHelper::GetFirstVisibleMCParticles(const MCParticle *const pRoot, MCParticleList &visibleParticleList)
363 {
365  {
366  visibleParticleList.emplace_back(pRoot);
367  }
368  else
369  {
370  for (const MCParticle *const pMCParticle : pRoot->GetDaughterList())
371  LArMCParticleHelper::GetFirstVisibleMCParticles(pMCParticle, visibleParticleList);
372  }
373 }
374 
375 //------------------------------------------------------------------------------------------------------------------------------------------
376 
377 const MCParticle *LArMCParticleHelper::GetPrimaryMCParticle(const MCParticle *const pMCParticle)
378 {
379  // Navigate upward through MC daughter/parent links - collect this particle and all its parents
380  MCParticleVector mcVector;
381 
382  const MCParticle *pParentMCParticle = pMCParticle;
383  mcVector.push_back(pParentMCParticle);
384 
385  while (!pParentMCParticle->GetParentList().empty())
386  {
387  if (1 != pParentMCParticle->GetParentList().size())
388  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
389 
390  pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
391  mcVector.push_back(pParentMCParticle);
392  }
393 
394  // Navigate downward through MC parent/daughter links - return the first long-lived charged particle
395  for (MCParticleVector::const_reverse_iterator iter = mcVector.rbegin(), iterEnd = mcVector.rend(); iter != iterEnd; ++iter)
396  {
397  const MCParticle *const pNextParticle = *iter;
398 
399  if (LArMCParticleHelper::IsVisible(pNextParticle))
400  return pNextParticle;
401  }
402 
403  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
404 }
405 
406 //------------------------------------------------------------------------------------------------------------------------------------------
407 
408 const MCParticle *LArMCParticleHelper::GetLeadingMCParticle(const MCParticle *const pMCParticle, const int hierarchyTierLimit)
409 {
410  // ATTN: If not beam particle return primary particle
411  const bool isBeamParticle(LArMCParticleHelper::IsBeamParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle)));
412 
413  if (!isBeamParticle)
414  return LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle);
415 
416  // Navigate upward through MC daughter/parent links - collect this particle and all its parents
417  MCParticleVector mcVector;
418 
419  const MCParticle *pParentMCParticle = pMCParticle;
420  mcVector.push_back(pParentMCParticle);
421 
422  while (!pParentMCParticle->GetParentList().empty())
423  {
424  if (1 != pParentMCParticle->GetParentList().size())
425  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
426 
427  pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
428  mcVector.push_back(pParentMCParticle);
429  }
430 
431  int hierarchyTier(0);
432  const MCParticle *pLeadingMCParticle(nullptr);
433 
434  // Navigate downward through MC parent/daughter links - return the first long-lived charged particle
435  for (MCParticleVector::const_reverse_iterator iter = mcVector.rbegin(), iterEnd = mcVector.rend(); iter != iterEnd; ++iter)
436  {
437  const MCParticle *const pNextParticle = *iter;
438 
439  // ATTN: Squash any invisible particles (e.g. pizero)
440  if (!LArMCParticleHelper::IsVisible(pNextParticle))
441  continue;
442 
443  if (hierarchyTier <= hierarchyTierLimit)
444  pLeadingMCParticle = pNextParticle;
445 
446  hierarchyTier++;
447  }
448 
449  if (!pLeadingMCParticle)
450  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
451 
452  return pLeadingMCParticle;
453 }
454 
455 //------------------------------------------------------------------------------------------------------------------------------------------
456 
457 void LArMCParticleHelper::GetMCPrimaryMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcPrimaryMap)
458 {
459  for (const MCParticle *const pMCParticle : *pMCParticleList)
460  {
461  try
462  {
463  const MCParticle *const pPrimaryMCParticle = LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle);
464  mcPrimaryMap[pMCParticle] = pPrimaryMCParticle;
465  }
466  catch (const StatusCodeException &)
467  {
468  }
469  }
470 }
471 
472 //------------------------------------------------------------------------------------------------------------------------------------------
473 
474 void LArMCParticleHelper::GetMCLeadingMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcLeadingMap)
475 {
476  for (const MCParticle *const pMCParticle : *pMCParticleList)
477  {
478  try
479  {
480  const MCParticle *const pLeadingMCParticle = LArMCParticleHelper::GetLeadingMCParticle(pMCParticle);
481  mcLeadingMap[pMCParticle] = pLeadingMCParticle;
482  }
483  catch (const StatusCodeException &)
484  {
485  }
486  }
487 }
488 
489 //------------------------------------------------------------------------------------------------------------------------------------------
490 
491 void LArMCParticleHelper::GetMCToSelfMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcToSelfMap)
492 {
493  for (const MCParticle *const pMCParticle : *pMCParticleList)
494  {
495  mcToSelfMap[pMCParticle] = pMCParticle;
496  }
497 }
498 
499 //-----------------------------------------------------------------------------------------------------------------------------------------
500 
501 void LArMCParticleHelper::GetMCToHitsMap(const CaloHitList *const pCaloHitList2D, const MCParticleList *const pMCParticleList,
503 {
504  PrimaryParameters parameters;
505  parameters.m_maxPhotonPropagation = std::numeric_limits<float>::max();
507  pMCParticleList, pCaloHitList2D, parameters, LArMCParticleHelper::IsBeamNeutrinoFinalState, mcToHitsMap);
508 }
509 
510 //-----------------------------------------------------------------------------------------------------------------------------------------
511 
512 void LArMCParticleHelper::CompleteMCHierarchy(const LArMCParticleHelper::MCContributionMap &mcToHitsMap, MCParticleList &mcHierarchy)
513 {
514  try
515  {
516  for (const auto &[mc, hits] : mcToHitsMap)
517  {
518  mcHierarchy.emplace_back(mc);
520  }
521  }
522  catch (const StatusCodeException &e)
523  {
524  throw;
525  }
526 
527  // Move the neutrino to the front of the list
528  auto pivot{
529  std::find_if(mcHierarchy.begin(), mcHierarchy.end(), [](const MCParticle *mc) -> bool { return LArMCParticleHelper::IsNeutrino(mc); })};
530  if (pivot != mcHierarchy.end())
531  std::rotate(mcHierarchy.begin(), pivot, std::next(pivot));
532  else
533  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
534 }
535 
536 //------------------------------------------------------------------------------------------------------------------------------------------
537 
538 const MCParticle *LArMCParticleHelper::GetMainMCParticle(const ParticleFlowObject *const pPfo)
539 {
540  ClusterList clusterList;
541  LArPfoHelper::GetTwoDClusterList(pPfo, clusterList);
542  return MCParticleHelper::GetMainMCParticle(&clusterList);
543 }
544 
545 //------------------------------------------------------------------------------------------------------------------------------------------
546 
547 bool LArMCParticleHelper::SortByMomentum(const MCParticle *const pLhs, const MCParticle *const pRhs)
548 {
549  // Sort by momentum (prefer higher momentum)
550  const float momentumLhs(pLhs->GetMomentum().GetMagnitudeSquared());
551  const float momentumRhs(pRhs->GetMomentum().GetMagnitudeSquared());
552 
553  if (std::fabs(momentumLhs - momentumRhs) > std::numeric_limits<float>::epsilon())
554  return (momentumLhs > momentumRhs);
555 
556  // Sort by energy (prefer lighter particles)
557  if (std::fabs(pLhs->GetEnergy() - pRhs->GetEnergy()) > std::numeric_limits<float>::epsilon())
558  return (pLhs->GetEnergy() < pRhs->GetEnergy());
559 
560  // Sort by PDG code (prefer smaller numbers)
561  if (pLhs->GetParticleId() != pRhs->GetParticleId())
562  return (pLhs->GetParticleId() < pRhs->GetParticleId());
563 
564  // Sort by vertex position (tie-breaker)
565  const float positionLhs(pLhs->GetVertex().GetMagnitudeSquared());
566  const float positionRhs(pRhs->GetVertex().GetMagnitudeSquared());
567 
568  return (positionLhs < positionRhs);
569 }
570 
571 //------------------------------------------------------------------------------------------------------------------------------------------
572 
573 void LArMCParticleHelper::GetMCParticleToCaloHitMatches(const CaloHitList *const pCaloHitList, const MCRelationMap &mcToTargetMCMap,
574  CaloHitToMCMap &hitToMCMap, MCContributionMap &mcToTrueHitListMap)
575 {
576  for (const CaloHit *const pCaloHit : *pCaloHitList)
577  {
578  try
579  {
580  const MCParticle *const pHitParticle(MCParticleHelper::GetMainMCParticle(pCaloHit));
581  const MCParticle *pTargetParticle(pHitParticle);
582 
583  // ATTN Do not map back to target if mc to primary mc map or mc to self map not provided
584  if (!mcToTargetMCMap.empty())
585  {
586  MCRelationMap::const_iterator mcIter = mcToTargetMCMap.find(pHitParticle);
587 
588  if (mcToTargetMCMap.end() == mcIter)
589  continue;
590 
591  pTargetParticle = mcIter->second;
592  }
593 
594  mcToTrueHitListMap[pTargetParticle].push_back(pCaloHit);
595  hitToMCMap[pCaloHit] = pTargetParticle;
596  }
597  catch (StatusCodeException &statusCodeException)
598  {
599  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
600  throw statusCodeException;
601  }
602  }
603 }
604 
605 //------------------------------------------------------------------------------------------------------------------------------------------
606 
607 void LArMCParticleHelper::SelectReconstructableMCParticles(const MCParticleList *pMCParticleList, const CaloHitList *pCaloHitList,
608  const PrimaryParameters &parameters, std::function<bool(const MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
609 {
610  // Obtain map: [mc particle -> target mc particle]
611  LArMCParticleHelper::MCRelationMap mcToTargetMCMap;
612  parameters.m_foldBackHierarchy ? LArMCParticleHelper::GetMCPrimaryMap(pMCParticleList, mcToTargetMCMap)
613  : LArMCParticleHelper::GetMCToSelfMap(pMCParticleList, mcToTargetMCMap);
614 
615  // Remove non-reconstructable hits, e.g. those downstream of a neutron
616  // Unless selectInputHits == false
617  CaloHitList selectedCaloHitList;
618  LArMCParticleHelper::SelectCaloHits(pCaloHitList, mcToTargetMCMap, selectedCaloHitList, parameters.m_selectInputHits, parameters.m_maxPhotonPropagation);
619 
620  // Obtain maps: [hit -> target mc particle], [target mc particle -> list of hits]
621  CaloHitToMCMap trueHitToTargetMCMap;
622  MCContributionMap targetMCToTrueHitListMap;
623  LArMCParticleHelper::GetMCParticleToCaloHitMatches(&selectedCaloHitList, mcToTargetMCMap, trueHitToTargetMCMap, targetMCToTrueHitListMap);
624 
625  // Obtain vector: target mc particles
626  MCParticleVector targetMCVector;
627  if (parameters.m_foldBackHierarchy)
628  {
629  LArMCParticleHelper::GetPrimaryMCParticleList(pMCParticleList, targetMCVector);
630  }
631  else
632  {
633  std::copy(pMCParticleList->begin(), pMCParticleList->end(), std::back_inserter(targetMCVector));
634  }
635 
636  // Select MCParticles matching criteria
637  MCParticleVector candidateTargets;
638  LArMCParticleHelper::SelectParticlesMatchingCriteria(targetMCVector, fCriteria, candidateTargets, parameters, false);
639 
640  // Ensure the MCParticles have enough "good" hits to be reconstructed
641  LArMCParticleHelper::SelectParticlesByHitCount(candidateTargets, targetMCToTrueHitListMap, mcToTargetMCMap, parameters, selectedMCParticlesToHitsMap);
642 }
643 
644 //------------------------------------------------------------------------------------------------------------------------------------------
645 
646 void LArMCParticleHelper::SelectReconstructableTestBeamHierarchyMCParticles(const MCParticleList *pMCParticleList, const CaloHitList *pCaloHitList,
647  const PrimaryParameters &parameters, std::function<bool(const MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
648 {
649  // Obtain map: [mc particle -> target mc particle]
650  LArMCParticleHelper::MCRelationMap mcToTargetMCMap;
651  parameters.m_foldBackHierarchy ? LArMCParticleHelper::GetMCLeadingMap(pMCParticleList, mcToTargetMCMap)
652  : LArMCParticleHelper::GetMCToSelfMap(pMCParticleList, mcToTargetMCMap);
653 
654  // Remove non-reconstructable hits, e.g. those downstream of a neutron
655  // Unless selectInputHits == false
656  CaloHitList selectedCaloHitList;
657  LArMCParticleHelper::SelectCaloHits(pCaloHitList, mcToTargetMCMap, selectedCaloHitList, parameters.m_selectInputHits, parameters.m_maxPhotonPropagation);
658 
659  // Obtain maps: [hit -> target mc particle], [target mc particle -> list of hits]
660  CaloHitToMCMap trueHitToTargetMCMap;
661  MCContributionMap targetMCToTrueHitListMap;
662  LArMCParticleHelper::GetMCParticleToCaloHitMatches(&selectedCaloHitList, mcToTargetMCMap, trueHitToTargetMCMap, targetMCToTrueHitListMap);
663 
664  // Obtain vector: target mc particles
665  MCParticleVector targetMCVector;
666  if (parameters.m_foldBackHierarchy)
667  {
668  LArMCParticleHelper::GetLeadingMCParticleList(pMCParticleList, targetMCVector);
669  }
670  else
671  {
672  std::copy(pMCParticleList->begin(), pMCParticleList->end(), std::back_inserter(targetMCVector));
673  }
674 
675  // Select MCParticles matching criteria
676  MCParticleVector candidateTargets;
677  LArMCParticleHelper::SelectParticlesMatchingCriteria(targetMCVector, fCriteria, candidateTargets, parameters, true);
678 
679  // Ensure the MCParticles have enough "good" hits to be reconstructed
680  LArMCParticleHelper::SelectParticlesByHitCount(candidateTargets, targetMCToTrueHitListMap, mcToTargetMCMap, parameters, selectedMCParticlesToHitsMap);
681 
682  // ATTN: The parent particle must be in the hierarchy map, event if not reconstructable
683  for (const MCParticle *const pMCParticle : candidateTargets)
684  {
685  if (!LArMCParticleHelper::IsBeamParticle(pMCParticle))
686  continue;
687 
688  const MCParticle *const pParentMCParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle));
689  if (selectedMCParticlesToHitsMap.find(pParentMCParticle) == selectedMCParticlesToHitsMap.end())
690  {
691  CaloHitList caloHitList;
692  selectedMCParticlesToHitsMap.insert(MCContributionMap::value_type(pParentMCParticle, caloHitList));
693  }
694  }
695 }
696 
697 //------------------------------------------------------------------------------------------------------------------------------------------
698 
699 void LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(const PfoList &pfoList, const MCContributionMap &selectedMCParticleToHitsMap,
700  PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
701 {
703  pfoList, MCContributionMapVector({selectedMCParticleToHitsMap}), pfoToReconstructable2DHitsMap, foldBackHierarchy);
704 }
705 
706 //------------------------------------------------------------------------------------------------------------------------------------------
707 
709  const MCContributionMap &selectedMCParticleToHitsMap, PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
710 {
712  pfoList, MCContributionMapVector({selectedMCParticleToHitsMap}), pfoToReconstructable2DHitsMap, foldBackHierarchy);
713 }
714 
715 //------------------------------------------------------------------------------------------------------------------------------------------
716 
717 void LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(const PfoList &pfoList, const MCContributionMapVector &selectedMCParticleToHitsMaps,
718  PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
719 {
720  for (const ParticleFlowObject *const pPfo : pfoList)
721  {
722  CaloHitList pfoHitList;
723  LArMCParticleHelper::CollectReconstructable2DHits(pPfo, selectedMCParticleToHitsMaps, pfoHitList, foldBackHierarchy);
724 
725  if (!pfoToReconstructable2DHitsMap.insert(PfoContributionMap::value_type(pPfo, pfoHitList)).second)
726  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
727  }
728 }
729 
730 //------------------------------------------------------------------------------------------------------------------------------------------
731 
733  const MCContributionMapVector &selectedMCParticleToHitsMaps, PfoContributionMap &pfoToReconstructable2DHitsMap, const bool foldBackHierarchy)
734 {
735  for (const ParticleFlowObject *const pPfo : pfoList)
736  {
737  CaloHitList pfoHitList;
738  LArMCParticleHelper::CollectReconstructableTestBeamHierarchy2DHits(pPfo, selectedMCParticleToHitsMaps, pfoHitList, foldBackHierarchy);
739 
740  if (!pfoToReconstructable2DHitsMap.insert(PfoContributionMap::value_type(pPfo, pfoHitList)).second)
741  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
742  }
743 }
744 
745 //------------------------------------------------------------------------------------------------------------------------------------------
746 
748  const MCContributionMapVector &selectedMCParticleToHitsMaps, PfoToMCParticleHitSharingMap &pfoToMCParticleHitSharingMap,
749  MCParticleToPfoHitSharingMap &mcParticleToPfoHitSharingMap)
750 {
751  PfoVector sortedPfos;
752  for (const auto &mapEntry : pfoToReconstructable2DHitsMap)
753  sortedPfos.push_back(mapEntry.first);
754  std::sort(sortedPfos.begin(), sortedPfos.end(), LArPfoHelper::SortByNHits);
755 
756  for (const ParticleFlowObject *const pPfo : sortedPfos)
757  {
758  for (const MCContributionMap &mcParticleToHitsMap : selectedMCParticleToHitsMaps)
759  {
760  MCParticleVector sortedMCParticles;
761  for (const auto &mapEntry : mcParticleToHitsMap)
762  sortedMCParticles.push_back(mapEntry.first);
763  std::sort(sortedMCParticles.begin(), sortedMCParticles.end(), PointerLessThan<MCParticle>());
764 
765  for (const MCParticle *const pMCParticle : sortedMCParticles)
766  {
767  // Add map entries for this Pfo & MCParticle if required
768  if (pfoToMCParticleHitSharingMap.find(pPfo) == pfoToMCParticleHitSharingMap.end())
769  if (!pfoToMCParticleHitSharingMap.insert(PfoToMCParticleHitSharingMap::value_type(pPfo, MCParticleToSharedHitsVector())).second)
770  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT); // ATTN maybe overkill
771 
772  if (mcParticleToPfoHitSharingMap.find(pMCParticle) == mcParticleToPfoHitSharingMap.end())
773  if (!mcParticleToPfoHitSharingMap.insert(MCParticleToPfoHitSharingMap::value_type(pMCParticle, PfoToSharedHitsVector())).second)
774  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
775 
776  // Check this Pfo & MCParticle pairing hasn't already been checked
777  MCParticleToSharedHitsVector &mcHitPairs(pfoToMCParticleHitSharingMap.at(pPfo));
778  PfoToSharedHitsVector &pfoHitPairs(mcParticleToPfoHitSharingMap.at(pMCParticle));
779 
780  if (std::any_of(mcHitPairs.begin(), mcHitPairs.end(),
781  [&](const MCParticleCaloHitListPair &pair) { return (pair.first == pMCParticle); }))
782  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
783 
784  if (std::any_of(pfoHitPairs.begin(), pfoHitPairs.end(), [&](const PfoCaloHitListPair &pair) { return (pair.first == pPfo); }))
785  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
786 
787  // Add records to maps if there are any shared hits
788  const CaloHitList sharedHits(
789  LArMCParticleHelper::GetSharedHits(pfoToReconstructable2DHitsMap.at(pPfo), mcParticleToHitsMap.at(pMCParticle)));
790 
791  if (!sharedHits.empty())
792  {
793  mcHitPairs.push_back(MCParticleCaloHitListPair(pMCParticle, sharedHits));
794  pfoHitPairs.push_back(PfoCaloHitListPair(pPfo, sharedHits));
795 
796  std::sort(mcHitPairs.begin(), mcHitPairs.end(),
797  [](const MCParticleCaloHitListPair &a, const MCParticleCaloHitListPair &b) -> bool
798  {
799  return ((a.second.size() != b.second.size()) ? a.second.size() > b.second.size()
800  : LArMCParticleHelper::SortByMomentum(a.first, b.first));
801  });
802 
803  std::sort(pfoHitPairs.begin(), pfoHitPairs.end(),
804  [](const PfoCaloHitListPair &a, const PfoCaloHitListPair &b) -> bool {
805  return ((a.second.size() != b.second.size()) ? a.second.size() > b.second.size()
806  : LArPfoHelper::SortByNHits(a.first, b.first));
807  });
808  }
809  }
810  }
811  }
812 }
813 
814 //------------------------------------------------------------------------------------------------------------------------------------------
815 
816 void LArMCParticleHelper::GetClusterToReconstructable2DHitsMap(const pandora::ClusterList &clusterList,
817  const MCContributionMap &selectedMCToHitsMap, ClusterContributionMap &clusterToReconstructable2DHitsMap)
818 {
819  LArMCParticleHelper::GetClusterToReconstructable2DHitsMap(clusterList, MCContributionMapVector({selectedMCToHitsMap}), clusterToReconstructable2DHitsMap);
820 }
821 
822 //------------------------------------------------------------------------------------------------------------------------------------------
823 
824 void LArMCParticleHelper::GetClusterToReconstructable2DHitsMap(const pandora::ClusterList &clusterList,
825  const MCContributionMapVector &selectedMCToHitsMaps, ClusterContributionMap &clusterToReconstructable2DHitsMap)
826 {
827  for (const Cluster *const pCluster : clusterList)
828  {
829  CaloHitList caloHitList;
830  LArMCParticleHelper::CollectReconstructable2DHits(pCluster, selectedMCToHitsMaps, caloHitList);
831 
832  if (!clusterToReconstructable2DHitsMap.insert(ClusterContributionMap::value_type(pCluster, caloHitList)).second)
833  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
834  }
835 }
836 
837 //------------------------------------------------------------------------------------------------------------------------------------------
838 
839 bool LArMCParticleHelper::IsBremsstrahlung(const MCParticle *const pMCParticle)
840 {
841  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
842  if (!pLArMCParticle)
843  return false;
844 
845  switch (pLArMCParticle->GetProcess())
846  {
847  case MC_PROC_E_BREM:
848  case MC_PROC_MU_BREM:
849  case MC_PROC_HAD_BREM:
850  return true;
851  default:
852  return false;
853  }
854 
855  return false;
856 }
857 
858 //------------------------------------------------------------------------------------------------------------------------------------------
859 
860 bool LArMCParticleHelper::IsCapture(const MCParticle *const pMCParticle)
861 {
862  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
863  if (!pLArMCParticle)
864  return false;
865 
866  switch (pLArMCParticle->GetProcess())
867  {
869  case MC_PROC_N_CAPTURE:
873  return true;
874  default:
875  return false;
876  }
877 
878  return false;
879 }
880 
881 //------------------------------------------------------------------------------------------------------------------------------------------
882 
883 bool LArMCParticleHelper::IsDecay(const MCParticle *const pMCParticle)
884 {
885  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
886  if (!pLArMCParticle)
887  return false;
888 
889  switch (pLArMCParticle->GetProcess())
890  {
891  case MC_PROC_DECAY:
892  return true;
893  default:
894  return false;
895  }
896 
897  return false;
898 }
899 
900 //------------------------------------------------------------------------------------------------------------------------------------------
901 
902 bool LArMCParticleHelper::IsElasticScatter(const MCParticle *const pMCParticle)
903 {
904  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
905  if (!pLArMCParticle)
906  return false;
907 
908  switch (pLArMCParticle->GetProcess())
909  {
912  case MC_PROC_HAD_ELASTIC:
913  case MC_PROC_RAYLEIGH:
914  return true;
915  default:
916  return false;
917  }
918 
919  return false;
920 }
921 
922 //------------------------------------------------------------------------------------------------------------------------------------------
923 
924 bool LArMCParticleHelper::IsInelasticScatter(const MCParticle *const pMCParticle)
925 {
926  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
927  if (!pLArMCParticle)
928  return false;
929 
930  switch (pLArMCParticle->GetProcess())
931  {
932  case MC_PROC_COMPT:
951  return true;
952  default:
953  return false;
954  }
955 
956  return false;
957 }
958 
959 //------------------------------------------------------------------------------------------------------------------------------------------
960 
961 bool LArMCParticleHelper::IsIonisation(const MCParticle *const pMCParticle)
962 {
963  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
964  if (!pLArMCParticle)
965  return false;
966 
967  switch (pLArMCParticle->GetProcess())
968  {
969  case MC_PROC_E_IONI:
970  case MC_PROC_MU_IONI:
971  case MC_PROC_HAD_IONI:
972  case MC_PROC_ION_IONI:
973  return true;
974  default:
975  return false;
976  }
977 
978  return false;
979 }
980 
981 //------------------------------------------------------------------------------------------------------------------------------------------
982 
983 bool LArMCParticleHelper::IsNuclear(const MCParticle *const pMCParticle)
984 {
985  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
986  if (!pLArMCParticle)
987  return false;
988 
989  switch (pLArMCParticle->GetProcess())
990  {
993  case MC_PROC_MU_NUCLEAR:
994  return true;
995  default:
996  return false;
997  }
998 
999  return false;
1000 }
1001 
1002 //------------------------------------------------------------------------------------------------------------------------------------------
1003 
1004 bool LArMCParticleHelper::IsPairProduction(const MCParticle *const pMCParticle)
1005 {
1006  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
1007  if (!pLArMCParticle)
1008  return false;
1009 
1010  switch (pLArMCParticle->GetProcess())
1011  {
1012  case MC_PROC_MU_PAIR_PROD:
1013  case MC_PROC_HAD_PAIR_PROD:
1014  return true;
1015  default:
1016  return false;
1017  }
1018 
1019  return false;
1020 }
1021 
1022 //------------------------------------------------------------------------------------------------------------------------------------------
1023 
1024 CaloHitList LArMCParticleHelper::GetSharedHits(const CaloHitList &hitListA, const CaloHitList &hitListB)
1025 {
1026  CaloHitList sharedHits;
1027 
1028  for (const CaloHit *const pCaloHit : hitListA)
1029  {
1030  if (std::find(hitListB.begin(), hitListB.end(), pCaloHit) != hitListB.end())
1031  sharedHits.push_back(pCaloHit);
1032  }
1033 
1034  return sharedHits;
1035 }
1036 
1037 //------------------------------------------------------------------------------------------------------------------------------------------
1038 
1039 bool LArMCParticleHelper::AreTopologicallyContinuous(const MCParticle *const pMCParent, const MCParticle *const pMCChild, const float cosAngleTolerance)
1040 {
1041  CartesianVector childDirection{pMCChild->GetEndpoint() - pMCChild->GetVertex()};
1042  if (childDirection.GetMagnitude() < std::numeric_limits<float>::epsilon())
1043  return true;
1044  childDirection = childDirection.GetUnitVector();
1045 
1046  const MCParticle *pMCUpstream{pMCParent};
1047  while (true)
1048  {
1049  CartesianVector parentDirection{pMCUpstream->GetEndpoint() - pMCUpstream->GetVertex()};
1050  if (parentDirection.GetMagnitude() > std::numeric_limits<float>::epsilon())
1051  {
1052  parentDirection = parentDirection.GetUnitVector();
1053  return parentDirection.GetDotProduct(childDirection) >= cosAngleTolerance;
1054  }
1055  else
1056  {
1057  const MCParticleList &parentList{pMCUpstream->GetParentList()};
1058  const size_t size{parentList.size()};
1059  if (size == 1)
1060  pMCUpstream = parentList.front();
1061  else if (size == 0)
1062  return true;
1063  else
1064  return false;
1065  }
1066  }
1067 
1068  return false;
1069 }
1070 
1071 // private
1072 //------------------------------------------------------------------------------------------------------------------------------------------
1073 
1074 void LArMCParticleHelper::CollectReconstructable2DHits(const ParticleFlowObject *const pPfo,
1075  const MCContributionMapVector &selectedMCParticleToHitsMaps, CaloHitList &reconstructableCaloHitList2D, const bool foldBackHierarchy)
1076 {
1077 
1078  PfoList pfoList;
1079 
1080  // If foldBackHierarchy collect all 2D calo hits in pfo hierarchy
1081  // else collect hits directly belonging to pfo
1082  if (foldBackHierarchy)
1083  {
1084  LArPfoHelper::GetAllDownstreamPfos(pPfo, pfoList);
1085  }
1086  else
1087  {
1088  pfoList.push_back(pPfo);
1089  }
1090 
1091  LArMCParticleHelper::CollectReconstructable2DHits(pfoList, selectedMCParticleToHitsMaps, reconstructableCaloHitList2D);
1092 }
1093 
1094 //------------------------------------------------------------------------------------------------------------------------------------------
1095 
1097  const MCContributionMapVector &selectedMCParticleToHitsMaps, CaloHitList &reconstructableCaloHitList2D, const bool foldBackHierarchy)
1098 {
1099 
1100  PfoList pfoList;
1101  // If foldBackHierarchy collect all 2D calo hits in pfo hierarchy
1102  // else collect hits directly belonging to pfo
1103  if (foldBackHierarchy)
1104  {
1105  // ATTN: Only collect downstream pfos for daughter test beam particles & cosmics
1106  if (pPfo->GetParentPfoList().empty() && LArPfoHelper::IsTestBeam(pPfo))
1107  {
1108  pfoList.push_back(pPfo);
1109  }
1110  else
1111  {
1112  LArPfoHelper::GetAllDownstreamPfos(pPfo, pfoList);
1113  }
1114  }
1115  else
1116  {
1117  pfoList.push_back(pPfo);
1118  }
1119 
1120  LArMCParticleHelper::CollectReconstructable2DHits(pfoList, selectedMCParticleToHitsMaps, reconstructableCaloHitList2D);
1121 }
1122 
1123 //------------------------------------------------------------------------------------------------------------------------------------------
1124 
1126  const PfoList &pfoList, const MCContributionMapVector &selectedMCParticleToHitsMaps, CaloHitList &reconstructableCaloHitList2D)
1127 {
1128  CaloHitList caloHitList2D;
1129  LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_U, caloHitList2D);
1130  LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_V, caloHitList2D);
1131  LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_W, caloHitList2D);
1132  LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_U, caloHitList2D); // TODO check isolated usage throughout
1133  LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_V, caloHitList2D);
1134  LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_W, caloHitList2D);
1135 
1136  // Filter for only reconstructable hits
1137  for (const CaloHit *const pCaloHit : caloHitList2D)
1138  {
1139  bool isTargetHit(false);
1140  for (const MCContributionMap &mcParticleToHitsMap : selectedMCParticleToHitsMaps)
1141  {
1142  // ATTN This map is unordered, but this does not impact search for specific target hit
1143  for (const MCContributionMap::value_type &mapEntry : mcParticleToHitsMap)
1144  {
1145  if (std::find(mapEntry.second.begin(), mapEntry.second.end(), pCaloHit) != mapEntry.second.end())
1146  {
1147  isTargetHit = true;
1148  break;
1149  }
1150  }
1151  if (isTargetHit)
1152  break;
1153  }
1154 
1155  if (isTargetHit)
1156  reconstructableCaloHitList2D.push_back(pCaloHit);
1157  }
1158 }
1159 
1160 //------------------------------------------------------------------------------------------------------------------------------------------
1161 
1162 void LArMCParticleHelper::CollectReconstructable2DHits(const pandora::Cluster *const pCluster,
1163  const MCContributionMapVector &selectedMCToHitsMaps, pandora::CaloHitList &reconstructableCaloHitList2D)
1164 {
1165  const CaloHitList &isolatedCaloHitList{pCluster->GetIsolatedCaloHitList()};
1166  CaloHitList caloHitList;
1167  pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
1168  for (const CaloHit *pCaloHit : isolatedCaloHitList)
1169  caloHitList.push_back(pCaloHit);
1170 
1171  // Filter for only reconstructable hits
1172  for (const CaloHit *const pCaloHit : caloHitList)
1173  {
1174  bool isTargetHit{false};
1175  for (const MCContributionMap &mcParticleToHitsMap : selectedMCToHitsMaps)
1176  { // ATTN This map is unordered, but this does not impact search for specific target hit
1177  for (const MCContributionMap::value_type &mapEntry : mcParticleToHitsMap)
1178  {
1179  if (std::find(mapEntry.second.begin(), mapEntry.second.end(), pCaloHit) != mapEntry.second.end())
1180  {
1181  isTargetHit = true;
1182  break;
1183  }
1184  }
1185  if (isTargetHit)
1186  break;
1187  }
1188 
1189  if (isTargetHit)
1190  reconstructableCaloHitList2D.push_back(pCaloHit);
1191  }
1192 }
1193 
1194 //------------------------------------------------------------------------------------------------------------------------------------------
1195 
1196 void LArMCParticleHelper::SelectCaloHits(const CaloHitList *const pCaloHitList, const LArMCParticleHelper::MCRelationMap &mcToTargetMCMap,
1197  CaloHitList &selectedCaloHitList, const bool selectInputHits, const float maxPhotonPropagation)
1198 {
1199  if (!selectInputHits)
1200  {
1201  selectedCaloHitList.insert(selectedCaloHitList.end(), pCaloHitList->begin(), pCaloHitList->end());
1202  return;
1203  }
1204 
1205  for (const CaloHit *const pCaloHit : *pCaloHitList)
1206  {
1207  try
1208  {
1209  const MCParticle *const pHitParticle(MCParticleHelper::GetMainMCParticle(pCaloHit));
1210 
1211  LArMCParticleHelper::MCRelationMap::const_iterator mcIter = mcToTargetMCMap.find(pHitParticle);
1212 
1213  if (mcToTargetMCMap.end() == mcIter)
1214  continue;
1215 
1216  // ATTN With folding on or off, still require primary particle to review hierarchy details
1217  const MCParticle *const pPrimaryParticle = LArMCParticleHelper::GetPrimaryMCParticle(pHitParticle);
1218 
1219  if (PassMCParticleChecks(pPrimaryParticle, pPrimaryParticle, pHitParticle, maxPhotonPropagation))
1220  selectedCaloHitList.push_back(pCaloHit);
1221  }
1222  catch (const StatusCodeException &)
1223  {
1224  }
1225  }
1226 }
1227 
1228 //------------------------------------------------------------------------------------------------------------------------------------------
1229 
1230 bool LArMCParticleHelper::IsDescendentOf(const MCParticle *const pMCParticle, const int pdg, const bool isChargeSensitive)
1231 {
1232  const MCParticle *pCurrentParticle = pMCParticle;
1233  while (!pCurrentParticle->GetParentList().empty())
1234  {
1235  if (pCurrentParticle->GetParentList().size() > 1)
1236  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
1237 
1238  const MCParticle *pParent = *(pCurrentParticle->GetParentList().begin());
1239  const bool found{isChargeSensitive ? pParent->GetParticleId() == pdg : std::abs(pParent->GetParticleId()) == std::abs(pdg)};
1240  if (found)
1241  return true;
1242  pCurrentParticle = pParent;
1243  }
1244 
1245  return false;
1246 }
1247 
1248 //------------------------------------------------------------------------------------------------------------------------------------------
1249 
1250 void LArMCParticleHelper::GetBreadthFirstHierarchyRepresentation(const MCParticle *const pMCParticle, MCParticleList &mcParticleList)
1251 {
1252  const MCParticle *const pRoot{LArMCParticleHelper::GetParentMCParticle(pMCParticle)};
1253  MCParticleList queue;
1254  mcParticleList.emplace_back(pRoot);
1255  queue.emplace_back(pRoot);
1256 
1257  while (!queue.empty())
1258  {
1259  const MCParticleList &daughters{queue.front()->GetDaughterList()};
1260  queue.pop_front();
1261  for (const MCParticle *pDaughter : daughters)
1262  {
1263  mcParticleList.emplace_back(pDaughter);
1264  queue.emplace_back(pDaughter);
1265  }
1266  }
1267 }
1268 
1269 //------------------------------------------------------------------------------------------------------------------------------------------
1270 
1271 void LArMCParticleHelper::SelectParticlesByHitCount(const MCParticleVector &candidateTargets, const MCContributionMap &mcToTrueHitListMap,
1272  const MCRelationMap &mcToTargetMCMap, const PrimaryParameters &parameters, MCContributionMap &selectedMCParticlesToHitsMap)
1273 {
1274  // Apply restrictions on the number of good hits associated with the MCParticles
1275  for (const MCParticle *const pMCTarget : candidateTargets)
1276  {
1277  MCContributionMap::const_iterator trueHitsIter = mcToTrueHitListMap.find(pMCTarget);
1278  if (mcToTrueHitListMap.end() == trueHitsIter)
1279  continue;
1280 
1281  const CaloHitList &caloHitList(trueHitsIter->second);
1282 
1283  // Remove shared hits where target particle deposits below threshold energy fraction
1284  CaloHitList goodCaloHitList;
1286  &caloHitList, mcToTargetMCMap, goodCaloHitList, parameters.m_selectInputHits, parameters.m_minHitSharingFraction);
1287 
1288  if (goodCaloHitList.size() < parameters.m_minPrimaryGoodHits)
1289  continue;
1290 
1291  unsigned int nGoodViews(0);
1292  if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_U, goodCaloHitList) >= parameters.m_minHitsForGoodView)
1293  ++nGoodViews;
1294 
1295  if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_V, goodCaloHitList) >= parameters.m_minHitsForGoodView)
1296  ++nGoodViews;
1297 
1298  if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_W, goodCaloHitList) >= parameters.m_minHitsForGoodView)
1299  ++nGoodViews;
1300 
1301  if (nGoodViews < parameters.m_minPrimaryGoodViews)
1302  continue;
1303 
1304  if (!selectedMCParticlesToHitsMap.insert(MCContributionMap::value_type(pMCTarget, caloHitList)).second)
1305  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
1306  }
1307 }
1308 
1309 //------------------------------------------------------------------------------------------------------------------------------------------
1310 
1311 void LArMCParticleHelper::SelectGoodCaloHits(const CaloHitList *const pSelectedCaloHitList, const LArMCParticleHelper::MCRelationMap &mcToTargetMCMap,
1312  CaloHitList &selectedGoodCaloHitList, const bool selectInputHits, const float minHitSharingFraction)
1313 {
1314  if (!selectInputHits)
1315  {
1316  selectedGoodCaloHitList.insert(selectedGoodCaloHitList.end(), pSelectedCaloHitList->begin(), pSelectedCaloHitList->end());
1317  return;
1318  }
1319 
1320  for (const CaloHit *const pCaloHit : *pSelectedCaloHitList)
1321  {
1322  MCParticleVector mcParticleVector;
1323  for (const auto &mapEntry : pCaloHit->GetMCParticleWeightMap())
1324  mcParticleVector.push_back(mapEntry.first);
1325  std::sort(mcParticleVector.begin(), mcParticleVector.end(), PointerLessThan<MCParticle>());
1326 
1327  MCParticleWeightMap targetWeightMap;
1328 
1329  for (const MCParticle *const pMCParticle : mcParticleVector)
1330  {
1331  const float weight(pCaloHit->GetMCParticleWeightMap().at(pMCParticle));
1332  LArMCParticleHelper::MCRelationMap::const_iterator mcIter = mcToTargetMCMap.find(pMCParticle);
1333 
1334  if (mcToTargetMCMap.end() != mcIter)
1335  targetWeightMap[mcIter->second] += weight;
1336  }
1337 
1338  MCParticleVector mcTargetVector;
1339  for (const auto &mapEntry : targetWeightMap)
1340  mcTargetVector.push_back(mapEntry.first);
1341  std::sort(mcTargetVector.begin(), mcTargetVector.end(), PointerLessThan<MCParticle>());
1342 
1343  const MCParticle *pBestTargetParticle(nullptr);
1344  float bestTargetWeight(0.f), targetWeightSum(0.f);
1345 
1346  for (const MCParticle *const pTargetMCParticle : mcTargetVector)
1347  {
1348  const float targetWeight(targetWeightMap.at(pTargetMCParticle));
1349  targetWeightSum += targetWeight;
1350 
1351  if (targetWeight > bestTargetWeight)
1352  {
1353  bestTargetWeight = targetWeight;
1354  pBestTargetParticle = pTargetMCParticle;
1355  }
1356  }
1357 
1358  if (!pBestTargetParticle || (targetWeightSum < std::numeric_limits<float>::epsilon()) || ((bestTargetWeight / targetWeightSum) < minHitSharingFraction))
1359  continue;
1360 
1361  selectedGoodCaloHitList.push_back(pCaloHit);
1362  }
1363 }
1364 
1365 //------------------------------------------------------------------------------------------------------------------------------------------
1366 
1368  std::function<bool(const MCParticle *const)> fCriteria, MCParticleVector &selectedParticles, const PrimaryParameters &parameters, const bool isTestBeam)
1369 {
1370  for (const MCParticle *const pMCParticle : inputMCParticles)
1371  {
1372  if (parameters.m_foldBackHierarchy)
1373  {
1374  if (!fCriteria(pMCParticle))
1375  continue;
1376  }
1377  else
1378  {
1379  if (isTestBeam)
1380  {
1381  if (!LArMCParticleHelper::DoesLeadingMeetCriteria(pMCParticle, fCriteria))
1382  continue;
1383  }
1384  else
1385  {
1386  if (!LArMCParticleHelper::DoesPrimaryMeetCriteria(pMCParticle, fCriteria))
1387  continue;
1388  }
1389  }
1390  selectedParticles.push_back(pMCParticle);
1391  }
1392 }
1393 
1394 //------------------------------------------------------------------------------------------------------------------------------------------
1395 
1396 bool LArMCParticleHelper::PassMCParticleChecks(const MCParticle *const pOriginalPrimary, const MCParticle *const pThisMCParticle,
1397  const MCParticle *const pHitMCParticle, const float maxPhotonPropagation)
1398 {
1399  if (NEUTRON == std::abs(pThisMCParticle->GetParticleId()))
1400  return false;
1401 
1402  if ((PHOTON == pThisMCParticle->GetParticleId()) && (PHOTON != pOriginalPrimary->GetParticleId()) &&
1403  (E_MINUS != std::abs(pOriginalPrimary->GetParticleId())))
1404  {
1405  if ((pThisMCParticle->GetEndpoint() - pThisMCParticle->GetVertex()).GetMagnitude() > maxPhotonPropagation)
1406  return false;
1407  }
1408 
1409  if (pThisMCParticle == pHitMCParticle)
1410  return true;
1411 
1412  for (const MCParticle *const pDaughterMCParticle : pThisMCParticle->GetDaughterList())
1413  {
1414  if (PassMCParticleChecks(pOriginalPrimary, pDaughterMCParticle, pHitMCParticle, maxPhotonPropagation))
1415  return true;
1416  }
1417 
1418  return false;
1419 }
1420 
1421 } // namespace lar_content
static bool IsVisible(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is visible (i.e. long-lived charged particle)
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 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...
unsigned int m_minPrimaryGoodViews
the minimum number of primary good views
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
static bool IsNuclear(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a nuclear interaction process.
Header file for the pfo helper class.
std::unordered_map< const pandora::MCParticle *, pandora::CaloHitList > MCContributionMap
bool m_selectInputHits
whether to select input hits
std::pair< const pandora::MCParticle *, pandora::CaloHitList > MCParticleCaloHitListPair
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...
static bool IsPrimary(const pandora::MCParticle *const pMCParticle)
Whether a provided mc particle matches the implemented definition of being primary.
static void GetTwoDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 2D clusters from an input pfo.
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 bool IsLeadingBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a leading beam MCParticle.
unsigned int m_minPrimaryGoodHits
the minimum number of primary good Hits
int GetNuanceCode() const
Get the nuance code.
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...
std::unordered_map< const pandora::CaloHit *, const pandora::MCParticle * > CaloHitToMCMap
constexpr auto abs(T v)
Returns the absolute value of the argument.
static int GetHierarchyTier(const pandora::MCParticle *const pMCParticle)
Determine the position in the hierarchy for the MCParticle.
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 const pandora::MCParticle * GetPrimaryMCParticle(const pandora::MCParticle *const pMCParticle)
Get the primary parent mc particle.
std::map< const pandora::MCParticle *, PfoToSharedHitsVector > MCParticleToPfoHitSharingMap
std::vector< PfoCaloHitListPair > PfoToSharedHitsVector
intermediate_table::const_iterator const_iterator
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...
bool m_foldBackHierarchy
whether to fold the hierarchy back to the primary (neutrino) or leading particles (test beam) ...
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 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 bool IsPairProduction(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a pair production process.
Header file for the lar monitoring helper helper class.
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 unsigned int GetNuanceCode(const pandora::MCParticle *const pMCParticle)
Get the nuance code of an MCParticle.
unsigned int m_minHitsForGoodView
the minimum number of Hits for a good view
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.
float m_maxPhotonPropagation
the maximum photon propagation length
TFile f
Definition: plotHisto.C:6
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 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...
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
LAr mc particle class.
Definition: LArMCParticle.h:94
static bool IsCosmicRay(const pandora::MCParticle *const pMCParticle)
Return true if passed a primary cosmic ray MCParticle.
static bool IsInelasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an inelastic scattering process.
static bool IsLeading(const pandora::MCParticle *const pMCParticle)
Whether a provided mc particle matches the implemented definition of being leading.
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.
void hits()
Definition: readHits.C:15
static bool IsTestBeam(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a test beam particle.
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...
Header file for the lar monte carlo particle helper helper class.
Header file for the cluster helper class.
static void GetMCParticleToCaloHitMatches(const pandora::CaloHitList *const pCaloHitList, const MCRelationMap &mcToTargetMCMap, CaloHitToMCMap &hitToMCMap, MCContributionMap &mcToTrueHitListMap)
Match calo hits to their parent particles.
static bool IsBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary beam MCParticle.
std::unordered_map< const pandora::Cluster *, pandora::CaloHitList > ClusterContributionMap
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
static const pandora::MCParticle * GetParentMCParticle(const pandora::MCParticle *const pMCParticle)
Get the parent mc particle.
static bool IsTriggeredBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary triggered beam MCParticle.
static void GetMCToHitsMap(const pandora::CaloHitList *const pCaloHitList2S, const pandora::MCParticleList *const pMCParticleList, LArMCParticleHelper::MCContributionMap &mcToHitsMap)
float m_minHitSharingFraction
the minimum Hit sharing fraction
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 bool IsDecay(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a decay process.
static void CompleteMCHierarchy(const LArMCParticleHelper::MCContributionMap &mcToHitsMap, pandora::MCParticleList &mcHierarchy)
std::vector< MCContributionMap > MCContributionMapVector
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. If the parent does not travel any distance, a travelling parent is sought and the comparison made between this and the child. If no travelling parent can be found, the particles are treated as continuous.
static bool IsBremsstrahlung(const pandora::MCParticle *const pMCParticle)
static void GetPrimaryMCParticleList(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &mcPrimaryVector)
Get vector of primary MC particles from an input list of MC particles.
double weight
Definition: plottest35.C:25
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.
static void GetAllAncestorMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &ancestorMCParticleList)
Get all ancestor mc particles.
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 void GetTrueNeutrinos(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &trueNeutrinos)
Get neutrino MC particles from an input MC particle list.
std::pair< const pandora::ParticleFlowObject *, pandora::CaloHitList > PfoCaloHitListPair
static bool IsCapture(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a capture process.
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 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 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 bool IsIonisation(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from an ionisation process.
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.
static bool GetTrueVertex(const pandora::MCParticleList *const pMCParticleList, pandora::CartesianVector &trueVertex)
Retrieve the true neutrino vertex.
std::vector< MCParticleCaloHitListPair > MCParticleToSharedHitsVector
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 void GetTrueTestBeamParticles(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &trueTestBeamParticles)
Get triggered test beam MC particles from an input MC particle list.
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.
std::unordered_map< const pandora::ParticleFlowObject *, pandora::CaloHitList > PfoContributionMap
static void GetAllDescendentMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &descendentMCParticleList)
Get all descendent mc particles.
Float_t e
Definition: plot.C:35
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.
static pandora::CaloHitList GetSharedHits(const pandora::CaloHitList &hitListA, const pandora::CaloHitList &hitListB)
Get the hits in the intersection of two hit lists.
static bool IsBeamNeutrinoFinalState(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary neutrino final state MCParticle.
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.
std::unordered_map< const pandora::MCParticle *, const pandora::MCParticle * > MCRelationMap
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 IsElasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an elastic scattering process.
std::map< const pandora::ParticleFlowObject *, MCParticleToSharedHitsVector > PfoToMCParticleHitSharingMap
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
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...