8 #include "Pandora/AlgorithmHeaders.h" 21 TrackMergeRefinementAlgorithm::TrackMergeRefinementAlgorithm() :
22 m_maxLoopIterations(10),
23 m_minClusterLengthSum(75.
f),
24 m_minSeparationDistance(0.
f),
25 m_minDirectionDeviationCosAngle(0.99
f),
26 m_maxPredictedMergePointOffset(5.
f),
27 m_distanceToLine(0.35
f),
28 m_boundaryTolerance(2.
f)
36 const ClusterList *pClusterList(
nullptr);
37 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*
this, pClusterList));
39 const CaloHitList *pCaloHitList(
nullptr);
40 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*
this, pCaloHitList));
49 unsigned int loopIterations(0);
50 ClusterList createdMainTrackClusters;
59 ClusterList unavailableProtectedClusters;
73 std::find(createdMainTrackClusters.begin(), createdMainTrackClusters.end(), clusterAssociation.
GetUpstreamCluster()));
74 if (upstreamIter != createdMainTrackClusters.end())
75 createdMainTrackClusters.erase(upstreamIter);
78 std::find(createdMainTrackClusters.begin(), createdMainTrackClusters.end(), clusterAssociation.
GetDownstreamCluster()));
79 if (downstreamIter != createdMainTrackClusters.end())
80 createdMainTrackClusters.erase(downstreamIter);
82 createdMainTrackClusters.push_back(
83 this->
CreateMainTrack(clusterAssociation, clusterToCaloHitListMap, pClusterList, clusterVector, slidingFitResultMapPair));
86 return STATUS_CODE_SUCCESS;
94 bool foundAssociation(
false);
100 const Cluster *
const pCurrentCluster(*currentIter);
103 if (currentMicroFitIter == slidingFitResultMapPair.first->end())
107 if (currentMacroFitIter == slidingFitResultMapPair.second->end())
112 const Cluster *
const pTestCluster(*testIter);
119 if (testMicroFitIter == slidingFitResultMapPair.first->end())
123 if (testMacroFitIter == slidingFitResultMapPair.second->end())
129 const float currentMinLayerZ(currentMacroFitIter->second.GetGlobalMinLayerPosition().GetZ()),
130 currentMaxLayerZ(currentMacroFitIter->second.GetGlobalMaxLayerPosition().GetZ());
131 const float testMinLayerZ(testMacroFitIter->second.GetGlobalMinLayerPosition().GetZ()),
132 testMaxLayerZ(testMacroFitIter->second.GetGlobalMaxLayerPosition().GetZ());
134 if (((currentMinLayerZ > testMinLayerZ) && (currentMaxLayerZ < testMaxLayerZ)) ||
135 ((testMinLayerZ > currentMinLayerZ) && (testMaxLayerZ < currentMaxLayerZ)))
138 CartesianVector currentMergePoint(0.
f, 0.
f, 0.
f), testMergePoint(0.
f, 0.
f, 0.
f), currentMergeDirection(0.
f, 0.
f, 0.
f),
139 testMergeDirection(0.
f, 0.
f, 0.
f);
141 !isCurrentUpstream, currentMergePoint, currentMergeDirection) ||
142 !this->GetClusterMergingCoordinates(testMicroFitIter->second, testMacroFitIter->second, currentMacroFitIter->second,
143 isCurrentUpstream, testMergePoint, testMergeDirection))
148 if ((isCurrentUpstream && !this->
AreClustersAssociated(currentMergePoint, currentMergeDirection, testMergePoint, testMergeDirection)) ||
149 (!isCurrentUpstream && !this->
AreClustersAssociated(testMergePoint, testMergeDirection, currentMergePoint, currentMergeDirection)))
154 if (isCurrentUpstream)
157 currentMergePoint, currentMergeDirection, testMergePoint, testMergeDirection * (-1.
f), pCurrentCluster, pTestCluster);
162 testMergePoint, testMergeDirection, currentMergePoint, currentMergeDirection * (-1.
f), pTestCluster, pCurrentCluster);
165 foundAssociation =
true;
166 maxLength = lengthSum;
170 return foundAssociation;
176 const CartesianVector &downstreamPoint,
const CartesianVector &downstreamDirection)
const 178 if (downstreamPoint.GetZ() < upstreamPoint.GetZ())
181 const float separationDistance(std::sqrt(upstreamPoint.GetDistanceSquared(downstreamPoint)));
188 const CartesianVector predictedDownstreamPoint(upstreamPoint + (upstreamDirection * separationDistance));
189 const float predictedDownstreamOffset((predictedDownstreamPoint - downstreamPoint).GetMagnitude());
194 const CartesianVector predictedUpstreamPoint(downstreamPoint - (downstreamDirection * separationDistance));
195 const float predictedUpstreamOffset((predictedUpstreamPoint - upstreamPoint).GetMagnitude());
206 const ClusterPairAssociation &clusterAssociation,
const ClusterList &createdMainTrackClusters, ClusterList &protectedClusters)
const 208 for (
const Cluster *
const pMainTrackCluster : createdMainTrackClusters)
211 protectedClusters.push_back(pMainTrackCluster);
219 if (extrapolatedHitVector.empty())
240 const Cluster *
const pConsideredCluster(upstreamCluster->GetNCaloHits() > downstreamCluster->GetNCaloHits() ? downstreamCluster : upstreamCluster);
252 for (
const auto &
entry : clusterToCaloHitListMap)
255 showerClustersToFragment.push_back(
entry.
first);
260 ClusterList remnantClusterList;
261 const Cluster *
const pMainTrackCluster(
263 clusterToCaloHitListMap, remnantClusterList, *slidingFitResultMapPair.first, *slidingFitResultMapPair.second));
264 const Cluster *
const pClusterToDelete(
266 clusterToCaloHitListMap, remnantClusterList, *slidingFitResultMapPair.first, *slidingFitResultMapPair.second));
268 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*
this, pMainTrackCluster, pClusterToDelete));
270 for (
const Cluster *
const pShowerCluster : showerClustersToFragment)
272 const CaloHitList &caloHitsToMerge(clusterToCaloHitListMap.at(pShowerCluster));
273 this->
AddHitsToMainTrack(pMainTrackCluster, pShowerCluster, caloHitsToMerge, clusterAssociation, remnantClusterList);
276 ClusterList createdClusters;
280 ClusterList modifiedClusters(showerClustersToFragment.begin(), showerClustersToFragment.end());
283 createdClusters.push_back(pMainTrackCluster);
286 return pMainTrackCluster;
293 PANDORA_RETURN_RESULT_IF_AND_IF(
294 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxLoopIterations",
m_maxLoopIterations));
296 PANDORA_RETURN_RESULT_IF_AND_IF(
297 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLengthSum",
m_minClusterLengthSum));
299 PANDORA_RETURN_RESULT_IF_AND_IF(
300 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinSeparationDistance",
m_minSeparationDistance));
302 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
305 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
308 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"DistanceToLine",
m_distanceToLine));
310 PANDORA_RETURN_RESULT_IF_AND_IF(
311 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"BoundaryTolerance",
m_boundaryTolerance));
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.
ClusterAssociation class.
Header file for the track merge refinement class.
Header file for the lar hit width helper class.
bool AreExtrapolatedHitsNearBoundaries(const pandora::CaloHitVector &extrapolatedHitVector, ClusterAssociation &clusterAssociation) const
Check the separation of the extremal extrapolated hits with the cluster merge points or...
void AddHitsToMainTrack(const pandora::Cluster *const pMainTrackCluster, const pandora::Cluster *const pShowerTrackCluster, const pandora::CaloHitList &caloHitsToMerge, const ClusterAssociation &clusterAssociation, pandora::ClusterList &remnantClusterList) const
Remove the hits from a shower cluster that belong to the main track and add them into the main track ...
std::pair< TwoDSlidingFitResultMap *, TwoDSlidingFitResultMap * > SlidingFitResultMapPair
const pandora::CartesianVector GetUpstreamMergePoint() const
Returns the upstream cluster merge point.
void ConsiderClusterAssociation(const ClusterPairAssociation &clusterAssociation, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Remove the cluster association from the cluster vector so that the same cluster pair is not considere...
std::unordered_map< const pandora::Cluster *, pandora::CaloHitList > ClusterToCaloHitListMap
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)=0
float m_maxPredictedMergePointOffset
The threshold separation distance between the predicted and true cluster merge points.
QCollection::Item first()
bool GetClusterMergingCoordinates(const TwoDSlidingFitResult &clusterMicroFitResult, const TwoDSlidingFitResult &clusterMacroFitResult, const TwoDSlidingFitResult &associatedMacroFitResult, const bool isEndUpstream, pandora::CartesianVector &clusterMergePosition, pandora::CartesianVector &clusterMergeDirection) const
Get the merging coordinate and direction for an input cluster with respect to an associated cluster...
const pandora::Cluster * GetUpstreamCluster() const
Returns the address of the upstream cluster.
Header file for the geometry helper class.
static bool SortByPosition(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by position, then pulse-height.
float m_minClusterLengthSum
The threshold cluster and associated cluster length sum.
bool AreExtrapolatedHitsGood(const ClusterToCaloHitListMap &clusterToCaloHitListMap, ClusterAssociation &clusterAssociation) const
Perform topological checks on the collected hits to ensure no gaps are present.
void UpdateContainers(const pandora::ClusterList &clustersToAdd, const pandora::ClusterList &clustersToDelete, const T sortFunction, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Remove deleted clusters from the cluster vector and sliding fit maps and add in created clusters that...
Header file for the cluster helper class.
void ProcessRemnantClusters(const pandora::ClusterList &remnantClusterList, const pandora::Cluster *const pMainTrackCluster, const pandora::ClusterList *const pClusterList, pandora::ClusterList &createdClusters) const
Process the remnant clusters separating those that stradle the main track.
bool AreClustersAssociated(const pandora::CartesianVector &upstreamPoint, const pandora::CartesianVector &upstreamDirection, const pandora::CartesianVector &downstreamPoint, const pandora::CartesianVector &downstreamDirection) const
Whether two clusters are assoicated to one another.
bool FindBestClusterAssociation(const pandora::ClusterVector &clusterVector, const SlidingFitResultMapPair &slidingFitResultMapPair, ClusterPairAssociation &clusterAssociation) const
Find the best cluster association.
ClusterPairAssociation class.
static float GetLength(const pandora::Cluster *const pCluster)
Get length of cluster.
const pandora::CartesianVector GetDownstreamMergePoint() const
Returns the downstream cluster merge point.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
pandora::StatusCode Run()
void InitialiseContainers(const pandora::ClusterList *pClusterList, const T sortFunction, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Fill the cluster vector and sliding fit maps with clusters that are determined to be track-like...
void RemoveClusterFromContainers(const pandora::Cluster *const pClustertoRemove, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Remove a cluster from the cluster vector and sliding fit maps.
const pandora::Cluster * CreateMainTrack(const ClusterPairAssociation &clusterAssociation, const ClusterToCaloHitListMap &clusterToCaloHitListMap, const pandora::ClusterList *pClusterList, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const
Refine the cluster endpoints and merge together the associated clusters alongside any extrapolated hi...
float m_minSeparationDistance
The threshold separation distance between associated clusters.
unsigned int m_maxLoopIterations
The maximum number of main loop iterations.
float m_boundaryTolerance
The maximum allowed distance of an extremal extrapolate hit to a cluster merge point.
const pandora::Cluster * GetDownstreamCluster() const
Returns the address of the downstream cluster.
void GetHitsInBoundingBox(const pandora::CartesianVector &firstCorner, const pandora::CartesianVector &secondCorner, const pandora::ClusterList *const pClusterList, ClusterToCaloHitListMap &clusterToCaloHitListMap, const pandora::ClusterList &unavailableProtectedClusters=pandora::ClusterList(), const float distanceToLine=-1.f) const
Find the unprotected hits that are contained within a defined box with the option to apply a cut on t...
std::vector< art::Ptr< recob::Cluster > > ClusterVector
bool IsNearBoundary(const pandora::CaloHit *const pCaloHit, const pandora::CartesianVector &boundaryPosition2D, const float boundaryTolerance) const
Check whether a hit is close to a boundary point.
const pandora::Cluster * RemoveOffAxisHitsFromTrack(const pandora::Cluster *const pCluster, const pandora::CartesianVector &splitPosition, const bool isEndUpstream, const ClusterToCaloHitListMap &clusterToCaloHitListMap, pandora::ClusterList &remnantClusterList, TwoDSlidingFitResultMap µSlidingFitResultMap, TwoDSlidingFitResultMap ¯oSlidingFitResultMap) const
Remove any hits in the upstream/downstream cluster that lie off of the main track axis (i...
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void GetUnavailableProtectedClusters(const ClusterPairAssociation &clusterAssociation, const pandora::ClusterList &createdMainTrackClusters, pandora::ClusterList &unavailableProtectedClusters) const
Obtain a list of clusters whos hits are protected and cannot be reassigned.
float m_distanceToLine
The threshold hit distance of an extrapolated hit from the segment connecting line.
float m_minDirectionDeviationCosAngle
The threshold cos opening angle of the associated cluster directions.