9 #include "Pandora/PdgTable.h" 10 #include "Pandora/StatusCodes.h" 23 m_foldToLeadingShowers{
false},
53 std::cout <<
"LArHierarchyHelper: Error - attempting to fold to non-positive tier" << std::endl;
54 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
100 for (
const Node *pNode : nodeVector)
103 m_interactions.clear();
110 const auto predicate = [](
const MCParticle *pMCParticle) {
return std::abs(pMCParticle->GetParticleId()) == NEUTRON; };
112 for (
const CaloHit *pCaloHit : caloHitList)
116 const MCParticle *pMCParticle{MCParticleHelper::GetMainMCParticle(pCaloHit)};
119 catch (
const StatusCodeException &)
124 MCParticleList rootNodes;
125 for (
const MCParticle *pMCParticle : mcParticleList)
127 const MCParticleList &parentList{pMCParticle->GetParentList()};
128 if (parentList.empty())
130 rootNodes.emplace_back(pMCParticle);
134 for (
const MCParticle *pRoot : rootNodes)
138 MCParticleList primaries(primarySet.begin(), primarySet.end());
141 primaries.erase(std::remove_if(primaries.begin(), primaries.end(), predicate), primaries.end());
144 for (
const MCParticle *pPrimary : primaries)
146 MCParticleList allParticles{pPrimary};
154 MCParticleList dummy;
158 for (
const MCParticle *pMCParticle : allParticles)
164 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
172 for (
const MCParticle *pPrimary : primaries)
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};
181 for (
const MCParticle *pMCParticle : allParticles)
187 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
190 Node *pNode{
new Node(*
this, allParticles, allHits)};
192 if (!(isShower || isNeutron))
195 const MCParticleList &children{pPrimary->GetDaughterList()};
196 for (
const MCParticle *pChild : children)
197 pNode->FillHierarchy(pChild, foldParameters);
203 for (
const MCParticle *pPrimary : primaries)
205 MCParticleList leadingParticles, childParticles;
208 for (
const MCParticle *pMCParticle : leadingParticles)
214 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
218 Node *pNode{
new Node(*
this, leadingParticles, allHits)};
220 for (
const MCParticle *pChild : childParticles)
221 pNode->FillHierarchy(pChild, foldParameters);
227 for (
const MCParticle *pPrimary : primaries)
229 MCParticleList allParticles{pPrimary};
231 for (
const MCParticle *pMCParticle : allParticles)
237 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
240 Node *pNode{
new Node(*
this, allParticles, allHits)};
243 const MCParticleList &children{pPrimary->GetDaughterList()};
244 for (
const MCParticle *pChild : children)
245 pNode->FillHierarchy(pChild, foldParameters);
249 Node *pLeadingLepton{
nullptr};
250 float leadingLeptonEnergy{-std::numeric_limits<float>::max()};
256 const int pdg{
std::abs(pMC->GetParticleId())};
257 if ((pdg == MU_MINUS || pdg == E_MINUS || pdg == TAU_MINUS) && pMC->GetEnergy() > leadingLeptonEnergy)
259 pLeadingLepton =
const_cast<Node *
>(pNode);
260 leadingLeptonEnergy = pMC->GetEnergy();
274 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
284 rootMCParticles.emplace_back(iter->first);
290 const MCParticle *
const pRoot, MCParticleList &leadingParticles, MCParticleList &childParticles,
const float cosAngleTolerance)
const 292 leadingParticles.emplace_back(pRoot);
293 MCParticleList foldCandidates, childCandidates;
294 const MCParticleList &children{pRoot->GetDaughterList()};
295 for (
const MCParticle *pMCParticle : children)
304 if (pMCParticle->GetParticleId() == pRoot->GetParticleId())
305 foldCandidates.emplace_back(pMCParticle);
307 childCandidates.emplace_back(pMCParticle);
312 childCandidates.emplace_back(pMCParticle);
315 const MCParticle *pBestFoldCandidate{
nullptr};
316 float bestDp{std::numeric_limits<float>::max()};
317 for (
const MCParticle *pMCParticle : foldCandidates)
319 if (foldCandidates.size() == 1)
324 pBestFoldCandidate = pMCParticle;
326 childCandidates.emplace_back(pMCParticle);
333 const float dp{pRoot->GetMomentum().GetMagnitude() - pMCParticle->GetMomentum().GetMagnitude()};
336 pBestFoldCandidate = pMCParticle;
342 childCandidates.emplace_back(pMCParticle);
346 if (pBestFoldCandidate)
348 leadingParticles.emplace_back(pBestFoldCandidate);
351 this->
CollectContinuations(pBestFoldCandidate, leadingParticles, childCandidates, cosAngleTolerance);
353 for (
const MCParticle *pMCParticle : childCandidates)
357 childParticles.emplace_back(pMCParticle);
360 MCParticleList localHierarchy{pMCParticle};
361 CaloHitList localHits;
363 for (
const MCParticle *pLocalMCParticle : localHierarchy)
367 const CaloHitList &caloHits(
m_mcToHitsMap.at(pLocalMCParticle));
368 localHits.insert(localHits.begin(), caloHits.begin(), caloHits.end());
372 childParticles.emplace_back(pMCParticle);
380 const MCParticle *pRoot, MCParticleList &continuingParticles, MCParticleList &childParticles,
const float cosAngleTolerance)
const 382 const MCParticleList &children{pRoot->GetDaughterList()};
383 MCParticleList foldCandidates;
384 for (
const MCParticle *pMCParticle : children)
392 if (pMCParticle->GetParticleId() == pRoot->GetParticleId())
393 foldCandidates.emplace_back(pMCParticle);
398 childParticles.emplace_back(pMCParticle);
401 const MCParticle *pBestFoldCandidate{
nullptr};
402 float bestDp{std::numeric_limits<float>::max()};
403 for (
const MCParticle *pMCParticle : foldCandidates)
405 if (foldCandidates.size() == 1)
410 pBestFoldCandidate = pMCParticle;
417 const float dp{pRoot->GetMomentum().GetMagnitude() - pMCParticle->GetMomentum().GetMagnitude()};
420 pBestFoldCandidate = pMCParticle;
426 if (pBestFoldCandidate)
428 continuingParticles.emplace_back(pBestFoldCandidate);
429 const MCParticleList &newLeadingParticles{pBestFoldCandidate->GetDaughterList()};
431 childParticles.insert(childParticles.begin(), newLeadingParticles.begin(), newLeadingParticles.end());
433 const auto iter{std::find(childParticles.begin(), childParticles.end(), pBestFoldCandidate)};
434 if (iter != childParticles.end())
435 childParticles.erase(iter);
449 nodeVector.emplace_back(pNode);
450 queue.emplace_back(pNode);
452 while (!queue.empty())
454 const NodeVector &children{queue.front()->GetChildren()};
456 for (
const Node *pChild : children)
458 nodeVector.emplace_back(pChild);
459 queue.emplace_back(pChild);
481 str +=
"=== MC Interaction : PDG " +
std::to_string(pLArRoot->GetParticleId()) +
485 for (
const Node *pNode : nodeVector)
486 str +=
" " + pNode->ToString(
"") +
"\n";
498 unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
499 for (
const CaloHit *pCaloHit :
m_mcToHitsMap.at(pMCParticle))
501 const HitType view{pCaloHit->GetHitType()};
502 if (view == TPC_VIEW_U)
504 else if (view == TPC_VIEW_V)
506 else if (view == TPC_VIEW_W)
509 const unsigned int nHits{nHitsU + nHitsV + nHitsW};
510 unsigned int nGoodViews{0};
525 unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
526 for (
const CaloHit *pCaloHit : caloHits)
528 const HitType view{pCaloHit->GetHitType()};
529 if (view == TPC_VIEW_U)
531 else if (view == TPC_VIEW_V)
533 else if (view == TPC_VIEW_W)
536 const unsigned int nHits{nHitsU + nHitsV + nHitsW};
537 unsigned int nGoodViews{0};
549 m_hierarchy(hierarchy),
550 m_mainParticle(pMCParticle),
553 m_isLeadingLepton{
false}
557 m_pdg = pMCParticle->GetParticleId();
558 m_mcParticles.emplace_back(pMCParticle);
560 m_hierarchy.RegisterNode(
this);
566 m_hierarchy(hierarchy),
567 m_mcParticles(mcParticleList),
568 m_caloHits(caloHitList),
569 m_mainParticle(
nullptr),
572 m_isLeadingLepton{
false}
574 if (!mcParticleList.empty())
576 m_mainParticle = mcParticleList.front();
577 m_pdg = m_mainParticle->GetParticleId();
581 m_hierarchy.RegisterNode(
this);
588 m_mcParticles.clear();
590 for (
const Node *node : m_children)
601 MCParticleList leadingParticles, childParticles;
602 m_hierarchy.InterpretHierarchy(pRoot, leadingParticles, childParticles, foldParameters.
m_cosAngleTolerance);
604 for (
const MCParticle *pMCParticle : leadingParticles)
607 if (m_hierarchy.m_mcToHitsMap.find(pMCParticle) != m_hierarchy.m_mcToHitsMap.end())
609 const CaloHitList &caloHits(m_hierarchy.m_mcToHitsMap.at(pMCParticle));
610 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
614 Node *pNode{
new Node(m_hierarchy, leadingParticles, allHits, this->m_tier + 1)};
615 m_children.emplace_back(pNode);
616 for (
const MCParticle *pChild : childParticles)
621 MCParticleList allParticles{pRoot};
622 const int pdg{
std::abs(pRoot->GetParticleId())};
623 const bool isShower{pdg == E_MINUS || pdg == PHOTON};
624 const bool isNeutron{pdg == NEUTRON};
628 else if (foldParameters.
m_foldToLeadingShowers && (isShower || (isNeutron && !m_hierarchy.m_recoCriteria.m_removeNeutrons)))
630 else if (m_hierarchy.m_recoCriteria.m_removeNeutrons && isNeutron)
634 for (
const MCParticle *pMCParticle : allParticles)
637 if (m_hierarchy.m_mcToHitsMap.find(pMCParticle) != m_hierarchy.m_mcToHitsMap.end())
639 const CaloHitList &caloHits(m_hierarchy.m_mcToHitsMap.at(pMCParticle));
640 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
644 if (!allParticles.empty())
650 if (hasChildren || (!hasChildren && !allHits.empty()))
652 Node *pNode{
new Node(m_hierarchy, allParticles, allHits, this->m_tier + 1)};
653 m_children.emplace_back(pNode);
657 const MCParticleList &children{pRoot->GetDaughterList()};
658 for (
const MCParticle *pChild : children)
670 MCParticleList allParticles{pRoot};
671 if (!m_hierarchy.m_recoCriteria.m_removeNeutrons)
681 for (
const MCParticle *pMCParticle : allParticles)
684 if (m_hierarchy.m_mcToHitsMap.find(pMCParticle) != m_hierarchy.m_mcToHitsMap.end())
686 const CaloHitList &caloHits(m_hierarchy.m_mcToHitsMap.at(pMCParticle));
687 allHits.insert(allHits.begin(), caloHits.begin(), caloHits.end());
690 if (!allParticles.empty())
692 Node *pNode{
new Node(m_hierarchy, allParticles, allHits, this->m_tier + 1)};
693 m_children.emplace_back(pNode);
701 return m_hierarchy.m_nodeToIdMap.at(
this);
708 const bool enoughHits{m_caloHits.size() >= m_hierarchy.m_recoCriteria.m_minHits};
711 bool enoughGoodViews{
false};
712 unsigned int nHitsU{0}, nHitsV{0}, nHitsW{0};
713 for (
const CaloHit *pCaloHit : m_caloHits)
715 switch (pCaloHit->GetHitType())
729 unsigned int nGoodViews{0};
730 if (nHitsU >= m_hierarchy.m_recoCriteria.m_minHitsForGoodView)
732 if (nHitsV >= m_hierarchy.m_recoCriteria.m_minHitsForGoodView)
734 if (nHitsW >= m_hierarchy.m_recoCriteria.m_minHitsForGoodView)
736 if (nGoodViews >= m_hierarchy.m_recoCriteria.m_minGoodViews)
738 enoughGoodViews =
true;
743 return enoughGoodViews;
770 std::string str(prefix +
"PDG: " +
std::to_string(m_pdg) +
" Energy: " +
std::to_string(m_mainParticle ? m_mainParticle->GetEnergy() : 0) +
772 for (
const Node *pChild : m_children)
773 str += pChild->ToString(prefix +
" ");
802 const unsigned int minHits,
const unsigned int minHitsForGoodView,
const unsigned int minGoodViews,
const bool removeNeutrons) :
823 for (
const Node *pNode : nodeVector)
826 m_interactions.clear();
834 for (
const ParticleFlowObject *pPfo : pfoList)
836 const PfoList &parentList{pPfo->GetParentPfoList()};
837 if (parentList.empty())
839 rootNodes.emplace_back(pPfo);
843 for (
const ParticleFlowObject *
const pRoot : rootNodes)
847 PfoList primaries(primarySet.begin(), primarySet.end());
851 for (
const ParticleFlowObject *pPrimary : primaries)
853 PfoList allParticles;
857 for (
const ParticleFlowObject *pPfo : allParticles)
864 for (
const ParticleFlowObject *pPrimary : primaries)
866 PfoList allParticles;
867 int pdg{
std::abs(pPrimary->GetParticleId())};
868 const bool isShower{pdg == E_MINUS};
873 allParticles.emplace_back(pPrimary);
876 for (
const ParticleFlowObject *pPfo : allParticles)
878 Node *pNode{
new Node(*
this, allParticles, allHits)};
883 const PfoList &children{pPrimary->GetDaughterPfoList()};
884 for (
const ParticleFlowObject *pChild : children)
885 pNode->FillHierarchy(pChild, foldParameters);
892 for (
const ParticleFlowObject *pPrimary : primaries)
894 PfoList allParticles{pPrimary};
896 for (
const ParticleFlowObject *pPfo : allParticles)
898 Node *pNode{
new Node(*
this, allParticles, allHits)};
901 const PfoList &children{pPrimary->GetDaughterPfoList()};
902 for (
const ParticleFlowObject *pChild : children)
914 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
924 rootPfos.emplace_back(iter->first);
934 nodeVector.emplace_back(pNode);
935 queue.emplace_back(pNode);
937 while (!queue.empty())
939 const NodeVector &children{queue.front()->GetChildren()};
941 for (
const Node *pChild : children)
943 nodeVector.emplace_back(pChild);
944 queue.emplace_back(pChild);
956 str +=
"=== Reco Interaction : PDG " +
std::to_string(pRoot->GetParticleId()) +
"\n";
957 for (
const Node *pNode : nodeVector)
958 str +=
" " + pNode->ToString(
"") +
"\n";
968 m_hierarchy{hierarchy},
975 m_pdg = pPfo->GetParticleId();
976 m_pfos.emplace_back(pPfo);
988 if (!pfoList.empty())
991 m_pdg = pfoList.front()->GetParticleId();
1014 PfoList allParticles;
1015 int pdg{
std::abs(pRoot->GetParticleId())};
1016 const bool isShower{pdg == E_MINUS};
1022 allParticles.emplace_back(pRoot);
1024 CaloHitList allHits;
1025 for (
const ParticleFlowObject *pPfo : allParticles)
1030 if (hasChildren || (!hasChildren && !allHits.empty()))
1037 const PfoList &children{pRoot->GetDaughterPfoList()};
1038 for (
const ParticleFlowObject *pChild : children)
1039 pNode->FillHierarchy(pChild, foldParameters);
1048 PfoList allParticles;
1050 CaloHitList allHits;
1051 for (
const ParticleFlowObject *pPfo : allParticles)
1085 str += pChild->ToString(prefix +
" ");
1094 m_pMCParticle{pMCParticle}
1113 return iter->second;
1124 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1136 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1140 CaloHitVector intersection;
1141 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1143 return this->
GetPurity(intersection, recoHits, adcWeighted);
1152 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1154 CaloHitList recoHits;
1156 if (pCaloHit->GetHitType() == view)
1157 recoHits.emplace_back(pCaloHit);
1160 if (pCaloHit->GetHitType() == view)
1161 mcHits.emplace_back(pCaloHit);
1163 CaloHitVector intersection;
1164 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1166 return this->
GetPurity(intersection, recoHits, adcWeighted);
1175 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1179 CaloHitVector intersection;
1180 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1191 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1193 CaloHitList recoHits;
1195 if (pCaloHit->GetHitType() == view)
1196 recoHits.emplace_back(pCaloHit);
1199 if (pCaloHit->GetHitType() == view)
1200 mcHits.emplace_back(pCaloHit);
1202 CaloHitVector intersection;
1203 std::set_intersection(mcHits.begin(), mcHits.end(), recoHits.begin(), recoHits.end(), std::back_inserter(intersection));
1213 if (!intersection.empty())
1218 for (
const CaloHit *pCaloHit : recoHits)
1219 adcSum += pCaloHit->GetInputEnergy();
1220 if (adcSum > std::numeric_limits<float>::epsilon())
1222 for (
const CaloHit *pCaloHit : intersection)
1223 purity += pCaloHit->GetInputEnergy();
1229 purity = intersection.size() /
static_cast<float>(recoHits.size());
1240 float completeness{0.f};
1241 if (!intersection.empty())
1246 for (
const CaloHit *pCaloHit : mcHits)
1247 adcSum += pCaloHit->GetInputEnergy();
1248 if (adcSum > std::numeric_limits<float>::epsilon())
1250 for (
const CaloHit *pCaloHit : intersection)
1251 completeness += pCaloHit->GetInputEnergy();
1252 completeness /= adcSum;
1257 completeness = intersection.size() /
static_cast<float>(mcHits.size());
1261 return completeness;
1271 int nAboveThreshold{0};
1277 if (nAboveThreshold != 1)
1311 MCParticleList rootMCParticles;
1315 std::map<const MCHierarchy::Node *, MCMatches> mcToMatchMap;
1317 for (
const MCParticle *
const pRootMC : rootMCParticles)
1323 CaloHitList allMCHits;
1326 const CaloHitList &mcHits{pMCNode->GetCaloHits()};
1327 allMCHits.insert(allMCHits.begin(), mcHits.begin(), mcHits.end());
1330 for (
const ParticleFlowObject *
const pRootPfo : rootPfos)
1335 std::sort(mcNodes.begin(), mcNodes.end(),
1337 {
return lhs->
GetCaloHits().size() > rhs->GetCaloHits().size(); });
1338 std::sort(recoNodes.begin(), recoNodes.end(),
1340 {
return lhs->
GetCaloHits().size() > rhs->GetCaloHits().size(); });
1348 : pRecoNode->GetCaloHits();
1351 size_t bestSharedHits{0};
1354 if (!pMCNode->IsReconstructable())
1356 const CaloHitList &mcHits{pMCNode->
GetCaloHits()};
1357 CaloHitVector intersection;
1358 std::set_intersection(
1359 mcHits.begin(), mcHits.end(), selectedRecoHits.begin(), selectedRecoHits.end(), std::back_inserter(intersection));
1361 if (!intersection.empty())
1363 const size_t sharedHits{intersection.size()};
1364 if (sharedHits > bestSharedHits)
1366 bestSharedHits = sharedHits;
1367 pBestNode = pMCNode;
1373 auto iter{mcToMatchMap.find(pBestNode)};
1374 if (iter != mcToMatchMap.end())
1377 match.
AddRecoMatch(pRecoNode, static_cast<int>(bestSharedHits), selectedRecoHits);
1382 match.
AddRecoMatch(pRecoNode, static_cast<int>(bestSharedHits), selectedRecoHits);
1383 mcToMatchMap.insert(std::make_pair(pBestNode, match));
1394 for (
auto [pMCNode, matches] : mcToMatchMap)
1397 for (
const MCParticle *
const pRootMC : rootMCParticles)
1401 if (std::find(mcNodes.begin(), mcNodes.end(), pMCNode) != mcNodes.end())
1403 m_matches[pRootMC].emplace_back(matches);
1410 {
return lhs.
GetMC()->
GetCaloHits().size() > rhs.GetMC()->GetCaloHits().size(); };
1412 for (
const MCParticle *
const pRootMC : rootMCParticles)
1421 if (pMCNode->IsReconstructable() && mcToMatchMap.find(pMCNode) == mcToMatchMap.end())
1435 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1437 return static_cast<unsigned int>(
m_matches.at(pRoot).size());
1445 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1447 unsigned int nNodes{0};
1451 if (!(pNode->IsCosmicRay() || pNode->IsTestBeamParticle()))
1463 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1465 unsigned int nNodes{0};
1469 if (pNode->IsCosmicRay())
1481 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
1483 unsigned int nNodes{0};
1487 if (pNode->IsTestBeamParticle())
1499 CaloHitList selectedHits;
1502 const CaloHitList recoHits{pRecoNode->
GetCaloHits()};
1503 for (
const CaloHit *pRecoHit : recoHits)
1505 const int recoId =
reinterpret_cast<intptr_t
>(pRecoHit->GetParentAddress());
1506 for (
const CaloHit *pMCHit : allMCHits)
1508 const int mcId =
reinterpret_cast<intptr_t
>(pMCHit->GetParentAddress());
1511 selectedHits.emplace_back(pRecoHit);
1517 return selectedHits;
1524 MCParticleList rootMCParticles;
1527 for (
const MCParticle *
const pRootMC : rootMCParticles)
1531 MCParticleList primaries;
1535 if (pMCNode->GetHierarchyTier() == 1)
1538 primaries.emplace_back(pLeadingMC);
1541 if (primaries.size() == 0)
1548 std::cout <<
"=== MC Interaction : PDG " <<
std::to_string(pLArRoot->GetParticleId())
1549 <<
" Energy: " <<
std::to_string(pLArRoot->GetEnergy()) <<
" Type: " << descriptor.ToString() << std::endl;
1551 std::cout <<
"=== MC Interaction : PDG " <<
std::to_string(pRootMC->GetParticleId())
1552 <<
" Energy: " <<
std::to_string(pRootMC->GetEnergy()) <<
" Type: " << descriptor.ToString() << std::endl;
1554 unsigned int nNeutrinoMCParticles{this->
GetNNeutrinoMCNodes(pRootMC)}, nNeutrinoRecoParticles{0};
1556 unsigned int nTestBeamMCParticles{this->
GetNTestBeamMCNodes(pRootMC)}, nTestBeamRecoParticles{0};
1557 std::cout <<
" === Matches ===" << std::endl;
1558 std::cout << std::fixed << std::setprecision(2);
1563 const size_t mcHits{pMCNode->GetCaloHits().size()};
1564 const std::string tag{pMCNode->IsTestBeamParticle() ?
"(Beam) " : pMCNode->IsCosmicRay() ?
"(Cosmic) " :
""};
1565 std::cout <<
" MC " << tag << pdg <<
" hits " << mcHits << std::endl;
1570 const CaloHitList recoHits = match.GetSelectedRecoHits(pRecoNode);
1571 const unsigned int nRecoHits{
static_cast<unsigned int>(recoHits.size())};
1572 const unsigned int sharedHits{match.GetSharedHits(pRecoNode)};
1573 const float purity{match.GetPurity(pRecoNode)};
1574 const float completeness{match.GetCompleteness(pRecoNode)};
1575 if (completeness > 0.1
f)
1576 std::cout <<
" Matched " << sharedHits <<
" out of " << nRecoHits <<
" with purity " << purity <<
" and completeness " 1577 << completeness << std::endl;
1579 std::cout <<
" (Below threshold) " << sharedHits <<
" out of " << nRecoHits <<
" with purity " << purity
1580 <<
" and completeness " << completeness << std::endl;
1582 if (nodeVector.empty())
1584 std::cout <<
" Unmatched" << std::endl;
1586 else if (match.IsQuality(this->GetQualityCuts()))
1588 if (pMCNode->IsTestBeamParticle())
1589 ++nTestBeamRecoParticles;
1590 else if (pMCNode->IsCosmicRay())
1591 ++nCosmicRecoParticles;
1593 ++nNeutrinoRecoParticles;
1599 std::cout <<
" Neutrino Interaction Summary:" << std::endl;
1600 if (nNeutrinoMCParticles)
1602 std::cout <<
" Good final state particles: " << nNeutrinoRecoParticles <<
" of " << nNeutrinoMCParticles <<
" : " 1603 << (100 * nNeutrinoRecoParticles /
static_cast<float>(nNeutrinoMCParticles)) <<
"%" << std::endl;
1608 std::cout <<
" Cosmic Ray Interaction Summary:" << std::endl;
1609 std::cout << std::fixed << std::setprecision(1);
1610 if (nCosmicMCParticles)
1612 std::cout <<
" Good cosmics: " << nCosmicRecoParticles <<
" of " << nCosmicMCParticles <<
" : " 1613 << (100 * nCosmicRecoParticles /
static_cast<float>(nCosmicMCParticles)) <<
"%" << std::endl;
1618 std::cout <<
" Test Beam Interaction Summary:" << std::endl;
1619 std::cout << std::fixed << std::setprecision(1);
1620 if (nTestBeamMCParticles)
1622 std::cout <<
" Good test beam particles: " << nTestBeamRecoParticles <<
" of " << nTestBeamMCParticles <<
" : " 1623 << (100 * nTestBeamRecoParticles /
static_cast<float>(nTestBeamMCParticles)) <<
"%" << std::endl;
1625 if (nCosmicMCParticles)
1627 std::cout <<
" Matched cosmics: " << nCosmicRecoParticles <<
" of " << nCosmicMCParticles <<
" : " 1628 << (100 * nCosmicRecoParticles /
static_cast<float>(nCosmicMCParticles)) <<
"%" << std::endl;
1632 std::cout <<
" Unmatched reco: " << this->
GetUnmatchedReco().size() << std::endl;
1641 rootMCParticles.emplace_back(iter->first);
1650 hierarchy.
FillHierarchy(mcParticleList, caloHitList, foldParameters);
1674 MCParticleList visible;
1677 for (
const MCParticle *
const pMCParticle : visible)
1678 primaries.insert(pMCParticle);
1680 catch (
const StatusCodeException &)
1682 if (pRoot->GetParticleId() != 111 && pRoot->GetParticleId() < 1e9)
1683 std::cout <<
"LArHierarchyHelper::MCHierarchy::FillHierarchy: MC particle with PDG code " << pRoot->GetParticleId()
1684 <<
" at address " << pRoot <<
" has no associated primary particle" << std::endl;
1692 const PfoList &children{pRoot->GetDaughterPfoList()};
1694 for (
const ParticleFlowObject *
const pPfo : children)
1695 primaries.insert(pPfo);
1701 primaries.insert(pRoot);
static void GetRecoPrimaries(const pandora::ParticleFlowObject *pRoot, PfoSet &primaries)
Retrieves the primary PFOs from a list and returns the root (neutrino) for hierarchy, if it exists.
int m_tier
The hierarchy tier for this node.
const pandora::CaloHitList & GetCaloHits() const
Retrieve the CaloHits associated with this node.
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...
const unsigned int m_minHitsForGoodView
the minimum number of Hits for a good view
std::set< const pandora::MCParticle * > MCParticleSet
FoldingParameters()
Default constructor.
void GetRootMCParticles(pandora::MCParticleList &rootMCParticles) const
Retrieve the root MC particles of the interaction hierarchies.
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
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 ...
void GetFlattenedNodes(const pandora::MCParticle *const pRoot, NodeVector &nodeVector) const
Retrieve a flat vector of the ndoes in the hierarchy.
const pandora::CaloHitList GetSelectedRecoHits(const RecoHierarchy::Node *pReco) const
Retrieve the selected hits for the given reco node.
const MCHierarchy::Node * m_pMCParticle
MC node associated with any matches.
bool m_foldToTier
Whether or not to apply folding based on particle tier.
int m_tier
If folding to a tier, the tier to be combined with its child particles.
Header file for the interaction type helper class.
RecoHierarchy::NodeVector m_recoNodes
Matched reco nodes.
const NodeVector & GetInteractions(const pandora::ParticleFlowObject *pRoot) const
Retrieve the root nodes in the hierarchy for a given interaction.
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...
const std::string ToString() const
Produce a string representation of the hierarchy.
std::vector< const Node * > NodeVector
pandora::IntVector m_sharedHits
Number of shared hits for each match.
void GetRootMCParticles(pandora::MCParticleList &rootMCParticles) const
Retrieve the root MC particles of the interaction hierarchies.
const std::string ToString(const std::string &prefix) const
Produce a string representation of the hierarchy.
std::map< const pandora::MCParticle *, pandora::CaloHitList > m_mcToHitsMap
The map between MC particles and calo hits.
MCHierarchy()
Default constructor.
constexpr auto abs(T v)
Returns the absolute value of the argument.
ReconstructabilityCriteria()
Default constructor.
static int GetHierarchyTier(const pandora::MCParticle *const pMCParticle)
Determine the position in the hierarchy for the MCParticle.
static void GetMCPrimaries(const pandora::MCParticle *pRoot, MCParticleSet &primaries)
Retrieves the primary MC particles from a list and returns the root (neutrino) for hierarchy...
const RecoHierarchy & m_hierarchy
The parent reco hierarchy.
int m_pdg
The particle ID (track = muon, shower = electron)
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...
QualityCuts m_qualityCuts
The quality cuts to be applied to matches.
virtual ~RecoHierarchy()
Destructor.
const pandora::CaloHitList & GetCaloHits() const
Retrieve the CaloHits associated with this node.
MatchInfo(const MCHierarchy &mcHierarchy, const RecoHierarchy &recoHierarchy)
Default constructor.
static void MatchHierarchies(MatchInfo &matchInfo)
Finds the matches between reconstructed and MC hierarchies.
SelectedRecoHitsMap m_selectedRecoHitsMap
Map storing the selected CaloHits for a given reco node.
const pandora::CaloHitList GetSelectedRecoHits(const RecoHierarchy::Node *pRecoNode, const pandora::CaloHitList &allMCHits) const
Get the selected reco node hits that are contained in the allMCHits list.
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.
bool IsQuality(const QualityCuts &qualityCuts) const
Get whether this match passes quality cuts.
void Match()
Match the nodes in the MC and reco hierarchies.
const MCHierarchy::Node * GetMC() const
Retrieve the MC node.
MCMatches(const MCHierarchy::Node *pMCParticle)
Constructor.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
unsigned int GetNTestBeamMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of test beam derived MC nodes available to match.
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
void FillHierarchy(const pandora::PfoList &pfoList, const FoldingParameters &foldParameters)
Creates a reconstructed hierarchy representation. Without folding this will be a mirror image of the ...
virtual ~Node()
Destructor.
static bool IsCosmicRay(const pandora::MCParticle *const pMCParticle)
Return true if passed a primary cosmic ray MCParticle.
static bool IsInelasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an inelastic scattering process.
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::vector< const Node * > NodeVector
static int GetHierarchyTier(const pandora::ParticleFlowObject *const pPfo)
Determine the position in the hierarchy for the MCParticle.
void AddRecoMatch(const RecoHierarchy::Node *pReco, const int nSharedHits, const pandora::CaloHitList &selectedRecoHits)
Add a reconstructed node as a match for this MC node.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
const bool m_selectRecoHits
Whether to only use reco hits that overlap with the MC particle hits.
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...
const float m_minPurity
The minimum purity for a match to be considered good.
static bool IsBeamParticle(const pandora::MCParticle *const pMCParticle)
Returns true if passed a primary beam MCParticle.
bool IsReconstructable() const
Return whether or not this node should be considered reconstructable.
ReconstructabilityCriteria class.
bool IsCosmicRay() const
Check if this is a cosmic ray particle.
std::list< const Node * > NodeList
void FillHierarchy(const pandora::ParticleFlowObject *pRoot, const FoldingParameters &foldParameters)
Recursively fill the hierarchy based on the criteria established for this RecoHierarchy.
int GetParticleId() const
Retrieve the PDG code for the leading particle in this 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.
pandora::PfoList m_pfos
The list of PFOs of which this node is composed.
const std::string ToString(const std::string &prefix) const
Produce a string representation of the hierarchy.
float m_cosAngleTolerance
Cosine of the maximum angle at which topologies can be considered continuous.
virtual ~MCHierarchy()
Destructor.
static bool IsNeutrino(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a neutrino or (antineutrino)
NodeVector m_children
The child nodes of this node.
virtual ~Node()
Destructor.
bool m_foldDynamic
Whether or not to use process and topological information to make folding decisions.
const RecoHierarchy::NodeVector & GetUnmatchedReco() const
Retrieve the vector of unmatched reco nodes.
const pandora::PfoList & GetRecoParticles() const
Retrieve the PFOs associated with this node.
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.
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.
const bool m_removeNeutrons
whether to remove neutrons and their downstream particles
Header file for the lar hierarchy helper class.
QualityCuts()
Default constructor.
const NodeVector & GetInteractions(const pandora::MCParticle *pRoot) const
Retrieve the root nodes in this hierarchy.
const std::string ToString() const
Produce a string representation of the hierarchy.
const pandora::ParticleFlowObject * m_mainPfo
The leading particle flow object for this node.
std::vector< MCMatches > MCMatchesVector
pandora::CaloHitList m_caloHits
The list of calo hits of which this node is composed.
unsigned int GetNNeutrinoMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of neutrino interaction derived MC nodes available to match.
const MCHierarchy & m_mcHierarchy
The MC hierarchy for the matching procedure.
bool IsReconstructable(const pandora::MCParticle *pMCParticle) const
Checks if an individual particle meets reconstructability criteria.
void SetLeadingLepton()
Tags the particle as the leading lepton.
Node(MCHierarchy &hierarchy, const pandora::MCParticle *pMCParticle, const int tier=1)
Create a node with a primary MC particle.
const RecoHierarchy & m_recoHierarchy
The Reco hierarchy for the matching procedure.
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...
Node(const RecoHierarchy &hierarchy, const pandora::ParticleFlowObject *pPfo, const int tier=1)
Create a node with a primary PFO.
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.
std::list< const Node * > NodeList
int GetParticleId() const
Retrieve the PDG code for the leading particle in this node Note, for reco objects the PDG codes repr...
void GetFlattenedNodes(const pandora::ParticleFlowObject *const pRoot, NodeVector &nodeVector) const
Retrieve a flat vector of the nodes in the hierarchy.
void FillFlat(const pandora::MCParticle *pRoot)
Fill this node by folding all descendent particles to this node.
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
int GetId() const
Retrieve the unique ID of this node.
int m_nextNodeId
The ID to use for the next node.
const unsigned int m_minHits
the minimum number of primary good Hits
RecoHierarchy::NodeVector m_unmatchedReco
The vector of unmatched reco nodes.
const unsigned int m_minGoodViews
the minimum number of primary good views
static InteractionDescriptor GetInteractionDescriptor(const pandora::MCParticleList &mcPrimaryList)
Get the interaction descriptor of an event.
void RegisterNode(const Node *pNode)
Register a node with the hierarchy.
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.
float GetCompleteness(const RecoHierarchy::Node *pReco, const bool adcWeighted=false) const
Retrieve the completeness of the match.
RecoHierarchy()
Default constructor.
void FillHierarchy(const pandora::MCParticle *pRoot, const FoldingParameters &foldParameters)
Recursively fill the hierarchy based on the criteria established for this MCHierarchy.
bool IsTestBeamParticle() const
Check if this is a test beam particle.
std::set< const pandora::ParticleFlowObject * > PfoSet
const float m_minCompleteness
The minimum completeness for a match to be considered good.
static bool IsElasticScatter(const pandora::MCParticle *const pMCParticle)
Check whether or not an MC particle came from an elastic scattering process.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
void FillFlat(const pandora::ParticleFlowObject *pRoot)
Fill this node by folding all descendent particles to this node.
std::map< const Node *, int > m_nodeToIdMap
A map from nodes to unique ids.
InteractionInfo m_matches
The map between an interaction and the vector of good matches from MC to reco.
unsigned int GetNCosmicRayMCNodes(const pandora::MCParticle *const pRoot) const
Retrieve the number of cosmic ray derived MC nodes available to match.