LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
HierarchyValidationAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
15 
16 using namespace pandora;
17 
18 namespace lar_content
19 {
20 
21 HierarchyValidationAlgorithm::HierarchyValidationAlgorithm() :
22  m_event{-1},
23  m_detector{"dune_fd_hd"},
24  m_writeEventTree{false},
25  m_writeMCTree{false},
26  m_foldToPrimaries{false},
27  m_foldDynamic{false},
29  m_validateEvent{false},
30  m_validateMC{false},
31  m_minPurity{0.8f},
32  m_minCompleteness{0.65f},
33  m_minRecoHits{30},
37  m_selectRecoHits{false}
38 {
39 }
40 
41 //------------------------------------------------------------------------------------------------------------------------------------------
42 
44 {
45  if (m_writeEventTree)
46  {
47  PANDORA_MONITORING_API(SaveTree(this->GetPandora(), m_eventTreeName.c_str(), m_eventFileName.c_str(), "UPDATE"));
48  }
49  if (m_writeMCTree)
50  {
51  PANDORA_MONITORING_API(SaveTree(this->GetPandora(), m_MCTreeName.c_str(), m_MCFileName.c_str(), "UPDATE"));
52  }
53 }
54 
55 //------------------------------------------------------------------------------------------------------------------------------------------
56 
58 {
59  ++m_event;
60  const CaloHitList *pCaloHitList(nullptr);
61  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, m_caloHitListName, pCaloHitList));
62  const MCParticleList *pMCParticleList(nullptr);
63  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pMCParticleList));
64  const PfoList *pPfoList(nullptr);
65  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, m_pfoListName, pPfoList));
66 
69  foldParameters.m_foldToTier = true;
70  else if (m_foldDynamic)
71  foldParameters.m_foldDynamic = true;
72  else if (m_foldToLeadingShowers)
73  foldParameters.m_foldToLeadingShowers = true;
76 
77  LArHierarchyHelper::MCHierarchy mcHierarchy(recoCriteria);
78  LArHierarchyHelper::FillMCHierarchy(*pMCParticleList, *pCaloHitList, foldParameters, mcHierarchy);
80  LArHierarchyHelper::FillRecoHierarchy(*pPfoList, foldParameters, recoHierarchy);
82  LArHierarchyHelper::MatchInfo matchInfo(mcHierarchy, recoHierarchy, quality);
84  matchInfo.Print(mcHierarchy);
85 
86 #ifdef MONITORING
87  if (m_validateEvent)
88  this->EventValidation(matchInfo);
89  if (m_validateMC)
90  this->MCValidation(matchInfo);
91 #endif
92 
93  return STATUS_CODE_SUCCESS;
94 }
95 
96 //------------------------------------------------------------------------------------------------------------------------------------------
97 
98 #ifdef MONITORING
99 void HierarchyValidationAlgorithm::EventValidation(const LArHierarchyHelper::MatchInfo &matchInfo) const
100 {
101  if (m_writeEventTree)
102  {
103  int interaction{0};
104  MCParticleList rootMCParticles;
105  matchInfo.GetRootMCParticles(rootMCParticles);
106 
107  const LArHierarchyHelper::RecoHierarchy &recoHierarchy{matchInfo.GetRecoHierarchy()};
108  PfoList rootPfos;
109  recoHierarchy.GetRootPfos(rootPfos);
110  std::map<const LArHierarchyHelper::RecoHierarchy::Node *, const ParticleFlowObject *> recoNodeToRootMap;
111  for (const ParticleFlowObject *const pRoot : rootPfos)
112  {
114  recoHierarchy.GetFlattenedNodes(pRoot, nodes);
115  for (const LArHierarchyHelper::RecoHierarchy::Node *pNode : nodes)
116  recoNodeToRootMap[pNode] = pRoot;
117  }
118 
119  std::set<const pandora::ParticleFlowObject *> matchedRecoSliceRoots;
120  for (const MCParticle *const pRoot : rootMCParticles)
121  {
122  const LArHierarchyHelper::MCMatchesVector &matches{matchInfo.GetMatches(pRoot)};
123 
124  MCParticleList primaries;
125  for (const LArHierarchyHelper::MCMatches &match : matches)
126  {
127  const LArHierarchyHelper::MCHierarchy::Node *pMCNode{match.GetMC()};
128  if (pMCNode->GetHierarchyTier() == 1)
129  {
130  const MCParticle *const pLeadingMC{pMCNode->GetLeadingMCParticle()};
131  primaries.emplace_back(pLeadingMC);
132  }
133  }
134  // Check primaries is not empty before proceeding
135  if (primaries.size() == 0)
136  continue;
137  primaries.sort(LArMCParticleHelper::SortByMomentum);
138 
139  int isCC{0}, isQE{0}, isResonant{0}, isDIS{0}, isCoherent{0}, isNuMu{0}, isNuE{0}, nPiZero{0}, nPiPlus{0}, nPiMinus{0},
140  nPhotons{0}, nProtons{0};
141 
142  try
143  {
145  isCC = descriptor.IsCC();
146  isQE = descriptor.IsQE();
147  isResonant = descriptor.IsResonant();
148  isDIS = descriptor.IsDIS();
149  isCoherent = descriptor.IsCoherent();
150  isNuMu = descriptor.IsMuonNeutrino();
151  isNuE = descriptor.IsElectronNeutrino();
152  nPiZero = static_cast<int>(descriptor.GetNumPiZero());
153  nPiPlus = static_cast<int>(descriptor.GetNumPiPlus());
154  nPiMinus = static_cast<int>(descriptor.GetNumPiMinus());
155  nPhotons = static_cast<int>(descriptor.GetNumPhotons());
156  nProtons = static_cast<int>(descriptor.GetNumProtons());
157  }
158  catch (...)
159  {
160  }
161 
162  std::set<const LArHierarchyHelper::MCHierarchy::Node *> trackNodeSet, showerNodeSet;
163  int nGoodTrackMatches{0}, nGoodShowerMatches{0};
164  int nGoodMatches{0}, nPoorMatches{0}, nUnmatched{0};
165  int nGoodTier1Matches{0}, nTier1Nodes{0};
166  int nGoodTier1TrackMatches{0}, nTier1TrackNodes{0};
167  int nGoodTier1ShowerMatches{0}, nTier1ShowerNodes{0};
168  int hasLeadingMuon{0}, hasLeadingElectron{0}, isLeadingLeptonCorrect{0};
169  for (const LArHierarchyHelper::MCMatches &mcMatch : matches)
170  {
171  const LArHierarchyHelper::MCHierarchy::Node *pNode{mcMatch.GetMC()};
172 
173  for (const LArHierarchyHelper::RecoHierarchy::Node *pReco : mcMatch.GetRecoMatches())
174  matchedRecoSliceRoots.insert(recoNodeToRootMap[pReco]);
175 
176  const int nReco{static_cast<int>(mcMatch.GetRecoMatches().size())};
177  const bool isQuality{mcMatch.IsQuality(matchInfo.GetQualityCuts())};
178  if (nReco == 1 && isQuality)
179  ++nGoodMatches;
180  else if (nReco >= 1)
181  ++nPoorMatches;
182  else
183  ++nUnmatched;
184  if (pNode->GetHierarchyTier() == 1)
185  {
186  ++nTier1Nodes;
187  if (nReco == 1 && isQuality)
188  ++nGoodTier1Matches;
189  }
190 
191  const int pdg{std::abs(pNode->GetParticleId())};
192  if (pNode->IsLeadingLepton())
193  {
194  if (pdg == MU_MINUS)
195  hasLeadingMuon = 1;
196  else if (pdg == E_MINUS)
197  hasLeadingElectron = 1;
198  isLeadingLeptonCorrect = nReco == 1 ? 1 : 0;
199  }
200 
201  if (pdg == PHOTON || pdg == E_MINUS)
202  {
203  showerNodeSet.insert(pNode);
204  if (nReco == 1 && isQuality)
205  {
206  ++nGoodShowerMatches;
207  if (pNode->GetHierarchyTier() == 1)
208  ++nGoodTier1ShowerMatches;
209  }
210  if (pNode->GetHierarchyTier() == 1)
211  ++nTier1ShowerNodes;
212  }
213  else
214  {
215  trackNodeSet.insert(pNode);
216  if (nReco == 1 && isQuality)
217  {
218  ++nGoodTrackMatches;
219  if (pNode->GetHierarchyTier() == 1)
220  ++nGoodTier1TrackMatches;
221  }
222  if (pNode->GetHierarchyTier() == 1)
223  ++nTier1TrackNodes;
224  }
225  }
226 
227  const int nNodes{static_cast<int>(matchInfo.GetNMCNodes(pRoot))};
228  const int nTrackNodes{static_cast<int>(trackNodeSet.size())}, nShowerNodes{static_cast<int>(showerNodeSet.size())};
229  const int nRecoSlices{static_cast<int>(matchedRecoSliceRoots.size())};
230  const CartesianVector &trueVertex{pRoot->GetVertex()};
231  const float trueVtxX{trueVertex.GetX()};
232  const float trueVtxY{trueVertex.GetY()};
233  const float trueVtxZ{trueVertex.GetZ()};
234  float recoVtxX{std::numeric_limits<float>::max()};
235  float recoVtxY{std::numeric_limits<float>::max()};
236  float recoVtxZ{std::numeric_limits<float>::max()};
237  float vtxDx{std::numeric_limits<float>::max()};
238  float vtxDy{std::numeric_limits<float>::max()};
239  float vtxDz{std::numeric_limits<float>::max()};
240  float vtxDr{std::numeric_limits<float>::max()};
241  const int isFiducial{LArVertexHelper::IsInFiducialVolume(this->GetPandora(), trueVertex, m_detector)};
242 
243  for (const ParticleFlowObject *pRootPfo : matchedRecoSliceRoots)
244  {
245  try
246  {
247  const CartesianVector &recoVertex{LArPfoHelper::GetVertex(pRootPfo)->GetPosition()};
248  const float recoVertexX{recoVertex.GetX()};
249  const float recoVertexY{recoVertex.GetY()};
250  const float recoVertexZ{recoVertex.GetZ()};
251  const float dx{recoVertexX - trueVtxX};
252  const float dy{recoVertexY - trueVtxY};
253  const float dz{recoVertexZ - trueVtxZ};
254  const float dr{std::sqrt(dx * dx + dy * dy + dz * dz)};
255  if (dr < vtxDr)
256  {
257  recoVtxX = recoVertexX;
258  recoVtxY = recoVertexY;
259  recoVtxZ = recoVertexZ;
260  vtxDx = dx;
261  vtxDy = dy;
262  vtxDz = dz;
263  vtxDr = dr;
264  }
265  }
266  catch (StatusCodeException &)
267  {
268  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
269  std::cout << "HierarchyValidationAlgorithm::EventValidation could not retrieve recoVertex" << std::endl;
270  }
271  }
272 
273  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "event", m_event));
274  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "interaction", interaction));
275  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nRecoSlices", nRecoSlices));
276  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isCC", isCC));
277  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isQE", isQE));
278  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isResonant", isResonant));
279  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isDIS", isDIS));
280  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isCoherent", isCoherent));
281  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isNuMu", isNuMu));
282  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isNuE", isNuE));
283  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nPiZero", nPiZero));
284  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nPiPlus", nPiPlus));
285  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nPiMinus", nPiMinus));
286  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nPhotons", nPhotons));
287  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nProtons", nProtons));
288  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isFiducial", isFiducial));
289  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "recoVtxX", recoVtxX));
290  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "recoVtxY", recoVtxY));
291  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "recoVtxZ", recoVtxZ));
292  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "trueVtxX", recoVtxX));
293  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "trueVtxY", recoVtxY));
294  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "trueVtxZ", recoVtxZ));
295  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "vtxDx", vtxDx));
296  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "vtxDy", vtxDy));
297  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "vtxDz", vtxDz));
298  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "vtxDr", vtxDr));
299  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nGoodMatches", nGoodMatches));
300  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nPoorMatches", nPoorMatches));
301  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nUnmatched", nUnmatched));
302  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nNodes", nNodes));
303  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nGoodTier1Matches", nGoodTier1Matches));
304  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nTier1Nodes", nTier1Nodes));
305  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nGoodTrackMatches", nGoodTrackMatches));
306  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nGoodShowerMatches", nGoodShowerMatches));
307  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nTrackNodes", nTrackNodes));
308  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nShowerNodes", nShowerNodes));
309  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nGoodTier1TrackMatches", nGoodTier1TrackMatches));
310  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nTier1TrackNodes", nTier1TrackNodes));
311  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nGoodTier1ShowerMatches", nGoodTier1ShowerMatches));
312  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "nTier1ShowerNodes", nTier1ShowerNodes));
313  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "hasLeadingMuon", hasLeadingMuon));
314  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "hasLeadingElectron", hasLeadingElectron));
315  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_eventTreeName.c_str(), "isLeadingLeptonCorrect", isLeadingLeptonCorrect));
316  PANDORA_MONITORING_API(FillTree(this->GetPandora(), m_eventTreeName.c_str()));
317  ++interaction;
318  }
319  }
320 }
321 
322 //------------------------------------------------------------------------------------------------------------------------------------------
323 
324 void HierarchyValidationAlgorithm::MCValidation(const LArHierarchyHelper::MatchInfo &matchInfo) const
325 {
326  if (m_writeMCTree)
327  {
328  int interaction{0};
329  MCParticleList rootMCParticles;
330  const CartesianVector null(0.f, 0.f, 0.f);
331  matchInfo.GetRootMCParticles(rootMCParticles);
332  PfoList rootPfos;
333  const LArHierarchyHelper::RecoHierarchy &recoHierarchy{matchInfo.GetRecoHierarchy()};
334  recoHierarchy.GetRootPfos(rootPfos);
335  std::map<const LArHierarchyHelper::RecoHierarchy::Node *, const ParticleFlowObject *> recoNodeToRootMap;
336  for (const ParticleFlowObject *const pRoot : rootPfos)
337  {
339  recoHierarchy.GetFlattenedNodes(pRoot, nodes);
340  for (const LArHierarchyHelper::RecoHierarchy::Node *pNode : nodes)
341  recoNodeToRootMap[pNode] = pRoot;
342  }
343 
344  for (const MCParticle *const pRoot : rootMCParticles)
345  {
346  MCParticleList primaries;
347  for (const LArHierarchyHelper::MCMatches &matches : matchInfo.GetMatches(pRoot))
348  {
349  const LArHierarchyHelper::MCHierarchy::Node *pMCNode{matches.GetMC()};
350  if (pMCNode->GetHierarchyTier() == 1)
351  {
352  const MCParticle *const pLeadingMC{pMCNode->GetLeadingMCParticle()};
353  primaries.emplace_back(pLeadingMC);
354  }
355  }
356  // Check primaries is not empty before proceeding
357  if (primaries.size() == 0)
358  continue;
359  primaries.sort(LArMCParticleHelper::SortByMomentum);
360 
361  for (const LArHierarchyHelper::MCMatches &matches : matchInfo.GetMatches(pRoot))
362  {
363  const LArHierarchyHelper::MCHierarchy::Node *pMCNode{matches.GetMC()};
364  const int isSignal{LArMCParticleHelper::IsNeutrino(LArMCParticleHelper::GetParentMCParticle(pMCNode->GetLeadingMCParticle())) ? 1 : 0};
365  const int isTestBeam{pMCNode->IsTestBeamParticle() ? 1 : 0};
366  const int isCosmicRay{!isTestBeam && pMCNode->IsCosmicRay() ? 1 : 0};
367  const int isNeutrinoInt{!(isTestBeam || isCosmicRay) ? 1 : 0};
368  const int mcId{pMCNode->GetId()};
369  const int pdg{pMCNode->GetParticleId()};
370  const int tier{pMCNode->GetHierarchyTier()};
371  const int mcHits{static_cast<int>(pMCNode->GetCaloHits().size())};
372  const int isLeadingLepton{pMCNode->IsLeadingLepton() ? 1 : 0};
373  const CaloHitList mcCaloHits{pMCNode->GetCaloHits()};
374  float mcTotalMipEnergy{0};
375  for (const CaloHit *pCaloHit : mcCaloHits)
376  {
377  mcTotalMipEnergy += pCaloHit->GetMipEquivalentEnergy();
378  }
379 
380  const MCParticle *const pLeadingMC{pMCNode->GetLeadingMCParticle()};
381  const MCParticleList &parentList{pLeadingMC->GetParentList()};
382  const int isElectron{std::abs(pLeadingMC->GetParticleId()) == E_MINUS ? 1 : 0};
383  const int hasMuonParent{parentList.size() == 1 && std::abs(parentList.front()->GetParticleId()) == MU_MINUS ? 1 : 0};
384  const int isMichel{isElectron && hasMuonParent && LArMCParticleHelper::IsDecay(pLeadingMC) ? 1 : 0};
385  const CartesianVector mcMomentum{pLeadingMC->GetMomentum()};
386  const float mcMtm{mcMomentum.GetMagnitude()};
387  const float mcMtmX{mcMomentum.GetX()};
388  const float mcMtmY{mcMomentum.GetY()};
389  const float mcMtmZ{mcMomentum.GetZ()};
390  const float mcEnergy{pLeadingMC->GetEnergy()};
391 
392  const LArHierarchyHelper::RecoHierarchy::NodeVector &nodeVector{matches.GetRecoMatches()};
393  const int nMatches{static_cast<int>(nodeVector.size())};
394  IntVector recoSliceIdVector, recoIdVector, nRecoHitsVector, nSharedHitsVector;
395  FloatVector recoTotalAdcVector;
396  FloatVector purityVector, completenessVector;
397  FloatVector purityAdcVector, completenessAdcVector;
398  FloatVector purityVectorU, purityVectorV, purityVectorW, completenessVectorU, completenessVectorV, completenessVectorW;
399  FloatVector purityAdcVectorU, purityAdcVectorV, purityAdcVectorW, completenessAdcVectorU, completenessAdcVectorV, completenessAdcVectorW;
400  const CartesianVector &trueVertex{isSignal == 1 ? pLeadingMC->GetVertex() : null};
401  const float trueVtxX{trueVertex.GetX()};
402  const float trueVtxY{trueVertex.GetY()};
403  const float trueVtxZ{trueVertex.GetZ()};
404  float recoVtxX{std::numeric_limits<float>::max()};
405  float recoVtxY{std::numeric_limits<float>::max()};
406  float recoVtxZ{std::numeric_limits<float>::max()};
407  float vtxDx{std::numeric_limits<float>::max()};
408  float vtxDy{std::numeric_limits<float>::max()};
409  float vtxDz{std::numeric_limits<float>::max()};
410  float vtxDr{std::numeric_limits<float>::max()};
411 
412  int isCC{0}, isQE{0}, isResonant{0}, isDIS{0}, isCoherent{0}, isNuMu{0}, isNuE{0}, nPiZero{0}, nPiPlus{0}, nPiMinus{0},
413  nPhotons{0}, nProtons{0};
414  try
415  {
417  isCC = descriptor.IsCC();
418  isQE = descriptor.IsQE();
419  isResonant = descriptor.IsResonant();
420  isDIS = descriptor.IsDIS();
421  isCoherent = descriptor.IsCoherent();
422  isNuMu = descriptor.IsMuonNeutrino();
423  isNuE = descriptor.IsElectronNeutrino();
424  nPiZero = static_cast<int>(descriptor.GetNumPiZero());
425  nPiPlus = static_cast<int>(descriptor.GetNumPiPlus());
426  nPiMinus = static_cast<int>(descriptor.GetNumPiMinus());
427  nPhotons = static_cast<int>(descriptor.GetNumPhotons());
428  nProtons = static_cast<int>(descriptor.GetNumProtons());
429  }
430  catch (...)
431  {
432  }
433 
434  for (const LArHierarchyHelper::RecoHierarchy::Node *pRecoNode : nodeVector)
435  {
436  const int sliceId{static_cast<int>(
437  std::distance(rootPfos.begin(), std::find(rootPfos.begin(), rootPfos.end(), recoNodeToRootMap[pRecoNode])))};
438  recoSliceIdVector.emplace_back(sliceId);
439  recoIdVector.emplace_back(pRecoNode->GetParticleId());
440  nRecoHitsVector.emplace_back(static_cast<int>(matches.GetSelectedRecoHits(pRecoNode).size()));
441  const CaloHitList recoCaloHits{pRecoNode->GetCaloHits()};
442  float recoTotalMipEnergy{0};
443  for (const CaloHit *pCaloHit : recoCaloHits)
444  {
445  recoTotalMipEnergy += pCaloHit->GetMipEquivalentEnergy();
446  }
447  recoTotalAdcVector.emplace_back(recoTotalMipEnergy);
448  nSharedHitsVector.emplace_back(static_cast<int>(matches.GetSharedHits(pRecoNode)));
449  purityVector.emplace_back(matches.GetPurity(pRecoNode));
450  completenessVector.emplace_back(matches.GetCompleteness(pRecoNode));
451  purityAdcVector.emplace_back(matches.GetPurity(pRecoNode, true));
452  completenessAdcVector.emplace_back(matches.GetCompleteness(pRecoNode, true));
453  purityVectorU.emplace_back(matches.GetPurity(pRecoNode, TPC_VIEW_U));
454  purityVectorV.emplace_back(matches.GetPurity(pRecoNode, TPC_VIEW_V));
455  purityVectorW.emplace_back(matches.GetPurity(pRecoNode, TPC_VIEW_W));
456  completenessVectorU.emplace_back(matches.GetCompleteness(pRecoNode, TPC_VIEW_U));
457  completenessVectorV.emplace_back(matches.GetCompleteness(pRecoNode, TPC_VIEW_V));
458  completenessVectorW.emplace_back(matches.GetCompleteness(pRecoNode, TPC_VIEW_W));
459  purityAdcVectorU.emplace_back(matches.GetPurity(pRecoNode, TPC_VIEW_U, true));
460  purityAdcVectorV.emplace_back(matches.GetPurity(pRecoNode, TPC_VIEW_V, true));
461  purityAdcVectorW.emplace_back(matches.GetPurity(pRecoNode, TPC_VIEW_W, true));
462  completenessAdcVectorU.emplace_back(matches.GetCompleteness(pRecoNode, TPC_VIEW_U, true));
463  completenessAdcVectorV.emplace_back(matches.GetCompleteness(pRecoNode, TPC_VIEW_V, true));
464  completenessAdcVectorW.emplace_back(matches.GetCompleteness(pRecoNode, TPC_VIEW_W, true));
465  if (nMatches > 0)
466  {
467  try
468  {
469  const CartesianVector recoVertex{isSignal == 1 ? LArPfoHelper::GetVertex(pRecoNode->GetLeadingPfo())->GetPosition() : null};
470  recoVtxX = recoVertex.GetX();
471  recoVtxY = recoVertex.GetY();
472  recoVtxZ = recoVertex.GetZ();
473  vtxDx = recoVtxX - trueVtxX;
474  vtxDy = recoVtxY - trueVtxY;
475  vtxDz = recoVtxZ - trueVtxZ;
476  vtxDr = std::sqrt(vtxDx * vtxDx + vtxDy * vtxDy + vtxDz * vtxDz);
477  }
478  catch (StatusCodeException &)
479  {
480  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
481  std::cout << "HierarchyValidationAlgorithm::MCValidation could not retrieve recoVertex" << std::endl;
482  }
483  }
484  }
485 
486  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "event", m_event));
487  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "interaction", interaction));
488  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcId", mcId));
489  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcPDG", pdg));
490  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcTier", tier));
491  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcNHits", mcHits));
492  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcMtm", mcMtm));
493  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcMtmX", mcMtmX));
494  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcMtmY", mcMtmY));
495  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcMtmZ", mcMtmZ));
496  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcEnergy", mcEnergy));
497  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "recoTotalAdc", &recoTotalAdcVector));
498  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "mcTotalAdc", mcTotalMipEnergy));
499  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isSignal", isSignal));
500  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isNuInteraction", isNeutrinoInt));
501  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isCosmicRay", isCosmicRay));
502  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isTestBeam", isTestBeam));
503  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isLeadingLepton", isLeadingLepton));
504  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isMichel", isMichel));
505  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nMatches", nMatches));
506  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "recoSliceIdVector", &recoSliceIdVector));
507  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "recoIdVector", &recoIdVector));
508  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nRecoHitsVector", &nRecoHitsVector));
509  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nSharedHitsVector", &nSharedHitsVector));
510  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityVector", &purityVector));
511  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessVector", &completenessVector));
512  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityAdcVector", &purityAdcVector));
513  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessAdcVector", &completenessAdcVector));
514  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityVectorU", &purityVectorU));
515  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityVectorV", &purityVectorV));
516  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityVectorW", &purityVectorW));
517  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessVectorU", &completenessVectorU));
518  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessVectorV", &completenessVectorV));
519  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessVectorW", &completenessVectorW));
520  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityAdcVectorU", &purityAdcVectorU));
521  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityAdcVectorV", &purityAdcVectorV));
522  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "purityAdcVectorW", &purityAdcVectorW));
523  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessAdcVectorU", &completenessAdcVectorU));
524  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessAdcVectorV", &completenessAdcVectorV));
525  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "completenessAdcVectorW", &completenessAdcVectorW));
526  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "recoVtxX", recoVtxX));
527  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "recoVtxY", recoVtxY));
528  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "recoVtxZ", recoVtxZ));
529  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "trueVtxX", trueVtxX));
530  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "trueVtxY", trueVtxY));
531  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "trueVtxZ", trueVtxZ));
532  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "vtxDx", vtxDx));
533  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "vtxDy", vtxDy));
534  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "vtxDz", vtxDz));
535  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "vtxDr", vtxDr));
536  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isCC", isCC));
537  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isQE", isQE));
538  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isResonant", isResonant));
539  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isDIS", isDIS));
540  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isCoherent", isCoherent));
541  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isNuMu", isNuMu));
542  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "isNuE", isNuE));
543  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nPiZero", nPiZero));
544  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nPiPlus", nPiPlus));
545  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nPiMinus", nPiMinus));
546  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nPhotons", nPhotons));
547  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_MCTreeName.c_str(), "nProtons", nProtons));
548  PANDORA_MONITORING_API(FillTree(this->GetPandora(), m_MCTreeName.c_str()));
549  }
550  ++interaction;
551  }
552  }
553 }
554 #endif
555 
556 //------------------------------------------------------------------------------------------------------------------------------------------
557 
558 StatusCode HierarchyValidationAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
559 {
560  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "CaloHitListName", m_caloHitListName));
561  if (m_caloHitListName.empty())
562  m_caloHitListName = "CaloHitList2D";
563  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "PfoListName", m_pfoListName));
564  if (m_pfoListName.empty())
565  m_pfoListName = "RecreatedPfos";
566 
567  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "Detector", m_detector));
568 
569  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ValidateEvent", m_validateEvent));
570  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ValidateMC", m_validateMC));
571 
572  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "WriteEventTree", m_writeEventTree));
573  if (m_writeEventTree)
574  {
575  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "EventFileName", m_eventFileName));
576  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "EventTreeName", m_eventTreeName));
577  }
578 
579  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "WriteMCTree", m_writeMCTree));
580  if (m_writeMCTree)
581  {
582  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "MCFileName", m_MCFileName));
583  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "MCTreeName", m_MCTreeName));
584  }
585 
586  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "FoldToPrimaries", m_foldToPrimaries));
587  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "FoldDynamic", m_foldDynamic));
588  PANDORA_RETURN_RESULT_IF_AND_IF(
589  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "FoldToLeadingShowers", m_foldToLeadingShowers));
590 
591  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinPurity", m_minPurity));
592  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCompleteness", m_minCompleteness));
593  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinRecoHits", m_minRecoHits));
594  PANDORA_RETURN_RESULT_IF_AND_IF(
595  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinRecoHitsPerView", m_minRecoHitsPerView));
596  PANDORA_RETURN_RESULT_IF_AND_IF(
597  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinRecoGoodViews", m_minRecoGoodViews));
598  PANDORA_RETURN_RESULT_IF_AND_IF(
599  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "RemoveRecoNeutrons", m_removeRecoNeutrons));
600  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SelectRecoHits", m_selectRecoHits));
601 
602  return STATUS_CODE_SUCCESS;
603 }
604 
605 } // namespace lar_content
unsigned int m_minRecoGoodViews
Minimum number of reconstructed primary good views.
const MCMatchesVector & GetMatches(const pandora::MCParticle *const pRoot) const
Retrieve the vector of matches (this will include null matches - i.e. MC nodes with no corresponding ...
const RecoHierarchy & GetRecoHierarchy() const
Retrieve the reco hierarchy used for the matching.
bool m_foldToTier
Whether or not to apply folding based on particle tier.
bool m_foldToPrimaries
Whether or not to fold the hierarchy back to primary particles.
Header file for the interaction type helper class.
unsigned int m_minRecoHits
Minimum number of reconstructed primary good hits.
void GetRootMCParticles(pandora::MCParticleList &rootMCParticles) const
Retrieve the root MC particles of the interaction hierarchies.
bool m_foldToLeadingShowers
Whether or not to fold the hierarchy back to leading shower particles.
bool m_writeEventTree
Whether or not to output event validation information to a ROOT file.
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
bool m_writeMCTree
Whether or not to output MC validation information to a ROOT file.
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< int > IntVector
static void MatchHierarchies(MatchInfo &matchInfo)
Finds the matches between reconstructed and MC hierarchies.
float m_minPurity
Minimum purity to tag a node as being of good quality.
std::string m_MCFileName
The name of the MC ROOT file to write.
TFile f
Definition: plotHisto.C:6
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
bool m_removeRecoNeutrons
Whether to remove reconstructed neutrons and their downstream particles.
bool m_selectRecoHits
Whether to select reco hits that overlap with the MC particle hits.
static void FillRecoHierarchy(const pandora::PfoList &pfoList, const FoldingParameters &foldParameters, RecoHierarchy &hierarchy)
Fill a reconstructed hierarchy based on the specified folding criteria (see RecoHierarchy::FillHierar...
const pandora::MCParticle * GetLeadingMCParticle() const
Retrieve the leading MC particle associated with this node.
std::string m_eventTreeName
The name of the event ROOT tree to write.
static const pandora::MCParticle * GetParentMCParticle(const pandora::MCParticle *const pMCParticle)
Get the parent mc particle.
float m_minCompleteness
Minimum completeness to tag a node as being of good quality.
static bool IsInFiducialVolume(const pandora::Pandora &pandora, const pandora::CartesianVector &vertex, const std::string &detector)
Determine if a vertex is within a detector&#39;s fiducial volume. This throws a STATUS_CODE_INVALID_PARAM...
std::string m_MCTreeName
The name of the MC ROOT tree to write.
static bool IsDecay(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle comes from a decay process.
const QualityCuts & GetQualityCuts() const
Retrieve the quality cuts for matching.
std::string m_pfoListName
Name of input PFO list.
bool m_foldDynamic
Whether or not to use process and topological information to make folding decisions.
Header file for the vertex helper class.
bool m_foldDynamic
Whether or not to fold the hierarchy dynamically.
void Print(const MCHierarchy &mcHierarchy) const
Prints information about which reco nodes are matched to the MC nodes, information about hit sharing...
bool m_foldToLeadingShowers
Whether or not to fold shower children to the leading shower particle.
std::string m_caloHitListName
Name of input calo hit list.
std::vector< MCMatches > MCMatchesVector
std::string m_eventFileName
The name of the event ROOT file to write.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void GetRootPfos(pandora::PfoList &rootPfos) const
Retrieve the root particle flow objects of the interaction hierarchies.
static void FillMCHierarchy(const pandora::MCParticleList &mcParticleList, const pandora::CaloHitList &caloHitList, const FoldingParameters &foldParameters, MCHierarchy &hierarchy)
Fill an MC hierarchy based on the specified folding criteria (see MCHierarchy::FillHierarchy for deta...
unsigned int GetNMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of MC nodes available to match.
unsigned int m_minRecoHitsPerView
Minimum number of reconstructed hits for a good view.
static InteractionDescriptor GetInteractionDescriptor(const pandora::MCParticleList &mcPrimaryList)
Get the interaction descriptor of an event.
bool m_validateMC
Whether to validate at the level of MC nodes.
bool IsCC() const
Whether or not the interaction is CC.
Header file for the hierarchy validation algorithm.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
bool m_validateEvent
Whether to validate at the level of an event.