Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
CrossedTrackSplittingAlgorithm.cc
Go to the documentation of this file.
1
10
13
15
17
18using namespace pandora;
19
20namespace lar_content
21{
22
24 m_maxClusterSeparation(2.f),
25 m_maxClusterSeparationSquared(m_maxClusterSeparation * m_maxClusterSeparation),
26 m_minCosRelativeAngle(0.966f),
27 m_searchRegion1D(2.f)
28{
29}
30
31//------------------------------------------------------------------------------------------------------------------------------------------
32
34{
35 // ATTN Don't need to update nearby cluster map after cluster merges because algorithm does not revisit processed clusters
36 HitToClusterMap hitToClusterMap;
37 CaloHitList allCaloHits;
38
39 for (const Cluster *const pCluster : clusterVector)
40 {
41 CaloHitList daughterHits;
42 pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
43 allCaloHits.insert(allCaloHits.end(), daughterHits.begin(), daughterHits.end());
44
45 for (const CaloHit *const pCaloHit : daughterHits)
46 (void)hitToClusterMap.insert(HitToClusterMap::value_type(pCaloHit, pCluster));
47 }
48
49 HitKDTree2D kdTree;
50 HitKDNode2DList hitKDNode2DList;
51
52 KDTreeBox hitsBoundingRegion2D(fill_and_bound_2d_kd_tree(allCaloHits, hitKDNode2DList));
53 kdTree.build(hitKDNode2DList, hitsBoundingRegion2D);
54
55 for (const Cluster *const pCluster : clusterVector)
56 {
57 CaloHitList daughterHits;
58 pCluster->GetOrderedCaloHitList().FillCaloHitList(daughterHits);
59
60 for (const CaloHit *const pCaloHit : daughterHits)
61 {
63
64 HitKDNode2DList found;
65 kdTree.search(searchRegionHits, found);
66
67 for (const auto &hit : found)
68 (void)m_nearbyClusters[pCluster].insert(hitToClusterMap.at(hit.data));
69 }
70 }
71
72 return STATUS_CODE_SUCCESS;
73}
74
75//------------------------------------------------------------------------------------------------------------------------------------------
76
78{
79 m_nearbyClusters.clear();
80
81 return STATUS_CODE_SUCCESS;
82}
83
84//------------------------------------------------------------------------------------------------------------------------------------------
85
87 const TwoDSlidingFitResult &slidingFitResult2, CartesianVector &splitPosition, CartesianVector &firstDirection, CartesianVector &secondDirection) const
88{
89 // Use cached results from kd-tree to avoid expensive calculations
90 if (!m_nearbyClusters.count(slidingFitResult1.GetCluster()) || !m_nearbyClusters.count(slidingFitResult2.GetCluster()) ||
91 !m_nearbyClusters.at(slidingFitResult1.GetCluster()).count(slidingFitResult2.GetCluster()) ||
92 !m_nearbyClusters.at(slidingFitResult2.GetCluster()).count(slidingFitResult1.GetCluster()))
93 {
94 return STATUS_CODE_NOT_FOUND;
95 }
96
97 // Identify crossed-track topology and find candidate intersection positions
98 const CartesianVector &minPosition1(slidingFitResult1.GetGlobalMinLayerPosition());
99 const CartesianVector &maxPosition1(slidingFitResult1.GetGlobalMaxLayerPosition());
100
101 const CartesianVector &minPosition2(slidingFitResult2.GetGlobalMinLayerPosition());
102 const CartesianVector &maxPosition2(slidingFitResult2.GetGlobalMaxLayerPosition());
103
104 if (LArClusterHelper::GetClosestDistance(minPosition1, slidingFitResult2.GetCluster()) < 2.f * m_maxClusterSeparation ||
105 LArClusterHelper::GetClosestDistance(maxPosition1, slidingFitResult2.GetCluster()) < 2.f * m_maxClusterSeparation ||
106 LArClusterHelper::GetClosestDistance(minPosition2, slidingFitResult1.GetCluster()) < 2.f * m_maxClusterSeparation ||
107 LArClusterHelper::GetClosestDistance(maxPosition2, slidingFitResult1.GetCluster()) < 2.f * m_maxClusterSeparation)
108 {
109 return STATUS_CODE_NOT_FOUND;
110 }
111
112 if (LArClusterHelper::GetClosestDistance(slidingFitResult1.GetCluster(), slidingFitResult2.GetCluster()) > m_maxClusterSeparation)
113 return STATUS_CODE_NOT_FOUND;
114
115 CartesianPointVector candidateVector;
116 this->FindCandidateSplitPositions(slidingFitResult1.GetCluster(), slidingFitResult2.GetCluster(), candidateVector);
117
118 if (candidateVector.empty())
119 return STATUS_CODE_NOT_FOUND;
120
121 // Loop over candidate positions and find best split position
122 bool foundSplit(false);
123 float closestSeparationSquared(std::numeric_limits<float>::max());
124
125 const float halfWindowLength1(slidingFitResult1.GetLayerFitHalfWindowLength());
126 const float halfWindowLength2(slidingFitResult2.GetLayerFitHalfWindowLength());
127
128 for (CartesianPointVector::const_iterator iter = candidateVector.begin(), iterEnd = candidateVector.end(); iter != iterEnd; ++iter)
129 {
130 const CartesianVector &candidatePosition(*iter);
131
132 // Projections onto first cluster
133 float rL1(0.f), rT1(0.f);
134 CartesianVector R1(0.f, 0.f, 0.f);
135 CartesianVector F1(0.f, 0.f, 0.f);
136 CartesianVector B1(0.f, 0.f, 0.f);
137
138 if (STATUS_CODE_SUCCESS != slidingFitResult1.GetGlobalFitProjection(candidatePosition, R1))
139 continue;
140
141 slidingFitResult1.GetLocalPosition(R1, rL1, rT1);
142 if ((STATUS_CODE_SUCCESS != slidingFitResult1.GetGlobalFitPosition(rL1 + halfWindowLength1, F1)) ||
143 (STATUS_CODE_SUCCESS != slidingFitResult1.GetGlobalFitPosition(rL1 - halfWindowLength1, B1)))
144 {
145 continue;
146 }
147
148 // Projections onto second cluster
149 float rL2(0.f), rT2(0.f);
150 CartesianVector R2(0.f, 0.f, 0.f);
151 CartesianVector F2(0.f, 0.f, 0.f);
152 CartesianVector B2(0.f, 0.f, 0.f);
153
154 if (STATUS_CODE_SUCCESS != slidingFitResult2.GetGlobalFitProjection(candidatePosition, R2))
155 continue;
156
157 slidingFitResult2.GetLocalPosition(R2, rL2, rT2);
158 if ((STATUS_CODE_SUCCESS != slidingFitResult2.GetGlobalFitPosition(rL2 + halfWindowLength2, F2)) ||
159 (STATUS_CODE_SUCCESS != slidingFitResult2.GetGlobalFitPosition(rL2 - halfWindowLength2, B2)))
160 {
161 continue;
162 }
163
164 // Calculate average position
165 const CartesianVector C0((R1 + R2) * 0.5);
166
167 // Calculate intersected position:
168 // ==============================
169 // First cluster gives set of points: B1->R1->F1
170 // Second cluster gives set of points: B2->R2->F2
171 //
172 // Try swapping B1 with B2 to see if this gives intersecting straight lines:
173 //
174 // F1 F2 a2 b1
175 // | | | |
176 // | | | |
177 // R1 R2 R1 R2
178 // | | | |
179 // | | | |
180 // B1 B2 a1 b2
181
182 // First straight line is a1->R1->b1
183 // Second straight line is a2->R2->b2
184
185 const CartesianVector a1(B1);
186 const CartesianVector a2(F1);
187
188 for (unsigned int iForward = 0; iForward < 2; ++iForward)
189 {
190 const CartesianVector b1((0 == iForward) ? F2 : B2);
191 const CartesianVector b2((0 == iForward) ? B2 : F2);
192
193 const CartesianVector s1((b1 - R2).GetUnitVector());
194 const CartesianVector t1((R1 - a1).GetUnitVector());
195 const CartesianVector s2((b2 - R2).GetUnitVector());
196 const CartesianVector t2((R1 - a2).GetUnitVector());
197
198 if (s1.GetDotProduct(t1) < std::max(m_minCosRelativeAngle, -s1.GetDotProduct(s2)) ||
199 s2.GetDotProduct(t2) < std::max(m_minCosRelativeAngle, -t1.GetDotProduct(t2)))
200 continue;
201
202 const CartesianVector p1((b1 - a1).GetUnitVector());
203 const CartesianVector p2((b2 - a2).GetUnitVector());
204
205 float mu1(0.f), mu2(0.f);
206 CartesianVector C1(0.f, 0.f, 0.f);
207
208 try
209 {
210 LArPointingClusterHelper::GetIntersection(a1, p1, a2, p2, C1, mu1, mu2);
211 }
212 catch (const StatusCodeException &)
213 {
214 continue;
215 }
216
217 if (mu1 < 0.f || mu2 < 0.f || mu1 > (b1 - a1).GetMagnitude() || mu2 > (b2 - a2).GetMagnitude())
218 continue;
219
220 const float thisSeparationSquared((C0 - C1).GetMagnitudeSquared());
221
222 if (thisSeparationSquared < closestSeparationSquared)
223 {
224 closestSeparationSquared = thisSeparationSquared;
225 splitPosition = (C0 + C1) * 0.5;
226 firstDirection = t2 * -1.f;
227 secondDirection = t1;
228 foundSplit = true;
229 }
230 }
231 }
232
233 if (!foundSplit)
234 return STATUS_CODE_NOT_FOUND;
235
236 return STATUS_CODE_SUCCESS;
237}
238
239//------------------------------------------------------------------------------------------------------------------------------------------
240
242 const Cluster *const pCluster1, const Cluster *const pCluster2, CartesianPointVector &candidateVector) const
243{
244 // ATTN The following is double-double counting
245 CaloHitList caloHitList1, caloHitList2;
246 pCluster1->GetOrderedCaloHitList().FillCaloHitList(caloHitList1);
247 pCluster2->GetOrderedCaloHitList().FillCaloHitList(caloHitList2);
248
249 CaloHitVector caloHitVector1(caloHitList1.begin(), caloHitList1.end()), caloHitVector2(caloHitList2.begin(), caloHitList2.end());
250 std::sort(caloHitVector1.begin(), caloHitVector1.end(), LArClusterHelper::SortHitsByPosition);
251 std::sort(caloHitVector2.begin(), caloHitVector2.end(), LArClusterHelper::SortHitsByPosition);
252
253 for (const CaloHit *const pCaloHit : caloHitVector1)
254 {
255 const CartesianVector position1(pCaloHit->GetPositionVector());
256 const CartesianVector position2(LArClusterHelper::GetClosestPosition(position1, pCluster2));
257
258 if ((position1 - position2).GetMagnitudeSquared() < m_maxClusterSeparationSquared)
259 candidateVector.push_back((position1 + position2) * 0.5);
260 }
261
262 for (const CaloHit *const pCaloHit : caloHitVector2)
263 {
264 const CartesianVector position2(pCaloHit->GetPositionVector());
265 const CartesianVector position1(LArClusterHelper::GetClosestPosition(position2, pCluster1));
266
267 if ((position2 - position1).GetMagnitudeSquared() < m_maxClusterSeparationSquared)
268 candidateVector.push_back((position2 + position1) * 0.5);
269 }
270}
271
272//------------------------------------------------------------------------------------------------------------------------------------------
273
275{
277 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxClusterSeparation", m_maxClusterSeparation));
279
281 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCosRelativeAngle", m_minCosRelativeAngle));
282
283 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SearchRegion1D", m_searchRegion1D));
284
286}
287
288} // namespace lar_content
Grouping of header files for many classes of use in particle flow algorithms.
Header file for the crossed track splitting algorithm class.
Header file for the kd tree linker algo template class.
Header file for the cluster helper class.
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:31
float m_minCosRelativeAngle
maximum relative angle between tracks after un-crossing
float m_maxClusterSeparation
maximum separation of two clusters
void FindCandidateSplitPositions(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, pandora::CartesianPointVector &candidateVector) const
Find average positions of pairs of hits within a maximum separation.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
pandora::StatusCode TidyUpStep()
Tidy up any information cached in e.g. the preparation step.
float m_maxClusterSeparationSquared
maximum separation of two clusters (squared)
pandora::StatusCode FindBestSplitPosition(const TwoDSlidingFitResult &slidingFit1, const TwoDSlidingFitResult &slidingFit2, pandora::CartesianVector &splitPosition, pandora::CartesianVector &direction1, pandora::CartesianVector &direction2) const
Find the best split position and direction for a pair of clusters.
std::unordered_map< const pandora::CaloHit *, const pandora::Cluster * > HitToClusterMap
pandora::StatusCode PreparationStep(const pandora::ClusterVector &clusterVector)
Perform any preparatory actions, such as caching information for subsequent expensive calculations.
ClusterToClustersMap m_nearbyClusters
The nearby clusters map.
float m_searchRegion1D
Search region, applied to each dimension, for look-up from kd-trees.
Box structure used to define 2D field. It's used in KDTree building step to divide the detector space...
void build(std::vector< KDTreeNodeInfoT< DATA, DIM > > &eltList, const KDTreeBoxT< DIM > &region)
Build the KD tree from the "eltList" in the space define by "region".
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...
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 SortHitsByPosition(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs)
Sort calo hits by their position (use Z, followed by X, followed by Y)
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.
static void GetIntersection(const LArPointingCluster::Vertex &firstVertex, const LArPointingCluster::Vertex &secondVertex, pandora::CartesianVector &intersectPosition, float &firstDisplacement, float &secondDisplacement)
Get intersection of two vertices.
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 GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
float GetLayerFitHalfWindowLength() const
Get the layer fit half window length.
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
pandora::StatusCode GetGlobalFitProjection(const pandora::CartesianVector &inputPosition, pandora::CartesianVector &projectedPosition) const
Get projected position on global fit for a given position vector.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
CaloHit class.
Definition CaloHit.h:26
CartesianVector class.
float GetDotProduct(const CartesianVector &rhs) const
Get the dot product of the cartesian vector with a second cartesian vector.
Cluster class.
Definition Cluster.h:31
const OrderedCaloHitList & GetOrderedCaloHitList() const
Get the ordered calo hit list.
Definition Cluster.h:470
void FillCaloHitList(CaloHitList &caloHitList) const
Fill a provided calo hit list with all the calo hits in the ordered calo hit list.
StatusCodeException class.
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
Definition XmlHelper.h:136
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
KDTreeBox build_2d_kd_search_region(const pandora::CaloHit *const point, const float x_span, const float z_span)
build_2d_kd_search_region
std::vector< const CaloHit * > CaloHitVector
std::vector< const Cluster * > ClusterVector
std::vector< CartesianVector > CartesianPointVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList
StatusCode
The StatusCode enum.