9 #include "Pandora/AlgorithmHeaders.h" 
   24 SplitShowersTool::SplitShowersTool() :
 
   26     m_minMatchedFraction(0.25f),
 
   27     m_minMatchedSamplingPoints(40),
 
   28     m_checkClusterProximities(
true),
 
   29     m_maxClusterSeparation(25.f),
 
   30     m_checkClusterVertexRelations(
true),
 
   31     m_minVertexLongitudinalDistance(-2.5f),
 
   32     m_maxVertexLongitudinalDistance(20.f),
 
   33     m_maxVertexTransverseDistance(1.5f),
 
   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);
 
  122         for (IteratorList::const_iterator iIter = iteratorList.begin(); iIter != iteratorList.end(); ++iIter)
 
  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);
 
  152     for (IteratorList::const_iterator iIter1 = iteratorList.begin(), iIter1End = iteratorList.end(); iIter1 != iIter1End; ++iIter1)
 
  154         for (IteratorList::const_iterator iIter2 = iIter1; iIter2 != iIter1End; ++iIter2)
 
  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);
 
  257     for (ClusterList::const_iterator iter = clusterList.begin(), iterEnd = clusterList.end(); iter != iterEnd; ++iter)
 
  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...
required by fuzzyCluster table::sbnd_g4_services gaushitTruthMatch pandora
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. 
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
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
TwoDSlidingFitResult class. 
BEGIN_PROLOG could also be cout
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.