LArSoft  v06_85_00
Liquid Argon Software toolkit - http://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 {
39 }
40 
41 //------------------------------------------------------------------------------------------------------------------------------------------
42 //------------------------------------------------------------------------------------------------------------------------------------------
43 
44 bool LArMCParticleHelper::IsBeamNeutrinoFinalState(const MCParticle *const pMCParticle)
45 {
46  const MCParticle *const pParentMCParticle(LArMCParticleHelper::GetParentMCParticle(pMCParticle));
47  return (LArMCParticleHelper::IsPrimary(pMCParticle) && LArMCParticleHelper::IsNeutrino(pParentMCParticle));
48 }
49 
50 //------------------------------------------------------------------------------------------------------------------------------------------
51 
52 bool LArMCParticleHelper::IsBeamParticle(const MCParticle *const pMCParticle)
53 {
54  const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
55  return (LArMCParticleHelper::IsPrimary(pMCParticle) && ((nuance == 2000) || (nuance == 2001)));
56 }
57 
58 //------------------------------------------------------------------------------------------------------------------------------------------
59 
60 bool LArMCParticleHelper::IsCosmicRay(const MCParticle *const pMCParticle)
61 {
62  const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
63  return (LArMCParticleHelper::IsPrimary(pMCParticle) && ((nuance == 3000) || ((nuance == 0) && !LArMCParticleHelper::IsBeamNeutrinoFinalState(pMCParticle))));
64 }
65 
66 //------------------------------------------------------------------------------------------------------------------------------------------
67 
68 unsigned int LArMCParticleHelper::GetNuanceCode(const MCParticle *const pMCParticle)
69 {
70  const LArMCParticle *const pLArMCParticle(dynamic_cast<const LArMCParticle*>(pMCParticle));
71  if (pLArMCParticle)
72  return pLArMCParticle->GetNuanceCode();
73 
74  std::cout << "LArMCParticleHelper::GetNuanceCode - Error: Can't cast to LArMCParticle" << std::endl;
75  throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
76 }
77 
78 //------------------------------------------------------------------------------------------------------------------------------------------
79 
80 bool LArMCParticleHelper::IsNeutrino(const MCParticle *const pMCParticle)
81 {
82  const int nuance(LArMCParticleHelper::GetNuanceCode(pMCParticle));
83  if ((nuance == 0) || (nuance == 2000) || (nuance == 2001) || (nuance == 3000))
84  return false;
85 
86  const int absoluteParticleId(std::abs(pMCParticle->GetParticleId()));
87  return ((NU_E == absoluteParticleId) || (NU_MU == absoluteParticleId) || (NU_TAU == absoluteParticleId));
88 }
89 
90 //------------------------------------------------------------------------------------------------------------------------------------------
91 
92 bool LArMCParticleHelper::IsPrimary(const pandora::MCParticle *const pMCParticle)
93 {
94  try
95  {
96  return (LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle) == pMCParticle);
97  }
98  catch (const StatusCodeException &) {}
99 
100  return false;
101 }
102 
103 //------------------------------------------------------------------------------------------------------------------------------------------
104 
105 bool LArMCParticleHelper::IsVisible(const MCParticle *const pMCParticle)
106 {
107  const int absoluteParticleId(std::abs(pMCParticle->GetParticleId()));
108 
109  if ((E_MINUS == absoluteParticleId) || (MU_MINUS == absoluteParticleId) ||
110  (PI_PLUS == absoluteParticleId) || (K_PLUS == absoluteParticleId) ||
111  (SIGMA_MINUS == absoluteParticleId) || (SIGMA_PLUS == absoluteParticleId) || (HYPERON_MINUS == absoluteParticleId) ||
112  (PROTON == absoluteParticleId) || (PHOTON == absoluteParticleId) ||
113  (NEUTRON == absoluteParticleId))
114  return true;
115 
116  return false;
117 }
118 
119 //------------------------------------------------------------------------------------------------------------------------------------------
120 
121 void LArMCParticleHelper::GetTrueNeutrinos(const MCParticleList *const pMCParticleList, MCParticleVector &trueNeutrinos)
122 {
123  for (const MCParticle *const pMCParticle : *pMCParticleList)
124  {
125  if (LArMCParticleHelper::IsNeutrino(pMCParticle))
126  trueNeutrinos.push_back(pMCParticle);
127  }
128 
129  std::sort(trueNeutrinos.begin(), trueNeutrinos.end(), LArMCParticleHelper::SortByMomentum);
130 }
131 
132 //------------------------------------------------------------------------------------------------------------------------------------------
133 
134 const MCParticle *LArMCParticleHelper::GetParentMCParticle(const MCParticle *const pMCParticle)
135 {
136  const MCParticle *pParentMCParticle = pMCParticle;
137 
138  while (pParentMCParticle->GetParentList().empty() == false)
139  {
140  if (1 != pParentMCParticle->GetParentList().size())
141  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
142 
143  pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
144  }
145 
146  return pParentMCParticle;
147 }
148 
149 //------------------------------------------------------------------------------------------------------------------------------------------
150 
151 void LArMCParticleHelper::GetPrimaryMCParticleList(const MCParticleList *const pMCParticleList, MCParticleVector &mcPrimaryVector)
152 {
153  for (const MCParticle *const pMCParticle : *pMCParticleList)
154  {
155  if (LArMCParticleHelper::IsPrimary(pMCParticle))
156  mcPrimaryVector.push_back(pMCParticle);
157  }
158 
159  std::sort(mcPrimaryVector.begin(), mcPrimaryVector.end(), LArMCParticleHelper::SortByMomentum);
160 }
161 
162 //------------------------------------------------------------------------------------------------------------------------------------------
163 
164 const MCParticle *LArMCParticleHelper::GetPrimaryMCParticle(const MCParticle *const pMCParticle)
165 {
166  // Navigate upward through MC daughter/parent links - collect this particle and all its parents
167  MCParticleVector mcVector;
168 
169  const MCParticle *pParentMCParticle = pMCParticle;
170  mcVector.push_back(pParentMCParticle);
171 
172  while (!pParentMCParticle->GetParentList().empty())
173  {
174  if (1 != pParentMCParticle->GetParentList().size())
175  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
176 
177  pParentMCParticle = *(pParentMCParticle->GetParentList().begin());
178  mcVector.push_back(pParentMCParticle);
179  }
180 
181  // Navigate downward through MC parent/daughter links - return the first long-lived charged particle
182  for (MCParticleVector::const_reverse_iterator iter = mcVector.rbegin(), iterEnd = mcVector.rend(); iter != iterEnd; ++iter)
183  {
184  const MCParticle *const pNextParticle = *iter;
185 
186  if (LArMCParticleHelper::IsVisible(pNextParticle))
187  return pNextParticle;
188  }
189 
190  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
191 }
192 
193 //------------------------------------------------------------------------------------------------------------------------------------------
194 
195 void LArMCParticleHelper::GetMCPrimaryMap(const MCParticleList *const pMCParticleList, MCRelationMap &mcPrimaryMap)
196 {
197  for (const MCParticle *const pMCParticle : *pMCParticleList)
198  {
199  try
200  {
201  const MCParticle *const pPrimaryMCParticle = LArMCParticleHelper::GetPrimaryMCParticle(pMCParticle);
202  mcPrimaryMap[pMCParticle] = pPrimaryMCParticle;
203  }
204  catch (const StatusCodeException &) {}
205  }
206 }
207 
208 //------------------------------------------------------------------------------------------------------------------------------------------
209 
210 const MCParticle *LArMCParticleHelper::GetMainMCParticle(const ParticleFlowObject *const pPfo)
211 {
212  ClusterList clusterList;
213  LArPfoHelper::GetTwoDClusterList(pPfo, clusterList);
214  return MCParticleHelper::GetMainMCParticle(&clusterList);
215 }
216 
217 //------------------------------------------------------------------------------------------------------------------------------------------
218 
219 bool LArMCParticleHelper::SortByMomentum(const MCParticle *const pLhs, const MCParticle *const pRhs)
220 {
221  // Sort by momentum (prefer higher momentum)
222  const float momentumLhs(pLhs->GetMomentum().GetMagnitudeSquared());
223  const float momentumRhs(pRhs->GetMomentum().GetMagnitudeSquared());
224 
225  if (std::fabs(momentumLhs - momentumRhs) > std::numeric_limits<float>::epsilon())
226  return (momentumLhs > momentumRhs);
227 
228  // Sort by energy (prefer lighter particles)
229  if (std::fabs(pLhs->GetEnergy() - pRhs->GetEnergy()) > std::numeric_limits<float>::epsilon())
230  return (pLhs->GetEnergy() < pRhs->GetEnergy());
231 
232  // Sort by PDG code (prefer smaller numbers)
233  if (pLhs->GetParticleId() != pRhs->GetParticleId())
234  return (pLhs->GetParticleId() < pRhs->GetParticleId());
235 
236  // Sort by vertex position (tie-breaker)
237  const float positionLhs(pLhs->GetVertex().GetMagnitudeSquared());
238  const float positionRhs(pRhs->GetVertex().GetMagnitudeSquared());
239 
240  return (positionLhs < positionRhs);
241 }
242 
243 //------------------------------------------------------------------------------------------------------------------------------------------
244 
245 void LArMCParticleHelper::GetMCParticleToCaloHitMatches(const CaloHitList *const pCaloHitList, const MCRelationMap &mcToPrimaryMCMap,
246  CaloHitToMCMap &hitToMCMap, MCContributionMap &mcToTrueHitListMap)
247 {
248  for (const CaloHit *const pCaloHit : *pCaloHitList)
249  {
250  try
251  {
252  const MCParticle *const pHitParticle(MCParticleHelper::GetMainMCParticle(pCaloHit));
253  const MCParticle *pPrimaryParticle(pHitParticle);
254 
255  // ATTN Do not map back to mc primaries if mc to primary mc map not provided
256  if (!mcToPrimaryMCMap.empty())
257  {
258  MCRelationMap::const_iterator mcIter = mcToPrimaryMCMap.find(pHitParticle);
259 
260  if (mcToPrimaryMCMap.end() == mcIter)
261  continue;
262 
263  pPrimaryParticle = mcIter->second;
264  }
265 
266  mcToTrueHitListMap[pPrimaryParticle].push_back(pCaloHit);
267  hitToMCMap[pCaloHit] = pPrimaryParticle;
268  }
269  catch (StatusCodeException &statusCodeException)
270  {
271  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
272  throw statusCodeException;
273  }
274  }
275 }
276 
277 //------------------------------------------------------------------------------------------------------------------------------------------
278 
279 void LArMCParticleHelper::SelectReconstructableMCParticles(const MCParticleList *pMCParticleList, const CaloHitList *pCaloHitList, const PrimaryParameters &parameters,
280  std::function<bool(const MCParticle *const)> fCriteria, MCContributionMap &selectedMCParticlesToHitsMap)
281 {
282  // Obtain map: [mc particle -> primary mc particle]
283  LArMCParticleHelper::MCRelationMap mcToPrimaryMCMap;
284  LArMCParticleHelper::GetMCPrimaryMap(pMCParticleList, mcToPrimaryMCMap);
285 
286  // Remove non-reconstructable hits, e.g. those downstream of a neutron
287  CaloHitList selectedCaloHitList;
288  LArMCParticleHelper::SelectCaloHits(pCaloHitList, mcToPrimaryMCMap, selectedCaloHitList, parameters.m_selectInputHits, parameters.m_maxPhotonPropagation);
289 
290  // Obtain maps: [hit -> primary mc particle], [primary mc particle -> list of hits]
291  CaloHitToMCMap hitToPrimaryMCMap;
292  MCContributionMap mcToTrueHitListMap;
293  LArMCParticleHelper::GetMCParticleToCaloHitMatches(&selectedCaloHitList, mcToPrimaryMCMap, hitToPrimaryMCMap, mcToTrueHitListMap);
294 
295  // Obtain vector: primary mc particles
296  MCParticleVector mcPrimaryVector;
297  LArMCParticleHelper::GetPrimaryMCParticleList(pMCParticleList, mcPrimaryVector);
298 
299  // Select MCParticles matching criteria
300  MCParticleVector candidateTargets;
301  LArMCParticleHelper::SelectParticlesMatchingCriteria(mcPrimaryVector, fCriteria, candidateTargets);
302 
303  // Ensure the MCParticles have enough "good" hits to be reconstructed
304  LArMCParticleHelper::SelectParticlesByHitCount(candidateTargets, mcToTrueHitListMap, mcToPrimaryMCMap, parameters, selectedMCParticlesToHitsMap);
305 }
306 
307 //------------------------------------------------------------------------------------------------------------------------------------------
308 
309 void LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(const PfoList &pfoList, const MCContributionMap &selectedMCParticleToHitsMap,
310  PfoContributionMap &pfoToReconstructable2DHitsMap)
311 {
312  LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(pfoList, MCContributionMapVector({selectedMCParticleToHitsMap}), pfoToReconstructable2DHitsMap);
313 }
314 
315 //------------------------------------------------------------------------------------------------------------------------------------------
316 
317 void LArMCParticleHelper::GetPfoToReconstructable2DHitsMap(const PfoList &pfoList, const MCContributionMapVector &selectedMCParticleToHitsMaps,
318  PfoContributionMap &pfoToReconstructable2DHitsMap)
319 {
320  for (const ParticleFlowObject *const pPfo : pfoList)
321  {
322  CaloHitList pfoHitList;
323  LArMCParticleHelper::CollectReconstructable2DHits(pPfo, selectedMCParticleToHitsMaps, pfoHitList);
324 
325  if (!pfoToReconstructable2DHitsMap.insert(PfoContributionMap::value_type(pPfo, pfoHitList)).second)
326  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
327  }
328 }
329 
330 //------------------------------------------------------------------------------------------------------------------------------------------
331 
332 void LArMCParticleHelper::GetPfoMCParticleHitSharingMaps(const PfoContributionMap &pfoToReconstructable2DHitsMap, const MCContributionMapVector &selectedMCParticleToHitsMaps,
333  PfoToMCParticleHitSharingMap &pfoToMCParticleHitSharingMap, MCParticleToPfoHitSharingMap &mcParticleToPfoHitSharingMap)
334 {
335  PfoVector sortedPfos;
336  for (const auto &mapEntry : pfoToReconstructable2DHitsMap) sortedPfos.push_back(mapEntry.first);
337  std::sort(sortedPfos.begin(), sortedPfos.end(), LArPfoHelper::SortByNHits);
338 
339  for (const ParticleFlowObject *const pPfo : sortedPfos)
340  {
341  for (const MCContributionMap &mcParticleToHitsMap : selectedMCParticleToHitsMaps)
342  {
343  MCParticleVector sortedMCParticles;
344  for (const auto &mapEntry : mcParticleToHitsMap) sortedMCParticles.push_back(mapEntry.first);
345  std::sort(sortedMCParticles.begin(), sortedMCParticles.end(), PointerLessThan<MCParticle>());
346 
347  for (const MCParticle *const pMCParticle : sortedMCParticles)
348  {
349  // Add map entries for this Pfo & MCParticle if required
350  if (pfoToMCParticleHitSharingMap.find(pPfo) == pfoToMCParticleHitSharingMap.end())
351  if (!pfoToMCParticleHitSharingMap.insert(PfoToMCParticleHitSharingMap::value_type(pPfo, MCParticleToSharedHitsVector())).second)
352  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT); // ATTN maybe overkill
353 
354  if (mcParticleToPfoHitSharingMap.find(pMCParticle) == mcParticleToPfoHitSharingMap.end())
355  if (!mcParticleToPfoHitSharingMap.insert(MCParticleToPfoHitSharingMap::value_type(pMCParticle, PfoToSharedHitsVector())).second)
356  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
357 
358  // Check this Pfo & MCParticle pairing hasn't already been checked
359  MCParticleToSharedHitsVector &mcHitPairs(pfoToMCParticleHitSharingMap.at(pPfo));
360  PfoToSharedHitsVector &pfoHitPairs(mcParticleToPfoHitSharingMap.at(pMCParticle));
361 
362  if (std::any_of(mcHitPairs.begin(), mcHitPairs.end(), [&] (const MCParticleCaloHitListPair &pair) { return (pair.first == pMCParticle); }))
363  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
364 
365  if (std::any_of(pfoHitPairs.begin(), pfoHitPairs.end(), [&] (const PfoCaloHitListPair &pair) { return (pair.first == pPfo); }))
366  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
367 
368  // Add records to maps if there are any shared hits
369  const CaloHitList sharedHits(LArMCParticleHelper::GetSharedHits(pfoToReconstructable2DHitsMap.at(pPfo), mcParticleToHitsMap.at(pMCParticle)));
370 
371  if (!sharedHits.empty())
372  {
373  mcHitPairs.push_back(MCParticleCaloHitListPair(pMCParticle, sharedHits));
374  pfoHitPairs.push_back(PfoCaloHitListPair(pPfo, sharedHits));
375 
376  std::sort(mcHitPairs.begin(), mcHitPairs.end(), [] (const MCParticleCaloHitListPair &a, const MCParticleCaloHitListPair &b) -> bool {
377  return ((a.second.size() != b.second.size()) ? a.second.size() > b.second.size() : LArMCParticleHelper::SortByMomentum(a.first, b.first)); });
378 
379  std::sort(pfoHitPairs.begin(), pfoHitPairs.end(), [] (const PfoCaloHitListPair &a, const PfoCaloHitListPair &b) -> bool {
380  return ((a.second.size() != b.second.size()) ? a.second.size() > b.second.size() : LArPfoHelper::SortByNHits(a.first, b.first)); });
381  }
382  }
383  }
384  }
385 }
386 
387 // private
388 //------------------------------------------------------------------------------------------------------------------------------------------
389 
390 void LArMCParticleHelper::CollectReconstructable2DHits(const ParticleFlowObject *const pPfo, const MCContributionMapVector &selectedMCParticleToHitsMaps,
391  pandora::CaloHitList &reconstructableCaloHitList2D)
392 {
393  // Collect all 2D calo hits in pfo hierarchy
394  PfoList pfoList;
395  LArPfoHelper::GetAllDownstreamPfos(pPfo, pfoList);
396 
397  CaloHitList caloHitList2D;
398  LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_U, caloHitList2D);
399  LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_V, caloHitList2D);
400  LArPfoHelper::GetCaloHits(pfoList, TPC_VIEW_W, caloHitList2D);
401  LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_U, caloHitList2D); // TODO check isolated usage throughout
402  LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_V, caloHitList2D);
403  LArPfoHelper::GetIsolatedCaloHits(pfoList, TPC_VIEW_W, caloHitList2D);
404 
405  // Filter for only reconstructable hits
406  for (const CaloHit *const pCaloHit : caloHitList2D)
407  {
408  bool isTargetHit(false);
409  for (const MCContributionMap &mcParticleToHitsMap : selectedMCParticleToHitsMaps)
410  {
411  // ATTN This map is unordered, but this does not impact search for specific target hit
412  for (const MCContributionMap::value_type &mapEntry : mcParticleToHitsMap)
413  {
414  if (std::find(mapEntry.second.begin(), mapEntry.second.end(), pCaloHit) != mapEntry.second.end())
415  {
416  isTargetHit = true;
417  break;
418  }
419  }
420  if (isTargetHit) break;
421  }
422 
423  if (isTargetHit)
424  reconstructableCaloHitList2D.push_back(pCaloHit);
425  }
426 }
427 
428 //------------------------------------------------------------------------------------------------------------------------------------------
429 
430 void LArMCParticleHelper::SelectCaloHits(const CaloHitList *const pCaloHitList, const LArMCParticleHelper::MCRelationMap &mcToPrimaryMCMap,
431  CaloHitList &selectedCaloHitList, const bool selectInputHits, const float maxPhotonPropagation)
432 {
433  if (!selectInputHits)
434  {
435  selectedCaloHitList.insert(selectedCaloHitList.end(), pCaloHitList->begin(), pCaloHitList->end());
436  return;
437  }
438 
439  for (const CaloHit *const pCaloHit : *pCaloHitList)
440  {
441  try
442  {
443  const MCParticle *const pHitParticle(MCParticleHelper::GetMainMCParticle(pCaloHit));
444 
445  LArMCParticleHelper::MCRelationMap::const_iterator mcIter = mcToPrimaryMCMap.find(pHitParticle);
446 
447  if (mcToPrimaryMCMap.end() == mcIter)
448  continue;
449 
450  const MCParticle *const pPrimaryParticle = mcIter->second;
451 
452  if (PassMCParticleChecks(pPrimaryParticle, pPrimaryParticle, pHitParticle, maxPhotonPropagation))
453  selectedCaloHitList.push_back(pCaloHit);
454  }
455  catch (const StatusCodeException &)
456  {
457  }
458  }
459 }
460 
461 //------------------------------------------------------------------------------------------------------------------------------------------
462 
463 void LArMCParticleHelper::SelectGoodCaloHits(const CaloHitList *const pSelectedCaloHitList, const LArMCParticleHelper::MCRelationMap &mcToPrimaryMCMap,
464  CaloHitList &selectedGoodCaloHitList, const bool selectInputHits, const float minHitSharingFraction)
465 {
466  if (!selectInputHits)
467  {
468  selectedGoodCaloHitList.insert(selectedGoodCaloHitList.end(), pSelectedCaloHitList->begin(), pSelectedCaloHitList->end());
469  return;
470  }
471 
472  for (const CaloHit *const pCaloHit : *pSelectedCaloHitList)
473  {
474  MCParticleVector mcParticleVector;
475  for (const auto &mapEntry : pCaloHit->GetMCParticleWeightMap()) mcParticleVector.push_back(mapEntry.first);
476  std::sort(mcParticleVector.begin(), mcParticleVector.end(), PointerLessThan<MCParticle>());
477 
478  MCParticleWeightMap primaryWeightMap;
479 
480  for (const MCParticle *const pMCParticle : mcParticleVector)
481  {
482  const float weight(pCaloHit->GetMCParticleWeightMap().at(pMCParticle));
483  LArMCParticleHelper::MCRelationMap::const_iterator mcIter = mcToPrimaryMCMap.find(pMCParticle);
484 
485  if (mcToPrimaryMCMap.end() != mcIter)
486  primaryWeightMap[mcIter->second] += weight;
487  }
488 
489  MCParticleVector mcPrimaryVector;
490  for (const auto &mapEntry : primaryWeightMap) mcPrimaryVector.push_back(mapEntry.first);
491  std::sort(mcPrimaryVector.begin(), mcPrimaryVector.end(), PointerLessThan<MCParticle>());
492 
493  const MCParticle *pBestPrimaryParticle(nullptr);
494  float bestPrimaryWeight(0.f), primaryWeightSum(0.f);
495 
496  for (const MCParticle *const pPrimaryMCParticle : mcPrimaryVector)
497  {
498  const float primaryWeight(primaryWeightMap.at(pPrimaryMCParticle));
499  primaryWeightSum += primaryWeight;
500 
501  if (primaryWeight > bestPrimaryWeight)
502  {
503  bestPrimaryWeight = primaryWeight;
504  pBestPrimaryParticle = pPrimaryMCParticle;
505  }
506  }
507 
508  if (!pBestPrimaryParticle || (primaryWeightSum < std::numeric_limits<float>::epsilon()) || ((bestPrimaryWeight / primaryWeightSum) < minHitSharingFraction))
509  continue;
510 
511  selectedGoodCaloHitList.push_back(pCaloHit);
512  }
513 }
514 
515 //------------------------------------------------------------------------------------------------------------------------------------------
516 
517 void LArMCParticleHelper::SelectParticlesMatchingCriteria(const MCParticleVector &inputMCParticles, std::function<bool(const MCParticle *const)> fCriteria,
518  MCParticleVector &selectedParticles)
519 {
520  for (const MCParticle *const pMCParticle : inputMCParticles)
521  {
522  if (fCriteria(pMCParticle))
523  selectedParticles.push_back(pMCParticle);
524  }
525 }
526 
527 //------------------------------------------------------------------------------------------------------------------------------------------
528 
529 void LArMCParticleHelper::SelectParticlesByHitCount(const MCParticleVector &candidateTargets, const MCContributionMap &mcToTrueHitListMap,
530  const MCRelationMap &mcToPrimaryMCMap, const PrimaryParameters &parameters, MCContributionMap &selectedMCParticlesToHitsMap)
531 {
532  // Apply restrictions on the number of good hits associated with the MCParticles
533  for (const MCParticle * const pMCTarget : candidateTargets)
534  {
535  MCContributionMap::const_iterator trueHitsIter = mcToTrueHitListMap.find(pMCTarget);
536  if (mcToTrueHitListMap.end() == trueHitsIter)
537  continue;
538 
539  const CaloHitList &caloHitList(trueHitsIter->second);
540 
541  // Remove shared hits where target particle deposits below threshold energy fraction
542  CaloHitList goodCaloHitList;
543  LArMCParticleHelper::SelectGoodCaloHits(&caloHitList, mcToPrimaryMCMap, goodCaloHitList, parameters.m_selectInputHits, parameters.m_minHitSharingFraction);
544 
545  if (goodCaloHitList.size() < parameters.m_minPrimaryGoodHits)
546  continue;
547 
548  unsigned int nGoodViews(0);
549  if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_U, goodCaloHitList) >= parameters.m_minHitsForGoodView)
550  ++nGoodViews;
551 
552  if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_V, goodCaloHitList) >= parameters.m_minHitsForGoodView)
553  ++nGoodViews;
554 
555  if (LArMonitoringHelper::CountHitsByType(TPC_VIEW_W, goodCaloHitList) >= parameters.m_minHitsForGoodView)
556  ++nGoodViews;
557 
558  if (nGoodViews < parameters.m_minPrimaryGoodViews)
559  continue;
560 
561  if (!selectedMCParticlesToHitsMap.insert(MCContributionMap::value_type(pMCTarget, caloHitList)).second)
562  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
563  }
564 }
565 
566 //------------------------------------------------------------------------------------------------------------------------------------------
567 
568 bool LArMCParticleHelper::PassMCParticleChecks(const MCParticle *const pOriginalPrimary, const MCParticle *const pThisMCParticle,
569  const MCParticle *const pHitMCParticle, const float maxPhotonPropagation)
570 {
571  if (NEUTRON == std::abs(pThisMCParticle->GetParticleId()))
572  return false;
573 
574  if ((PHOTON == pThisMCParticle->GetParticleId()) && (PHOTON != pOriginalPrimary->GetParticleId()) && (E_MINUS != std::abs(pOriginalPrimary->GetParticleId())))
575  {
576  if ((pThisMCParticle->GetEndpoint() - pThisMCParticle->GetVertex()).GetMagnitude() > maxPhotonPropagation)
577  return false;
578  }
579 
580  if (pThisMCParticle == pHitMCParticle)
581  return true;
582 
583  for (const MCParticle *const pDaughterMCParticle : pThisMCParticle->GetDaughterList())
584  {
585  if (PassMCParticleChecks(pOriginalPrimary, pDaughterMCParticle, pHitMCParticle, maxPhotonPropagation))
586  return true;
587  }
588 
589  return false;
590 }
591 
592 //------------------------------------------------------------------------------------------------------------------------------------------
593 
594 CaloHitList LArMCParticleHelper::GetSharedHits(const CaloHitList &hitListA, const CaloHitList &hitListB)
595 {
596  CaloHitList sharedHits;
597 
598  for (const CaloHit *const pCaloHit : hitListA)
599  {
600  if (std::find(hitListB.begin(), hitListB.end(), pCaloHit) != hitListB.end())
601  sharedHits.push_back(pCaloHit);
602  }
603 
604  return sharedHits;
605 }
606 
607 } // namespace lar_content
static bool IsVisible(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is visible (i.e. long-lived charged particle)
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.
Header file for the pfo helper class.
bool m_selectInputHits
whether to select input hits
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.
Definition: LArPfoHelper.cc:97
unsigned int m_minPrimaryGoodHits
the minimum number of primary good Hits
int GetNuanceCode() const
Get the nuance code.
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::vector< PfoCaloHitListPair > PfoToSharedHitsVector
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...
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...
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
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
float m_maxPhotonPropagation
the maximum photon propagation length
static void SelectCaloHits(const pandora::CaloHitList *const pCaloHitList, const MCRelationMap &mcToPrimaryMCMap, pandora::CaloHitList &selectedCaloHitList, const bool selectInputHits, const float maxPhotonPropagation)
Select a subset of calo hits representing those that represent "reconstructable" regions of the event...
TFile f
Definition: plotHisto.C:6
static void SelectParticlesByHitCount(const pandora::MCParticleVector &candidateTargets, const MCContributionMap &mcToTrueHitListMap, const MCRelationMap &mcToPrimaryMCMap, const PrimaryParameters &parameters, MCContributionMap &selectedMCParticlesToHitsMap)
Filter an input vector of MCParticles to ensure they have sufficient good hits to be reconstructable...
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:38
static bool IsCosmicRay(const pandora::MCParticle *const pMCParticle)
Return true if passed a primary cosmic ray MCParticle.
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 primary, reconstructable mc particles that match given criteria.
static void SelectParticlesMatchingCriteria(const pandora::MCParticleVector &inputMCParticles, std::function< bool(const pandora::MCParticle *const)> fCriteria, pandora::MCParticleVector &selectedParticles)
Select mc particles matching given criteria from an input list.
intermediate_table::const_iterator const_iterator
std::unordered_map< const pandora::MCParticle *, pandora::CaloHitList > MCContributionMap
static void GetPfoToReconstructable2DHitsMap(const pandora::PfoList &pfoList, const MCContributionMap &selectedMCParticleToHitsMap, PfoContributionMap &pfoToReconstructable2DHitsMap)
Get mapping from Pfo to reconstructable 2D hits (=good hits belonging to a selected reconstructable M...
Header file for the lar monte carlo particle helper helper class.
Header file for the cluster helper class.
static bool IsBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary beam MCParticle.
std::map< const pandora::MCParticle *, PfoToSharedHitsVector > MCParticleToPfoHitSharingMap
static const pandora::MCParticle * GetParentMCParticle(const pandora::MCParticle *const pMCParticle)
Get the parent mc particle.
static void CollectReconstructable2DHits(const pandora::ParticleFlowObject *const pPfo, const MCContributionMapVector &selectedMCParticleToHitsMaps, pandora::CaloHitList &reconstructableCaloHitList2D)
For a given Pfo, collect the hits which are reconstructable (=good hits belonging to a selected recon...
float m_minHitSharingFraction
the minimum Hit sharing fraction
static void SelectGoodCaloHits(const pandora::CaloHitList *const pSelectedCaloHitList, const MCRelationMap &mcToPrimaryMCMap, 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...
std::vector< MCContributionMap > MCContributionMapVector
std::map< const pandora::ParticleFlowObject *, MCParticleToSharedHitsVector > PfoToMCParticleHitSharingMap
static void GetPrimaryMCParticleList(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &mcPrimaryVector)
Get vector of primary MC particles from an input list of MC particles.
std::unordered_map< const pandora::CaloHit *, const pandora::MCParticle * > CaloHitToMCMap
double weight
Definition: plottest35.C:25
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::MCParticle *, pandora::CaloHitList > MCParticleCaloHitListPair
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 GetMCParticleToCaloHitMatches(const pandora::CaloHitList *const pCaloHitList, const MCRelationMap &mcToPrimaryMCMap, CaloHitToMCMap &hitToMCMap, MCContributionMap &mcToTrueHitListMap)
Match calo hits to their parent particles.
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...
std::vector< MCParticleCaloHitListPair > MCParticleToSharedHitsVector
std::unordered_map< const pandora::ParticleFlowObject *, pandora::CaloHitList > PfoContributionMap
std::unordered_map< const pandora::MCParticle *, const pandora::MCParticle * > MCRelationMap
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.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
std::pair< const pandora::ParticleFlowObject *, pandora::CaloHitList > PfoCaloHitListPair