9 #include "Pandora/AlgorithmHeaders.h" 24 SplitShowersTool::SplitShowersTool() :
26 m_minMatchedFraction(0.25
f),
27 m_minMatchedSamplingPoints(40),
28 m_checkClusterProximities(true),
29 m_maxClusterSeparation(25.
f),
30 m_checkClusterVertexRelations(true),
31 m_minVertexLongitudinalDistance(-2.5
f),
32 m_maxVertexLongitudinalDistance(20.
f),
33 m_maxVertexTransverseDistance(1.5
f),
34 m_vertexAngularAllowance(3.
f),
35 m_maxVertexAssociations(1),
36 m_checkClusterSplitPositions(false),
37 m_vetoMergeXDifference(2.
f),
38 m_vetoMergeXOverlap(2.
f)
46 if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
47 std::cout <<
"----> Running Algorithm Tool: " << this->GetInstanceName() <<
", " << this->GetType() << std::endl;
59 ClusterSet usedClusters;
63 for (
const Cluster *
const pKeyCluster : sortedKeyClusters)
65 if (!pKeyCluster->IsAvailable())
68 unsigned int nU(0), nV(0), nW(0);
83 if (iteratorList.size() < 2)
86 this->
FindShowerMerges(pAlgorithm, iteratorList, usedClusters, clusterMergeMap);
95 if (usedClusters.count(eIter->GetClusterU()) || usedClusters.count(eIter->GetClusterV()) || usedClusters.count(eIter->GetClusterW()))
110 const ClusterSet &usedClusters,
IteratorList &iteratorList)
const 112 iteratorList.push_back(eIter);
124 if ((*iIter) == eIter2)
127 unsigned int nMatchedClusters(0);
129 if ((*iIter)->GetClusterU() == eIter2->GetClusterU())
132 if ((*iIter)->GetClusterV() == eIter2->GetClusterV())
135 if ((*iIter)->GetClusterW() == eIter2->GetClusterW())
140 iteratorList.push_back(eIter2);
158 if (iIter1 == iIter2)
161 const TensorType::Element &element1(*(*iIter1));
162 const TensorType::Element &element2(*(*iIter2));
164 ClusterList clusterListU(1, element1.GetClusterU());
165 if (element1.GetClusterU() != element2.GetClusterU())
166 clusterListU.push_back(element2.GetClusterU());
168 ClusterList clusterListV(1, element1.GetClusterV());
169 if (element1.GetClusterV() != element2.GetClusterV())
170 clusterListV.push_back(element2.GetClusterV());
172 ClusterList clusterListW(1, element1.GetClusterW());
173 if (element1.GetClusterW() != element2.GetClusterW())
174 clusterListW.push_back(element2.GetClusterW());
176 const unsigned int nClustersU(clusterListU.size()), nClustersV(clusterListV.size()), nClustersW(clusterListW.size());
177 const unsigned int nClustersProduct(nClustersU * nClustersV * nClustersW);
180 throw StatusCodeException(STATUS_CODE_FAILURE);
182 if ((1 ==
m_nCommonClusters) && !((2 == nClustersU) || (2 == nClustersV) || (2 == nClustersW)))
183 throw StatusCodeException(STATUS_CODE_FAILURE);
208 usedClusters.insert(clusterListU.begin(), clusterListU.end());
209 usedClusters.insert(clusterListV.begin(), clusterListV.end());
210 usedClusters.insert(clusterListW.begin(), clusterListW.end());
212 catch (StatusCodeException &)
223 if (1 == clusterList.size())
226 if (2 != clusterList.size())
227 throw StatusCodeException(STATUS_CODE_FAILURE);
229 const Cluster *
const pCluster1(*(clusterList.begin()));
230 const Cluster *
const pCluster2(*(++(clusterList.begin())));
248 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pVertexList));
249 const Vertex *
const pVertex(((pVertexList->size() == 1) && (VERTEX_3D == (*(pVertexList->begin()))->GetVertexType())) ? *(pVertexList->begin()) : NULL);
254 unsigned int nVertexAssociations(0);
269 ++nVertexAssociations;
272 catch (StatusCodeException &) {}
284 const ClusterList &clusterListV,
const ClusterList &clusterListW)
const 286 const unsigned int nClustersU(clusterListU.size()), nClustersV(clusterListV.size()), nClustersW(clusterListW.size());
287 const unsigned int nClustersProduct(nClustersU * nClustersV * nClustersW);
289 if (2 == nClustersProduct)
292 const ClusterList &clusterList1((1 == nClustersU) ? clusterListV : clusterListU);
293 const ClusterList &clusterList2((1 == nClustersU) ? clusterListW : (1 == nClustersV) ? clusterListW : clusterListV);
295 if ((2 != clusterList1.size()) || (2 != clusterList2.size()))
296 throw StatusCodeException(STATUS_CODE_FAILURE);
298 float splitXPosition1(0.
f), overlapX1(0.
f);
299 this->
GetSplitXDetails(pAlgorithm, *(clusterList1.begin()), *(++(clusterList1.begin())), splitXPosition1, overlapX1);
301 float splitXPosition2(0.
f), overlapX2(0.
f);
302 this->
GetSplitXDetails(pAlgorithm, *(clusterList2.begin()), *(++(clusterList2.begin())), splitXPosition2, overlapX2);
313 float &splitXPosition,
float &overlapX)
const 318 const float minXA(
std::min(fitResultA.GetGlobalMinLayerPosition().GetX(), fitResultA.GetGlobalMaxLayerPosition().GetX()));
319 const float maxXA(
std::max(fitResultA.GetGlobalMinLayerPosition().GetX(), fitResultA.GetGlobalMaxLayerPosition().GetX()));
320 const float minXB(
std::min(fitResultB.GetGlobalMinLayerPosition().GetX(), fitResultB.GetGlobalMaxLayerPosition().GetX()));
321 const float maxXB(
std::max(fitResultB.GetGlobalMinLayerPosition().GetX(), fitResultB.GetGlobalMaxLayerPosition().GetX()));
323 FloatVector floatVector;
324 floatVector.push_back(minXA);
325 floatVector.push_back(maxXA);
326 floatVector.push_back(minXB);
327 floatVector.push_back(maxXB);
328 std::sort(floatVector.begin(), floatVector.end());
330 if (4 != floatVector.size())
331 throw StatusCodeException(STATUS_CODE_FAILURE);
333 splitXPosition = 0.5f * (floatVector.at(1) + floatVector.at(2));
341 if (1 == clusterList.size())
344 if (2 != clusterList.size())
345 throw StatusCodeException(STATUS_CODE_FAILURE);
347 const Cluster *
const pClusterA(*(clusterList.begin())), *
const pClusterB(*(++(clusterList.begin())));
351 const float minXA(
std::min(fitResultA.GetGlobalMinLayerPosition().GetX(), fitResultA.GetGlobalMaxLayerPosition().GetX()));
352 const float minXB(
std::min(fitResultB.GetGlobalMinLayerPosition().GetX(), fitResultB.GetGlobalMaxLayerPosition().GetX()));
354 const Cluster *
const pLowXCluster((minXA < minXB) ? pClusterA : pClusterB);
355 const Cluster *
const pHighXCluster((minXA < minXB) ? pClusterB : pClusterA);
356 clusterMergeMap[pLowXCluster].push_back(pHighXCluster);
365 ClusterList clusterList;
366 for (
const auto &mapEntry : clusterMergeMap) clusterList.push_back(mapEntry.first);
369 for (
const Cluster *
const pParentCluster : clusterList)
371 const ClusterList &daughterClusters(clusterMergeMap.at(pParentCluster));
373 for (
const Cluster *
const pDaughterCluster : daughterClusters)
375 if (consolidatedMergeMap.count(pDaughterCluster))
376 throw StatusCodeException(STATUS_CODE_FAILURE);
379 ClusterList &targetClusterList(consolidatedMergeMap[pParentCluster]);
380 targetClusterList.insert(targetClusterList.end(), daughterClusters.begin(), daughterClusters.end());
390 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
395 std::cout <<
"SplitShowersTool: NCommonClusters must be set to either 1 or 2 (provided: " <<
m_nCommonClusters <<
") " << std::endl;
396 return STATUS_CODE_INVALID_PARAMETER;
399 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
402 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
405 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
408 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
411 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
414 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
417 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
420 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
423 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
426 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
429 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
432 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
435 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
438 return STATUS_CODE_SUCCESS;
static bool SortByNHits(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by number of hits, then layer span, then inner layer, then position, then pulse-height.
float m_maxVertexLongitudinalDistance
Vertex association check: max longitudinal distance cut.
Header file for the lar pointing cluster class.
bool CheckClusterProximities(ThreeDShowersAlgorithm *const pAlgorithm, const pandora::ClusterList &clusterList) const
Check the clusters in a provided cluster list are in suitable proximity for merging.
bool ApplyChanges(ThreeDShowersAlgorithm *const pAlgorithm, const ClusterMergeMap &clusterMergeMap) const
Apply the changes cached in a cluster merge map and update the tensor accordingly.
bool CheckClusterVertexRelations(ThreeDShowersAlgorithm *const pAlgorithm, const pandora::ClusterList &clusterList) const
Check the consistency of the clusters in a provided cluster list with the event vertex, if available.
static bool IsEmission(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxLongitudinalDistance, const float maxTransverseDistance, const float angularAllowance)
Whether pointing vertex is emitted from a given position.
bool Run(ThreeDShowersAlgorithm *const pAlgorithm, TensorType &overlapTensor)
Run the algorithm tool.
void GetConnectedElements(const pandora::Cluster *const pCluster, const bool ignoreUnavailable, ElementList &elementList) const
Get a list of elements connected to a specified cluster.
const TwoDSlidingFitResult & GetShowerFitResult() const
Get the sliding fit result for the full shower cluster.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
LArPointingCluster class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
float m_maxVertexTransverseDistance
Vertex association check: max transverse distance cut.
ThreeDShowersAlgorithm class.
unsigned int m_nCommonClusters
The number of common clusters.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the geometry helper class.
void FindShowerMerges(ThreeDShowersAlgorithm *const pAlgorithm, const IteratorList &iteratorList, pandora::ClusterSet &usedClusters, ClusterMergeMap &clusterMergeMap) const
Get cluster merges specific elements of the tensor.
const TwoDSlidingShowerFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding shower fit result from the algorithm cache.
std::vector< TensorType::ElementList::const_iterator > IteratorList
std::vector< Element > ElementList
bool m_checkClusterProximities
Whether to check the proximities of the candidate split shower clusters.
Header file for the cluster helper class.
float m_vetoMergeXOverlap
The x overlap between candidate cluster sliding fits below which may refuse a merge.
void SpecifyClusterMerges(ThreeDShowersAlgorithm *const pAlgorithm, const pandora::ClusterList &clusterList, ClusterMergeMap &clusterMergeMap) const
Populate the cluster merge map, based on the information contained in the provided cluster list...
void GetSortedKeyClusters(pandora::ClusterVector &sortedKeyClusters) const
Get a sorted vector of key clusters (U clusters with current implementation)
unsigned int m_minMatchedSamplingPoints
The min number of matched sampling points for use as a key tensor element.
void FindSplitShowers(ThreeDShowersAlgorithm *const pAlgorithm, const TensorType &overlapTensor, ClusterMergeMap &clusterMergeMap) const
Find split showers, using information from the overlap tensor.
float m_maxClusterSeparation
The maximum separation for clusters to be merged.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
void GetSplitXDetails(ThreeDShowersAlgorithm *const pAlgorithm, const pandora::Cluster *const pClusterA, const pandora::Cluster *const pClusterB, float &splitXPosition, float &overlapX) const
Get the x coordinate representing the midpoint between two clusters (hypothesis: clusters represent a...
bool PassesElementCuts(TensorType::ElementList::const_iterator eIter, const pandora::ClusterSet &usedClusters) const
Whether a provided (iterator to a) tensor element passes the selection cuts for undershoots identific...
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
bool m_checkClusterSplitPositions
Whether to check the cluster split positions, if there are splits in multiple views.
float m_vetoMergeXDifference
The x distance between split positions in two views below which may refuse a merge.
float m_minMatchedFraction
The min matched sampling point fraction for use as a key tensor element.
float m_vertexAngularAllowance
Vertex association check: pointing angular allowance in degrees.
float m_minVertexLongitudinalDistance
Vertex association check: min longitudinal distance cut.
std::list< Vertex > VertexList
TwoDSlidingFitResult class.
bool m_checkClusterVertexRelations
Whether to check the consistency of the clusters with the event vertex.
TheTensor::const_iterator const_iterator
void SelectTensorElements(TensorType::ElementList::const_iterator eIter, const TensorType::ElementList &elementList, const pandora::ClusterSet &usedClusters, IteratorList &iteratorList) const
Select elements representing possible components of interest due to undershoots in clustering...
bool CheckClusterSplitPositions(ThreeDShowersAlgorithm *const pAlgorithm, const pandora::ClusterList &clusterListU, const pandora::ClusterList &clusterListV, const pandora::ClusterList &clusterListW) const
Check the consistency of the split positions in the provided u, v and w cluster lists.
static bool IsNode(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxTransverseDistance)
Whether pointing vertex is adjacent to a given position.
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.
unsigned int m_maxVertexAssociations
The maximum number of vertex associations for clusters to be merged.
virtual bool MakeClusterMerges(const ClusterMergeMap &clusterMergeMap)
Merge clusters together.