LArSoft  v10_04_05
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 90 of file LArHierarchyHelper.h.

Member Typedef Documentation

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

Definition at line 129 of file LArHierarchyHelper.h.

Definition at line 128 of file LArHierarchyHelper.h.

Definition at line 126 of file LArHierarchyHelper.h.

Constructor & Destructor Documentation

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

Default constructor.

Definition at line 80 of file LArHierarchyHelper.cc.

80  :
81  m_nextNodeId{1}
82 {
83 }
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 87 of file LArHierarchyHelper.cc.

87  :
88  m_recoCriteria(recoCriteria),
89  m_nextNodeId{1}
90 {
91 }
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 95 of file LArHierarchyHelper.cc.

References m_interactions.

96 {
97  for (const auto &[pRoot, nodeVector] : m_interactions)
98  {
99  (void)pRoot;
100  for (const Node *pNode : nodeVector)
101  delete pNode;
102  }
103  m_interactions.clear();
104 }
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 379 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().

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

109 {
110  const auto predicate = [](const MCParticle *pMCParticle) { return std::abs(pMCParticle->GetParticleId()) == NEUTRON; };
111  m_mcToHitsMap.clear();
112  for (const CaloHit *pCaloHit : caloHitList)
113  {
114  try
115  {
116  const MCParticle *pMCParticle{MCParticleHelper::GetMainMCParticle(pCaloHit)};
117  m_mcToHitsMap[pMCParticle].emplace_back(pCaloHit);
118  }
119  catch (const StatusCodeException &)
120  {
121  }
122  }
123 
124  MCParticleList rootNodes;
125  for (const MCParticle *pMCParticle : mcParticleList)
126  {
127  const MCParticleList &parentList{pMCParticle->GetParentList()};
128  if (parentList.empty())
129  {
130  rootNodes.emplace_back(pMCParticle);
131  }
132  }
133 
134  for (const MCParticle *pRoot : rootNodes)
135  {
136  MCParticleSet primarySet;
137  LArHierarchyHelper::GetMCPrimaries(pRoot, primarySet);
138  MCParticleList primaries(primarySet.begin(), primarySet.end());
139  primaries.sort(LArMCParticleHelper::SortByMomentum);
141  primaries.erase(std::remove_if(primaries.begin(), primaries.end(), predicate), primaries.end());
142  if (foldParameters.m_foldToTier && foldParameters.m_tier == 1)
143  {
144  for (const MCParticle *pPrimary : primaries)
145  {
146  MCParticleList allParticles{pPrimary};
148  {
149  LArMCParticleHelper::GetAllDescendentMCParticles(pPrimary, allParticles);
150  }
151  else
152  {
153  // Collect track-like and shower-like particles together, but throw out neutrons and descendents
154  MCParticleList dummy;
155  LArMCParticleHelper::GetAllDescendentMCParticles(pPrimary, allParticles, allParticles, dummy);
156  }
157  CaloHitList allHits;
158  for (const MCParticle *pMCParticle : allParticles)
159  {
160  // Not all MC particles will have hits
161  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
162  {
163  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
164  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
165  }
166  }
167  m_interactions[pRoot].emplace_back(new Node(*this, allParticles, allHits));
168  }
169  }
170  else if (foldParameters.m_foldToLeadingShowers)
171  {
172  for (const MCParticle *pPrimary : primaries)
173  {
174  MCParticleList allParticles{pPrimary};
175  int pdg{std::abs(pPrimary->GetParticleId())};
176  const bool isShower{pdg == E_MINUS || pdg == PHOTON};
177  const bool isNeutron{pdg == NEUTRON};
178  if (isShower || (isNeutron && !m_recoCriteria.m_removeNeutrons))
179  LArMCParticleHelper::GetAllDescendentMCParticles(pPrimary, allParticles);
180  CaloHitList allHits;
181  for (const MCParticle *pMCParticle : allParticles)
182  {
183  // ATTN - Not all MC particles will have hits
184  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
185  {
186  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
187  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
188  }
189  }
190  Node *pNode{new Node(*this, allParticles, allHits)};
191  m_interactions[pRoot].emplace_back(pNode);
192  if (!(isShower || isNeutron))
193  {
194  // Find the children of this particle and recursively add them to the hierarchy
195  const MCParticleList &children{pPrimary->GetDaughterList()};
196  for (const MCParticle *pChild : children)
197  pNode->FillHierarchy(pChild, foldParameters);
198  }
199  }
200  }
201  else if (foldParameters.m_foldDynamic)
202  {
203  for (const MCParticle *pPrimary : primaries)
204  {
205  MCParticleList leadingParticles, childParticles;
206  this->InterpretHierarchy(pPrimary, leadingParticles, childParticles, foldParameters.m_cosAngleTolerance);
207  CaloHitList allHits;
208  for (const MCParticle *pMCParticle : leadingParticles)
209  {
210  // ATTN - Not all MC particles will have hits
211  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
212  {
213  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
214  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
215  }
216  }
217 
218  Node *pNode{new Node(*this, leadingParticles, allHits)};
219  m_interactions[pRoot].emplace_back(pNode);
220  for (const MCParticle *pChild : childParticles)
221  pNode->FillHierarchy(pChild, foldParameters);
222  }
223  }
224  else
225  {
226  // Unfolded and folded to tier > 1 have the same behaviour for primaries
227  for (const MCParticle *pPrimary : primaries)
228  {
229  MCParticleList allParticles{pPrimary};
230  CaloHitList allHits;
231  for (const MCParticle *pMCParticle : allParticles)
232  {
233  // ATTN - Not all MC particles will have hits
234  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
235  {
236  const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
237  allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
238  }
239  }
240  Node *pNode{new Node(*this, allParticles, allHits)};
241  m_interactions[pRoot].emplace_back(pNode);
242  // Find the children of this particle and recursively add them to the hierarchy
243  const MCParticleList &children{pPrimary->GetDaughterList()};
244  for (const MCParticle *pChild : children)
245  pNode->FillHierarchy(pChild, foldParameters);
246  }
247  }
248 
249  Node *pLeadingLepton{nullptr};
250  float leadingLeptonEnergy{-std::numeric_limits<float>::max()};
251  for (const Node *pNode : m_interactions[pRoot])
252  {
253  const MCParticle *pMC{pNode->GetLeadingMCParticle()};
254  if (pMC)
255  {
256  const int pdg{std::abs(pMC->GetParticleId())};
257  if ((pdg == MU_MINUS || pdg == E_MINUS || pdg == TAU_MINUS) && pMC->GetEnergy() > leadingLeptonEnergy)
258  {
259  pLeadingLepton = const_cast<Node *>(pNode);
260  leadingLeptonEnergy = pMC->GetEnergy();
261  }
262  }
263  }
264  if (pLeadingLepton)
265  pLeadingLepton->SetLeadingLepton();
266  }
267 }
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 444 of file LArHierarchyHelper.cc.

References m_interactions.

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

445 {
446  NodeList queue;
447  for (const Node *pNode : m_interactions.at(pRoot))
448  {
449  nodeVector.emplace_back(pNode);
450  queue.emplace_back(pNode);
451  }
452  while (!queue.empty())
453  {
454  const NodeVector &children{queue.front()->GetChildren()};
455  queue.pop_front();
456  for (const Node *pChild : children)
457  {
458  nodeVector.emplace_back(pChild);
459  queue.emplace_back(pChild);
460  }
461  }
462 }
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 271 of file LArHierarchyHelper.cc.

References m_interactions.

272 {
273  if (m_interactions.find(pRoot) == m_interactions.end())
274  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
275 
276  return m_interactions.at(pRoot);
277 }
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 281 of file LArHierarchyHelper.cc.

References m_interactions.

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

282 {
283  for (auto iter = m_interactions.begin(); iter != m_interactions.end(); ++iter)
284  rootMCParticles.emplace_back(iter->first);
285 }
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 289 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().

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

495 {
496  if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
497  {
498  unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
499  for (const CaloHit *pCaloHit : m_mcToHitsMap.at(pMCParticle))
500  {
501  const HitType view{pCaloHit->GetHitType()};
502  if (view == TPC_VIEW_U)
503  ++nHitsU;
504  else if (view == TPC_VIEW_V)
505  ++nHitsV;
506  else if (view == TPC_VIEW_W)
507  ++nHitsW;
508  }
509  const unsigned int nHits{nHitsU + nHitsV + nHitsW};
510  unsigned int nGoodViews{0};
511  nGoodViews += nHitsU >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
512  nGoodViews += nHitsV >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
513  nGoodViews += nHitsW >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
514 
515  return nHits >= m_recoCriteria.m_minHits && nGoodViews >= m_recoCriteria.m_minGoodViews;
516  }
517 
518  return false;
519 }
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 466 of file LArHierarchyHelper.cc.

References m_nextNodeId, and m_nodeToIdMap.

467 {
468  m_nodeToIdMap.insert(std::make_pair(pNode, m_nextNodeId));
469  ++m_nextNodeId;
470 }
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 474 of file LArHierarchyHelper.cc.

References m_interactions, and util::to_string().

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

475 {
476  std::string str;
477  for (const auto &[pRoot, nodeVector] : m_interactions)
478  {
479  const LArMCParticle *const pLArRoot{dynamic_cast<const LArMCParticle *const>(pRoot)};
480  if (pLArRoot)
481  str += "=== MC Interaction : PDG " + std::to_string(pLArRoot->GetParticleId()) +
482  " Energy: " + std::to_string(pLArRoot->GetEnergy()) + " Nuance: " + std::to_string(pLArRoot->GetNuanceCode()) + "\n";
483  else
484  str += "=== MC Interaction : PDG " + std::to_string(pRoot->GetParticleId()) + " Energy: " + std::to_string(pRoot->GetEnergy()) + "\n";
485  for (const Node *pNode : nodeVector)
486  str += " " + pNode->ToString("") + "\n";
487  }
488 
489  return str;
490 }
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 416 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 418 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 417 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 415 of file LArHierarchyHelper.h.

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


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