23 m_clusterMinLength(10.f),
24 m_halfWindowLayers(30),
26 m_maxCosSplittingAngle(0.9925f),
27 m_minCosMergingAngle(0.94f),
28 m_maxTransverseDisplacement(5.f),
29 m_maxLongitudinalDisplacement(30.f),
30 m_maxLongitudinalDisplacementSquared(m_maxLongitudinalDisplacement * m_maxLongitudinalDisplacement)
52 for (ClusterVector::const_iterator bIter = clusterVector.begin(), bIterEnd1 = clusterVector.end(); bIter != bIterEnd1; ++bIter)
54 if (splitClusters.count(*bIter) > 0)
57 TwoDSlidingFitResultMap::const_iterator bFitIter = slidingFitResultMap.find(*bIter);
59 if (slidingFitResultMap.end() == bFitIter)
69 if (STATUS_CODE_SUCCESS != this->
FindBestSplitPosition(branchSlidingFitResult, splitPosition, splitDirection1, splitDirection2))
73 TwoDSlidingFitResultMap::const_iterator bestReplacementIter1(slidingFitResultMap.end());
74 TwoDSlidingFitResultMap::const_iterator bestReplacementIter2(slidingFitResultMap.end());
79 for (ClusterVector::const_iterator rIter = clusterVector.begin(), rIterEnd = clusterVector.end(); rIter != rIterEnd; ++rIter)
81 if (splitClusters.count(*rIter) > 0)
84 TwoDSlidingFitResultMap::const_iterator rFitIter = slidingFitResultMap.find(*rIter);
86 if (slidingFitResultMap.end() == rFitIter)
94 float lengthSquared1(std::numeric_limits<float>::max());
95 float lengthSquared2(std::numeric_limits<float>::max());
97 if (STATUS_CODE_SUCCESS != this->
ConfirmSplitPosition(branchSlidingFitResult, replacementSlidingFitResult, splitPosition,
98 splitDirection1, splitDirection2, lengthSquared1, lengthSquared2))
101 if (lengthSquared1 < bestLengthSquared1)
103 bestLengthSquared1 = lengthSquared1;
104 bestReplacementIter1 = rFitIter;
107 if (lengthSquared2 < bestLengthSquared2)
109 bestLengthSquared2 = lengthSquared2;
110 bestReplacementIter2 = rFitIter;
114 const Cluster *pReplacementCluster1 = NULL;
115 const Cluster *pReplacementCluster2 = NULL;
117 if (slidingFitResultMap.end() != bestReplacementIter1)
118 pReplacementCluster1 = bestReplacementIter1->first;
120 if (slidingFitResultMap.end() != bestReplacementIter2)
121 pReplacementCluster2 = bestReplacementIter2->first;
123 if (NULL == pReplacementCluster1 && NULL == pReplacementCluster2)
129 if (pReplacementCluster1 && pReplacementCluster2)
131 if (!(this->
IdentifyCrossedTracks(pBranchCluster, pReplacementCluster1, pReplacementCluster2, splitPosition)))
135 this->
PerformDoubleSplit(pBranchCluster, pReplacementCluster1, pReplacementCluster2, splitPosition, splitDirection1, splitDirection2));
138 else if (pReplacementCluster1)
141 this->
PerformSingleSplit(pBranchCluster, pReplacementCluster1, splitPosition, splitDirection1, splitDirection2));
143 else if (pReplacementCluster2)
146 this->
PerformSingleSplit(pBranchCluster, pReplacementCluster2, splitPosition, splitDirection2, splitDirection1));
150 if (pReplacementCluster1)
151 splitClusters.insert(pReplacementCluster1);
153 if (pReplacementCluster2)
154 splitClusters.insert(pReplacementCluster2);
156 splitClusters.insert(pBranchCluster);
159 return STATUS_CODE_SUCCESS;
166 for (ClusterList::const_iterator iter = pClusterList->begin(), iterEnd = pClusterList->end(); iter != iterEnd; ++iter)
168 const Cluster *
const pCluster = *iter;
173 clusterVector.push_back(pCluster);
185 for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
187 if (slidingFitResultMap.end() == slidingFitResultMap.find(*iter))
193 if (!slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(*iter, slidingFitResult)).second)
198 if (STATUS_CODE_FAILURE == statusCodeException.
GetStatusCode())
199 throw statusCodeException;
212 bool foundSplit(
false);
218 float minL(0.f), maxL(0.f), minT(0.f), maxT(0.f);
222 const unsigned int nSamplingPoints =
static_cast<unsigned int>((maxL - minL) /
m_samplingPitch);
224 for (
unsigned int n = 0; n < nSamplingPoints; ++n)
226 const float alpha((0.5f +
static_cast<float>(n)) /
static_cast<float>(nSamplingPoints));
227 const float rL(minL + (maxL - minL) * alpha);
229 CartesianVector centralPosition(0.f, 0.f, 0.f), forwardDirection(0.f, 0.f, 0.f), backwardDirection(0.f, 0.f, 0.f);
231 if ((STATUS_CODE_SUCCESS != branchSlidingFitResult.
GetGlobalFitPosition(rL, centralPosition)) ||
232 (STATUS_CODE_SUCCESS != branchSlidingFitResult.
GetGlobalFitDirection(rL + halfWindowLength, forwardDirection)) ||
233 (STATUS_CODE_SUCCESS != branchSlidingFitResult.
GetGlobalFitDirection(rL - halfWindowLength, backwardDirection)))
238 const float cosTheta(forwardDirection.GetDotProduct(backwardDirection));
240 if (cosTheta < splitCosTheta)
245 if ((STATUS_CODE_SUCCESS != branchSlidingFitResult.
GetGlobalFitPosition(rL + halfWindowLength, forwardPosition)) ||
246 (STATUS_CODE_SUCCESS != branchSlidingFitResult.
GetGlobalFitPosition(rL - halfWindowLength, backwardPosition)))
251 CartesianVector forwardVectorOutwards(forwardPosition - centralPosition);
252 CartesianVector backwardVectorOutwards(backwardPosition - centralPosition);
254 splitPosition = centralPosition;
255 splitDirection1 = (forwardDirection.GetDotProduct(forwardVectorOutwards) > 0.f) ? forwardDirection : forwardDirection * -1.f;
256 splitDirection2 = (backwardDirection.
GetDotProduct(backwardVectorOutwards) > 0.f) ? backwardDirection : backwardDirection * -1.f;
257 splitCosTheta = cosTheta;
263 return STATUS_CODE_NOT_FOUND;
265 return STATUS_CODE_SUCCESS;
272 const CartesianVector &splitDirection2,
float &bestLengthSquared1,
float &bestLengthSquared2)
const
275 bestLengthSquared1 = std::numeric_limits<float>::max();
276 bestLengthSquared2 = std::numeric_limits<float>::max();
278 bool foundMatch(
false);
290 const float cosSplittingAngle(-splitDirection1.
GetDotProduct(splitDirection2));
291 const float branchLengthSquared((branchVertex2 - branchVertex1).GetMagnitudeSquared());
292 const float replacementLengthSquared((maxPosition - minPosition).GetMagnitudeSquared());
295 for (
unsigned int iFwd = 0; iFwd < 2; ++iFwd)
297 const CartesianVector pAxis((0 == iFwd) ? (maxPosition - minPosition) : (minPosition - maxPosition));
298 const CartesianVector vtxPosition((0 == iFwd) ? minPosition : maxPosition);
299 const CartesianVector endPosition((0 == iFwd) ? maxPosition : minPosition);
301 : (pAxis.
GetDotProduct(maxDirection) > 0 ? maxDirection : maxDirection * -1.f));
307 const float lengthSquared((vtxPosition - splitPosition).GetMagnitudeSquared());
308 const float lengthSquared1((vtxPosition - branchVertex1).GetMagnitudeSquared());
309 const float lengthSquared2((vtxPosition - branchVertex2).GetMagnitudeSquared());
311 if (vtxDisplacement > endDisplacement)
314 if (std::min(lengthSquared, std::min(lengthSquared1, lengthSquared2)) > std::min(branchLengthSquared, replacementLengthSquared))
318 float impactL(0.f), impactT(0.f);
322 impactT > std::max(1.5f, 0.577f * (1.f + impactL)))
326 if (vtxDirection.GetDotProduct(branchDirection1) > std::max(
m_minCosMergingAngle, cosSplittingAngle))
328 if (lengthSquared < bestLengthSquared1)
330 bestLengthSquared1 = lengthSquared;
336 if (vtxDirection.GetDotProduct(branchDirection2) > std::max(
m_minCosMergingAngle, cosSplittingAngle))
338 if (lengthSquared < bestLengthSquared2)
340 bestLengthSquared2 = lengthSquared;
347 return STATUS_CODE_NOT_FOUND;
349 return STATUS_CODE_SUCCESS;
358 this->
GetCaloHitListToMove(pBranchCluster, pReplacementCluster, splitPosition, forwardDirection, backwardDirection, caloHitListToMove);
363 if (caloHitListToKeep.empty())
366 return this->
SplitCluster(pBranchCluster, pReplacementCluster, caloHitListToMove);
375 CaloHitList caloHitListToMove1, caloHitListToMove2;
376 this->
GetCaloHitListsToMove(pBranchCluster, splitPosition, splitDirection1, splitDirection2, caloHitListToMove1, caloHitListToMove2);
381 if (caloHitListToKeep1.empty())
382 return STATUS_CODE_FAILURE;
389 if (caloHitListToKeep2.empty())
392 return this->
SplitCluster(pBranchCluster, pReplacementCluster2, caloHitListToMove2);
403 const CartesianVector vtxDirection((forwardPosition - vtxPosition).GetUnitVector());
408 for (CaloHitList::const_iterator iter = caloHitListToSort.begin(), iterEnd = caloHitListToSort.end(); iter != iterEnd; ++iter)
410 const CaloHit *
const pCaloHit = *iter;
414 caloHitListToMove.push_back(pCaloHit);
418 caloHitListToCheck.push_back(pCaloHit);
422 float closestLengthSquared(std::numeric_limits<float>::max());
424 for (CaloHitList::const_iterator iter = caloHitListToCheck.begin(), iterEnd = caloHitListToCheck.end(); iter != iterEnd; ++iter)
426 const CaloHit *
const pCaloHit = *iter;
432 const float lengthSquared((pCaloHit->
GetPositionVector() - vtxPosition).GetMagnitudeSquared());
434 if (lengthSquared < closestLengthSquared)
435 closestLengthSquared = lengthSquared;
438 for (CaloHitList::const_iterator iter = caloHitListToCheck.begin(), iterEnd = caloHitListToCheck.end(); iter != iterEnd; ++iter)
440 const CaloHit *
const pCaloHit = *iter;
442 if ((pCaloHit->
GetPositionVector() - vtxPosition).GetMagnitudeSquared() >= closestLengthSquared)
443 caloHitListToMove.push_back(pCaloHit);
455 for (CaloHitList::const_iterator iter = caloHitListToSort.begin(), iterEnd = caloHitListToSort.end(); iter != iterEnd; ++iter)
457 const CaloHit *
const pCaloHit = *iter;
462 if (displacement1 > displacement2)
464 caloHitListToMove1.push_back(pCaloHit);
468 caloHitListToMove2.push_back(pCaloHit);
477 CartesianVector branchVertex1(0.f, 0.f, 0.f), branchVertex2(0.f, 0.f, 0.f);
483 if ((replacementVertex2 - replacementVertex1).GetMagnitudeSquared() > (branchVertex2 - branchVertex1).GetMagnitudeSquared())
494 if (caloHitListToMove.empty())
495 return STATUS_CODE_FAILURE;
500 for (CaloHitList::const_iterator iter = caloHitList.begin(), iterEnd = caloHitList.end(); iter != iterEnd; ++iter)
502 const CaloHit *
const pCaloHit = *iter;
504 if (caloHitListToMove.end() == std::find(caloHitListToMove.begin(), caloHitListToMove.end(), pCaloHit))
505 caloHitListToKeep.push_back(pCaloHit);
508 return STATUS_CODE_SUCCESS;
514 const Cluster *
const pBranchCluster,
const Cluster *
const pReplacementCluster,
const CaloHitList &caloHitListToMove)
const
516 if (caloHitListToMove.empty())
517 return STATUS_CODE_FAILURE;
519 for (CaloHitList::const_iterator iter = caloHitListToMove.begin(), iterEnd = caloHitListToMove.end(); iter != iterEnd; ++iter)
521 const CaloHit *
const pCaloHit = *iter;
526 return STATUS_CODE_SUCCESS;
542 return STATUS_CODE_INVALID_PARAMETER;
557 return STATUS_CODE_SUCCESS;
Header file for the cosmic ray splitting algorithm class.
Header file for the cluster helper class.
Header file for the geometry helper class.
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
#define PANDORA_RETURN_RESULT_IF(StatusCode1, Operator, Command)
static pandora::StatusCode GetCurrentList(const pandora::Algorithm &algorithm, const T *&pT)
Get the current list.
static pandora::StatusCode MergeAndDeleteClusters(const pandora::Algorithm &algorithm, const pandora::Cluster *const pClusterToEnlarge, const pandora::Cluster *const pClusterToDelete)
Merge two clusters in the current list, enlarging one cluster and deleting the second.
static pandora::StatusCode AddToCluster(const pandora::Algorithm &algorithm, const pandora::Cluster *const pCluster, const T *const pT)
Add a calo hit, or a list of calo hits, to a cluster.
static pandora::StatusCode RemoveFromCluster(const pandora::Algorithm &algorithm, const pandora::Cluster *const pCluster, const pandora::CaloHit *const pCaloHit)
Remove a calo hit from a cluster. Note this function will not remove the final calo hit from a cluste...
pandora::StatusCode PerformDoubleSplit(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster1, const pandora::Cluster *const pReplacementCluster2, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection1, const pandora::CartesianVector &splitDirection2) const
Split a branch cluster for case of two replacement clusters.
pandora::StatusCode FindBestSplitPosition(const TwoDSlidingFitResult &slidingFitResult, pandora::CartesianVector &splitPosition, pandora::CartesianVector &splitDirection1, pandora::CartesianVector &splitDirection2) const
Find the position of greatest scatter along a sliding linear fit.
float m_minCosMergingAngle
largest relative angle allowed when merging clusters
pandora::StatusCode ConfirmSplitPosition(const TwoDSlidingFitResult &branchSlidingFitResult, const TwoDSlidingFitResult &replacementSlidingFitResult, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection1, const pandora::CartesianVector &splitDirection2, float &lengthSquared1, float &lengthSquared2) const
Find a second replacement cluster that aligns with the scatter of the first branch cluster.
float m_maxCosSplittingAngle
smallest scatter angle allowed when splitting cluster
float m_maxLongitudinalDisplacement
maximum longitudinal displacement of associated clusters
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
float m_maxLongitudinalDisplacementSquared
longitudinal displacement squared
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.
float m_maxTransverseDisplacement
maximum transverse displacement of associated clusters
pandora::StatusCode Run()
Run the algorithm.
unsigned int m_halfWindowLayers
number of layers to use for half-window of sliding fit
void BuildSlidingFitResultMap(const pandora::ClusterVector &clusterVector, TwoDSlidingFitResultMap &slidingFitResultMap) const
Build the map of sliding fit results.
pandora::StatusCode GetCaloHitListToKeep(const pandora::Cluster *const pBranchCluster, const pandora::CaloHitList &caloHitListToMove, pandora::CaloHitList &caloHitListToKeep) const
Split the branch cluster and add hits to the replacement cluster.
void GetCaloHitListToMove(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &forwardDirection, const pandora::CartesianVector &backwardDirection, pandora::CaloHitList &caloHitList) const
Get list of calo hits to move in order to split a branch cluster into two segments for case of one re...
bool IdentifyCrossedTracks(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster1, const pandora::Cluster *const pReplacementCluster2, const pandora::CartesianVector &splitPosition) const
Identify crossed tracks formed from the branch cluster and its replacement cluster.
pandora::StatusCode PerformSingleSplit(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &forwardDirection, const pandora::CartesianVector &backwardDirection) const
Split a branch cluster for case of one replacement cluster.
pandora::StatusCode SplitCluster(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CaloHitList &caloHitListToMove) const
Split the branch cluster and add hits to the replacement cluster.
float m_samplingPitch
sampling pitch for walking along sliding linear fit
CosmicRaySplittingAlgorithm()
Default constructor.
float m_clusterMinLength
minimum length of clusters for this algorithm
void GetCaloHitListsToMove(const pandora::Cluster *const pBranchCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection1, const pandora::CartesianVector &splitDirection2, pandora::CaloHitList &caloHitList1, pandora::CaloHitList &caloHitList2) const
Get lists of calo hits to move in order to split a branch cluster into two segments for case of two r...
static pandora::CartesianVector GetClosestPosition(const pandora::CartesianVector &position, const pandora::ClusterList &clusterList)
Get closest position in a list of clusters to a specified input position vector.
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,...
static void GetExtremalCoordinates(const pandora::ClusterList &clusterList, pandora::CartesianVector &innerCoordinate, pandora::CartesianVector &outerCoordinate)
Get positions of the two most distant calo hits in a list of cluster (ordered by Z)
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
TwoDSlidingFitResult class.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
pandora::StatusCode GetGlobalFitPosition(const float rL, pandora::CartesianVector &position) const
Get global fit position for a given longitudinal coordinate.
pandora::CartesianVector GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
float GetLayerFitHalfWindowLength() const
Get the layer fit half window length.
pandora::StatusCode GetGlobalFitDirection(const float rL, pandora::CartesianVector &direction) const
Get global fit direction for a given longitudinal coordinate.
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
pandora::CartesianVector GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
const CartesianVector & GetPositionVector() const
Get the position vector of center of calorimeter cell, units mm.
float GetDotProduct(const CartesianVector &rhs) const
Get the dot product of the cartesian vector with a second cartesian vector.
float GetMagnitude() const
Get the magnitude.
CartesianVector GetCrossProduct(const CartesianVector &rhs) const
Get the cross product of the cartesian vector with a second cartesian vector.
const OrderedCaloHitList & GetOrderedCaloHitList() const
Get the ordered calo hit list.
void FillCaloHitList(CaloHitList &caloHitList) const
Fill a provided calo hit list with all the calo hits in the ordered calo hit list.
const Pandora & GetPandora() const
Get the associated pandora instance.
StatusCodeException class.
StatusCode GetStatusCode() const
Get status code.
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
std::vector< const Cluster * > ClusterVector
MANAGED_CONTAINER< const Cluster * > ClusterList
std::unordered_set< const Cluster * > ClusterSet
MANAGED_CONTAINER< const CaloHit * > CaloHitList
StatusCode
The StatusCode enum.