LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
lar_content::LArHierarchyHelper::MCHierarchy Class Reference

MCHierarchy class. More...

#include "LArHierarchyHelper.h"

Classes

class  Node
 Node class. More...
 
class  ReconstructabilityCriteria
 ReconstructabilityCriteria class. More...
 

Public Types

typedef std::vector< const Node * > NodeVector
 
typedef std::list< const Node * > NodeList
 
typedef std::map< const pandora::MCParticle *, NodeVectorMCNodeVectorMap
 

Public Member Functions

 MCHierarchy ()
 Default constructor. More...
 
 MCHierarchy (const ReconstructabilityCriteria &recoCriteria)
 Construct a new MCHierarchy object using specified reconstructability criteria. More...
 
virtual ~MCHierarchy ()
 Destructor. More...
 
void FillHierarchy (const pandora::MCParticleList &mcParticleList, const pandora::CaloHitList &caloHitList, const FoldingParameters &foldParameters)
 Creates an MC hierarchy representation. Without folding this will be a mirror image of the standard MCParticle relationships. However, with folding options selected the hierarchy structure will group together MC particles into nodes based on the folding requirements. More...
 
void InterpretHierarchy (const pandora::MCParticle *const pRoot, pandora::MCParticleList &leadingParticles, pandora::MCParticleList &childParticles, const float cosAngleTolerance) const
 Interpret the hierarchy below a particular particle to determine if and how it should be folded. Folded particles are added to the leadingParticles list and child particles are added to the childParticles list. More...
 
const pandora::MCParticle * GetNeutrino () const
 Retrieve the neutrino at the root of the hierarchy if it exists. More...
 
const NodeVectorGetInteractions (const pandora::MCParticle *pRoot) const
 Retrieve the root nodes in this hierarchy. More...
 
void GetRootMCParticles (pandora::MCParticleList &rootMCParticles) const
 Retrieve the root MC particles of the interaction hierarchies. More...
 
void GetFlattenedNodes (const pandora::MCParticle *const pRoot, NodeVector &nodeVector) const
 Retrieve a flat vector of the ndoes in the hierarchy. More...
 
void RegisterNode (const Node *pNode)
 Register a node with the hierarchy. More...
 
const std::string ToString () const
 Produce a string representation of the hierarchy. More...
 

Private Member Functions

void CollectContinuations (const pandora::MCParticle *pRoot, pandora::MCParticleList &continuingParticles, pandora::MCParticleList &childParticles, const float cosAngleTolerance) const
 Identify downstream particles that represent continuations of the parent particle from a reconstruction perspective. More...
 
bool IsReconstructable (const pandora::MCParticle *pMCParticle) const
 Checks if an individual particle meets reconstructability criteria. More...
 
bool IsReconstructable (const pandora::CaloHitList &caloHits) const
 Checks if a set of hits meet reconstructability criteria. More...
 

Private Attributes

MCNodeVectorMap m_interactions
 Map from incident particles (e.g. neutrino) to primaries. More...
 
ReconstructabilityCriteria m_recoCriteria
 The criteria used to determine if the node is reconstructable. More...
 
std::map< const pandora::MCParticle *, pandora::CaloHitList > m_mcToHitsMap
 The map between MC particles and calo hits. More...
 
std::map< const Node *, int > m_nodeToIdMap
 A map from nodes to unique ids. More...
 
int m_nextNodeId
 The ID to use for the next node. More...
 

Detailed Description

MCHierarchy class.

Definition at line 88 of file LArHierarchyHelper.h.

Member Typedef Documentation

typedef std::map<const pandora::MCParticle *, NodeVector> lar_content::LArHierarchyHelper::MCHierarchy::MCNodeVectorMap

Definition at line 127 of file LArHierarchyHelper.h.

Definition at line 126 of file LArHierarchyHelper.h.

Definition at line 124 of file LArHierarchyHelper.h.

Constructor & Destructor Documentation

lar_content::LArHierarchyHelper::MCHierarchy::MCHierarchy ( )

Default constructor.

Definition at line 78 of file LArHierarchyHelper.cc.

78  :
79  m_nextNodeId{1}
80 {
81 }
int m_nextNodeId
The ID to use for the next node.
lar_content::LArHierarchyHelper::MCHierarchy::MCHierarchy ( const ReconstructabilityCriteria recoCriteria)

Construct a new MCHierarchy object using specified reconstructability criteria.

Parameters
recoCriteriaThe reconstructability criteria to be applied

Definition at line 85 of file LArHierarchyHelper.cc.

85  :
86  m_recoCriteria(recoCriteria),
87  m_nextNodeId{1}
88 {
89 }
ReconstructabilityCriteria m_recoCriteria
The criteria used to determine if the node is reconstructable.
int m_nextNodeId
The ID to use for the next node.
lar_content::LArHierarchyHelper::MCHierarchy::~MCHierarchy ( )
virtual

Destructor.

Definition at line 93 of file LArHierarchyHelper.cc.

References m_interactions.

94 {
95  for (const auto &[pRoot, nodeVector] : m_interactions)
96  {
97  (void)pRoot;
98  for (const Node *pNode : nodeVector)
99  delete pNode;
100  }
101  m_interactions.clear();
102 }
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.

Member Function Documentation

void lar_content::LArHierarchyHelper::MCHierarchy::CollectContinuations ( const pandora::MCParticle *  pRoot,
pandora::MCParticleList &  continuingParticles,
pandora::MCParticleList &  childParticles,
const float  cosAngleTolerance 
) const
private

Identify downstream particles that represent continuations of the parent particle from a reconstruction perspective.

Parameters
pRootThe root MC particle
continuingParticlesAn output list of the particles identified as continuations
childParticlesAn output list of the particles identified as child particles given any continuations
cosAngleToleranceThe cosine of the maximum angle for which trajectories are considered continuous

Definition at line 377 of file LArHierarchyHelper.cc.

References lar_content::LArMCParticleHelper::AreTopologicallyContinuous(), lar_content::LArMCParticleHelper::IsElasticScatter(), lar_content::LArMCParticleHelper::IsInelasticScatter(), m_recoCriteria, lar_content::LArHierarchyHelper::MCHierarchy::ReconstructabilityCriteria::m_removeNeutrons, and lar_content::MC_PROC_N_CAPTURE.

Referenced by InterpretHierarchy().

379 {
380  const MCParticleList &children{pRoot->GetDaughterList()};
381  MCParticleList foldCandidates;
382  for (const MCParticle *pMCParticle : children)
383  {
384  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
385  if (!pLArMCParticle)
386  continue;
387  // Only elastic and inelastic scattering can lead to folding
389  {
390  if (pMCParticle->GetParticleId() == pRoot->GetParticleId())
391  foldCandidates.emplace_back(pMCParticle);
392  }
393  else if (!m_recoCriteria.m_removeNeutrons || (m_recoCriteria.m_removeNeutrons && pLArMCParticle->GetProcess() != MC_PROC_N_CAPTURE))
394  {
395  // Non-scattering process particles become leading candidates unless it's neutron capture and we're removing neutrons
396  childParticles.emplace_back(pMCParticle);
397  }
398  }
399  const MCParticle *pBestFoldCandidate{nullptr};
400  float bestDp{std::numeric_limits<float>::max()};
401  for (const MCParticle *pMCParticle : foldCandidates)
402  {
403  if (foldCandidates.size() == 1)
404  {
405  // No alternative options, so this is either the best folding option by default, or a sufficiently large scatter to
406  // treat as a new particle for reconstruction purposes
407  if (LArMCParticleHelper::AreTopologicallyContinuous(pRoot, pMCParticle, cosAngleTolerance))
408  pBestFoldCandidate = pMCParticle;
409  }
410  else
411  {
412  // Assess which, if any, of the children might be a continuation of the trajectory, otherwise move to child candidates
413  if (LArMCParticleHelper::AreTopologicallyContinuous(pRoot, pMCParticle, cosAngleTolerance))
414  {
415  const float dp{pRoot->GetMomentum().GetMagnitude() - pMCParticle->GetMomentum().GetMagnitude()};
416  if (dp < bestDp)
417  {
418  pBestFoldCandidate = pMCParticle;
419  bestDp = dp;
420  }
421  }
422  }
423  }
424  if (pBestFoldCandidate)
425  {
426  continuingParticles.emplace_back(pBestFoldCandidate);
427  const MCParticleList &newLeadingParticles{pBestFoldCandidate->GetDaughterList()};
428  // We need to add the children as child particles to ensure these sub-hierarchies are explored...
429  childParticles.insert(childParticles.begin(), newLeadingParticles.begin(), newLeadingParticles.end());
430  // but this current best fold candidate may have been added to the child particles by previously, so remove it
431  const auto iter{std::find(childParticles.begin(), childParticles.end(), pBestFoldCandidate)};
432  if (iter != childParticles.end())
433  childParticles.erase(iter);
434  // Having found a particle to fold back at this level, continue to explore its downstream hierarchy for further folding
435  // opportunities and make their respective children child particles for the folded node we are creating
436  LArHierarchyHelper::MCHierarchy::CollectContinuations(pBestFoldCandidate, continuingParticles, childParticles, cosAngleTolerance);
437  }
438 }
void CollectContinuations(const pandora::MCParticle *pRoot, pandora::MCParticleList &continuingParticles, pandora::MCParticleList &childParticles, const float cosAngleTolerance) const
Identify downstream particles that represent continuations of the parent particle from a reconstructi...
static bool IsInelasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an inelastic scattering process.
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.
ReconstructabilityCriteria m_recoCriteria
The criteria used to determine if the node is reconstructable.
const bool m_removeNeutrons
whether to remove neutrons and their downstream particles
static bool IsElasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an elastic scattering process.
void lar_content::LArHierarchyHelper::MCHierarchy::FillHierarchy ( const pandora::MCParticleList &  mcParticleList,
const pandora::CaloHitList &  caloHitList,
const FoldingParameters foldParameters 
)

Creates an MC hierarchy representation. Without folding this will be a mirror image of the standard MCParticle relationships. However, with folding options selected the hierarchy structure will group together MC particles into nodes based on the folding requirements.

If only folding back to primaries, the hierarchy will be relatively flat, with a top-level neutrino or test beam particle, if appropriate, and then a set of leaf nodes, one for each primary particles also containing the MC particles (and corresponding hits) from daughter particles.

If only folding back to leading shower particles, the hierarchy will largely mirror the standard MCParticle hierarchy, but, when a shower particle is reached (for this purpose an electron or photon), this particle and all daughter particles will be represented by a single leaf node.

If folding back to both primary and leading shower particles the hierarchy will again be rather flat, but in this case, if a primary track-like particle (i.e. not an electron or photon) has a downstream shower particle then all downstream particles above the shower-like particle will be folded into the primary node, but a new, daughter leaf node will be created for the shower-like particle and all of its daughters, and a parent-child relationship will be formed between the primary node and shower node.

Parameters
mcParticleListThe list of MC particles with which to fill the hierarchy
caloHitListThe list of hits with which to fill the hierarchy
foldParametersThe folding parameters to use for the hierarchy

Definition at line 106 of file LArHierarchyHelper.cc.

References util::abs(), lar_content::LArMCParticleHelper::GetAllDescendentMCParticles(), lar_content::LArHierarchyHelper::MCHierarchy::Node::GetLeadingMCParticle(), lar_content::LArHierarchyHelper::GetMCPrimaries(), InterpretHierarchy(), lar_content::LArHierarchyHelper::FoldingParameters::m_cosAngleTolerance, lar_content::LArHierarchyHelper::FoldingParameters::m_foldDynamic, lar_content::LArHierarchyHelper::FoldingParameters::m_foldToLeadingShowers, lar_content::LArHierarchyHelper::FoldingParameters::m_foldToTier, m_interactions, m_mcToHitsMap, m_recoCriteria, lar_content::LArHierarchyHelper::MCHierarchy::ReconstructabilityCriteria::m_removeNeutrons, lar_content::LArHierarchyHelper::FoldingParameters::m_tier, lar_content::LArHierarchyHelper::MCHierarchy::Node::SetLeadingLepton(), and lar_content::LArMCParticleHelper::SortByMomentum().

Referenced by lar_content::LArHierarchyHelper::FillMCHierarchy().

107 {
108  const auto predicate = [](const MCParticle *pMCParticle) { return std::abs(pMCParticle->GetParticleId()) == NEUTRON; };
109  m_mcToHitsMap.clear();
110  for (const CaloHit *pCaloHit : caloHitList)
111  {
112  try
113  {
114  const MCParticle *pMCParticle{MCParticleHelper::GetMainMCParticle(pCaloHit)};
115  m_mcToHitsMap[pMCParticle].emplace_back(pCaloHit);
116  }
117  catch (const StatusCodeException &)
118  {
119  }
120  }
121 
122  MCParticleList rootNodes;
123  for (const MCParticle *pMCParticle : mcParticleList)
124  {
125  const MCParticleList &parentList{pMCParticle->GetParentList()};
126  if (parentList.empty())
127  {
128  rootNodes.emplace_back(pMCParticle);
129  }
130  }
131 
132  for (const MCParticle *pRoot : rootNodes)
133  {
134  MCParticleSet primarySet;
135  LArHierarchyHelper::GetMCPrimaries(pRoot, primarySet);
136  MCParticleList primaries(primarySet.begin(), primarySet.end());
137  primaries.sort(LArMCParticleHelper::SortByMomentum);
139  primaries.erase(std::remove_if(primaries.begin(), primaries.end(), predicate), primaries.end());
140  if (foldParameters.m_foldToTier && foldParameters.m_tier == 1)
141  {
142  for (const MCParticle *pPrimary : primaries)
143  {
144  MCParticleList allParticles{pPrimary};
146  {
147  LArMCParticleHelper::GetAllDescendentMCParticles(pPrimary, allParticles);
148  }
149  else
150  {
151  // Collect track-like and shower-like particles together, but throw out neutrons and descendents
152  MCParticleList dummy;
153  LArMCParticleHelper::GetAllDescendentMCParticles(pPrimary, allParticles, allParticles, dummy);
154  }
155  CaloHitList allHits;
156  for (const MCParticle *pMCParticle : allParticles)
157  {
158  // Not all MC particles will have hits
159  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
160  {
161  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
162  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
163  }
164  }
165  m_interactions[pRoot].emplace_back(new Node(*this, allParticles, allHits));
166  }
167  }
168  else if (foldParameters.m_foldToLeadingShowers)
169  {
170  for (const MCParticle *pPrimary : primaries)
171  {
172  MCParticleList allParticles{pPrimary};
173  int pdg{std::abs(pPrimary->GetParticleId())};
174  const bool isShower{pdg == E_MINUS || pdg == PHOTON};
175  const bool isNeutron{pdg == NEUTRON};
176  if (isShower || (isNeutron && !m_recoCriteria.m_removeNeutrons))
177  LArMCParticleHelper::GetAllDescendentMCParticles(pPrimary, allParticles);
178  CaloHitList allHits;
179  for (const MCParticle *pMCParticle : allParticles)
180  {
181  // ATTN - Not all MC particles will have hits
182  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
183  {
184  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
185  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
186  }
187  }
188  Node *pNode{new Node(*this, allParticles, allHits)};
189  m_interactions[pRoot].emplace_back(pNode);
190  if (!(isShower || isNeutron))
191  {
192  // Find the children of this particle and recursively add them to the hierarchy
193  const MCParticleList &children{pPrimary->GetDaughterList()};
194  for (const MCParticle *pChild : children)
195  pNode->FillHierarchy(pChild, foldParameters);
196  }
197  }
198  }
199  else if (foldParameters.m_foldDynamic)
200  {
201  for (const MCParticle *pPrimary : primaries)
202  {
203  MCParticleList leadingParticles, childParticles;
204  this->InterpretHierarchy(pPrimary, leadingParticles, childParticles, foldParameters.m_cosAngleTolerance);
205  CaloHitList allHits;
206  for (const MCParticle *pMCParticle : leadingParticles)
207  {
208  // ATTN - Not all MC particles will have hits
209  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
210  {
211  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
212  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
213  }
214  }
215 
216  Node *pNode{new Node(*this, leadingParticles, allHits)};
217  m_interactions[pRoot].emplace_back(pNode);
218  for (const MCParticle *pChild : childParticles)
219  pNode->FillHierarchy(pChild, foldParameters);
220  }
221  }
222  else
223  {
224  // Unfolded and folded to tier > 1 have the same behaviour for primaries
225  for (const MCParticle *pPrimary : primaries)
226  {
227  MCParticleList allParticles{pPrimary};
228  CaloHitList allHits;
229  for (const MCParticle *pMCParticle : allParticles)
230  {
231  // ATTN - Not all MC particles will have hits
232  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
233  {
234  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
235  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
236  }
237  }
238  Node *pNode{new Node(*this, allParticles, allHits)};
239  m_interactions[pRoot].emplace_back(pNode);
240  // Find the children of this particle and recursively add them to the hierarchy
241  const MCParticleList &children{pPrimary->GetDaughterList()};
242  for (const MCParticle *pChild : children)
243  pNode->FillHierarchy(pChild, foldParameters);
244  }
245  }
246 
247  Node *pLeadingLepton{nullptr};
248  float leadingLeptonEnergy{-std::numeric_limits<float>::max()};
249  for (const Node *pNode : m_interactions[pRoot])
250  {
251  const MCParticle *pMC{pNode->GetLeadingMCParticle()};
252  if (pMC)
253  {
254  const int pdg{std::abs(pMC->GetParticleId())};
255  if ((pdg == MU_MINUS || pdg == E_MINUS || pdg == TAU_MINUS) && pMC->GetEnergy() > leadingLeptonEnergy)
256  {
257  pLeadingLepton = const_cast<Node *>(pNode);
258  leadingLeptonEnergy = pMC->GetEnergy();
259  }
260  }
261  }
262  if (pLeadingLepton)
263  pLeadingLepton->SetLeadingLepton();
264  }
265 }
std::set< const pandora::MCParticle * > MCParticleSet
std::map< const pandora::MCParticle *, pandora::CaloHitList > m_mcToHitsMap
The map between MC particles and calo hits.
constexpr auto abs(T v)
Returns the absolute value of the argument.
static void GetMCPrimaries(const pandora::MCParticle *pRoot, MCParticleSet &primaries)
Retrieves the primary MC particles from a list and returns the root (neutrino) for hierarchy...
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
void InterpretHierarchy(const pandora::MCParticle *const pRoot, pandora::MCParticleList &leadingParticles, pandora::MCParticleList &childParticles, const float cosAngleTolerance) const
Interpret the hierarchy below a particular particle to determine if and how it should be folded...
ReconstructabilityCriteria m_recoCriteria
The criteria used to determine if the node is reconstructable.
const bool m_removeNeutrons
whether to remove neutrons and their downstream particles
static void GetAllDescendentMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &descendentMCParticleList)
Get all descendent mc particles.
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.
void lar_content::LArHierarchyHelper::MCHierarchy::GetFlattenedNodes ( const pandora::MCParticle *const  pRoot,
NodeVector nodeVector 
) const

Retrieve a flat vector of the ndoes in the hierarchy.

Parameters
pRootThe root MC particle for an interaction
nodeVectorThe output vector for the nodes in the hierarchy in breadth first order

Definition at line 442 of file LArHierarchyHelper.cc.

References m_interactions.

Referenced by lar_content::LArHierarchyHelper::MatchInfo::Match(), and lar_content::HierarchyMonitoringAlgorithm::Run().

443 {
444  NodeList queue;
445  for (const Node *pNode : m_interactions.at(pRoot))
446  {
447  nodeVector.emplace_back(pNode);
448  queue.emplace_back(pNode);
449  }
450  while (!queue.empty())
451  {
452  const NodeVector &children{queue.front()->GetChildren()};
453  queue.pop_front();
454  for (const Node *pChild : children)
455  {
456  nodeVector.emplace_back(pChild);
457  queue.emplace_back(pChild);
458  }
459  }
460 }
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.
const LArHierarchyHelper::MCHierarchy::NodeVector & lar_content::LArHierarchyHelper::MCHierarchy::GetInteractions ( const pandora::MCParticle *  pRoot) const

Retrieve the root nodes in this hierarchy.

Parameters
pRootThe root of the interaction hierarchy
Returns
The primary nodes in the requested interaction hierarchy

Definition at line 269 of file LArHierarchyHelper.cc.

References m_interactions.

270 {
271  if (m_interactions.find(pRoot) == m_interactions.end())
272  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
273 
274  return m_interactions.at(pRoot);
275 }
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.
const pandora::MCParticle* lar_content::LArHierarchyHelper::MCHierarchy::GetNeutrino ( ) const

Retrieve the neutrino at the root of the hierarchy if it exists.

Returns
The address of the incident neutrino (nullptr if it doesn't exist)
void lar_content::LArHierarchyHelper::MCHierarchy::GetRootMCParticles ( pandora::MCParticleList &  rootMCParticles) const

Retrieve the root MC particles of the interaction hierarchies.

Parameters
rootMCParticlesThe output list of root MC particles

Definition at line 279 of file LArHierarchyHelper.cc.

References m_interactions.

Referenced by lar_content::LArHierarchyHelper::MatchInfo::Match(), lar_content::LArHierarchyHelper::MatchInfo::Print(), and lar_content::HierarchyMonitoringAlgorithm::Run().

280 {
281  for (auto iter = m_interactions.begin(); iter != m_interactions.end(); ++iter)
282  rootMCParticles.emplace_back(iter->first);
283 }
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.
void lar_content::LArHierarchyHelper::MCHierarchy::InterpretHierarchy ( const pandora::MCParticle *const  pRoot,
pandora::MCParticleList &  leadingParticles,
pandora::MCParticleList &  childParticles,
const float  cosAngleTolerance 
) const

Interpret the hierarchy below a particular particle to determine if and how it should be folded. Folded particles are added to the leadingParticles list and child particles are added to the childParticles list.

Parameters
pRootThe root of the hierarchy to interpret
leadingParticlesThe output list of particles that should be folded into the root particle
childParticlesThe output list of particles that should be considered children of the folded particle
cosAngleToleranceThe cosine of the maximum angle for which trajectories are considered continuous

Definition at line 287 of file LArHierarchyHelper.cc.

References lar_content::LArMCParticleHelper::AreTopologicallyContinuous(), CollectContinuations(), lar_content::LArMCParticleHelper::GetAllDescendentMCParticles(), lar_content::LArMCParticleHelper::IsElasticScatter(), lar_content::LArMCParticleHelper::IsInelasticScatter(), IsReconstructable(), m_mcToHitsMap, m_recoCriteria, lar_content::LArHierarchyHelper::MCHierarchy::ReconstructabilityCriteria::m_removeNeutrons, and lar_content::MC_PROC_N_CAPTURE.

Referenced by FillHierarchy().

289 {
290  leadingParticles.emplace_back(pRoot);
291  MCParticleList foldCandidates, childCandidates;
292  const MCParticleList &children{pRoot->GetDaughterList()};
293  for (const MCParticle *pMCParticle : children)
294  {
295  const LArMCParticle *pLArMCParticle{dynamic_cast<const LArMCParticle *>(pMCParticle)};
296  if (!pLArMCParticle)
297  continue;
299  {
300  // Elastic and inelastic scattering can either lead to folding, distinct nodes or disposable hits, all other processes
301  // are either distinct nodes, or disposable
302  if (pMCParticle->GetParticleId() == pRoot->GetParticleId())
303  foldCandidates.emplace_back(pMCParticle);
304  else
305  childCandidates.emplace_back(pMCParticle);
306  }
307  else if (!m_recoCriteria.m_removeNeutrons || (m_recoCriteria.m_removeNeutrons && pLArMCParticle->GetProcess() != MC_PROC_N_CAPTURE))
308  {
309  // Non-scattering process particles become leading candidates unless it's neutron capture and we're removing neutrons
310  childCandidates.emplace_back(pMCParticle);
311  }
312  }
313  const MCParticle *pBestFoldCandidate{nullptr};
314  float bestDp{std::numeric_limits<float>::max()};
315  for (const MCParticle *pMCParticle : foldCandidates)
316  {
317  if (foldCandidates.size() == 1)
318  {
319  // No alternative options, so this is either the best folding option by default, or a sufficiently large scatter to
320  // treat as a new particle for reconstruction purposes
321  if (LArMCParticleHelper::AreTopologicallyContinuous(pRoot, pMCParticle, cosAngleTolerance))
322  pBestFoldCandidate = pMCParticle;
323  else
324  childCandidates.emplace_back(pMCParticle);
325  }
326  else
327  {
328  // Assess which, if any, of the children might be a continuation of the trajectory, otherwise move to child candidates
329  if (LArMCParticleHelper::AreTopologicallyContinuous(pRoot, pMCParticle, cosAngleTolerance))
330  {
331  const float dp{pRoot->GetMomentum().GetMagnitude() - pMCParticle->GetMomentum().GetMagnitude()};
332  if (dp < bestDp)
333  {
334  pBestFoldCandidate = pMCParticle;
335  bestDp = dp;
336  }
337  }
338  else
339  {
340  childCandidates.emplace_back(pMCParticle);
341  }
342  }
343  }
344  if (pBestFoldCandidate)
345  {
346  leadingParticles.emplace_back(pBestFoldCandidate);
347  // Having found a particle to fold back at this level, continue to explore its downstream hierarchy for further folding
348  // opportunities and make their respective children leading particles for the folded node we are creating
349  this->CollectContinuations(pBestFoldCandidate, leadingParticles, childCandidates, cosAngleTolerance);
350  }
351  for (const MCParticle *pMCParticle : childCandidates)
352  {
353  // Consider if the child particle will produce enough downstream hits to warrant inclusion
354  if (this->IsReconstructable(pMCParticle))
355  childParticles.emplace_back(pMCParticle);
356  else
357  {
358  MCParticleList localHierarchy{pMCParticle};
359  CaloHitList localHits;
360  LArMCParticleHelper::GetAllDescendentMCParticles(pMCParticle, localHierarchy);
361  for (const MCParticle *pLocalMCParticle : localHierarchy)
362  {
363  if (m_mcToHitsMap.find(pLocalMCParticle) != m_mcToHitsMap.end())
364  {
365  const CaloHitList &caloHits(m_mcToHitsMap.at(pLocalMCParticle));
366  localHits.insert(localHits.begin(), caloHits.begin(), caloHits.end());
367  }
368  }
369  if (this->IsReconstructable(localHits))
370  childParticles.emplace_back(pMCParticle);
371  }
372  }
373 }
void CollectContinuations(const pandora::MCParticle *pRoot, pandora::MCParticleList &continuingParticles, pandora::MCParticleList &childParticles, const float cosAngleTolerance) const
Identify downstream particles that represent continuations of the parent particle from a reconstructi...
std::map< const pandora::MCParticle *, pandora::CaloHitList > m_mcToHitsMap
The map between MC particles and calo hits.
static bool IsInelasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an inelastic scattering process.
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.
ReconstructabilityCriteria m_recoCriteria
The criteria used to determine if the node is reconstructable.
const bool m_removeNeutrons
whether to remove neutrons and their downstream particles
bool IsReconstructable(const pandora::MCParticle *pMCParticle) const
Checks if an individual particle meets reconstructability criteria.
static void GetAllDescendentMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &descendentMCParticleList)
Get all descendent mc particles.
static bool IsElasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an elastic scattering process.
bool lar_content::LArHierarchyHelper::MCHierarchy::IsReconstructable ( const pandora::MCParticle *  pMCParticle) const
private

Checks if an individual particle meets reconstructability criteria.

Parameters
pMCParticleThe MC particle to assess
Returns
Whether or not the MC particle meets reconstructability criteria

Definition at line 492 of file LArHierarchyHelper.cc.

References m_mcToHitsMap, lar_content::LArHierarchyHelper::MCHierarchy::ReconstructabilityCriteria::m_minGoodViews, lar_content::LArHierarchyHelper::MCHierarchy::ReconstructabilityCriteria::m_minHits, lar_content::LArHierarchyHelper::MCHierarchy::ReconstructabilityCriteria::m_minHitsForGoodView, m_recoCriteria, lar_content::LArHierarchyHelper::MCHierarchy::Node::Node(), and lar_content::LArMCParticleHelper::SortByMomentum().

Referenced by InterpretHierarchy().

493 {
494  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
495  {
496  unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
497  for (const CaloHit *pCaloHit : m_mcToHitsMap.at(pMCParticle))
498  {
499  const HitType view{pCaloHit->GetHitType()};
500  if (view == TPC_VIEW_U)
501  ++nHitsU;
502  else if (view == TPC_VIEW_V)
503  ++nHitsV;
504  else if (view == TPC_VIEW_W)
505  ++nHitsW;
506  }
507  const unsigned int nHits{nHitsU + nHitsV + nHitsW};
508  unsigned int nGoodViews{0};
509  nGoodViews += nHitsU >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
510  nGoodViews += nHitsV >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
511  nGoodViews += nHitsW >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
512 
513  return nHits >= m_recoCriteria.m_minHits && nGoodViews >= m_recoCriteria.m_minGoodViews;
514  }
515 
516  return false;
517 }
const unsigned int m_minHitsForGoodView
the minimum number of Hits for a good view
std::map< const pandora::MCParticle *, pandora::CaloHitList > m_mcToHitsMap
The map between MC particles and calo hits.
ReconstructabilityCriteria m_recoCriteria
The criteria used to determine if the node is reconstructable.
HitType
Definition: HitType.h:12
const unsigned int m_minHits
the minimum number of primary good Hits
const unsigned int m_minGoodViews
the minimum number of primary good views
bool lar_content::LArHierarchyHelper::MCHierarchy::IsReconstructable ( const pandora::CaloHitList &  caloHits) const
private

Checks if a set of hits meet reconstructability criteria.

Parameters
caloHitsThe calo hits to assess
Returns
Whether or not the hits meet reconstructability criteria
void lar_content::LArHierarchyHelper::MCHierarchy::RegisterNode ( const Node pNode)

Register a node with the hierarchy.

Parameters
pNodeThe node to register

Definition at line 464 of file LArHierarchyHelper.cc.

References m_nextNodeId, and m_nodeToIdMap.

465 {
466  m_nodeToIdMap.insert(std::make_pair(pNode, m_nextNodeId));
467  ++m_nextNodeId;
468 }
int m_nextNodeId
The ID to use for the next node.
std::map< const Node *, int > m_nodeToIdMap
A map from nodes to unique ids.
const std::string lar_content::LArHierarchyHelper::MCHierarchy::ToString ( ) const

Produce a string representation of the hierarchy.

Returns
The string representation of the hierarchy

Definition at line 472 of file LArHierarchyHelper.cc.

References m_interactions, and util::to_string().

Referenced by lar_content::HierarchyMonitoringAlgorithm::Run().

473 {
474  std::string str;
475  for (const auto &[pRoot, nodeVector] : m_interactions)
476  {
477  const LArMCParticle *const pLArRoot{dynamic_cast<const LArMCParticle *const>(pRoot)};
478  if (pLArRoot)
479  str += "=== MC Interaction : PDG " + std::to_string(pLArRoot->GetParticleId()) +
480  " Energy: " + std::to_string(pLArRoot->GetEnergy()) + " Nuance: " + std::to_string(pLArRoot->GetNuanceCode()) + "\n";
481  else
482  str += "=== MC Interaction : PDG " + std::to_string(pRoot->GetParticleId()) + " Energy: " + std::to_string(pRoot->GetEnergy()) + "\n";
483  for (const Node *pNode : nodeVector)
484  str += " " + pNode->ToString("") + "\n";
485  }
486 
487  return str;
488 }
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.

Member Data Documentation

std::map<const pandora::MCParticle *, pandora::CaloHitList> lar_content::LArHierarchyHelper::MCHierarchy::m_mcToHitsMap
private

The map between MC particles and calo hits.

Definition at line 414 of file LArHierarchyHelper.h.

Referenced by FillHierarchy(), InterpretHierarchy(), and IsReconstructable().

int lar_content::LArHierarchyHelper::MCHierarchy::m_nextNodeId
private

The ID to use for the next node.

Definition at line 416 of file LArHierarchyHelper.h.

Referenced by RegisterNode().

std::map<const Node *, int> lar_content::LArHierarchyHelper::MCHierarchy::m_nodeToIdMap
private

A map from nodes to unique ids.

Definition at line 415 of file LArHierarchyHelper.h.

Referenced by RegisterNode().

ReconstructabilityCriteria lar_content::LArHierarchyHelper::MCHierarchy::m_recoCriteria
private

The criteria used to determine if the node is reconstructable.

Definition at line 413 of file LArHierarchyHelper.h.

Referenced by CollectContinuations(), FillHierarchy(), InterpretHierarchy(), and IsReconstructable().


The documentation for this class was generated from the following files: