9 #include "Pandora/AlgorithmHeaders.h" 22 TransverseAssociationAlgorithm::TransverseAssociationAlgorithm() :
23 m_firstLengthCut(1.5
f),
24 m_secondLengthCut(7.5
f),
27 m_clusterCosAngle(
std::cos(m_clusterAngle * M_PI / 180.
f)),
28 m_clusterTanAngle(
std::tan(m_clusterAngle * M_PI / 180.
f)),
29 m_maxTransverseOverlap(0.5
f),
30 m_maxProjectedOverlap(1.
f),
31 m_maxLongitudinalOverlap(1.5
f),
32 m_transverseClusterMinCosTheta(0.866
f),
33 m_transverseClusterMinLength(0.5
f),
34 m_transverseClusterMaxDisplacement(1.5
f),
35 m_searchRegionX(3.5
f),
44 clusterVector.clear();
45 clusterVector.insert(clusterVector.begin(), pClusterList->begin(), pClusterList->end());
60 if (nearbyClusters.empty())
67 ClusterVector shortClusters, transverseMediumClusters, longitudinalMediumClusters, longClusters;
68 this->
SortInputClusters(allClusters, shortClusters, transverseMediumClusters, longitudinalMediumClusters, longClusters);
70 ClusterVector transverseClusters(shortClusters.begin(), shortClusters.end());
71 transverseClusters.insert(transverseClusters.end(), transverseMediumClusters.begin(), transverseMediumClusters.end());
73 ClusterVector establishedClusters(transverseMediumClusters.begin(), transverseMediumClusters.end());
74 establishedClusters.insert(establishedClusters.end(), longitudinalMediumClusters.begin(), longitudinalMediumClusters.end());
75 establishedClusters.insert(establishedClusters.end(), longClusters.begin(), longClusters.end());
105 catch (StatusCodeException &statusCodeException)
107 std::cout <<
"TransverseAssociationAlgorithm: exception " << statusCodeException.ToString() << std::endl;
121 CaloHitList allCaloHits;
123 for (
const Cluster *
const pCluster : allClusters)
125 CaloHitList daughterHits;
126 pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
127 allCaloHits.insert(allCaloHits.end(), daughterHits.begin(), daughterHits.end());
129 for (
const CaloHit *
const pCaloHit : daughterHits)
130 (void) hitToClusterMap.insert(HitToClusterMap::value_type(pCaloHit, pCluster));
137 kdTree.
build(hitKDNode2DList, hitsBoundingRegion2D);
139 for (
const Cluster *
const pCluster : allClusters)
141 CaloHitList daughterHits;
142 pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
144 for (
const CaloHit *
const pCaloHit : daughterHits)
149 kdTree.
search(searchRegionHits, found);
151 for (
const auto &
hit : found)
152 (void) nearbyClusters[pCluster].insert(hitToClusterMap.at(
hit.data));
163 const Cluster *
const pCluster = *iter;
167 const float clusterLengthSquared(clusterLengthT * clusterLengthT + clusterLengthL * clusterLengthL);
171 shortVector.push_back(pCluster);
176 transverseMediumVector.push_back(pCluster);
178 longitudinalMediumVector.push_back(pCluster);
182 longVector.push_back(pCluster);
204 this->
FillAssociationMap(nearbyClusters, firstVector, firstVector, firstAssociationMap, firstAssociationMapSwapped);
205 this->
FillAssociationMap(nearbyClusters, firstVector, secondVector, secondAssociationMap, secondAssociationMapSwapped);
206 this->
FillReducedAssociationMap(firstAssociationMap, secondAssociationMap, secondAssociationMapSwapped, clusterAssociationMap);
216 const Cluster *
const pClusterI = *iterI;
220 const Cluster *
const pClusterJ = *iterJ;
222 if (pClusterI == pClusterJ)
225 if (this->
IsAssociated(
true, pClusterI, pClusterJ, nearbyClusters))
227 firstAssociationMap[pClusterI].m_forwardAssociations.insert(pClusterJ);
228 secondAssociationMap[pClusterJ].m_backwardAssociations.insert(pClusterI);
231 if (this->
IsAssociated(
false, pClusterI, pClusterJ, nearbyClusters))
233 firstAssociationMap[pClusterI].m_backwardAssociations.insert(pClusterJ);
234 secondAssociationMap[pClusterJ].m_forwardAssociations.insert(pClusterI);
247 const Cluster *
const pCluster = *iter;
267 const Cluster *
const pInnerCluster(pInnerTransverseCluster->
GetSeedCluster());
270 if (transverseAssociationMap.end() == iterInner)
276 const Cluster *
const pOuterCluster(pOuterTransverseCluster->
GetSeedCluster());
279 if(transverseAssociationMap.end() == iterOuter)
282 if (pInnerCluster == pOuterCluster)
285 if (iterInner->second.m_forwardAssociations.count(pOuterCluster) == 0 ||
286 iterOuter->second.m_backwardAssociations.count(pInnerCluster) == 0)
296 clusterAssociationMap[pInnerCluster].m_forwardAssociations.insert(pOuterCluster);
297 clusterAssociationMap[pOuterCluster].m_backwardAssociations.insert(pInnerCluster);
308 if (associationMap.end() == iterI)
311 for (
ClusterSet::const_iterator iterJ = iterI->second.m_forwardAssociations.begin(), iterEndJ = iterI->second.m_forwardAssociations.end(); iterJ != iterEndJ; ++iterJ)
313 const Cluster *
const pClusterJ = *iterJ;
316 associatedVector.push_back(pClusterJ);
319 for (
ClusterSet::const_iterator iterJ = iterI->second.m_backwardAssociations.begin(), iterEndJ = iterI->second.m_backwardAssociations.end(); iterJ != iterEndJ; ++iterJ)
321 const Cluster *
const pClusterJ = *iterJ;
324 associatedVector.push_back(pClusterJ);
335 if ((0 == nearbyClusters.at(pFirstCluster).count(pSecondCluster)) || (0 == nearbyClusters.at(pSecondCluster).count(pFirstCluster)))
338 CartesianVector firstInner(0.
f,0.
f,0.
f), firstOuter(0.
f,0.
f,0.
f);
339 CartesianVector secondInner(0.
f,0.
f,0.
f), secondOuter(0.
f,0.
f,0.
f);
343 const CartesianVector firstCoordinate(isForward ? firstOuter : firstInner);
344 const CartesianVector secondCoordinate(isForward ? secondOuter : secondInner);
350 if ((isForward && secondCoordinate.GetX() < firstCoordinate.GetX()) ||
351 (!isForward && secondCoordinate.GetX() > firstCoordinate.GetX()))
360 if((isForward && firstProjection.GetX() > firstCoordinate.GetX() +
m_clusterWindow) ||
361 (!isForward && firstProjection.GetX() < firstCoordinate.GetX() -
m_clusterWindow))
372 if ((0 == nearbyClusters.at(pInnerCluster).count(pOuterCluster)) || (0 == nearbyClusters.at(pOuterCluster).count(pInnerCluster)))
375 CartesianVector innerInner(0.
f,0.
f,0.
f), innerOuter(0.
f,0.
f,0.
f);
376 CartesianVector outerInner(0.
f,0.
f,0.
f), outerOuter(0.
f,0.
f,0.
f);
380 const CartesianVector innerCentroid((innerInner + innerOuter) * 0.5);
381 const CartesianVector outerCentroid((outerInner + outerOuter) * 0.5);
383 if ((std::fabs(innerCentroid.GetZ() - outerInner.GetZ()) > std::fabs(innerCentroid.GetX() - outerInner.GetX()) * std::fabs(
m_clusterTanAngle)) &&
384 (std::fabs(innerCentroid.GetZ() - outerOuter.GetZ()) > std::fabs(innerCentroid.GetX() - outerOuter.GetX()) * std::fabs(
m_clusterTanAngle)))
387 if ((std::fabs(outerCentroid.GetZ() - innerInner.GetZ()) > std::fabs(outerCentroid.GetX() - innerInner.GetX()) * std::fabs(
m_clusterTanAngle)) &&
388 (std::fabs(outerCentroid.GetZ() - innerOuter.GetZ()) > std::fabs(outerCentroid.GetX() - innerOuter.GetX()) * std::fabs(
m_clusterTanAngle)))
428 const CartesianVector &innerVertex(pTransverseCluster->
GetInnerVertex());
429 const CartesianVector &outerVertex(pTransverseCluster->
GetOuterVertex());
430 const CartesianVector &direction(pTransverseCluster->
GetDirection());
435 if ((direction.GetDotProduct(testVertex - innerVertex) < -1.f *
m_clusterWindow) || (direction.GetDotProduct(testVertex - outerVertex) > +1.f *
m_clusterWindow))
445 CartesianVector innerInner(0.
f,0.
f,0.
f), innerOuter(0.
f,0.
f,0.
f);
446 CartesianVector outerInner(0.
f,0.
f,0.
f), outerOuter(0.
f,0.
f,0.
f);
453 const float innerOverlapSquared((innerProjection - innerOuter).GetMagnitudeSquared());
454 const float outerOverlapSquared((outerProjection - outerInner).GetMagnitudeSquared());
468 return (maxX - minX);
480 return (maxZ - minZ);
497 const Cluster *
const pAssociatedCluster = *iter;
501 if (localMinX < overallMinX)
502 overallMinX = localMinX;
504 if (localMaxX > overallMaxX)
505 overallMaxX = localMaxX;
508 return (overallMaxX - overallMinX);
515 float currentMinX(0.
f), currentMaxX(0.
f);
518 float testMinX(0.
f), testMaxX(0.
f);
523 if (std::fabs(testMaxX - currentMaxX) > std::numeric_limits<float>::epsilon())
524 return (testMaxX > currentMaxX);
528 if (std::fabs(testMinX - currentMaxX) > std::numeric_limits<float>::epsilon())
529 return (testMinX < currentMinX);
556 const OrderedCaloHitList &orderedCaloHitList(pCluster->GetOrderedCaloHitList());
560 for (
CaloHitList::const_iterator hitIter = iter->second->begin(), hitIterEnd = iter->second->end(); hitIter != hitIterEnd; ++hitIter)
562 const float caloHitXZ(useX ? (*hitIter)->GetPositionVector().GetX() : (*hitIter)->GetPositionVector().GetZ());
564 if (caloHitXZ < minXZ)
567 if (caloHitXZ > maxXZ)
573 throw pandora::StatusCodeException(STATUS_CODE_FAILURE);
580 CartesianVector firstCoordinate(0.
f,0.
f,0.
f), secondCoordinate(0.
f,0.
f,0.
f);
583 innerCoordinate = (firstCoordinate.GetX() < secondCoordinate.GetX() ? firstCoordinate : secondCoordinate);
584 outerCoordinate = (firstCoordinate.GetX() > secondCoordinate.GetX() ? firstCoordinate : secondCoordinate);
591 return this->
FillReducedAssociationMap(inputAssociationMap, inputAssociationMap, inputAssociationMap, outputAssociationMap);
607 for (
const auto &mapEntry : firstAssociationMap) sortedClusters.push_back(mapEntry.first);
610 for (
const Cluster *
const pCluster : sortedClusters)
614 ClusterVector sortedOuterClusters(firstAssociation.m_forwardAssociations.begin(), firstAssociation.m_forwardAssociations.end());
617 ClusterVector sortedInnerClusters(firstAssociation.m_backwardAssociations.begin(), firstAssociation.m_backwardAssociations.end());
623 if (secondAssociationMap.end() != iterSecond)
625 sortedMiddleClustersF.insert(sortedMiddleClustersF.end(), iterSecond->second.m_forwardAssociations.begin(), iterSecond->second.m_forwardAssociations.end());
626 sortedMiddleClustersB.insert(sortedMiddleClustersB.end(), iterSecond->second.m_backwardAssociations.begin(), iterSecond->second.m_backwardAssociations.end());
631 for (
const Cluster *
const pOuterCluster : sortedOuterClusters)
633 bool isNeighbouringCluster(
true);
635 for (
const Cluster *
const pMiddleCluster : sortedMiddleClustersF)
638 if (secondAssociationMapSwapped.end() == iterSecondCheck)
641 if (iterSecondCheck->second.m_forwardAssociations.count(pOuterCluster) > 0)
643 isNeighbouringCluster =
false;
648 if (isNeighbouringCluster)
649 clusterAssociationMap[pCluster].m_forwardAssociations.insert(pOuterCluster);
652 for (
const Cluster *
const pInnerCluster : sortedInnerClusters)
654 bool isNeighbouringCluster(
true);
656 for (
const Cluster *
const pMiddleCluster : sortedMiddleClustersB)
659 if (secondAssociationMapSwapped.end() == iterSecondCheck)
662 if (iterSecondCheck->second.m_backwardAssociations.count(pInnerCluster) > 0)
664 isNeighbouringCluster =
false;
669 if (isNeighbouringCluster)
670 clusterAssociationMap[pCluster].m_backwardAssociations.insert(pInnerCluster);
684 for (
const auto &mapEntry : inputAssociationMap) sortedClusters.push_back(mapEntry.first);
687 for (
const Cluster *
const pCluster : sortedClusters)
691 ClusterVector sortedForwardClusters(inputAssociation.m_forwardAssociations.begin(), inputAssociation.m_forwardAssociations.end());
694 ClusterVector sortedBackwardClusters(inputAssociation.m_backwardAssociations.begin(), inputAssociation.m_backwardAssociations.end());
698 for (
const Cluster *
const pForwardCluster : sortedForwardClusters)
702 if (inputAssociation.m_backwardAssociations.count(pForwardCluster))
706 if (inputAssociationMap.end() != iterCheck)
708 if (iterCheck->second.m_forwardAssociations.count(pCluster))
711 if (iterCheck->second.m_backwardAssociations.count(pCluster))
717 if(!(outputAssociationMap[pCluster].m_backwardAssociations.count(pForwardCluster) == 0 &&
718 outputAssociationMap[pForwardCluster].m_forwardAssociations.count(pCluster) == 0))
719 throw StatusCodeException(STATUS_CODE_FAILURE);
721 outputAssociationMap[pCluster].m_forwardAssociations.insert(pForwardCluster);
722 outputAssociationMap[pForwardCluster].m_backwardAssociations.insert(pCluster);
727 for (
const Cluster *
const pBackwardCluster : sortedBackwardClusters)
731 if (inputAssociation.m_forwardAssociations.count(pBackwardCluster))
735 if (inputAssociationMap.end() != iterCheck)
737 if (iterCheck->second.m_backwardAssociations.count(pCluster))
740 if (iterCheck->second.m_forwardAssociations.count(pCluster))
746 if(!(outputAssociationMap[pCluster].m_forwardAssociations.count(pBackwardCluster) == 0 &&
747 outputAssociationMap[pBackwardCluster].m_backwardAssociations.count(pCluster) == 0))
748 throw StatusCodeException(STATUS_CODE_FAILURE);
750 outputAssociationMap[pCluster].m_backwardAssociations.insert(pBackwardCluster);
751 outputAssociationMap[pBackwardCluster].m_forwardAssociations.insert(pCluster);
770 m_pSeedCluster(pSeedCluster),
771 m_associatedClusters(associatedClusters),
772 m_innerVertex(0.
f, 0.
f, 0.
f),
773 m_outerVertex(0.
f, 0.
f, 0.
f),
774 m_direction(0.
f, 0.
f, 0.
f)
776 double Swzz(0.), Swxx(0.), Swzx(0.), Swz(0.), Swx(0.), Sw(0.);
780 ClusterList clusterList(1, pSeedCluster);
781 clusterList.insert(clusterList.end(), associatedClusters.begin(), associatedClusters.end());
785 for (
OrderedCaloHitList::const_iterator iterJ = (*iterI)->GetOrderedCaloHitList().begin(), iterEndJ = (*iterI)->GetOrderedCaloHitList().end(); iterJ != iterEndJ; ++iterJ)
789 const CaloHit *
const pCaloHit = *iterK;
791 if (pCaloHit->GetPositionVector().GetX() < minX)
792 minX = pCaloHit->GetPositionVector().GetX();
794 if (pCaloHit->GetPositionVector().GetX() > maxX)
795 maxX = pCaloHit->GetPositionVector().GetX();
797 Swzz += pCaloHit->GetPositionVector().GetZ() * pCaloHit->GetPositionVector().GetZ();
798 Swxx += pCaloHit->GetPositionVector().GetX() * pCaloHit->GetPositionVector().GetX();
799 Swzx += pCaloHit->GetPositionVector().GetZ() * pCaloHit->GetPositionVector().GetX();
800 Swz += pCaloHit->GetPositionVector().GetZ();
801 Swx += pCaloHit->GetPositionVector().GetX();
809 const double averageX(Swx / Sw);
810 const double averageZ(Swz / Sw);
812 if (Sw * Swxx - Swx * Swx > 0.)
814 double m((Sw * Swzx - Swx * Swz) / (Sw * Swxx - Swx * Swx));
815 double px(1. / std::sqrt(1. + m * m));
816 double pz(m / std::sqrt(1. + m * m));
818 m_innerVertex.SetValues(static_cast<float>(minX), 0.
f, static_cast<float>(averageZ + m * (minX - averageX)));
819 m_outerVertex.SetValues(static_cast<float>(maxX), 0.
f, static_cast<float>(averageZ + m * (maxX - averageX)));
820 m_direction.SetValues(static_cast<float>(px), 0.
f, static_cast<float>(pz));
824 m_innerVertex.SetValues(static_cast<float>(averageX), 0.
f, static_cast<float>(averageZ));
825 m_outerVertex.SetValues(static_cast<float>(averageX), 0.
f, static_cast<float>(averageZ));
831 throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
840 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
843 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
846 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
849 const StatusCode angleStatusCode(XmlHelper::ReadValue(xmlHandle,
"clusterAngle",
m_clusterAngle));
851 if (STATUS_CODE_SUCCESS == angleStatusCode)
856 else if (STATUS_CODE_NOT_FOUND != angleStatusCode)
858 return angleStatusCode;
861 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
864 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
867 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
870 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
873 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
876 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
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.
void PopulateClusterAssociationMap(const pandora::ClusterVector &clusterVector, ClusterAssociationMap &clusterAssociationMap) const
Populate the cluster association map.
const pandora::Cluster * GetSeedCluster() const
Constructor.
Header file for the kd tree linker algo template class.
pandora::CartesianVector m_outerVertex
const pandora::CartesianVector & GetInnerVertex() const
Get the inner vertex position.
float GetTransverseSpan(const pandora::Cluster *const pCluster) const
Calculate the overall span in X for a clusters.
Class that implements the KDTree partition of 2D space and a closest point search algorithm...
void FillTransverseAssociationMap(const ClusterToClustersMap &nearbyClusters, const TransverseClusterList &transverseClusterList, const ClusterAssociationMap &transverseAssociationMap, ClusterAssociationMap &clusterAssociationMap) const
Form associations between transverse cluster objects.
Box structure used to define 2D field. It's used in KDTree building step to divide the detector space...
float m_transverseClusterMinLength
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void GetExtremalCoordinatesXZ(const pandora::Cluster *const pCluster, const bool useX, float &minXZ, float &maxXZ) const
Get minimum and maximum X or Z coordinates for a given cluster.
pandora::CartesianVector m_innerVertex
bool IsExtremalCluster(const bool isForward, const pandora::Cluster *const pCurrentCluster, const pandora::Cluster *const pTestCluster) const
Determine which of two clusters is extremal.
void FillSymmetricAssociationMap(const ClusterAssociationMap &inputAssociationMap, ClusterAssociationMap &outputAssociationMap) const
Symmetrise an association map.
std::vector< LArTransverseCluster * > TransverseClusterList
bool IsTransverseAssociated(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, const ClusterToClustersMap &nearbyClusters) const
Determine whether two clusters are within the same cluster window.
void FillAssociationMap(const ClusterToClustersMap &nearbyClusters, const pandora::ClusterVector &firstVector, const pandora::ClusterVector &secondVector, ClusterAssociationMap &firstAssociationMap, ClusterAssociationMap &secondAssociationMap) const
Form associations between two input lists of cluster.
float m_transverseClusterMaxDisplacement
bool IsOverlapping(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2) const
Determine whether two clusters are overlapping.
float m_maxTransverseOverlap
void search(const KDTreeBoxT< DIM > &searchBox, std::vector< KDTreeNodeInfoT< DATA, DIM > > &resRecHitList)
Search in the KDTree for all points that would be contained in the given searchbox The founded points...
void GetExtremalCoordinatesX(const pandora::Cluster *const pCluster, float &minX, float &maxX) const
Get minimum and maximum X coordinates for a given cluster.
Header file for the cluster helper class.
pandora::CartesianVector m_direction
float m_searchRegionX
Search region, applied to x dimension, for look-up from kd-trees.
void SortInputClusters(const pandora::ClusterVector &inputClusters, pandora::ClusterVector &shortClusters, pandora::ClusterVector &transverseMediumClusters, pandora::ClusterVector &longitudinalMediumClusters, pandora::ClusterVector &longClusters) const
Separate input clusters by length.
void FillTransverseClusterList(const ClusterToClustersMap &nearbyClusters, const pandora::ClusterVector &inputClusters, const ClusterAssociationMap &inputAssociationMap, TransverseClusterList &transverseClusterList) const
Create transverse cluster objects, these are protoclusters with a direction and inner/outer vertices...
const pandora::CartesianVector & GetOuterVertex() const
Get the outer vertex position.
float m_maxLongitudinalOverlap
std::unordered_map< const pandora::Cluster *, pandora::ClusterSet > ClusterToClustersMap
float m_transverseClusterMinCosTheta
Detector simulation of raw signals on wires.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
ClusterAssociation class.
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) ...
void FinalizeClusterAssociationMap(const ClusterAssociationMap &inputAssociationMap, ClusterAssociationMap &outputAssociationMap) const
Symmetrise and then remove double-counting from an association map.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
float m_maxProjectedOverlap
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 GetNearbyClusterMap(const pandora::ClusterVector &allClusters, ClusterToClustersMap &nearbyClusters) const
Use a kd-tree to obtain details of all nearby cluster combinations.
const pandora::CartesianVector & GetDirection() const
Get the direction.
KDTreeBox fill_and_bound_2d_kd_tree(const MANAGED_CONTAINER< const T * > &points, std::vector< KDTreeNodeInfoT< const T *, 2 > > &nodes)
fill_and_bound_2d_kd_tree
std::unordered_map< const pandora::CaloHit *, const pandora::Cluster * > HitToClusterMap
bool IsAssociated(const bool isForward, const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, const ClusterToClustersMap &nearbyClusters) const
Determine whether clusters are association.
std::vector< HitKDNode2D > HitKDNode2DList
void FillReducedAssociationMap(const ClusterToClustersMap &nearbyClusters, const pandora::ClusterVector &firstVector, const pandora::ClusterVector &secondVector, ClusterAssociationMap &clusterAssociationMap) const
Form a reduced set of associations between two input lists of clusters.
float GetLongitudinalSpan(const pandora::Cluster *const pCluster) const
Calculate the overall span in Z for a clusters.
Header file for the transverse association algorithm class.
LArTransverseCluster class.
std::unordered_map< const pandora::Cluster *, ClusterAssociation > ClusterAssociationMap
void GetAssociatedClusters(const ClusterToClustersMap &nearbyClusters, const pandora::Cluster *const pCluster, const ClusterAssociationMap &inputAssociationMap, pandora::ClusterVector &associatedClusters) const
Find the clusters that are transversely associated with a target cluster.
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.
float m_searchRegionZ
Search region, applied to u/v/w dimension, for look-up from kd-trees.
KDTreeBox build_2d_kd_search_region(const pandora::CaloHit *const point, const float x_span, const float z_span)
build_2d_kd_search_region
void GetExtremalCoordinatesZ(const pandora::Cluster *const pCluster, float &minZ, float &maxZ) const
Get minimum and maximum Z coordinates for a given cluster.
void build(std::vector< KDTreeNodeInfoT< DATA, DIM > > &eltList, const KDTreeBoxT< DIM > ®ion)
Build the KD tree from the "eltList" in the space define by "region".
LArTransverseCluster(const pandora::Cluster *const pSeedCluster, const pandora::ClusterVector &associatedClusters)
Constructor.