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(
250 ((pVertexList->size() == 1) && (VERTEX_3D == (*(pVertexList->begin()))->GetVertexType())) ? *(pVertexList->begin()) : NULL);
255 unsigned int nVertexAssociations(0);
272 ++nVertexAssociations;
275 catch (StatusCodeException &)
289 const ClusterList &clusterListV,
const ClusterList &clusterListW)
const 291 const unsigned int nClustersU(clusterListU.size()), nClustersV(clusterListV.size()), nClustersW(clusterListW.size());
292 const unsigned int nClustersProduct(nClustersU * nClustersV * nClustersW);
294 if (2 == nClustersProduct)
297 const ClusterList &clusterList1((1 == nClustersU) ? clusterListV : clusterListU);
298 const ClusterList &clusterList2((1 == nClustersU) ? clusterListW : (1 == nClustersV) ? clusterListW : clusterListV);
300 if ((2 != clusterList1.size()) || (2 != clusterList2.size()))
301 throw StatusCodeException(STATUS_CODE_FAILURE);
303 float splitXPosition1(0.
f), overlapX1(0.
f);
304 this->
GetSplitXDetails(pAlgorithm, *(clusterList1.begin()), *(++(clusterList1.begin())), splitXPosition1, overlapX1);
306 float splitXPosition2(0.
f), overlapX2(0.
f);
307 this->
GetSplitXDetails(pAlgorithm, *(clusterList2.begin()), *(++(clusterList2.begin())), splitXPosition2, overlapX2);
318 const Cluster *
const pClusterB,
float &splitXPosition,
float &overlapX)
const 323 const float minXA(std::min(fitResultA.GetGlobalMinLayerPosition().GetX(), fitResultA.GetGlobalMaxLayerPosition().GetX()));
324 const float maxXA(std::max(fitResultA.GetGlobalMinLayerPosition().GetX(), fitResultA.GetGlobalMaxLayerPosition().GetX()));
325 const float minXB(std::min(fitResultB.GetGlobalMinLayerPosition().GetX(), fitResultB.GetGlobalMaxLayerPosition().GetX()));
326 const float maxXB(std::max(fitResultB.GetGlobalMinLayerPosition().GetX(), fitResultB.GetGlobalMaxLayerPosition().GetX()));
328 FloatVector floatVector;
329 floatVector.push_back(minXA);
330 floatVector.push_back(maxXA);
331 floatVector.push_back(minXB);
332 floatVector.push_back(maxXB);
333 std::sort(floatVector.begin(), floatVector.end());
335 if (4 != floatVector.size())
336 throw StatusCodeException(STATUS_CODE_FAILURE);
338 splitXPosition = 0.5f * (floatVector.at(1) + floatVector.at(2));
339 overlapX = std::max(0.
f, std::min(maxXA, maxXB) - std::max(minXA, minXB));
346 if (1 == clusterList.size())
349 if (2 != clusterList.size())
350 throw StatusCodeException(STATUS_CODE_FAILURE);
352 const Cluster *
const pClusterA(*(clusterList.begin())), *
const pClusterB(*(++(clusterList.begin())));
356 const float minXA(std::min(fitResultA.GetGlobalMinLayerPosition().GetX(), fitResultA.GetGlobalMaxLayerPosition().GetX()));
357 const float minXB(std::min(fitResultB.GetGlobalMinLayerPosition().GetX(), fitResultB.GetGlobalMaxLayerPosition().GetX()));
359 const Cluster *
const pLowXCluster((minXA < minXB) ? pClusterA : pClusterB);
360 const Cluster *
const pHighXCluster((minXA < minXB) ? pClusterB : pClusterA);
361 clusterMergeMap[pLowXCluster].push_back(pHighXCluster);
370 ClusterList clusterList;
371 for (
const auto &mapEntry : clusterMergeMap)
372 clusterList.push_back(mapEntry.first);
375 for (
const Cluster *
const pParentCluster : clusterList)
377 const ClusterList &daughterClusters(clusterMergeMap.at(pParentCluster));
379 for (
const Cluster *
const pDaughterCluster : daughterClusters)
381 if (consolidatedMergeMap.count(pDaughterCluster))
382 throw StatusCodeException(STATUS_CODE_FAILURE);
385 ClusterList &targetClusterList(consolidatedMergeMap[pParentCluster]);
386 targetClusterList.insert(targetClusterList.end(), daughterClusters.begin(), daughterClusters.end());
396 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NCommonClusters",
m_nCommonClusters));
400 std::cout <<
"SplitShowersTool: NCommonClusters must be set to either 1 or 2 (provided: " <<
m_nCommonClusters <<
") " << std::endl;
401 return STATUS_CODE_INVALID_PARAMETER;
404 PANDORA_RETURN_RESULT_IF_AND_IF(
405 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinMatchedFraction",
m_minMatchedFraction));
407 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
410 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
413 PANDORA_RETURN_RESULT_IF_AND_IF(
414 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxClusterSeparation",
m_maxClusterSeparation));
416 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
419 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
422 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
425 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
428 PANDORA_RETURN_RESULT_IF_AND_IF(
429 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"VertexAngularAllowance",
m_vertexAngularAllowance));
431 PANDORA_RETURN_RESULT_IF_AND_IF(
432 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxVertexAssociations",
m_maxVertexAssociations));
434 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
437 PANDORA_RETURN_RESULT_IF_AND_IF(
438 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"VetoMergeXDifference",
m_vetoMergeXDifference));
440 PANDORA_RETURN_RESULT_IF_AND_IF(
441 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"VetoMergeXOverlap",
m_vetoMergeXOverlap));
443 return STATUS_CODE_SUCCESS;
bool CheckClusterVertexRelations(ThreeViewShowersAlgorithm *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 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.
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.
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.
ThreeViewShowersAlgorithm class.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
void GetSplitXDetails(ThreeViewShowersAlgorithm *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...
LArPointingCluster class.
bool CheckClusterProximities(ThreeViewShowersAlgorithm *const pAlgorithm, const pandora::ClusterList &clusterList) const
Check the clusters in a provided cluster list are in suitable proximity for merging.
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.
unsigned int m_nCommonClusters
The number of common clusters.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the geometry helper class.
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 FindShowerMerges(ThreeViewShowersAlgorithm *const pAlgorithm, const IteratorList &iteratorList, pandora::ClusterSet &usedClusters, ClusterMergeMap &clusterMergeMap) const
Get cluster merges specific elements of the tensor.
bool CheckClusterSplitPositions(ThreeViewShowersAlgorithm *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.
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(ThreeViewShowersAlgorithm *const pAlgorithm, const TensorType &overlapTensor, ClusterMergeMap &clusterMergeMap) const
Find split showers, using information from the overlap tensor.
virtual bool MakeClusterMerges(const ClusterMergeMap &clusterMergeMap)
Merge clusters together.
float m_maxClusterSeparation
The maximum separation for clusters to be merged.
bool Run(ThreeViewShowersAlgorithm *const pAlgorithm, TensorType &overlapTensor)
Run the algorithm tool.
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...
void SpecifyClusterMerges(ThreeViewShowersAlgorithm *const pAlgorithm, const pandora::ClusterList &clusterList, ClusterMergeMap &clusterMergeMap) const
Populate the cluster merge map, based on the information contained in the provided cluster list...
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.
bool ApplyChanges(ThreeViewShowersAlgorithm *const pAlgorithm, const ClusterMergeMap &clusterMergeMap) const
Apply the changes cached in a cluster merge map and update the tensor accordingly.
float m_minMatchedFraction
The min matched sampling point fraction for use as a key tensor element.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
float m_vertexAngularAllowance
Vertex association check: pointing angular allowance in degrees.
float m_minVertexLongitudinalDistance
Vertex association check: min longitudinal distance cut.
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
std::vector< art::Ptr< recob::Cluster > > ClusterVector
const TwoDSlidingShowerFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding shower fit result from the algorithm cache.
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...
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.