9 #include "Pandora/AlgorithmHeaders.h" 23 EventClusterValidationAlgorithm::CaloHitParents::CaloHitParents() :
32 m_nRecoHits{std::vector<int>{}},
57 PANDORA_MONITORING_API(FillTree(this->GetPandora(),
m_treeName +
"_meta"));
58 PANDORA_MONITORING_API(SaveTree(this->GetPandora(),
m_treeName +
"_meta",
m_fileName,
"UPDATE"));
68 const CaloHitList *pFullCaloHitList{
nullptr};
69 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*
this,
m_caloHitListName, pFullCaloHitList));
70 std::map<HitType, CaloHitList> viewToCaloHits;
71 for (
const CaloHit *
const pCaloHit : *pFullCaloHitList)
72 viewToCaloHits[pCaloHit->GetHitType()].emplace_back(pCaloHit);
75 std::map<HitType, ClusterList> viewToClusters;
78 const ClusterList *pClusterList{
nullptr};
79 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*
this, listName, pClusterList));
80 for (
const Cluster *
const pCluster : *pClusterList)
83 viewToClusters[view].emplace_back(pCluster);
87 const std::vector<ValidationType> valTypes{ValidationType::ALL, ValidationType::SHOWER, ValidationType::TRACK};
88 for (
const auto &[view, caloHits] : viewToCaloHits)
90 const ClusterList &clusters{viewToClusters[view]};
94 std::map<const CaloHit *const, CaloHitParents> hitParents;
104 std::map<const CaloHit *const, CaloHitParents> hitParentsValid{
ApplyPDGCut(hitParents, valType)};
111 std::string branchPrefix;
112 if (valType == ValidationType::ALL)
113 branchPrefix =
"all_";
114 else if (valType == ValidationType::SHOWER)
115 branchPrefix =
"shower_";
116 else if (valType == ValidationType::TRACK)
117 branchPrefix =
"track_";
122 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName,
"view", static_cast<int>(view)));
123 PANDORA_MONITORING_API(FillTree(this->GetPandora(),
m_treeName));
126 return STATUS_CODE_SUCCESS;
132 const CaloHitList &caloHits,
const ClusterList &clusters, std::map<const CaloHit *const, CaloHitParents> &hitParents)
const 134 for (
const CaloHit *
const pCaloHit : caloHits)
136 const MCParticle *pMainMC{
nullptr};
137 const MCParticleWeightMap &weightMap{pCaloHit->GetMCParticleWeightMap()};
138 float maxWeight{std::numeric_limits<float>::lowest()};
139 for (
const auto &[pMC,
weight] : weightMap)
150 hitParents[pCaloHit].m_pMainMC = pMainMC;
154 for (
const Cluster *
const pCluster : clusters)
156 const CaloHitList &isolatedHits{pCluster->GetIsolatedCaloHitList()};
157 CaloHitList clusterCaloHits;
158 pCluster->GetOrderedCaloHitList().FillCaloHitList(clusterCaloHits);
159 clusterCaloHits.insert(clusterCaloHits.end(), isolatedHits.begin(), isolatedHits.end());
160 for (
const CaloHit *
const pCaloHit : clusterCaloHits)
163 if (hitParents.find(pCaloHit) == hitParents.end())
165 hitParents[pCaloHit].m_pCluster = pCluster;
174 std::map<const MCParticle *const, int> mcSumHits;
175 for (
const auto &[pCaloHit, parents] : hitParents)
177 const MCParticle *
const pMainMC{parents.m_pMainMC};
178 if (mcSumHits.find(pMainMC) == mcSumHits.end())
179 mcSumHits[pMainMC] = 0;
180 mcSumHits.at(pMainMC)++;
183 for (
auto it = hitParents.begin(); it != hitParents.end();)
186 it = hitParents.erase(it);
195 std::map<const CaloHit *const, CaloHitParents> &hitParents,
const ValidationType &valType)
const 197 std::map<const CaloHit *const, CaloHitParents> hitParentsValid;
198 for (
const auto &[pCaloHit, parents] : hitParents)
200 const MCParticle *
const pMainMC{parents.m_pMainMC};
201 if (valType != ValidationType::ALL)
203 const int pdg{
std::abs(pMainMC->GetParticleId())};
204 if ((valType == ValidationType::SHOWER && (pdg != PHOTON && pdg != E_MINUS)) ||
205 (valType == ValidationType::TRACK && (pdg == PHOTON || pdg == E_MINUS)))
208 hitParentsValid[pCaloHit] = parents;
211 return hitParentsValid;
219 std::set<const Cluster *> validClusters;
220 std::set<const MCParticle *> validMCParticles;
221 for (
const auto &[pCaloHit, parents] : hitParents)
223 validClusters.insert(parents.m_pCluster);
224 validMCParticles.insert(parents.m_pMainMC);
226 metrics.
m_nHits = hitParents.size();
230 for (
const Cluster *
const pCluster : validClusters)
232 CaloHitList clusterCaloHits;
235 const CaloHitList &isolatedHits{pCluster->GetIsolatedCaloHitList()};
236 pCluster->GetOrderedCaloHitList().FillCaloHitList(clusterCaloHits);
237 clusterCaloHits.insert(clusterCaloHits.end(), isolatedHits.begin(), isolatedHits.end());
241 for (
const auto &[pCaloHit, parents] : hitParents)
243 if (!parents.m_pCluster)
244 clusterCaloHits.emplace_back(pCaloHit);
248 std::map<const MCParticle *const, int> mainMCParticleHits;
250 for (
const CaloHit *
const pCaloHit : clusterCaloHits)
252 if (hitParents.find(pCaloHit) == hitParents.end())
255 const MCParticle *
const pMC = hitParents.at(pCaloHit).m_pMainMC;
256 if (mainMCParticleHits.find(pMC) == mainMCParticleHits.end())
257 mainMCParticleHits[pMC] = 0;
258 mainMCParticleHits.at(pMC)++;
265 const MCParticle *pMainMC{
nullptr};
267 for (
const auto &[pMC, nHits] : mainMCParticleHits)
275 metrics.
m_purities.emplace_back(maxHits / totalHits);
279 int nTotalMainMCHits{0};
280 for (
const auto &[pCaloHit, parents] : hitParents)
282 if (pMainMC == parents.m_pMainMC)
285 metrics.
m_completenesses.emplace_back(maxHits / static_cast<float>(nTotalMainMCHits));
295 for (
const auto &[pCaloHit, parents] : hitParents)
297 const MCParticle *
const pMC = parents.m_pMainMC;
298 const Cluster *
const pCluster = parents.m_pCluster;
300 if (cTable.find(pCluster) == cTable.end() || cTable.at(pCluster).find(pMC) == cTable.at(pCluster).end())
301 cTable[pCluster][pMC] = 0;
302 cTable.at(pCluster).at(pMC)++;
311 [[maybe_unused]]
ClusterMetrics &metrics, [[maybe_unused]]
float randIndex, [[maybe_unused]] std::string branchPrefix)
const 313 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"n_hits", metrics.m_nHits));
314 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"n_clusters", metrics.m_nClusters));
315 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"n_mainMCs", metrics.m_nMainMCs));
317 double meanPurity{-1.0}, meanCompleteness{-1.0}, meanNRecoHits{-1.0};
318 if (!metrics.m_purities.empty() && !metrics.m_completenesses.empty() && !metrics.m_nRecoHits.empty())
320 meanPurity = std::accumulate(metrics.m_purities.begin(), metrics.m_purities.end(), 0.0) / metrics.m_purities.size();
321 meanCompleteness = std::accumulate(metrics.m_completenesses.begin(), metrics.m_completenesses.end(), 0.0) / metrics.m_completenesses.size();
322 meanNRecoHits = std::accumulate(metrics.m_nRecoHits.begin(), metrics.m_nRecoHits.end(), 0.0) / metrics.m_nRecoHits.size();
325 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"mean_purity", meanPurity));
326 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"mean_completeness", meanCompleteness));
327 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"mean_n_reco_hits", meanNRecoHits));
328 PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(),
m_treeName, branchPrefix +
"adjusted_rand_idx", randIndex));
335 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"FileName",
m_fileName));
336 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"TreeName",
m_treeName));
337 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"CaloHitListName",
m_caloHitListName));
338 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"ClusterListNames",
m_clusterListNames));
339 PANDORA_RETURN_RESULT_IF_AND_IF(
340 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinMCHitsPerView",
m_minMCHitsPerView));
342 return STATUS_CODE_SUCCESS;
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
int m_eventNumber
To track the current event number.
std::map< const pandora::Cluster *const, std::map< const pandora::MCParticle *const, int > > ContingencyTable
float CalcRandIndex(std::map< const pandora::CaloHit *const, CaloHitParents > &hitParents) const
Calculate Rand Index for the clusters with the clusters of true MCParticles. (Ref. for Adjusted Rand Index: https://link.springer.com/article/10.1007/BF01908075)
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< float > m_purities
void GetHitParents(const pandora::CaloHitList &caloHits, const pandora::ClusterList &clusters, std::map< const pandora::CaloHit *const, CaloHitParents > &hitParents) const
Find the cluster and MCParticle each hit belongs to.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
Header file for the lar monitoring helper helper class.
EventClusterValidationAlgorithm()
Default constructor.
std::vector< float > m_completenesses
pandora::StatusCode Run()
std::string m_caloHitListName
The name of the hit list containing all 2D hits.
Header file for the cluster helper class.
const pandora::Cluster * m_pCluster
Header file of the event-level cluster validation.
void ApplyMCParticleMinSumHits(std::map< const pandora::CaloHit *const, CaloHitParents > &hitParents) const
Erase hits associated to an MCParticle that does meet a minimum number of hits in the view...
std::string m_fileName
The filename of the ROOT output file.
void GetMetrics(const std::map< const pandora::CaloHit *const, CaloHitParents > &hitParents, ClusterMetrics &metrics) const
Retrieve the metrics of every cluster in a view.
void SetBranches(ClusterMetrics &metrics, float randIdx, std::string branchPrefix) const
Update the branches of the TTree for this entry.
~EventClusterValidationAlgorithm()
Destructor saves the validation TTree along with making and saving a metadata TTree.
std::vector< std::string > m_clusterListNames
The names of the lists of 2D clusters to process.
int m_minMCHitsPerView
Threshold on total main MCParticle hits in each view for consideration in metric calculations.
std::string m_treeName
The name of the ROOT tree.
std::map< const pandora::CaloHit *const, CaloHitParents > ApplyPDGCut(std::map< const pandora::CaloHit *const, CaloHitParents > &hitParents, const ValidationType &valType) const
Erase hits not associated with an MCParticle PDG incompatible with track/shower/all.
static float CalcRandIndex(const std::map< const Ti, std::map< const Tj, int >> &cTable)
Calculate the adjusted Rand Index for a given contingency table that summarises two clusterings A and...
std::vector< int > m_nRecoHits