12 #include "Pandora/AlgorithmHeaders.h" 24 ThreeDMultiReclusteringAlgorithm::ThreeDMultiReclusteringAlgorithm() :
25 m_clusterListNames{{TPC_3D, {}}, {TPC_VIEW_U,
"ClustersU"}, {TPC_VIEW_V,
"ClustersV"}, {TPC_VIEW_W,
"ClustersW"}},
35 const PfoList *pPfos{
nullptr};
36 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this,
m_pfoListName, pPfos));
37 if (!pPfos || pPfos->empty())
38 return STATUS_CODE_SUCCESS;
41 PfoList pfosToRecluster;
43 if (pfosToRecluster.empty())
44 return STATUS_CODE_SUCCESS;
47 std::map<HitType, ClusterList> viewToFreeClusters = {{TPC_3D, {}}, {TPC_VIEW_U, {}}, {TPC_VIEW_V, {}}, {TPC_VIEW_W, {}}};
48 std::map<const Pfo *const, ClusterList> pfoToFreeClusters;
49 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
FreeClustersFromPfos(pfosToRecluster, viewToFreeClusters, pfoToFreeClusters));
50 if (viewToFreeClusters.at(TPC_3D).empty())
55 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Cluster>(*
this,
m_clusterListNames.at(TPC_3D)));
56 std::string originalClusterListName;
57 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
58 PandoraContentApi::InitializeReclustering(*
this, TrackList(), viewToFreeClusters.at(TPC_3D), originalClusterListName));
60 float bestReclusterFom{std::numeric_limits<float>::lowest()};
62 std::string bestReclusterListName{originalClusterListName};
63 ClusterList bestReclusterList;
67 std::string reclusterListName;
68 const ClusterList *pReclusterList{
nullptr};
69 PANDORA_RETURN_RESULT_IF(
70 STATUS_CODE_SUCCESS, !=, PandoraContentApi::RunClusteringAlgorithm(*
this, clusteringAlg, pReclusterList, reclusterListName));
71 if (!pReclusterList || pReclusterList->empty())
74 float reclusterFom{std::numeric_limits<float>::lowest()};
76 if (reclusterFom > bestReclusterFom)
78 bestReclusterFom = reclusterFom;
79 bestReclusterListName = reclusterListName;
80 bestReclusterList = *pReclusterList;
84 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::TemporarilyReplaceCurrentList<Cluster>(*
this, bestReclusterListName));
85 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndReclustering(*
this, bestReclusterListName));
87 if (bestReclusterListName == originalClusterListName)
95 for (
const Pfo *
const pPfo : pfosToRecluster)
96 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Delete(*
this, pPfo,
m_pfoListName));
101 std::map<HitType, CaloHitList> viewToFreeCaloHits2D = {{TPC_VIEW_U, {}}, {TPC_VIEW_V, {}}, {TPC_VIEW_W, {}}};
102 for (
const auto &[view, freeClusters] : viewToFreeClusters)
106 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
FreeCaloHitsFromClusters(freeClusters, view, viewToFreeCaloHits2D.at(view)));
110 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
BuildNewPfos(bestReclusterList, viewToFreeCaloHits2D));
112 return STATUS_CODE_SUCCESS;
118 std::map<const Pfo *const, ClusterList> &pfoToFreeClusters)
const 120 for (
const Pfo *
const pPfo : pfos)
122 ClusterList thisPfoClusters;
123 for (
auto &[view, freeClusters] : viewToFreeClusters)
125 ClusterList clusters;
127 for (
const Cluster *
const pCluster : clusters)
129 freeClusters.emplace_back(pCluster);
130 thisPfoClusters.emplace_back(pCluster);
131 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::RemoveFromPfo(*
this, pPfo, pCluster));
134 pfoToFreeClusters.insert(std::make_pair(pPfo, thisPfoClusters));
137 return STATUS_CODE_SUCCESS;
144 for (
const auto &[pPfo, clusters] : pfoToClusters)
145 for (
const Cluster *
const pCluster : clusters)
146 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToPfo(*
this, pPfo, pCluster));
148 return STATUS_CODE_SUCCESS;
156 for (
const Cluster *
const pCluster : clusters)
158 CaloHitList caloHits;
159 pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHits);
160 freeCaloHits.insert(freeCaloHits.end(), caloHits.begin(), caloHits.end());
161 freeCaloHits.insert(freeCaloHits.end(), pCluster->GetIsolatedCaloHitList().begin(), pCluster->GetIsolatedCaloHitList().end());
162 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Delete(*
this, pCluster, clusterListName));
165 return STATUS_CODE_SUCCESS;
173 std::map<HitType, ClusterList> viewToNewClusters2D = {{TPC_VIEW_U, {}}, {TPC_VIEW_V, {}}, {TPC_VIEW_W, {}}};
174 std::vector<ClusterList> newPfoClusters;
175 for (
const Cluster *
const pCluster3D : clusters)
177 ClusterList newClusters;
178 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
Build2DClustersFrom3D(pCluster3D, viewToFreeCaloHits2D, newClusters));
179 for (
const Cluster *
const pCluster : newClusters)
181 newClusters.emplace_back(pCluster3D);
182 newPfoClusters.emplace_back(newClusters);
189 for (
const auto &[view, caloHits2D] : viewToFreeCaloHits2D)
193 if (viewToNewClusters2D.at(view).empty())
196 const ClusterList *pOldClusters2D{
nullptr};
197 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*
this, clusterListName, pOldClusters2D));
200 if (pOldClusters2D->empty())
202 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
MopUpCaloHits(caloHits2D, *pOldClusters2D,
true));
205 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
MopUpCaloHits(caloHits2D, viewToNewClusters2D.at(view),
true));
212 const PfoList *pNewPfoList{
nullptr};
213 std::string tempPfoListName;
214 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pNewPfoList, tempPfoListName));
215 for (
const ClusterList &pfoClusters : newPfoClusters)
217 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*
this, tempPfoListName,
m_pfoListName));
219 return STATUS_CODE_SUCCESS;
225 const Cluster *
const pCluster3D, std::map<HitType, CaloHitList> &viewToFreeCaloHits2D, ClusterList &newClusters2D)
const 227 std::map<HitType, PandoraContentApi::Cluster::Parameters> viewToParamsCluster2D = {{TPC_VIEW_U, {}}, {TPC_VIEW_V, {}}, {TPC_VIEW_W, {}}};
229 CaloHitList cluster3DCaloHits3D;
230 pCluster3D->GetOrderedCaloHitList().FillCaloHitList(cluster3DCaloHits3D);
231 for (
const CaloHit *
const pCaloHit3D : cluster3DCaloHits3D)
233 const CaloHit *
const pCaloHit3DParent2D{
static_cast<const CaloHit *
>(pCaloHit3D->GetParentAddress())};
234 const HitType view{pCaloHit3DParent2D->GetHitType()};
235 if (std::find(viewToFreeCaloHits2D.at(view).begin(), viewToFreeCaloHits2D.at(view).end(), pCaloHit3DParent2D) ==
236 viewToFreeCaloHits2D.at(view).end())
237 return STATUS_CODE_FAILURE;
238 viewToParamsCluster2D.at(view).m_caloHitList.push_back(pCaloHit3DParent2D);
239 viewToFreeCaloHits2D.at(view).remove(pCaloHit3DParent2D);
242 CaloHitList cluster3DIsoCaloHits3D{pCluster3D->GetIsolatedCaloHitList()};
243 for (
const CaloHit *
const pCaloHit3D : cluster3DIsoCaloHits3D)
245 const CaloHit *
const pCaloHit3DParent2D{
static_cast<const CaloHit *
>(pCaloHit3D->GetParentAddress())};
246 const HitType view{pCaloHit3DParent2D->GetHitType()};
247 if (std::find(viewToFreeCaloHits2D.at(view).begin(), viewToFreeCaloHits2D.at(view).end(), pCaloHit3DParent2D) ==
248 viewToFreeCaloHits2D.at(view).end())
249 return STATUS_CODE_FAILURE;
250 viewToParamsCluster2D.at(view).m_isolatedCaloHitList.push_back(pCaloHit3DParent2D);
251 viewToFreeCaloHits2D.at(view).remove(pCaloHit3DParent2D);
254 for (
const auto &[view, params] : viewToParamsCluster2D)
256 if (params.m_caloHitList.empty() && params.m_isolatedCaloHitList.empty())
259 std::string tempListName;
260 const ClusterList *pTempClusterList{
nullptr};
261 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pTempClusterList, tempListName));
262 const Cluster *pNewCluster2D{
nullptr};
263 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, params, pNewCluster2D));
265 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Cluster>(*
this, tempListName, cluster2DListName));
266 newClusters2D.push_back(pNewCluster2D);
269 return STATUS_CODE_SUCCESS;
276 for (
const CaloHit *
const pCaloHit : caloHits)
278 const Cluster *pNearestCluster{
nullptr};
279 double minimumDistance{std::numeric_limits<float>::max()};
280 for (
const Cluster *
const pCluster : clusters)
283 if (dist < minimumDistance)
285 minimumDistance =
dist;
286 pNearestCluster = pCluster;
289 if (!pNearestCluster)
290 return STATUS_CODE_FAILURE;
294 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddIsolatedToCluster(*
this, pNearestCluster, pCaloHit));
298 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*
this, pNearestCluster, pCaloHit));
302 return STATUS_CODE_SUCCESS;
309 PandoraContentApi::ParticleFlowObject::Parameters params;
310 params.m_clusterList = clusters;
311 params.m_particleId = MU_MINUS;
312 params.m_charge = PdgTable::GetParticleCharge(params.m_particleId.Get());
313 params.m_mass = PdgTable::GetParticleMass(params.m_particleId.Get());
314 params.m_energy = 0.f;
315 params.m_momentum = CartesianVector(0.
f, 0.
f, 0.
f);
316 const Pfo *pPfo{
nullptr};
317 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*
this, params, pPfo));
319 return STATUS_CODE_SUCCESS;
326 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"PfoListName",
m_pfoListName));
327 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"Cluster3DListName",
m_clusterListNames.at(TPC_3D)));
328 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
329 XmlHelper::ReadValue(xmlHandle,
"ClusterUListName",
m_clusterListNames.at(TPC_VIEW_U)));
330 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
331 XmlHelper::ReadValue(xmlHandle,
"ClusterVListName",
m_clusterListNames.at(TPC_VIEW_V)));
332 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
333 XmlHelper::ReadValue(xmlHandle,
"ClusterWListName",
m_clusterListNames.at(TPC_VIEW_W)));
335 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MopUp2DCaloHits",
m_mopUp2DCaloHits));
337 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ProcessAlgorithmList(*
this, xmlHandle,
"ClusteringAlgorithms",
m_clusteringAlgs));
339 AlgorithmTool *pAlgTool{
nullptr};
340 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ProcessAlgorithmTool(*
this, xmlHandle,
"FomAlgorithmTool", pAlgTool));
343 return STATUS_CODE_INVALID_PARAMETER;
345 return STATUS_CODE_SUCCESS;
Header file for the pfo helper class.
ThreeDReclusteringFigureOfMeritBaseTool * m_pFomAlgTool
The address of the figure of merit algorithm tool to use.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
pandora::StatusCode FreeCaloHitsFromClusters(const pandora::ClusterList &clusters, const pandora::HitType &view, pandora::CaloHitList &freeCaloHits) const
Delete clusters of a single hit type and store the associated hits in a list.
static void GetClusters(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::ClusterList &clusterList)
Get a list of clusters of a particular hit type from a list of pfos.
pandora::StatusCode Run()
pandora::StatusCode RelinkClustersToOriginalPfos(std::map< const pandora::Pfo *const, pandora::ClusterList > &pfoToClusters) const
Remake the original pfos by adding back their removed clusters.
pandora::StatusCode CreatePfoFromClusters(const pandora::ClusterList &clusters) const
Create a new pfo from a list of clusters.
std::string m_pfoListName
Name of list of pfos to consider for reclustering.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
Header file for the cluster helper class.
ThreeDReclusteringFigureOfMeritBaseTool class.
Header file for the reclustering algorithm class. Tries multiple 3D clustering algorithms and reclust...
pandora::StatusCode Build2DClustersFrom3D(const pandora::Cluster *const pCluster3D, std::map< pandora::HitType, pandora::CaloHitList > &viewToFreeCaloHits2D, pandora::ClusterList &newClusters2D) const
Create 2D clusters following a 3D cluster.
virtual pandora::StatusCode CalcClusteringFom(const pandora::ClusterList &clusters, float &fom)=0
Calculate a measure of the goodness of a clustering.
bool m_mopUp2DCaloHits
Add hits from reclustered 2D clusters without an associated 3D hit to the nearest new 2D cluster in t...
virtual pandora::StatusCode GetPfosToRecluster(const pandora::PfoList *pPfos, pandora::PfoList &pfosToRecluster)=0
Identify pfos for which an attempt at 3D reclustering should be made.
pandora::StatusCode MopUpCaloHits(const pandora::CaloHitList &caloHits, const pandora::ClusterList &clusters, bool addAsIso) const
Add hits to their nearest cluster.
std::map< pandora::HitType, std::string > m_clusterListNames
Map of list names for 3D clusters that comprise the pfos and 2D U, V, W clusters that may need reclus...
double dist(const TReal *x, const TReal *y, const unsigned int dimension)
std::vector< std::string > m_clusteringAlgs
The ordered list of clustering algorithms to use.
pandora::StatusCode BuildNewPfos(const pandora::ClusterList &clusters3D, std::map< pandora::HitType, pandora::CaloHitList > &viewToFreeCaloHits2D) const
Create new pfos from the reclustered 3D clusters and original 2D hits. The original 2D hits are put i...
pandora::StatusCode FreeClustersFromPfos(const pandora::PfoList &pfos, std::map< pandora::HitType, pandora::ClusterList > &viewToFreeClusters, std::map< const pandora::Pfo *const, pandora::ClusterList > &pfoToFreeClusters) const
Remove clusters from the pfos and store them them in maps.
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.