23 m_foldToLeadingShowers{false},
26 m_cosAngleTolerance{0.9962f},
34 m_foldToLeadingShowers{false},
36 m_foldDynamic{foldDynamic},
37 m_cosAngleTolerance{cosAngleTolerance},
45 m_foldToLeadingShowers{false},
48 m_cosAngleTolerance{0.9962f},
53 std::cout <<
"LArHierarchyHelper: Error - attempting to fold to non-positive tier" << std::endl;
68 m_minPurity{minPurity},
69 m_minCompleteness{minCompleteness}
90 for (
const auto &[pRoot, nodeVector] : m_interactions)
93 for (
const Node *pNode : nodeVector)
96 m_interactions.clear();
103 const auto predicate = [](
const MCParticle *pMCParticle) {
return std::abs(pMCParticle->GetParticleId()) ==
NEUTRON; };
104 m_mcToHitsMap.clear();
105 for (
const CaloHit *pCaloHit : caloHitList)
110 m_mcToHitsMap[pMCParticle].emplace_back(pCaloHit);
118 for (
const MCParticle *pMCParticle : mcParticleList)
121 if (parentList.empty())
123 rootNodes.emplace_back(pMCParticle);
133 if (m_recoCriteria.m_removeNeutrons)
134 primaries.erase(std::remove_if(primaries.begin(), primaries.end(), predicate), primaries.end());
140 if (!m_recoCriteria.m_removeNeutrons)
151 for (
const MCParticle *pMCParticle : allParticles)
154 if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
156 const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
157 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
160 m_interactions[pRoot].emplace_back(
new Node(*
this, allParticles, allHits));
168 int pdg{std::abs(pPrimary->GetParticleId())};
169 const bool isShower{pdg == E_MINUS || pdg == PHOTON};
170 const bool isNeutron{pdg ==
NEUTRON};
171 if (isShower || (isNeutron && !m_recoCriteria.m_removeNeutrons))
174 for (
const MCParticle *pMCParticle : allParticles)
177 if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
179 const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
180 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
183 Node *pNode{
new Node(*
this, allParticles, allHits)};
184 m_interactions[pRoot].emplace_back(pNode);
185 if (!(isShower || isNeutron))
199 this->InterpretHierarchy(pPrimary, leadingParticles, childParticles, foldParameters.
m_cosAngleTolerance);
201 for (
const MCParticle *pMCParticle : leadingParticles)
204 if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
206 const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
207 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
211 Node *pNode{
new Node(*
this, leadingParticles, allHits)};
212 m_interactions[pRoot].emplace_back(pNode);
213 for (
const MCParticle *pChild : childParticles)
224 for (
const MCParticle *pMCParticle : allParticles)
227 if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
229 const CaloHitList &caloHits(m_mcToHitsMap.at(pMCParticle));
230 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
233 Node *pNode{
new Node(*
this, allParticles, allHits)};
234 m_interactions[pRoot].emplace_back(pNode);
242 Node *pLeadingLepton{
nullptr};
243 float leadingLeptonEnergy{-std::numeric_limits<float>::max()};
244 for (
const Node *pNode : m_interactions[pRoot])
246 const MCParticle *pMC{pNode->GetLeadingMCParticle()};
249 const int pdg{std::abs(pMC->GetParticleId())};
250 if ((pdg == MU_MINUS || pdg == E_MINUS || pdg == TAU_MINUS) && pMC->GetEnergy() > leadingLeptonEnergy)
252 pLeadingLepton =
const_cast<Node *
>(pNode);
253 leadingLeptonEnergy = pMC->GetEnergy();
266 if (m_interactions.find(pRoot) == m_interactions.end())
269 return m_interactions.at(pRoot);
276 for (
auto iter = m_interactions.begin(); iter != m_interactions.end(); ++iter)
277 rootMCParticles.emplace_back(iter->first);
285 leadingParticles.emplace_back(pRoot);
288 for (
const MCParticle *pMCParticle : children)
298 foldCandidates.emplace_back(pMCParticle);
300 childCandidates.emplace_back(pMCParticle);
302 else if (!m_recoCriteria.m_removeNeutrons || (m_recoCriteria.m_removeNeutrons && pLArMCParticle->GetProcess() !=
MC_PROC_N_CAPTURE))
305 childCandidates.emplace_back(pMCParticle);
308 const MCParticle *pBestFoldCandidate{
nullptr};
309 float bestDp{std::numeric_limits<float>::max()};
310 for (
const MCParticle *pMCParticle : foldCandidates)
312 if (foldCandidates.size() == 1)
317 pBestFoldCandidate = pMCParticle;
319 childCandidates.emplace_back(pMCParticle);
329 pBestFoldCandidate = pMCParticle;
335 childCandidates.emplace_back(pMCParticle);
339 if (pBestFoldCandidate)
341 leadingParticles.emplace_back(pBestFoldCandidate);
344 this->CollectContinuations(pBestFoldCandidate, leadingParticles, childCandidates, cosAngleTolerance);
346 for (
const MCParticle *pMCParticle : childCandidates)
349 if (this->IsReconstructable(pMCParticle))
350 childParticles.emplace_back(pMCParticle);
356 for (
const MCParticle *pLocalMCParticle : localHierarchy)
358 if (m_mcToHitsMap.find(pLocalMCParticle) != m_mcToHitsMap.end())
360 const CaloHitList &caloHits(m_mcToHitsMap.at(pLocalMCParticle));
361 localHits.insert(localHits.begin(), caloHits.begin(), caloHits.end());
364 if (this->IsReconstructable(localHits))
365 childParticles.emplace_back(pMCParticle);
377 for (
const MCParticle *pMCParticle : children)
386 foldCandidates.emplace_back(pMCParticle);
388 else if (!m_recoCriteria.m_removeNeutrons || (m_recoCriteria.m_removeNeutrons && pLArMCParticle->GetProcess() !=
MC_PROC_N_CAPTURE))
391 childParticles.emplace_back(pMCParticle);
394 const MCParticle *pBestFoldCandidate{
nullptr};
395 float bestDp{std::numeric_limits<float>::max()};
396 for (
const MCParticle *pMCParticle : foldCandidates)
398 if (foldCandidates.size() == 1)
403 pBestFoldCandidate = pMCParticle;
413 pBestFoldCandidate = pMCParticle;
419 if (pBestFoldCandidate)
421 continuingParticles.emplace_back(pBestFoldCandidate);
422 const MCParticleList &newLeadingParticles{pBestFoldCandidate->GetDaughterList()};
424 childParticles.insert(childParticles.begin(), newLeadingParticles.begin(), newLeadingParticles.end());
426 const auto iter{std::find(childParticles.begin(), childParticles.end(), pBestFoldCandidate)};
427 if (iter != childParticles.end())
428 childParticles.erase(iter);
440 for (
const Node *pNode : m_interactions.at(pRoot))
442 nodeVector.emplace_back(pNode);
443 queue.emplace_back(pNode);
445 while (!queue.empty())
447 const NodeVector &children{queue.front()->GetChildren()};
449 for (
const Node *pChild : children)
451 nodeVector.emplace_back(pChild);
452 queue.emplace_back(pChild);
461 m_nodeToIdMap.insert(std::make_pair(pNode, m_nextNodeId));
470 for (
const auto &[pRoot, nodeVector] : m_interactions)
474 str +=
"=== MC Interaction : PDG " + std::to_string(pLArRoot->GetParticleId()) +
475 " Energy: " + std::to_string(pLArRoot->GetEnergy()) +
" Nuance: " + std::to_string(pLArRoot->GetNuanceCode()) +
"\n";
477 str +=
"=== MC Interaction : PDG " + std::to_string(pRoot->GetParticleId()) +
" Energy: " + std::to_string(pRoot->GetEnergy()) +
"\n";
478 for (
const Node *pNode : nodeVector)
479 str +=
" " + pNode->ToString(
"") +
"\n";
489 if (m_mcToHitsMap.find(pMCParticle) != m_mcToHitsMap.end())
491 unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
492 for (
const CaloHit *pCaloHit : m_mcToHitsMap.at(pMCParticle))
494 const HitType view{pCaloHit->GetHitType()};
502 const unsigned int nHits{nHitsU + nHitsV + nHitsW};
503 unsigned int nGoodViews{0};
504 nGoodViews += nHitsU >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
505 nGoodViews += nHitsV >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
506 nGoodViews += nHitsW >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
508 return nHits >= m_recoCriteria.m_minHits && nGoodViews >= m_recoCriteria.m_minGoodViews;
518 unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
519 for (
const CaloHit *pCaloHit : caloHits)
521 const HitType view{pCaloHit->GetHitType()};
529 const unsigned int nHits{nHitsU + nHitsV + nHitsW};
530 unsigned int nGoodViews{0};
531 nGoodViews += nHitsU >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
532 nGoodViews += nHitsV >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
533 nGoodViews += nHitsW >= m_recoCriteria.m_minHitsForGoodView ? 1 : 0;
535 return nHits >= m_recoCriteria.m_minHits && nGoodViews >= m_recoCriteria.m_minGoodViews;
542 m_hierarchy(hierarchy),
543 m_mainParticle(pMCParticle),
546 m_isLeadingLepton{false}
559 m_hierarchy(hierarchy),
560 m_mcParticles(mcParticleList),
561 m_caloHits(caloHitList),
562 m_mainParticle(nullptr),
565 m_isLeadingLepton{false}
567 if (!mcParticleList.empty())
581 m_mcParticles.clear();
583 for (
const Node *node : m_children)
595 m_hierarchy.InterpretHierarchy(pRoot, leadingParticles, childParticles, foldParameters.
m_cosAngleTolerance);
597 for (
const MCParticle *pMCParticle : leadingParticles)
600 if (m_hierarchy.m_mcToHitsMap.find(pMCParticle) != m_hierarchy.m_mcToHitsMap.end())
602 const CaloHitList &caloHits(m_hierarchy.m_mcToHitsMap.at(pMCParticle));
603 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
607 Node *pNode{
new Node(m_hierarchy, leadingParticles, allHits, this->m_tier + 1)};
608 m_children.emplace_back(pNode);
609 for (
const MCParticle *pChild : childParticles)
616 const bool isShower{pdg == E_MINUS || pdg == PHOTON};
617 const bool isNeutron{pdg ==
NEUTRON};
621 else if (foldParameters.
m_foldToLeadingShowers && (isShower || (isNeutron && !m_hierarchy.m_recoCriteria.m_removeNeutrons)))
623 else if (m_hierarchy.m_recoCriteria.m_removeNeutrons && isNeutron)
627 for (
const MCParticle *pMCParticle : allParticles)
630 if (m_hierarchy.m_mcToHitsMap.find(pMCParticle) != m_hierarchy.m_mcToHitsMap.end())
632 const CaloHitList &caloHits(m_hierarchy.m_mcToHitsMap.at(pMCParticle));
633 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
637 if (!allParticles.empty())
643 if (hasChildren || (!hasChildren && !allHits.empty()))
645 Node *pNode{
new Node(m_hierarchy, allParticles, allHits, this->m_tier + 1)};
646 m_children.emplace_back(pNode);
652 pNode->FillHierarchy(pChild, foldParameters);
664 if (!m_hierarchy.m_recoCriteria.m_removeNeutrons)
674 for (
const MCParticle *pMCParticle : allParticles)
677 if (m_hierarchy.m_mcToHitsMap.find(pMCParticle) != m_hierarchy.m_mcToHitsMap.end())
679 const CaloHitList &caloHits(m_hierarchy.m_mcToHitsMap.at(pMCParticle));
680 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
683 if (!allParticles.empty())
685 Node *pNode{
new Node(m_hierarchy, allParticles, allHits, this->m_tier + 1)};
686 m_children.emplace_back(pNode);
694 return m_hierarchy.m_nodeToIdMap.at(
this);
701 const bool enoughHits{m_caloHits.size() >= m_hierarchy.m_recoCriteria.m_minHits};
704 bool enoughGoodViews{
false};
705 unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
706 for (
const CaloHit *pCaloHit : m_caloHits)
708 switch (pCaloHit->GetHitType())
722 unsigned int nGoodViews{0};
723 if (nHitsU >= m_hierarchy.m_recoCriteria.m_minHitsForGoodView)
725 if (nHitsV >= m_hierarchy.m_recoCriteria.m_minHitsForGoodView)
727 if (nHitsW >= m_hierarchy.m_recoCriteria.m_minHitsForGoodView)
729 if (nGoodViews >= m_hierarchy.m_recoCriteria.m_minGoodViews)
731 enoughGoodViews =
true;
736 return enoughGoodViews;
763 std::string str(prefix +
"PDG: " + std::to_string(m_pdg) +
" Energy: " + std::to_string(m_mainParticle ? m_mainParticle->GetEnergy() : 0) +
764 " Hits: " + std::to_string(m_caloHits.size()) +
"\n");
765 for (
const Node *pChild : m_children)
766 str += pChild->ToString(prefix +
" ");
776 m_minHitsForGoodView{10},
778 m_removeNeutrons{true}
785 m_minHits{obj.m_minHits},
786 m_minHitsForGoodView{obj.m_minHitsForGoodView},
787 m_minGoodViews{obj.m_minGoodViews},
788 m_removeNeutrons{obj.m_removeNeutrons}
795 const unsigned int minHits,
const unsigned int minHitsForGoodView,
const unsigned int minGoodViews,
const bool removeNeutrons) :
797 m_minHitsForGoodView{minHitsForGoodView},
798 m_minGoodViews{minGoodViews},
799 m_removeNeutrons{removeNeutrons}
816 for (
const Node *pNode : nodeVector)
829 const PfoList &parentList{pPfo->GetParentPfoList()};
830 if (parentList.empty())
832 rootNodes.emplace_back(pPfo);
840 PfoList primaries(primarySet.begin(), primarySet.end());
860 int pdg{std::abs(pPrimary->GetParticleId())};
861 const bool isShower{pdg == E_MINUS};
866 allParticles.emplace_back(pPrimary);
871 Node *pNode{
new Node(*
this, allParticles, allHits)};
876 const PfoList &children{pPrimary->GetDaughterPfoList()};
887 PfoList allParticles{pPrimary};
891 Node *pNode{
new Node(*
this, allParticles, allHits)};
894 const PfoList &children{pPrimary->GetDaughterPfoList()};
917 rootPfos.emplace_back(iter->first);
927 nodeVector.emplace_back(pNode);
928 queue.emplace_back(pNode);
930 while (!queue.empty())
932 const NodeVector &children{queue.front()->GetChildren()};
934 for (
const Node *pChild : children)
936 nodeVector.emplace_back(pChild);
937 queue.emplace_back(pChild);
949 str +=
"=== Reco Interaction : PDG " + std::to_string(pRoot->GetParticleId()) +
"\n";
950 for (
const Node *pNode : nodeVector)
951 str +=
" " + pNode->ToString(
"") +
"\n";
961 m_hierarchy{hierarchy},
968 m_pfos.emplace_back(pPfo);
975 m_hierarchy(hierarchy),
979 if (!pfoList.empty())
996 for (
const Node *node : m_children)
1007 const bool isShower{pdg == E_MINUS};
1013 allParticles.emplace_back(pRoot);
1022 if (hasChildren || (!hasChildren && !allHits.empty()))
1024 Node *pNode{
new Node(m_hierarchy, allParticles, allHits)};
1025 m_children.emplace_back(pNode);
1031 pNode->FillHierarchy(pChild, foldParameters);
1045 Node *pNode{
new Node(m_hierarchy, allParticles, allHits)};
1046 m_children.emplace_back(pNode);
1074 std::string str(prefix +
"PDG: " + std::to_string(m_pdg) +
" Hits: " + std::to_string(m_caloHits.size()) +
"\n");
1075 for (
const Node *pChild : m_children)
1076 str += pChild->ToString(prefix +
" ");
1092 m_recoNodes.emplace_back(pReco);
1093 m_sharedHits.emplace_back(nSharedHits);
1100 auto iter{std::find(m_recoNodes.begin(), m_recoNodes.end(), pReco)};
1101 if (iter == m_recoNodes.end())
1103 int index = iter - m_recoNodes.begin();
1105 return static_cast<int>(m_sharedHits[index]);
1112 auto iter{std::find(m_recoNodes.begin(), m_recoNodes.end(), pReco)};
1113 if (iter == m_recoNodes.end())
1117 const CaloHitList &mcHits{m_pMCParticle->GetCaloHits()};
1119 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1121 return this->GetPurity(intersection, recoHits, adcWeighted);
1128 auto iter{std::find(m_recoNodes.begin(), m_recoNodes.end(), pReco)};
1129 if (iter == m_recoNodes.end())
1134 if (pCaloHit->GetHitType() == view)
1135 recoHits.emplace_back(pCaloHit);
1137 for (
const CaloHit *pCaloHit : m_pMCParticle->GetCaloHits())
1138 if (pCaloHit->GetHitType() == view)
1139 mcHits.emplace_back(pCaloHit);
1142 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1144 return this->GetPurity(intersection, recoHits, adcWeighted);
1151 auto iter{std::find(m_recoNodes.begin(), m_recoNodes.end(), pReco)};
1152 if (iter == m_recoNodes.end())
1156 const CaloHitList &mcHits{m_pMCParticle->GetCaloHits()};
1158 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1160 return this->GetCompleteness(intersection, mcHits, adcWeighted);
1167 auto iter{std::find(m_recoNodes.begin(), m_recoNodes.end(), pReco)};
1168 if (iter == m_recoNodes.end())
1173 if (pCaloHit->GetHitType() == view)
1174 recoHits.emplace_back(pCaloHit);
1176 for (
const CaloHit *pCaloHit : m_pMCParticle->GetCaloHits())
1177 if (pCaloHit->GetHitType() == view)
1178 mcHits.emplace_back(pCaloHit);
1181 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1183 return this->GetCompleteness(intersection, mcHits, adcWeighted);
1191 if (!intersection.empty())
1196 for (
const CaloHit *pCaloHit : recoHits)
1197 adcSum += pCaloHit->GetInputEnergy();
1198 if (adcSum > std::numeric_limits<float>::epsilon())
1200 for (
const CaloHit *pCaloHit : intersection)
1201 purity += pCaloHit->GetInputEnergy();
1207 purity = intersection.size() /
static_cast<float>(recoHits.size());
1218 float completeness{0.f};
1219 if (!intersection.empty())
1224 for (
const CaloHit *pCaloHit : mcHits)
1225 adcSum += pCaloHit->GetInputEnergy();
1226 if (adcSum > std::numeric_limits<float>::epsilon())
1228 for (
const CaloHit *pCaloHit : intersection)
1229 completeness += pCaloHit->GetInputEnergy();
1230 completeness /= adcSum;
1235 completeness = intersection.size() /
static_cast<float>(mcHits.size());
1239 return completeness;
1246 if (m_recoNodes.empty())
1249 int nAboveThreshold{0};
1250 if (m_recoNodes.size() != 1)
1253 if (this->GetCompleteness(pNode) > 0.1f)
1255 if (nAboveThreshold != 1)
1259 if (this->GetPurity(m_recoNodes.front()) < qualityCuts.
m_minPurity)
1279 m_mcHierarchy{mcHierarchy},
1280 m_recoHierarchy{recoHierarchy},
1281 m_qualityCuts{qualityCuts}
1290 m_mcHierarchy.GetRootMCParticles(rootMCParticles);
1292 m_recoHierarchy.GetRootPfos(rootPfos);
1293 std::map<const MCHierarchy::Node *, MCMatches> mcToMatchMap;
1295 for (
const MCParticle *
const pRootMC : rootMCParticles)
1298 m_mcHierarchy.GetFlattenedNodes(pRootMC, mcNodes);
1302 m_recoHierarchy.GetFlattenedNodes(pRootPfo, recoNodes);
1305 return lhs->GetCaloHits().size() > rhs->GetCaloHits().size();
1308 return lhs->GetCaloHits().size() > rhs->GetCaloHits().size();
1313 const CaloHitList &recoHits{pRecoNode->GetCaloHits()};
1315 size_t bestSharedHits{0};
1318 if (!pMCNode->IsReconstructable())
1322 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1324 if (!intersection.empty())
1326 const size_t sharedHits{intersection.size()};
1327 if (sharedHits > bestSharedHits)
1329 bestSharedHits = sharedHits;
1330 pBestNode = pMCNode;
1336 auto iter{mcToMatchMap.find(pBestNode)};
1337 if (iter != mcToMatchMap.end())
1340 match.
AddRecoMatch(pRecoNode,
static_cast<int>(bestSharedHits));
1345 match.
AddRecoMatch(pRecoNode,
static_cast<int>(bestSharedHits));
1346 mcToMatchMap.insert(std::make_pair(pBestNode, match));
1351 m_unmatchedReco.emplace_back(pRecoNode);
1357 for (
auto [pMCNode, matches] : mcToMatchMap)
1360 for (
const MCParticle *
const pRootMC : rootMCParticles)
1363 m_mcHierarchy.GetFlattenedNodes(pRootMC, mcNodes);
1364 if (std::find(mcNodes.begin(), mcNodes.end(), pMCNode) != mcNodes.end())
1366 m_matches[pRootMC].emplace_back(matches);
1373 return lhs.
GetMC()->
GetCaloHits().size() > rhs.GetMC()->GetCaloHits().size();
1376 for (
const MCParticle *
const pRootMC : rootMCParticles)
1378 std::sort(m_matches[pRootMC].begin(), m_matches[pRootMC].end(), predicate);
1381 m_mcHierarchy.GetFlattenedNodes(pRootMC, mcNodes);
1385 if (pMCNode->IsReconstructable() && mcToMatchMap.find(pMCNode) == mcToMatchMap.end())
1388 m_matches[pRootMC].emplace_back(match);
1398 if (m_matches.find(pRoot) == m_matches.end())
1401 return static_cast<unsigned int>(m_matches.at(pRoot).size());
1408 if (m_matches.find(pRoot) == m_matches.end())
1411 unsigned int nNodes{0};
1412 for (
const MCMatches &match : m_matches.at(pRoot))
1415 if (!(pNode->IsCosmicRay() || pNode->IsTestBeamParticle()))
1426 if (m_matches.find(pRoot) == m_matches.end())
1429 unsigned int nNodes{0};
1430 for (
const MCMatches &match : m_matches.at(pRoot))
1433 if (pNode->IsCosmicRay())
1444 if (m_matches.find(pRoot) == m_matches.end())
1447 unsigned int nNodes{0};
1448 for (
const MCMatches &match : m_matches.at(pRoot))
1451 if (pNode->IsTestBeamParticle())
1466 for (
const MCParticle *
const pRootMC : rootMCParticles)
1474 if (pMCNode->GetHierarchyTier() == 1)
1476 const MCParticle *
const pLeadingMC{pMCNode->GetLeadingMCParticle()};
1477 primaries.emplace_back(pLeadingMC);
1485 std::cout <<
"=== MC Interaction : PDG " << std::to_string(pLArRoot->GetParticleId())
1486 <<
" Energy: " << std::to_string(pLArRoot->GetEnergy()) <<
" Type: " << descriptor.ToString() << std::endl;
1488 std::cout <<
"=== MC Interaction : PDG " << std::to_string(pRootMC->GetParticleId())
1489 <<
" Energy: " << std::to_string(pRootMC->GetEnergy()) <<
" Type: " << descriptor.ToString() << std::endl;
1491 unsigned int nNeutrinoMCParticles{this->GetNNeutrinoMCNodes(pRootMC)}, nNeutrinoRecoParticles{0};
1492 unsigned int nCosmicMCParticles{this->GetNCosmicRayMCNodes(pRootMC)}, nCosmicRecoParticles{0};
1493 unsigned int nTestBeamMCParticles{this->GetNTestBeamMCNodes(pRootMC)}, nTestBeamRecoParticles{0};
1494 std::cout <<
" === Matches ===" << std::endl;
1495 std::cout << std::fixed << std::setprecision(2);
1496 for (
const MCMatches &match : m_matches.at(pRootMC))
1500 const size_t mcHits{pMCNode->GetCaloHits().size()};
1501 const std::string tag{pMCNode->IsTestBeamParticle() ?
"(Beam) " : pMCNode->IsCosmicRay() ?
"(Cosmic) " :
""};
1502 std::cout <<
" MC " << tag << pdg <<
" hits " << mcHits << std::endl;
1507 const unsigned int recoHits{
static_cast<unsigned int>(pRecoNode->GetCaloHits().size())};
1508 const unsigned int sharedHits{match.GetSharedHits(pRecoNode)};
1509 const float purity{match.GetPurity(pRecoNode)};
1510 const float completeness{match.GetCompleteness(pRecoNode)};
1511 if (completeness > 0.1f)
1512 std::cout <<
" Matched " << sharedHits <<
" out of " << recoHits <<
" with purity " << purity <<
" and completeness "
1513 << completeness << std::endl;
1515 std::cout <<
" (Below threshold) " << sharedHits <<
" out of " << recoHits <<
" with purity " << purity
1516 <<
" and completeness " << completeness << std::endl;
1518 if (nodeVector.empty())
1520 std::cout <<
" Unmatched" << std::endl;
1522 else if (match.IsQuality(this->GetQualityCuts()))
1524 if (pMCNode->IsTestBeamParticle())
1525 ++nTestBeamRecoParticles;
1526 else if (pMCNode->IsCosmicRay())
1527 ++nCosmicRecoParticles;
1529 ++nNeutrinoRecoParticles;
1535 std::cout <<
" Neutrino Interaction Summary:" << std::endl;
1536 if (nNeutrinoMCParticles)
1538 std::cout <<
" Good final state particles: " << nNeutrinoRecoParticles <<
" of " << nNeutrinoMCParticles <<
" : "
1539 << (100 * nNeutrinoRecoParticles /
static_cast<float>(nNeutrinoMCParticles)) <<
"%" << std::endl;
1544 std::cout <<
" Cosmic Ray Interaction Summary:" << std::endl;
1545 std::cout << std::fixed << std::setprecision(1);
1546 if (nCosmicMCParticles)
1548 std::cout <<
" Good cosmics: " << nCosmicRecoParticles <<
" of " << nCosmicMCParticles <<
" : "
1549 << (100 * nCosmicRecoParticles /
static_cast<float>(nCosmicMCParticles)) <<
"%" << std::endl;
1554 std::cout <<
" Test Beam Interaction Summary:" << std::endl;
1555 std::cout << std::fixed << std::setprecision(1);
1556 if (nTestBeamMCParticles)
1558 std::cout <<
" Good test beam particles: " << nTestBeamRecoParticles <<
" of " << nTestBeamMCParticles <<
" : "
1559 << (100 * nTestBeamRecoParticles /
static_cast<float>(nTestBeamMCParticles)) <<
"%" << std::endl;
1561 if (nCosmicMCParticles)
1563 std::cout <<
" Matched cosmics: " << nCosmicRecoParticles <<
" of " << nCosmicMCParticles <<
" : "
1564 << (100 * nCosmicRecoParticles /
static_cast<float>(nCosmicMCParticles)) <<
"%" << std::endl;
1567 if (!this->GetUnmatchedReco().empty())
1568 std::cout <<
" Unmatched reco: " << this->GetUnmatchedReco().size() << std::endl;
1576 for (
auto iter = m_matches.begin(); iter != m_matches.end(); ++iter)
1577 rootMCParticles.emplace_back(iter->first);
1586 hierarchy.
FillHierarchy(mcParticleList, caloHitList, foldParameters);
1613 for (
const MCParticle *
const pMCParticle : visible)
1614 primaries.insert(pMCParticle);
1619 std::cout <<
"LArHierarchyHelper::MCHierarchy::FillHierarchy: MC particle with PDG code " << pRoot->
GetParticleId()
1620 <<
" at address " << pRoot <<
" has no associated primary particle" << std::endl;
1631 primaries.insert(pPfo);
1637 primaries.insert(pRoot);
Header file for the lar hierarchy helper class.
Header file for the interaction type helper class.
Header file defining status codes and relevant preprocessor macros.
bool m_foldToTier
Whether or not to apply folding based on particle tier.
bool m_foldDynamic
Whether or not to use process and topological information to make folding decisions.
float m_cosAngleTolerance
Cosine of the maximum angle at which topologies can be considered continuous.
FoldingParameters()
Default constructor.
int m_tier
If folding to a tier, the tier to be combined with its child particles.
bool m_foldToLeadingShowers
Whether or not to fold shower children to the leading shower particle.
const std::string ToString(const std::string &prefix) const
Produce a string representation of the hierarchy.
bool IsTestBeamParticle() const
Check if this is a test beam particle.
const pandora::CaloHitList & GetCaloHits() const
Retrieve the CaloHits associated with this node.
void FillFlat(const pandora::MCParticle *pRoot)
Fill this node by folding all descendent particles to this node.
void SetLeadingLepton()
Tags the particle as the leading lepton.
virtual ~Node()
Destructor.
void FillHierarchy(const pandora::MCParticle *pRoot, const FoldingParameters &foldParameters)
Recursively fill the hierarchy based on the criteria established for this MCHierarchy.
MCHierarchy & m_hierarchy
The parent MC hierarchy.
pandora::MCParticleList m_mcParticles
The list of MC particles of which this node is composed.
Node(MCHierarchy &hierarchy, const pandora::MCParticle *pMCParticle, const int tier=1)
Create a node with a primary MC particle.
bool IsReconstructable() const
Return whether or not this node should be considered reconstructable.
const pandora::MCParticle * m_mainParticle
The leading MC particle for this node.
int GetId() const
Retrieve the unique ID of this node.
int m_pdg
The PDG code of the leading MC particle for this node.
int GetParticleId() const
Retrieve the PDG code for the leading particle in this node.
pandora::CaloHitList m_caloHits
The list of calo hits of which this node is composed.
bool IsCosmicRay() const
Check if this is a cosmic ray particle.
ReconstructabilityCriteria class.
ReconstructabilityCriteria()
Default constructor.
const NodeVector & GetInteractions(const pandora::MCParticle *pRoot) const
Retrieve the root nodes in this hierarchy.
void GetFlattenedNodes(const pandora::MCParticle *const pRoot, NodeVector &nodeVector) const
Retrieve a flat vector of the ndoes in the hierarchy.
const std::string ToString() const
Produce a string representation of the hierarchy.
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....
void RegisterNode(const Node *pNode)
Register a node with the hierarchy.
std::list< const Node * > NodeList
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...
void GetRootMCParticles(pandora::MCParticleList &rootMCParticles) const
Retrieve the root MC particles of the interaction hierarchies.
bool IsReconstructable(const pandora::MCParticle *pMCParticle) const
Checks if an individual particle meets reconstructability criteria.
MCHierarchy()
Default constructor.
std::vector< const Node * > NodeVector
MCNodeVectorMap m_interactions
Map from incident particles (e.g. neutrino) to primaries.
virtual ~MCHierarchy()
Destructor.
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 M...
bool IsQuality(const QualityCuts &qualityCuts) const
Get whether this match passes quality cuts.
MCMatches(const MCHierarchy::Node *pMCParticle)
Constructor.
void AddRecoMatch(const RecoHierarchy::Node *pReco, const int nSharedHits)
Add a reconstructed node as a match for this MC node.
float GetCompleteness(const RecoHierarchy::Node *pReco, const bool adcWeighted=false) const
Retrieve the completeness of the match.
const MCHierarchy::Node * GetMC() const
Retrieve the MC node.
unsigned int GetSharedHits(const RecoHierarchy::Node *pReco) const
Retrieve the number of shared hits in the match.
float GetPurity(const RecoHierarchy::Node *pReco, const bool adcWeighted=false) const
Retrieve the purity of the match.
void Print(const MCHierarchy &mcHierarchy) const
Prints information about which reco nodes are matched to the MC nodes, information about hit sharing,...
void GetRootMCParticles(pandora::MCParticleList &rootMCParticles) const
Retrieve the root MC particles of the interaction hierarchies.
unsigned int GetNMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of MC nodes available to match.
unsigned int GetNTestBeamMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of test beam derived MC nodes available to match.
MatchInfo(const MCHierarchy &mcHierarchy, const RecoHierarchy &recoHierarchy)
Default constructor.
unsigned int GetNCosmicRayMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of cosmic ray derived MC nodes available to match.
unsigned int GetNNeutrinoMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of neutrino interaction derived MC nodes available to match.
void Match()
Match the nodes in the MC and reco hierarchies.
QualityCuts()
Default constructor.
const float m_minPurity
The minimum purity for a match to be considered good.
const float m_minCompleteness
The minimum completeness for a match to be considered good.
void FillFlat(const pandora::ParticleFlowObject *pRoot)
Fill this node by folding all descendent particles to this node.
void FillHierarchy(const pandora::ParticleFlowObject *pRoot, const FoldingParameters &foldParameters)
Recursively fill the hierarchy based on the criteria established for this RecoHierarchy.
pandora::CaloHitList m_caloHits
The list of calo hits of which this node is composed.
const pandora::ParticleFlowObject * m_mainPfo
The leading particle flow object for this node.
pandora::PfoList m_pfos
The list of PFOs of which this node is composed.
const pandora::PfoList & GetRecoParticles() const
Retrieve the PFOs associated with this node.
const pandora::CaloHitList & GetCaloHits() const
Retrieve the CaloHits associated with this node.
int m_pdg
The particle ID (track = muon, shower = electron)
const std::string ToString(const std::string &prefix) const
Produce a string representation of the hierarchy.
int GetParticleId() const
Retrieve the PDG code for the leading particle in this node Note, for reco objects the PDG codes repr...
virtual ~Node()
Destructor.
Node(const RecoHierarchy &hierarchy, const pandora::ParticleFlowObject *pPfo)
Create a node with a primary PFO.
std::list< const Node * > NodeList
std::vector< const Node * > NodeVector
void FillHierarchy(const pandora::PfoList &pfoList, const FoldingParameters &foldParameters)
Creates a reconstructed hierarchy representation. Without folding this will be a mirror image of the ...
const NodeVector & GetInteractions(const pandora::ParticleFlowObject *pRoot) const
Retrieve the root nodes in the hierarchy for a given interaction.
void GetRootPfos(pandora::PfoList &rootPfos) const
Retrieve the root particle flow objects of the interaction hierarchies.
void GetFlattenedNodes(const pandora::ParticleFlowObject *const pRoot, NodeVector &nodeVector) const
Retrieve a flat vector of the nodes in the hierarchy.
RecoHierarchy()
Default constructor.
const std::string ToString() const
Produce a string representation of the hierarchy.
virtual ~RecoHierarchy()
Destructor.
static void GetRecoPrimaries(const pandora::ParticleFlowObject *pRoot, PfoSet &primaries)
Retrieves the primary PFOs from a list and returns the root (neutrino) for hierarchy,...
static void GetMCPrimaries(const pandora::MCParticle *pRoot, MCParticleSet &primaries)
Retrieves the primary MC particles from a list and returns the root (neutrino) for hierarchy,...
std::set< const pandora::MCParticle * > MCParticleSet
static void MatchHierarchies(MatchInfo &matchInfo)
Finds the matches between reconstructed and MC hierarchies.
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...
std::vector< MCMatches > MCMatchesVector
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...
std::set< const pandora::ParticleFlowObject * > PfoSet
static InteractionDescriptor GetInteractionDescriptor(const pandora::MCParticleList &mcPrimaryList)
Get the interaction descriptor of an event.
static bool IsCosmicRay(const pandora::MCParticle *const pMCParticle)
Return true if passed a primary cosmic ray MCParticle.
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
static bool IsInelasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an inelastic scattering process.
static void GetFirstVisibleMCParticles(const pandora::MCParticle *const pRoot, pandora::MCParticleList &visibleParticleList)
Get the first visible MC particles given a root particle. For example, given a neutrino this would re...
static void GetAllDescendentMCParticles(const pandora::MCParticle *const pMCParticle, pandora::MCParticleList &descendentMCParticleList)
Get all descendent mc particles.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
static bool IsBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary beam MCParticle.
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....
static bool IsElasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an elastic scattering process.
static int GetHierarchyTier(const pandora::MCParticle *const pMCParticle)
Determine the position in the hierarchy for the MCParticle.
static void GetAllDownstreamPfos(const pandora::PfoList &inputPfoList, pandora::PfoList &outputPfoList)
Get a flat list of all pfos, recursively, of all daughters associated with those pfos in an input lis...
static void GetAllCaloHits(const pandora::ParticleFlowObject *pPfo, pandora::CaloHitList &caloHitList)
Get a list of all calo hits (including isolated) of all types from a given pfo.
static bool IsNeutrino(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a neutrino or (antineutrino)
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
static int GetHierarchyTier(const pandora::ParticleFlowObject *const pPfo)
Determine the position in the hierarchy for the MCParticle.
float GetMagnitude() const
Get the magnitude.
static const MCParticle * GetMainMCParticle(const T *const pT)
Find the mc particle making the largest contribution to a specified calo hit, track or cluster.
const MCParticleList & GetDaughterList() const
Get list of daughters of mc particle.
const CartesianVector & GetMomentum() const
Get momentum of mc particle, units GeV.
const MCParticleList & GetParentList() const
Get list of parents of mc particle.
int GetParticleId() const
Get the PDG code of the mc particle.
ParticleFlowObject class.
const PfoList & GetDaughterPfoList() const
Get the daughter pfo list.
int GetParticleId() const
Get the particle flow object id (PDG code)
StatusCodeException class.
HitType
Calorimeter hit type enum.
MANAGED_CONTAINER< const MCParticle * > MCParticleList
std::vector< const CaloHit * > CaloHitVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList
MANAGED_CONTAINER< const ParticleFlowObject * > PfoList