9 #include "Pandora/AlgorithmHeaders.h" 23 TwoViewThreeDKinkTool::TwoViewThreeDKinkTool() :
24 m_minXOverlapFraction(0.1
f),
25 m_minMatchingScore(0.95
f),
26 m_minLocallyMatchedFraction(0.3
f),
27 m_minLongitudinalImpactParameter(-1.
f),
28 m_nLayersForKinkSearch(10),
29 m_additionalXStepForKinkSearch(0.01
f),
30 m_maxTransverseImpactParameter(5.
f),
31 m_minImpactParameterCosTheta(0.5
f),
32 m_cosThetaCutForKinkSearch(0.75
f)
46 if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
47 std::cout <<
"----> Running Algorithm Tool: " << this->GetInstanceName() <<
", " << this->GetType() << std::endl;
51 const bool changesMade(this->
ApplyChanges(pAlgorithm, modificationList));
60 if (usedClusters.count(eIter->GetCluster1()) || usedClusters.count(eIter->GetCluster2()))
63 if (eIter->GetOverlapResult().GetTwoViewXOverlap().GetXOverlapFraction0() - m_minXOverlapFraction < std::numeric_limits<float>::epsilon())
66 if (eIter->GetOverlapResult().GetTwoViewXOverlap().GetXOverlapFraction1() - m_minXOverlapFraction < std::numeric_limits<float>::epsilon())
69 if (eIter->GetOverlapResult().GetMatchingScore() - m_minMatchingScore < std::numeric_limits<float>::epsilon())
72 if (eIter->GetOverlapResult().GetLocallyMatchedFraction() - m_minLocallyMatchedFraction < std::numeric_limits<float>::epsilon())
84 float xMin1(std::numeric_limits<float>::max()), xMax1(std::numeric_limits<float>::lowest());
85 float xMin2(std::numeric_limits<float>::max()), xMax2(std::numeric_limits<float>::lowest());
89 const float commonX(isForwardInX ? std::max(xMin1, xMin2) : std::min(xMax1, xMax2));
91 if (isForwardInX && ((commonX > xMax1) || (commonX > xMax2)))
92 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
94 if (!isForwardInX && ((commonX < xMin1) || (commonX < xMin2)))
95 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
98 float rL1(0.
f), rT1(0.
f);
100 const int splitLayer(fitResult1.
GetLayer(rL1));
105 CartesianVector minus(0.
f, 0.
f, 0.
f), plus(0.
f, 0.
f, 0.
f);
106 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, fitResult1.
GetGlobalFitPosition(fitResult1.
GetL(lowLayer), minus));
107 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, fitResult1.
GetGlobalFitPosition(fitResult1.
GetL(highLayer), plus));
109 if (minus.GetX() > plus.GetX())
110 std::swap(minus, plus);
112 const float layerStepX(isForwardInX ? plus.GetX() : minus.GetX());
115 const float chosenX(isForwardInX ? std::max(layerStepX, commonX) : std::min(layerStepX, commonX));
126 return xMinA < xMinB;
134 ClusterSet usedClusters;
138 for (
const Cluster *
const pKeyCluster : sortedKeyClusters)
140 if (!pKeyCluster->IsAvailable())
143 unsigned int n1(0), n2(0);
158 if (iteratorList.size() < 2)
164 if (localModificationList.empty())
169 usedClusters.insert(mIter->m_affectedClusters.begin(), mIter->m_affectedClusters.end());
172 modificationList.insert(modificationList.end(), localModificationList.begin(), localModificationList.end());
184 for (
const Modification &modification : modificationList)
186 ClusterList parentClusters;
187 for (
const auto &mapEntry : modification.m_clusterMergeMap)
188 parentClusters.push_back(mapEntry.first);
191 for (
const Cluster *
const pParentCluster : parentClusters)
193 const ClusterList &daughterClusters(modification.m_clusterMergeMap.at(pParentCluster));
195 for (
const Cluster *
const pDaughterCluster : daughterClusters)
197 if (consolidatedMergeMap.count(pDaughterCluster))
198 throw StatusCodeException(STATUS_CODE_FAILURE);
201 ClusterList &targetClusterList(consolidatedMergeMap[pParentCluster]);
202 targetClusterList.insert(targetClusterList.end(), daughterClusters.begin(), daughterClusters.end());
205 ClusterList splitClusters;
206 for (
const auto &mapEntry : modification.m_splitPositionMap)
207 splitClusters.push_back(mapEntry.first);
210 for (
const Cluster *
const pSplitCluster : splitClusters)
212 const CartesianPointVector &splitPositions(modification.m_splitPositionMap.at(pSplitCluster));
214 CartesianPointVector &cartesianPointVector(consolidatedSplitMap[pSplitCluster]);
215 cartesianPointVector.insert(cartesianPointVector.end(), splitPositions.begin(), splitPositions.end());
219 bool changesMade(
false);
229 const ClusterSet &usedClusters,
IteratorList &iteratorList)
const 231 iteratorList.push_back(eIter);
243 if ((*iIter) == eIter2)
246 unsigned int nMatchedClusters(0);
248 if ((*iIter)->GetCluster1() == eIter2->GetCluster1())
251 if ((*iIter)->GetCluster2() == eIter2->GetCluster2())
254 if (nMatchedClusters > 1)
257 if (nMatchedClusters)
259 iteratorList.push_back(eIter2);
277 const unsigned int nMatchedReUpsampledSamplingPoints1((*iIter1)->GetOverlapResult().GetNMatchedReUpsampledSamplingPoints());
278 const unsigned int nMatchedReUpsampledSamplingPoints2((*iIter2)->GetOverlapResult().GetNMatchedReUpsampledSamplingPoints());
282 Particle particle(*(*iIterA), *(*iIterB));
289 float transverseAB(std::numeric_limits<float>::max()), transverseBA(std::numeric_limits<float>::max());
290 float longitudinalAB(-std::numeric_limits<float>::max()), longitudinalBA(-std::numeric_limits<float>::max());
301 const float cosTheta(-vertexA.GetDirection().GetCosOpeningAngle(vertexB.GetDirection()));
306 const bool isALowestInX(this->
IsALowestInX(pointingClusterA, pointingClusterB));
307 const CartesianVector splitPosition((vertexA.GetPosition() + vertexB.GetPosition()) * 0.5
f);
308 const bool isThreeDKink(this->
IsThreeDKink(pAlgorithm, particle, splitPosition, isALowestInX));
317 CartesianVector splitPositionCommon(0.
f, 0.
f, 0.
f);
318 if (STATUS_CODE_SUCCESS != fitResultCommon.GetGlobalFitPositionAtX(splitPosition.GetX(), splitPositionCommon))
327 const bool vertexAIsLowX(vertexA.GetPosition().GetX() < vertexB.GetPosition().GetX());
337 modificationList.push_back(modification);
339 catch (
const StatusCodeException &statusCodeException)
341 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
342 throw statusCodeException;
353 const CartesianVector &splitPosition,
const bool isALowestInX)
const 363 const float minusX(this->
GetXSamplingPoint(splitPosition,
false, lowXFitResult, fitResultCommon));
364 const float plusX(this->
GetXSamplingPoint(splitPosition,
true, highXFitResult, fitResultCommon));
365 const float splitX(splitPosition.GetX());
367 CartesianVector minus1(0.
f, 0.
f, 0.
f), split1(0.
f, 0.
f, 0.
f), plus1(0.
f, 0.
f, 0.
f);
368 CartesianVector minus2(0.
f, 0.
f, 0.
f), split2(splitPosition), plus2(0.
f, 0.
f, 0.
f);
370 if ((STATUS_CODE_SUCCESS != fitResultCommon.GetGlobalFitPositionAtX(minusX, minus1)) ||
371 (STATUS_CODE_SUCCESS != fitResultCommon.GetGlobalFitPositionAtX(splitX, split1)) ||
372 (STATUS_CODE_SUCCESS != fitResultCommon.GetGlobalFitPositionAtX(plusX, plus1)) ||
373 (STATUS_CODE_SUCCESS != lowXFitResult.GetGlobalFitPositionAtX(minusX, minus2)) ||
374 (STATUS_CODE_SUCCESS != highXFitResult.GetGlobalFitPositionAtX(plusX, plus2)))
383 CartesianVector minus(0.
f, 0.
f, 0.
f), split(0.
f, 0.
f, 0.
f), plus(0.
f, 0.
f, 0.
f);
384 float chi2Dummy(std::numeric_limits<float>::max());
390 const CartesianVector minusToSplit((split - minus).GetUnitVector());
391 const CartesianVector splitToPlus((plus - split).GetUnitVector());
392 const float dotProduct(minusToSplit.GetDotProduct(splitToPlus));
397 catch (
const StatusCodeException &)
409 m_pClusterA = (elementA.GetCluster1() != elementB.GetCluster1()) ? elementA.GetCluster1() : elementA.GetCluster2();
410 m_pClusterB = (elementA.GetCluster1() != elementB.GetCluster1()) ? elementB.GetCluster1() : elementB.GetCluster2();
411 m_pCommonCluster = (elementA.GetCluster1() == elementB.GetCluster1()) ? elementA.GetCluster1() : elementA.GetCluster2();
413 if (m_pClusterA == m_pClusterB)
414 throw StatusCodeException(STATUS_CODE_FAILURE);
421 PANDORA_RETURN_RESULT_IF_AND_IF(
422 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinMatchingScore",
m_minMatchingScore));
424 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
427 PANDORA_RETURN_RESULT_IF_AND_IF(
428 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinXOverlapFraction",
m_minXOverlapFraction));
430 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
433 PANDORA_RETURN_RESULT_IF_AND_IF(
434 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NLayersForKinkSearch",
m_nLayersForKinkSearch));
436 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
439 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
442 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
445 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
448 return STATUS_CODE_SUCCESS;
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_minLocallyMatchedFraction
The min locally matched fraction for particle creation.
virtual bool MakeClusterSplits(const SplitPositionMap &splitPositionMap)
Make cluster splits.
Header file for the lar pointing cluster class.
const pandora::Cluster * m_pClusterB
Address of non-shared cluster in element B.
void GetMinAndMaxX(float &minX, float &maxX) const
Get the minimum and maximum x coordinates associated with the sliding fit.
static void MergeTwoPositions3D(const pandora::Pandora &pandora, const pandora::HitType view1, const pandora::HitType view2, const pandora::CartesianVector &position1, const pandora::CartesianVector &position2, pandora::CartesianVector &position3D, float &chiSquared)
Merge 2D positions from two views to give unified 3D position.
static bool IsALowestInX(const LArPointingCluster &pointingClusterA, const LArPointingCluster &pointingClusterB)
Whether pointing cluster labelled A extends to lowest x positions (as opposed to that labelled B) ...
SplitPositionMap m_splitPositionMap
The split position map.
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
TwoViewTransverseTracksAlgorithm class.
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
LArPointingCluster class.
std::vector< Element > ElementList
std::vector< Modification > ModificationList
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
void GetSortedKeyClusters(pandora::ClusterVector &sortedKeyClusters) const
Get a sorted vector of key clusters (view 1 clusters with current implementation) ...
float m_minMatchingScore
The min global matching score for particle creation.
static void GetClosestVertices(const bool useX, const bool useY, const bool useZ, const LArPointingCluster &pointingClusterI, const LArPointingCluster &pointingClusterJ, LArPointingCluster::Vertex &closestVertexI, LArPointingCluster::Vertex &closestVertexJ)
Given a pair of pointing clusters, receive the closest or farthest pair of vertices.
Particle(const MatrixType::Element &elementA, const MatrixType::Element &elementB)
Constructor.
const pandora::Cluster * m_pClusterA
Address of non-shared cluster in element A.
float m_minXOverlapFraction
The min x overlap fraction value for particle creation.
float m_additionalXStepForKinkSearch
An additional (safety) step to tack-on when choosing x sampling.
Header file for the geometry helper class.
bool IsThreeDKink(TwoViewTransverseTracksAlgorithm *const pAlgorithm, const Particle &particle, const pandora::CartesianVector &splitPosition, const bool isALowestInX) const
Whether the provided particle is consistent with being a kink, when examined in three dimensions at t...
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
void GetModifications(TwoViewTransverseTracksAlgorithm *const pAlgorithm, const MatrixType &overlapMatrix, ModificationList &modificationList) const
Get modification objects, identifying required splits and merges for clusters.
Header file for the cluster helper class.
void SelectMatrixElements(MatrixType::ElementList::const_iterator eIter, const MatrixType::ElementList &elementList, const pandora::ClusterSet &usedClusters, IteratorList &iteratorList) const
Select elements representing possible components of interest due to overshoots or undershoots in clus...
pandora::StatusCode GetGlobalFitPosition(const float rL, pandora::CartesianVector &position) const
Get global fit position for a given longitudinal coordinate.
const Vertex & GetOuterVertex() const
Get the outer vertex.
std::unordered_map< const pandora::Cluster *, pandora::CartesianPointVector > SplitPositionMap
virtual ~TwoViewThreeDKinkTool()
Destructor.
float m_maxTransverseImpactParameter
The maximum transverse impact parameter for connecting broken clusters.
const Vertex & GetInnerVertex() const
Get the inner vertex.
TheMatrix::const_iterator const_iterator
int m_nLayersForKinkSearch
The number of sliding fit layers to step in the kink search.
bool Run(TwoViewTransverseTracksAlgorithm *const pAlgorithm, MatrixType &overlapMatrix)
Run the algorithm tool.
virtual bool MakeClusterMerges(const ClusterMergeMap &clusterMergeMap)
Merge clusters together.
float m_cosThetaCutForKinkSearch
The cos theta cut used for the kink search in three dimensions.
bool PassesElementCuts(MatrixType::ElementList::const_iterator eIter, const pandora::ClusterSet &usedClusters) const
Whether a provided (iterator to a) matrix element passes the selection cuts for overshoot identificat...
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
float m_minImpactParameterCosTheta
The minimum cos theta (angle between vertex directions) for connecting broken clusters.
pandora::ClusterList m_affectedClusters
The list of affected clusters.
void GetIteratorListModifications(TwoViewTransverseTracksAlgorithm *const pAlgorithm, const IteratorList &iteratorList, ModificationList &modificationList) const
Get modification objects for specific elements of the matrix, identifying required splits and merges ...
float GetL(const int layer) const
Get longitudinal coordinate for a given sliding linear fit layer number.
bool ApplyChanges(TwoViewTransverseTracksAlgorithm *const pAlgorithm, const ModificationList &modificationList) const
Apply the changes cached in a modification list and update the matrix accordingly.
void GetConnectedElements(const pandora::Cluster *const pCluster, const bool ignoreUnavailable, ElementList &elementList) const
Get a list of elements connected to a specified cluster.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
ClusterMergeMap m_clusterMergeMap
The cluster merge map.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
float m_minLongitudinalImpactParameter
The min longitudinal impact parameter for connecting accompanying clusters.
std::vector< MatrixType::ElementList::const_iterator > IteratorList
float GetXSamplingPoint(const pandora::CartesianVector &splitPosition1, const bool isForwardInX, const TwoDSlidingFitResult &fitResult1, const TwoDSlidingFitResult &fitResult2) const
Get a sampling point in x that is common to sliding linear fit objects in two views.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
TwoDSlidingFitResult class.
int GetLayer(const float rL) const
Get layer number for given sliding linear fit longitudinal coordinate.
const pandora::Cluster * m_pCommonCluster
Address of the common cluster.