9 #include "Pandora/AlgorithmHeaders.h" 20 LongitudinalAssociationAlgorithm::LongitudinalAssociationAlgorithm() :
21 m_minClusterLayers(4),
24 m_maxGapDistanceSquared(10.
f),
25 m_minCosRelativeAngle(0.985
f),
26 m_maxTransverseDisplacement(2.
f),
27 m_maxLongitudinalDisplacement(2.
f),
39 const Cluster *
const pCluster = *iter;
41 if (1 + pCluster->GetOuterPseudoLayer() - pCluster->GetInnerPseudoLayer() <
m_minClusterLayers)
44 clusterVector.push_back(pCluster);
57 const Cluster *
const pInnerCluster = *iterI;
61 const Cluster *
const pOuterCluster = *iterJ;
63 if (pInnerCluster == pOuterCluster)
69 clusterAssociationMap[pInnerCluster].m_forwardAssociations.insert(pOuterCluster);
70 clusterAssociationMap[pOuterCluster].m_backwardAssociations.insert(pInnerCluster);
79 const unsigned int currentLayer(isForward ? pCurrentCluster->GetOuterPseudoLayer() : pCurrentCluster->GetInnerPseudoLayer());
80 const unsigned int testLayer(isForward ? pTestCluster->GetOuterPseudoLayer() : pTestCluster->GetInnerPseudoLayer());
82 if (isForward && ((testLayer > currentLayer) || ((testLayer == currentLayer) &&
LArClusterHelper::SortByNHits(pTestCluster, pCurrentCluster))))
85 if (!isForward && ((testLayer < currentLayer) || ((testLayer == currentLayer) &&
LArClusterHelper::SortByNHits(pTestCluster, pCurrentCluster))))
95 if (pOuterCluster->GetInnerPseudoLayer() < pInnerCluster->GetInnerPseudoLayer())
96 throw pandora::StatusCodeException(STATUS_CODE_NOT_ALLOWED);
99 if ((pOuterCluster->GetInnerPseudoLayer() < pInnerCluster->GetInnerPseudoLayer() + 3) ||
100 (pInnerCluster->GetOuterPseudoLayer() + 3 > pOuterCluster->GetOuterPseudoLayer()))
105 if ((pInnerCluster->GetOuterPseudoLayer() > pOuterCluster->GetInnerPseudoLayer() + 1) ||
106 (pOuterCluster->GetInnerPseudoLayer() > pInnerCluster->GetOuterPseudoLayer() +
m_maxGapLayers))
111 if ((2 * pInnerCluster->GetOuterPseudoLayer() < pOuterCluster->GetInnerPseudoLayer() + pInnerCluster->GetInnerPseudoLayer()) ||
112 (pInnerCluster->GetOuterPseudoLayer() + pOuterCluster->GetOuterPseudoLayer() < 2 * pOuterCluster->GetInnerPseudoLayer()))
117 const CartesianVector innerEndCentroid(pInnerCluster->GetCentroid(pInnerCluster->GetOuterPseudoLayer()));
118 const CartesianVector outerStartCentroid(pOuterCluster->GetCentroid(pOuterCluster->GetInnerPseudoLayer()));
123 ClusterFitResult innerEndFit, outerStartFit;
124 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, ClusterFitHelper::FitEnd(pInnerCluster,
m_fitLayers, innerEndFit));
125 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, ClusterFitHelper::FitStart(pOuterCluster,
m_fitLayers, outerStartFit));
136 const CartesianVector &outerClusterStart,
const ClusterFitResult &innerFit,
const ClusterFitResult &outerFit)
const 138 if (!innerFit.IsFitSuccessful() || !outerFit.IsFitSuccessful())
144 const CartesianVector innerEndFit1(
145 innerFit.GetIntercept() + innerFit.GetDirection() * (innerFit.GetDirection().GetDotProduct(innerClusterEnd - innerFit.GetIntercept())));
146 const CartesianVector innerEndFit2(
147 outerFit.GetIntercept() + outerFit.GetDirection() * (outerFit.GetDirection().GetDotProduct(innerClusterEnd - outerFit.GetIntercept())));
149 const CartesianVector outerStartFit1(
150 outerFit.GetIntercept() + outerFit.GetDirection() * (outerFit.GetDirection().GetDotProduct(outerClusterStart - outerFit.GetIntercept())));
151 const CartesianVector outerStartFit2(
152 innerFit.GetIntercept() + innerFit.GetDirection() * (innerFit.GetDirection().GetDotProduct(outerClusterStart - innerFit.GetIntercept())));
154 const CartesianVector clusterSeparation(outerClusterStart - innerClusterEnd);
160 const CartesianVector fittedSeparation(outerStartFit1 - innerEndFit1);
162 if ((std::fabs(fittedSeparation.GetX()) <
m_hitSizeX * m_maxTransverseDisplacement) &&
163 (std::fabs(fittedSeparation.GetZ()) <
m_hitSizeZ * m_maxLongitudinalDisplacement))
166 const CartesianVector fittedInnerSeparation(innerEndFit2 - innerEndFit1);
168 if ((std::fabs(fittedInnerSeparation.GetX()) <
m_hitSizeX * m_maxTransverseDisplacement) &&
169 (std::fabs(fittedInnerSeparation.GetZ()) <
m_hitSizeZ * m_maxLongitudinalDisplacement))
172 const CartesianVector fittedOuterSeparation(outerStartFit2 - outerStartFit1);
174 if ((std::fabs(fittedOuterSeparation.GetX()) <
m_hitSizeX * m_maxTransverseDisplacement) &&
175 (std::fabs(fittedOuterSeparation.GetZ()) <
m_hitSizeZ * m_maxLongitudinalDisplacement))
185 PANDORA_RETURN_RESULT_IF_AND_IF(
186 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLayers",
m_minClusterLayers));
188 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxGapLayers",
m_maxGapLayers));
190 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"FitLayers",
m_fitLayers));
193 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxGapDistance", maxGapDistance));
196 PANDORA_RETURN_RESULT_IF_AND_IF(
197 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinCosRelativeAngle",
m_minCosRelativeAngle));
199 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
202 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
205 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"HitSizeZ",
m_hitSizeZ));
207 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"HitSizeX",
m_hitSizeX));
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.
Header file for the longitudinal association algorithm class.
void GetListOfCleanClusters(const pandora::ClusterList *const pClusterList, pandora::ClusterVector &clusterVector) const
Populate cluster vector with subset of cluster list, containing clusters judged to be clean...
void PopulateClusterAssociationMap(const pandora::ClusterVector &clusterVector, ClusterAssociationMap &clusterAssociationMap) const
Populate the cluster association map.
float m_maxLongitudinalDisplacement
maximum allowed longitudinal displacement after extrapolation (normalised to cell size) ...
float m_minCosRelativeAngle
maximum allowed relative angle between associated clusters
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::Cluster *, ClusterAssociation > ClusterAssociationMap
unsigned int m_minClusterLayers
minimum allowed number of layers for a clean cluster
Header file for the cluster helper class.
float m_hitSizeX
estimated hit size in x (drift time) dimension, units cm
float m_maxGapDistanceSquared
maximum allowed distance (squared) between associated clusters
bool IsExtremalCluster(const bool isForward, const pandora::Cluster *const pCurrentCluster, const pandora::Cluster *const pTestCluster) const
Determine which of two clusters is extremal.
unsigned int m_maxGapLayers
maximum allowed number of layers between associated clusters
float m_hitSizeZ
estimated hit size in z (wire number) dimension, units cm
bool AreClustersAssociated(const pandora::Cluster *const pInnerCluster, const pandora::Cluster *const pOuterCluster) const
Determine whether two clusters are associated.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
unsigned int m_fitLayers
number of layers to fit at start and end of cluster
float m_maxTransverseDisplacement
maximum allowed transverse displacement after extrapolation (normalised to cell size) ...
static bool SortByInnerLayer(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by inner layer, then position, then pulse-height.