LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
LArEventTopology.cc
Go to the documentation of this file.
1 
9 #include "Helpers/MCParticleHelper.h"
10 #include "Objects/CaloHit.h"
11 #include "Pandora/PdgTable.h"
12 
15 
16 #include <sstream>
17 
18 using namespace pandora;
19 
20 namespace lar_content
21 {
22 
23 LArEventTopology::LArEventTopology(const CaloHitList &caloHitList2D) :
24  m_pRoot{nullptr},
25  m_pParticle{nullptr}
26 {
27  for (const CaloHit *const pCaloHit : caloHitList2D)
28  {
29  try
30  {
31  const MCParticle *pMCParticle{MCParticleHelper::GetMainMCParticle(pCaloHit)};
32  m_mcHitMap[pMCParticle].emplace_back(pCaloHit);
34  {
35  const MCParticle *pRoot{pMCParticle};
36  while (!pRoot->GetParentList().empty())
37  pRoot = pRoot->GetParentList().front();
38  m_pRoot = pRoot;
39  }
40  }
41  catch (const StatusCodeException &)
42  {
43  }
44  }
45 }
46 
47 //------------------------------------------------------------------------------------------------------------------------------------------
48 
50 {
51  delete m_pParticle;
52 }
53 
54 //------------------------------------------------------------------------------------------------------------------------------------------
55 
57 {
60 }
61 
62 //------------------------------------------------------------------------------------------------------------------------------------------
63 
64 void LArEventTopology::GetVertices(CartesianPointVector &vertices) const
65 {
66  m_pParticle->GetVertices(vertices);
67 
68  CartesianPointVector forRemoval;
69  for (auto iter1 = vertices.begin(); iter1 != vertices.end(); ++iter1)
70  {
71  const CartesianVector &vertex1{*iter1};
72  if (std::find(forRemoval.begin(), forRemoval.end(), vertex1) != forRemoval.end())
73  continue;
74  for (auto iter2 = std::next(iter1); iter2 != vertices.end(); ++iter2)
75  {
76  const CartesianVector &vertex2{*iter2};
77  if (std::find(forRemoval.begin(), forRemoval.end(), vertex2) != forRemoval.end())
78  continue;
79  if (vertex1.GetDistanceSquared(vertex2) < 1)
80  forRemoval.emplace_back(vertex2);
81  }
82  }
83 
84  for (auto iter = vertices.begin(); iter != vertices.end();)
85  {
86  if (std::find(forRemoval.begin(), forRemoval.end(), *iter) != forRemoval.end())
87  iter = vertices.erase(iter);
88  else
89  ++iter;
90  }
91 }
92 
93 //------------------------------------------------------------------------------------------------------------------------------------------
94 
96 {
97  std::string str{"Neutrino hierarchy: " + std::to_string(m_pRoot->GetParticleId()) + " E: " + std::to_string(m_pRoot->GetEnergy()) +
98  " GeV\n" + m_pParticle->Print(m_mcHitMap, " ")};
99  std::cout << str << std::endl;
100 }
101 
102 //------------------------------------------------------------------------------------------------------------------------------------------
103 
104 void LArEventTopology::ConstructVisibleHierarchy(Particle *pParticle, const MCParticle *const pRootMC)
105 {
106  for (const MCParticle *const pMC : pRootMC->GetDaughterList())
107  {
108  if (m_mcHitMap.find(pMC) != m_mcHitMap.end())
109  {
110  Particle *pChild{new Particle(pMC, m_mcHitMap.at(pMC))};
111  pParticle->AddChild(pChild);
112  this->ConstructVisibleHierarchy(pChild, pMC);
113  }
114  else
115  {
116  this->ConstructVisibleHierarchy(pParticle, pMC);
117  }
118  }
119 }
120 
121 //------------------------------------------------------------------------------------------------------------------------------------------
122 
124 {
126  m_pParticle->Prune();
127 }
128 
129 //------------------------------------------------------------------------------------------------------------------------------------------
130 //------------------------------------------------------------------------------------------------------------------------------------------
131 
132 LArEventTopology::Particle::Particle(const MCParticle *const pRoot) :
133  m_fold{false}
134 {
135  m_particles.emplace_back(pRoot);
136 }
137 
138 //------------------------------------------------------------------------------------------------------------------------------------------
139 
140 LArEventTopology::Particle::Particle(const MCParticle *const pRoot, const CaloHitList &caloHitList) :
141  m_caloHits{caloHitList},
142  m_fold{false}
143 {
144  m_particles.emplace_back(pRoot);
145 }
146 
147 //------------------------------------------------------------------------------------------------------------------------------------------
148 
150 {
151  for (Particle *pParticle : m_children)
152  delete pParticle;
153 }
154 
155 //------------------------------------------------------------------------------------------------------------------------------------------
156 
158 {
159  m_children.emplace_back(pChild);
160 }
161 
162 //------------------------------------------------------------------------------------------------------------------------------------------
163 
164 void LArEventTopology::Particle::GetVertices(CartesianPointVector &vertices) const
165 {
166  const MCParticle *const pMC{m_particles.front()};
168  {
169  if (std::find(vertices.begin(), vertices.end(), pMC->GetVertex()) == vertices.end())
170  vertices.emplace_back(pMC->GetVertex());
171  }
172  else
173  {
174  // Consider vertex
175  const MCParticle *const pParentMC{pMC->GetParentList().front()};
176  if (LArMCParticleHelper::IsNeutrino(pParentMC))
177  {
178  if (std::find(vertices.begin(), vertices.end(), pMC->GetVertex()) == vertices.end())
179  vertices.emplace_back(pMC->GetVertex());
180  }
181  else
182  {
183  const CartesianVector &momParent{pParentMC->GetMomentum().GetUnitVector()};
184  const CartesianVector &mom{pMC->GetMomentum().GetUnitVector()};
185  if ((pMC->GetParticleId() != pParentMC->GetParticleId()) || (mom.GetDotProduct(momParent) < 0.996f))
186  {
187  // Visible photon vertices occur at the endpoint, not the vertex, so skip photons here
188  if (pMC->GetParticleId() != PHOTON && std::find(vertices.begin(), vertices.end(), pMC->GetVertex()) == vertices.end())
189  vertices.emplace_back(pMC->GetVertex());
190  }
191  }
192  // Consider end point
193  int nTrackLikeChildren{0};
194  for (const Particle *const pChild : m_children)
195  {
196  const MCParticle *const pChildMC{pChild->m_particles.front()};
197  const int pdg{std::abs(pChildMC->GetParticleId())};
198  if (!(pdg == PHOTON || pdg == E_MINUS))
199  ++nTrackLikeChildren;
200  }
201  // If only shower children, or if more than 1 track, tag the endpoint as a vertex
202  // If we have exactly 1 track child, then downstream vertex checks will take care of this
203  // Also note that the endpoint of a photon actually marks the start of the associated hit deposition
204  if (nTrackLikeChildren != 1)
205  {
206  if (std::find(vertices.begin(), vertices.end(), pMC->GetEndpoint()) == vertices.end())
207  vertices.emplace_back(pMC->GetEndpoint());
208  }
209  }
210 
211  for (const Particle *const pChild : m_children)
212  pChild->GetVertices(vertices);
213 }
214 
215 //------------------------------------------------------------------------------------------------------------------------------------------
216 
218 {
219  const MCParticle *const pMC{m_particles.front()};
220  const CaloHitList &caloHitList{mcHitMap.find(pMC) != mcHitMap.end() ? mcHitMap.at(pMC) : CaloHitList()};
221  int uHits{0}, vHits{0}, wHits{0};
222  for (const CaloHit *const pCaloHit : caloHitList)
223  {
224  switch (pCaloHit->GetHitType())
225  {
226  case TPC_VIEW_U:
227  ++uHits;
228  break;
229  case TPC_VIEW_V:
230  ++vHits;
231  break;
232  case TPC_VIEW_W:
233  ++wHits;
234  break;
235  default:
236  break;
237  }
238  }
239 
240  const int pdg{std::abs(pMC->GetParticleId())};
241  const int target{pdg == PHOTON || pdg == E_MINUS ? 8 : 5};
242  const int totalHits{uHits + vHits + wHits};
243  int goodViews{uHits >= target ? 1 : 0};
244  goodViews += vHits >= target ? 1 : 0;
245  goodViews += wHits >= target ? 1 : 0;
246 
247  if (totalHits < (3 * target) || goodViews < 2)
248  m_fold = true;
249 
250  for (Particle *const pChild : m_children)
251  pChild->Parse(mcHitMap);
252 }
253 
254 //------------------------------------------------------------------------------------------------------------------------------------------
255 
257 {
258  for (Particle *const pChild : m_children)
259  pChild->Prune();
260 
261  std::list<Particle> toPrune;
262  for (auto iter = m_children.begin(); iter != m_children.end();)
263  {
264  if ((*iter)->m_fold && (*iter)->m_children.empty())
265  iter = m_children.erase(iter);
266  else
267  ++iter;
268  }
269 }
270 
271 //------------------------------------------------------------------------------------------------------------------------------------------
272 
273 const std::string LArEventTopology::Particle::Print(const MCHitMap &mcHitMap, const std::string &indent) const
274 {
275  const MCParticle *const pMC{m_particles.front()};
276  const CaloHitList &caloHitList{mcHitMap.find(pMC) != mcHitMap.end() ? mcHitMap.at(pMC) : CaloHitList()};
277  int uHits{0}, vHits{0}, wHits{0};
278  for (const CaloHit *const pCaloHit : caloHitList)
279  {
280  switch (pCaloHit->GetHitType())
281  {
282  case TPC_VIEW_U:
283  ++uHits;
284  break;
285  case TPC_VIEW_V:
286  ++vHits;
287  break;
288  case TPC_VIEW_W:
289  ++wHits;
290  break;
291  default:
292  break;
293  }
294  }
295 
296  std::ostringstream os;
297  os << indent << pMC->GetParticleId() << ": E: " << pMC->GetEnergy() << " GeV";
298  os << " (" << uHits << "," << vHits << "," << wHits << ") " << (m_fold ? "[fold]" : "") << "\n";
299  for (const Particle *const pChild : m_children)
300  os << pChild->Print(mcHitMap, indent + " ");
301 
302  return os.str();
303 }
304 
305 } // namespace lar_content
void Parse(const MCHitMap &mcHitMap)
Assess this child particle and its descendents to see if it is topologically significant either indep...
void AddChild(Particle *pChild)
Add a child particle to this particle.
void GetVertices(pandora::CartesianPointVector &vertices) const
Extract the clear topological vertices from the event.
constexpr auto abs(T v)
Returns the absolute value of the argument.
void ConstructVisibleHierarchy()
Construct a particle hierarchy based on the key topological features in an event. ...
Header file for lar event topology.
Header file for the lar monte carlo particle helper helper class.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
const pandora::MCParticle * m_pRoot
virtual ~LArEventTopology()
Destructor.
std::string indent(std::size_t const i)
Particle(const pandora::MCParticle *const pRoot)
Default constructor.
void Prune()
Prune particles from the hierarchy if they are not deemed topologically significant.
const std::string Print(const MCHitMap &mcHitMap, const std::string &indent) const
Print the visible hierarchy.
std::map< const pandora::MCParticle *, pandora::CaloHitList > MCHitMap
cout<< "-> Edep in the target
Definition: analysis.C:53
void PruneHierarchy()
Fold or remove particles that aren&#39;t substantive parts of the hierarchy.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
void Print() const
Print the visible hierarchy.
void GetVertices(pandora::CartesianPointVector &vertices) const
Extract the clear topological vertices from the event.