Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
ThreeViewTrackFragmentsAlgorithm.cc
Go to the documentation of this file.
1
10
13
15
16using namespace pandora;
17
18namespace lar_content
19{
20
22 m_nMaxTensorToolRepeats(1000),
23 m_minXOverlap(3.f),
24 m_minXOverlapFraction(0.8f),
25 m_maxPointDisplacementSquared(1.5f * 1.5f),
26 m_minMatchedSamplingPointFraction(0.5f),
27 m_minMatchedHits(5)
28{
29}
30
31//------------------------------------------------------------------------------------------------------------------------------------------
32
34{
35 try
36 {
37 this->AddToSlidingFitCache(pNewCluster);
38 }
39 catch (StatusCodeException &statusCodeException)
40 {
41 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
42 throw statusCodeException;
43
44 return;
45 }
46
47 const HitType hitType(LArClusterHelper::GetClusterHitType(pNewCluster));
48
49 if (!((TPC_VIEW_U == hitType) || (TPC_VIEW_V == hitType) || (TPC_VIEW_W == hitType)))
50 throw StatusCodeException(STATUS_CODE_FAILURE);
51
52 // ATTN This is non-standard usage, supported here only (for legacy purposes)
53 MatchingType &matchingControl(this->GetMatchingControl());
54 ClusterList &clusterList((TPC_VIEW_U == hitType) ? matchingControl.m_clusterListU
55 : (TPC_VIEW_V == hitType) ? matchingControl.m_clusterListV : matchingControl.m_clusterListW);
56
57 if (clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pNewCluster))
58 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
59
60 clusterList.push_back(pNewCluster);
61
62 ClusterList clusterList1(this->GetSelectedClusterList((TPC_VIEW_U == hitType) ? TPC_VIEW_V : TPC_VIEW_U));
63 ClusterList clusterList2(this->GetSelectedClusterList((TPC_VIEW_W == hitType) ? TPC_VIEW_V : TPC_VIEW_W));
64 clusterList1.sort(LArClusterHelper::SortByNHits);
65 clusterList2.sort(LArClusterHelper::SortByNHits);
66
67 for (const Cluster *const pCluster1 : clusterList1)
68 {
69 if (TPC_VIEW_U == hitType)
70 {
71 this->CalculateOverlapResult(pNewCluster, pCluster1, nullptr);
72 }
73 else if (TPC_VIEW_V == hitType)
74 {
75 this->CalculateOverlapResult(pCluster1, pNewCluster, nullptr);
76 }
77 else
78 {
79 this->CalculateOverlapResult(pCluster1, nullptr, pNewCluster);
80 }
81 }
82
83 for (const Cluster *const pCluster2 : clusterList2)
84 {
85 if (TPC_VIEW_U == hitType)
86 {
87 this->CalculateOverlapResult(pNewCluster, nullptr, pCluster2);
88 }
89 else if (TPC_VIEW_V == hitType)
90 {
91 this->CalculateOverlapResult(nullptr, pNewCluster, pCluster2);
92 }
93 else
94 {
95 this->CalculateOverlapResult(nullptr, pCluster2, pNewCluster);
96 }
97 }
98}
99
100//------------------------------------------------------------------------------------------------------------------------------------------
101
103{
104 const ClusterList *pNewClusterList = nullptr;
105 std::string oldClusterListName, newClusterListName;
106
107 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeReclustering(*this, TrackList(), rebuildList, oldClusterListName));
108 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
109 PandoraContentApi::RunClusteringAlgorithm(*this, m_reclusteringAlgorithmName, pNewClusterList, newClusterListName));
110
111 newClusters.insert(newClusters.end(), pNewClusterList->begin(), pNewClusterList->end());
112 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndReclustering(*this, newClusterListName));
113}
114
115//------------------------------------------------------------------------------------------------------------------------------------------
116
118{
119 ClusterList clusterListU(this->GetSelectedClusterList(TPC_VIEW_U));
120 ClusterList clusterListV(this->GetSelectedClusterList(TPC_VIEW_V));
121 ClusterList clusterListW(this->GetSelectedClusterList(TPC_VIEW_W));
122 clusterListU.sort(LArClusterHelper::SortByNHits);
123 clusterListV.sort(LArClusterHelper::SortByNHits);
124 clusterListW.sort(LArClusterHelper::SortByNHits);
125
126 for (const Cluster *const pClusterU : clusterListU)
127 {
128 for (const Cluster *const pClusterV : clusterListV)
129 this->CalculateOverlapResult(pClusterU, pClusterV, nullptr);
130 }
131
132 for (const Cluster *const pClusterU : clusterListU)
133 {
134 for (const Cluster *const pClusterW : clusterListW)
135 this->CalculateOverlapResult(pClusterU, nullptr, pClusterW);
136 }
137
138 for (const Cluster *const pClusterV : clusterListV)
139 {
140 for (const Cluster *const pClusterW : clusterListW)
141 this->CalculateOverlapResult(nullptr, pClusterV, pClusterW);
142 }
143}
144
145//------------------------------------------------------------------------------------------------------------------------------------------
146
147void ThreeViewTrackFragmentsAlgorithm::CalculateOverlapResult(const Cluster *const pClusterU, const Cluster *const pClusterV, const Cluster *const pClusterW)
148{
149 const HitType missingHitType(((nullptr != pClusterU) && (nullptr != pClusterV) && (nullptr == pClusterW))
150 ? TPC_VIEW_W
151 : ((nullptr != pClusterU) && (nullptr == pClusterV) && (nullptr != pClusterW))
152 ? TPC_VIEW_V
153 : ((nullptr == pClusterU) && (nullptr != pClusterV) && (nullptr != pClusterW)) ? TPC_VIEW_U : HIT_CUSTOM);
154
155 if (HIT_CUSTOM == missingHitType)
156 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
157
158 // Calculate new overlap result and replace old overlap result where necessary
159 FragmentOverlapResult oldOverlapResult, newOverlapResult;
160 const Cluster *pMatchedClusterU(nullptr), *pMatchedClusterV(nullptr), *pMatchedClusterW(nullptr);
161
162 const TwoDSlidingFitResult &fitResult1(
163 (TPC_VIEW_U == missingHitType) ? this->GetCachedSlidingFitResult(pClusterV) : this->GetCachedSlidingFitResult(pClusterU));
164
165 const TwoDSlidingFitResult &fitResult2(
166 (TPC_VIEW_U == missingHitType)
167 ? this->GetCachedSlidingFitResult(pClusterW)
168 : (TPC_VIEW_V == missingHitType) ? this->GetCachedSlidingFitResult(pClusterW) : this->GetCachedSlidingFitResult(pClusterV));
169
170 const ClusterList &inputClusterList(this->GetInputClusterList(missingHitType));
171
172 const Cluster *pBestMatchedCluster(nullptr);
173 const StatusCode statusCode(this->CalculateOverlapResult(fitResult1, fitResult2, inputClusterList, pBestMatchedCluster, newOverlapResult));
174
175 if ((STATUS_CODE_SUCCESS != statusCode) && (STATUS_CODE_NOT_FOUND != statusCode))
176 throw StatusCodeException(statusCode);
177
178 if (!newOverlapResult.IsInitialized())
179 return;
180
181 MatchingType::TensorType &overlapTensor(this->GetMatchingControl().GetOverlapTensor());
182
183 if (STATUS_CODE_SUCCESS == statusCode)
184 {
185 pMatchedClusterU = ((nullptr != pClusterU) ? pClusterU : pBestMatchedCluster);
186 pMatchedClusterV = ((nullptr != pClusterV) ? pClusterV : pBestMatchedCluster);
187 pMatchedClusterW = ((nullptr != pClusterW) ? pClusterW : pBestMatchedCluster);
188
189 if (nullptr == pMatchedClusterU || nullptr == pMatchedClusterV || nullptr == pMatchedClusterW)
190 throw StatusCodeException(STATUS_CODE_FAILURE);
191
192 try
193 {
194 oldOverlapResult = overlapTensor.GetOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW);
195 }
196 catch (StatusCodeException &)
197 {
198 }
199 }
200
201 if (!oldOverlapResult.IsInitialized())
202 {
203 overlapTensor.SetOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW, newOverlapResult);
204 }
205 else if (newOverlapResult.GetFragmentCaloHitList().size() > oldOverlapResult.GetFragmentCaloHitList().size())
206 {
207 overlapTensor.ReplaceOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW, newOverlapResult);
208 }
209 else if (newOverlapResult.GetFragmentCaloHitList().size() == oldOverlapResult.GetFragmentCaloHitList().size())
210 {
211 float newEnergySum(0.f), oldEnergySum(0.f);
212 for (const CaloHit *const pCaloHit : newOverlapResult.GetFragmentCaloHitList())
213 newEnergySum += pCaloHit->GetHadronicEnergy();
214 for (const CaloHit *const pCaloHit : oldOverlapResult.GetFragmentCaloHitList())
215 oldEnergySum += pCaloHit->GetHadronicEnergy();
216
217 if (newEnergySum > oldEnergySum)
218 overlapTensor.ReplaceOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW, newOverlapResult);
219 }
220}
221
222//------------------------------------------------------------------------------------------------------------------------------------------
223
225 const ClusterList &inputClusterList, const Cluster *&pBestMatchedCluster, FragmentOverlapResult &fragmentOverlapResult) const
226{
227 const Cluster *const pCluster1(fitResult1.GetCluster());
228 const Cluster *const pCluster2(fitResult2.GetCluster());
229
230 float xMin1(0.f), xMax1(0.f), xMin2(0.f), xMax2(0.f);
231 pCluster1->GetClusterSpanX(xMin1, xMax1);
232 pCluster2->GetClusterSpanX(xMin2, xMax2);
233
234 const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
235
236 if (xOverlap < std::numeric_limits<float>::epsilon())
237 return STATUS_CODE_NOT_FOUND;
238
239 CartesianPointVector projectedPositions;
240 const StatusCode statusCode1(this->GetProjectedPositions(fitResult1, fitResult2, projectedPositions));
241
242 if (STATUS_CODE_SUCCESS != statusCode1)
243 return statusCode1;
244
245 CaloHitList matchedHits;
246 ClusterList matchedClusters;
247 HitToClusterMap hitToClusterMap;
248 const StatusCode statusCode2(this->GetMatchedHits(inputClusterList, projectedPositions, hitToClusterMap, matchedHits));
249
250 if (STATUS_CODE_SUCCESS != statusCode2)
251 return statusCode2;
252
253 const StatusCode statusCode3(this->GetMatchedClusters(matchedHits, hitToClusterMap, matchedClusters, pBestMatchedCluster));
254
255 if (STATUS_CODE_SUCCESS != statusCode3)
256 return statusCode3;
257
258 if (!this->CheckMatchedClusters(projectedPositions, matchedClusters))
259 return STATUS_CODE_NOT_FOUND;
260
261 FragmentOverlapResult overlapResult;
262 this->GetFragmentOverlapResult(projectedPositions, matchedHits, matchedClusters, overlapResult);
263
264 if (!this->CheckOverlapResult(overlapResult))
265 return STATUS_CODE_NOT_FOUND;
266
267 fragmentOverlapResult = overlapResult;
268 return STATUS_CODE_SUCCESS;
269}
270
271//------------------------------------------------------------------------------------------------------------------------------------------
272
274 const TwoDSlidingFitResult &fitResult1, const TwoDSlidingFitResult &fitResult2, CartesianPointVector &projectedPositions) const
275{
276 const Cluster *const pCluster1(fitResult1.GetCluster());
277 const Cluster *const pCluster2(fitResult2.GetCluster());
278
279 // Check hit types
280 const HitType hitType1(LArClusterHelper::GetClusterHitType(pCluster1));
281 const HitType hitType2(LArClusterHelper::GetClusterHitType(pCluster2));
282 const HitType hitType3((TPC_VIEW_U != hitType1 && TPC_VIEW_U != hitType2)
283 ? TPC_VIEW_U
284 : (TPC_VIEW_V != hitType1 && TPC_VIEW_V != hitType2)
285 ? TPC_VIEW_V
286 : (TPC_VIEW_W != hitType1 && TPC_VIEW_W != hitType2) ? TPC_VIEW_W : HIT_CUSTOM);
287
288 if (HIT_CUSTOM == hitType3)
289 return STATUS_CODE_INVALID_PARAMETER;
290
291 // Check absolute and fractional overlap in x coordinate
292 float xMin1(0.f), xMax1(0.f), xMin2(0.f), xMax2(0.f);
293 pCluster1->GetClusterSpanX(xMin1, xMax1);
294 pCluster2->GetClusterSpanX(xMin2, xMax2);
295
296 const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
297 const float xSpan(std::max(xMax1, xMax2) - std::min(xMin1, xMin2));
298
299 if ((xOverlap < m_minXOverlap) || (xSpan < std::numeric_limits<float>::epsilon()) || ((xOverlap / xSpan) < m_minXOverlapFraction))
300 return STATUS_CODE_NOT_FOUND;
301
302 // Identify vertex and end positions (2D)
303 const CartesianVector minPosition1(fitResult1.GetGlobalMinLayerPosition());
304 const CartesianVector maxPosition1(fitResult1.GetGlobalMaxLayerPosition());
305 const CartesianVector minPosition2(fitResult2.GetGlobalMinLayerPosition());
306 const CartesianVector maxPosition2(fitResult2.GetGlobalMaxLayerPosition());
307
308 const float dx_A(std::fabs(minPosition2.GetX() - minPosition1.GetX()));
309 const float dx_B(std::fabs(maxPosition2.GetX() - maxPosition1.GetX()));
310 const float dx_C(std::fabs(maxPosition2.GetX() - minPosition1.GetX()));
311 const float dx_D(std::fabs(minPosition2.GetX() - maxPosition1.GetX()));
312
313 if (std::min(dx_C, dx_D) > std::max(dx_A, dx_B) && std::min(dx_A, dx_B) > std::max(dx_C, dx_D))
314 return STATUS_CODE_NOT_FOUND;
315
316 const CartesianVector &vtxPosition1(minPosition1);
317 const CartesianVector &endPosition1(maxPosition1);
318 const CartesianVector &vtxPosition2((dx_A < dx_C) ? minPosition2 : maxPosition2);
319 const CartesianVector &endPosition2((dx_A < dx_C) ? maxPosition2 : minPosition2);
320
321 // Calculate vertex and end positions (3D)
322 float vtxChi2(0.f);
323 CartesianVector vtxPosition3D(0.f, 0.f, 0.f);
324 LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), hitType1, hitType2, vtxPosition1, vtxPosition2, vtxPosition3D, vtxChi2);
325
326 float endChi2(0.f);
327 CartesianVector endPosition3D(0.f, 0.f, 0.f);
328 LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), hitType1, hitType2, endPosition1, endPosition2, endPosition3D, endChi2);
329
330 const CartesianVector vtxProjection3(LArGeometryHelper::ProjectPosition(this->GetPandora(), vtxPosition3D, hitType3));
331 const CartesianVector endProjection3(LArGeometryHelper::ProjectPosition(this->GetPandora(), endPosition3D, hitType3));
332
333 const float samplingPitch(0.5f * LArGeometryHelper::GetWireZPitch(this->GetPandora()));
334 const float nSamplingPoints((endProjection3 - vtxProjection3).GetMagnitude() / samplingPitch);
335
336 if (nSamplingPoints < 1.f)
337 return STATUS_CODE_NOT_FOUND;
338
339 // Loop over trajectory points
340 bool foundLastPosition(false);
341 CartesianVector lastPosition(0.f, 0.f, 0.f);
342
343 for (float iSample = 0.5f; iSample < nSamplingPoints; iSample += 1.f)
344 {
345 const CartesianVector linearPosition3D(vtxPosition3D + (endPosition3D - vtxPosition3D) * (iSample / nSamplingPoints));
346 const CartesianVector linearPosition1(LArGeometryHelper::ProjectPosition(this->GetPandora(), linearPosition3D, hitType1));
347 const CartesianVector linearPosition2(LArGeometryHelper::ProjectPosition(this->GetPandora(), linearPosition3D, hitType2));
348
349 float chi2(0.f);
350 CartesianVector fitPosition1(0.f, 0.f, 0.f), fitPosition2(0.f, 0.f, 0.f);
351
352 if ((STATUS_CODE_SUCCESS != fitResult1.GetGlobalFitProjection(linearPosition1, fitPosition1)) ||
353 (STATUS_CODE_SUCCESS != fitResult2.GetGlobalFitProjection(linearPosition2, fitPosition2)))
354 {
355 continue;
356 }
357
358 float rL1(0.f), rL2(0.f), rT1(0.f), rT2(0.f);
359 fitResult1.GetLocalPosition(fitPosition1, rL1, rT1);
360 fitResult2.GetLocalPosition(fitPosition2, rL2, rT2);
361
362 const float x(0.5 * (fitPosition1.GetX() + fitPosition2.GetX()));
363 CartesianVector position1(0.f, 0.f, 0.f), position2(0.f, 0.f, 0.f), position3(0.f, 0.f, 0.f);
364
365 try
366 {
367 const FitSegment &fitSegment1 = fitResult1.GetFitSegment(rL1);
368 const FitSegment &fitSegment2 = fitResult2.GetFitSegment(rL2);
369
370 if ((STATUS_CODE_SUCCESS != fitResult1.GetTransverseProjection(x, fitSegment1, position1)) ||
371 (STATUS_CODE_SUCCESS != fitResult2.GetTransverseProjection(x, fitSegment2, position2)))
372 {
373 continue;
374 }
375 }
376 catch (StatusCodeException &statusCodeException)
377 {
378 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
379 throw statusCodeException;
380
381 continue;
382 }
383
384 LArGeometryHelper::MergeTwoPositions(this->GetPandora(), hitType1, hitType2, position1, position2, position3, chi2);
385
386 // TODO For highly multi-valued x, projected positions can be unreliable. Need to make interpolation more robust for these cases.
387 if (foundLastPosition)
388 {
389 const float thisDisplacement((lastPosition - position3).GetMagnitude());
390 if (thisDisplacement > 2.f * samplingPitch)
391 {
392 const float nExtraPoints(thisDisplacement / samplingPitch);
393 for (float iExtra = 0.5f; iExtra < nExtraPoints; iExtra += 1.f)
394 {
395 const CartesianVector extraPosition(position3 + (lastPosition - position3) * (iExtra / nExtraPoints));
396 projectedPositions.push_back(extraPosition);
397 }
398 }
399 }
400
401 projectedPositions.push_back(position3);
402
403 lastPosition = position3;
404 foundLastPosition = true;
405 }
406
407 // Bail out if list of projected positions is empty
408 if (projectedPositions.empty())
409 return STATUS_CODE_NOT_FOUND;
410
411 return STATUS_CODE_SUCCESS;
412}
413
414//------------------------------------------------------------------------------------------------------------------------------------------
415
417 const CartesianPointVector &projectedPositions, HitToClusterMap &hitToClusterMap, CaloHitList &matchedHits) const
418{
419 CaloHitVector availableCaloHits;
420
421 for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
422 {
423 const Cluster *const pCluster = *iter;
424
425 if (!pCluster->IsAvailable())
426 continue;
427
428 CaloHitList caloHitList;
429 pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
430 availableCaloHits.insert(availableCaloHits.end(), caloHitList.begin(), caloHitList.end());
431
432 for (CaloHitList::const_iterator hIter = caloHitList.begin(), hIterEnd = caloHitList.end(); hIter != hIterEnd; ++hIter)
433 hitToClusterMap.insert(HitToClusterMap::value_type(*hIter, pCluster));
434 }
435
436 std::sort(availableCaloHits.begin(), availableCaloHits.end(), LArClusterHelper::SortHitsByPosition);
437
438 for (const CartesianVector &projectedPosition : projectedPositions)
439 {
440 const CaloHit *pClosestCaloHit(nullptr);
441 float closestDistanceSquared(std::numeric_limits<float>::max()), tieBreakerBestEnergy(0.f);
442
443 for (const CaloHit *const pCaloHit : availableCaloHits)
444 {
445 const float distanceSquared((pCaloHit->GetPositionVector() - projectedPosition).GetMagnitudeSquared());
446
447 if ((distanceSquared < closestDistanceSquared) ||
448 ((std::fabs(distanceSquared - closestDistanceSquared) < std::numeric_limits<float>::epsilon()) &&
449 (pCaloHit->GetHadronicEnergy() > tieBreakerBestEnergy)))
450 {
451 pClosestCaloHit = pCaloHit;
452 closestDistanceSquared = distanceSquared;
453 tieBreakerBestEnergy = pCaloHit->GetHadronicEnergy();
454 }
455 }
456
457 if ((closestDistanceSquared < m_maxPointDisplacementSquared) && (nullptr != pClosestCaloHit) &&
458 (matchedHits.end() == std::find(matchedHits.begin(), matchedHits.end(), pClosestCaloHit)))
459 matchedHits.push_back(pClosestCaloHit);
460 }
461
462 if (matchedHits.empty())
463 return STATUS_CODE_NOT_FOUND;
464
465 return STATUS_CODE_SUCCESS;
466}
467
468//------------------------------------------------------------------------------------------------------------------------------------------
469
471 ClusterList &matchedClusters, const Cluster *&pBestMatchedCluster) const
472{
473 ClusterToMatchedHitsMap clusterToMatchedHitsMap;
474
475 for (CaloHitList::const_iterator iter = matchedHits.begin(), iterEnd = matchedHits.end(); iter != iterEnd; ++iter)
476 {
477 const CaloHit *const pCaloHit = *iter;
478 HitToClusterMap::const_iterator cIter = hitToClusterMap.find(pCaloHit);
479
480 if (hitToClusterMap.end() == cIter)
481 throw StatusCodeException(STATUS_CODE_FAILURE);
482
483 ++clusterToMatchedHitsMap[cIter->second];
484
485 if (matchedClusters.end() == std::find(matchedClusters.begin(), matchedClusters.end(), cIter->second))
486 matchedClusters.push_back(cIter->second);
487 }
488
489 if (matchedClusters.empty())
490 return STATUS_CODE_NOT_FOUND;
491
492 pBestMatchedCluster = nullptr;
493 unsigned int bestClusterMatchedHits(0);
494 float tieBreakerBestEnergy(0.f);
495
496 ClusterVector sortedClusters;
497 for (const auto &mapEntry : clusterToMatchedHitsMap)
498 sortedClusters.push_back(mapEntry.first);
499 std::sort(sortedClusters.begin(), sortedClusters.end(), LArClusterHelper::SortByNHits);
500
501 for (const Cluster *const pCluster : sortedClusters)
502 {
503 const unsigned int nMatchedHits(clusterToMatchedHitsMap.at(pCluster));
504
505 if ((nMatchedHits > bestClusterMatchedHits) || ((nMatchedHits == bestClusterMatchedHits) && (pCluster->GetHadronicEnergy() > tieBreakerBestEnergy)))
506 {
507 pBestMatchedCluster = pCluster;
508 bestClusterMatchedHits = nMatchedHits;
509 tieBreakerBestEnergy = pCluster->GetHadronicEnergy();
510 }
511 }
512
513 if (nullptr == pBestMatchedCluster)
514 return STATUS_CODE_NOT_FOUND;
515
516 return STATUS_CODE_SUCCESS;
517}
518
519//------------------------------------------------------------------------------------------------------------------------------------------
520
522 const CaloHitList &matchedHits, const ClusterList &matchedClusters, FragmentOverlapResult &fragmentOverlapResult) const
523{
524 float chi2Sum(0.f);
525 unsigned int nMatchedSamplingPoints(0);
526
527 CaloHitVector sortedMatchedHits(matchedHits.begin(), matchedHits.end());
528 std::sort(sortedMatchedHits.begin(), sortedMatchedHits.end(), LArClusterHelper::SortHitsByPosition);
529
530 for (const CartesianVector &projectedPosition : projectedPositions)
531 {
532 float closestDistanceSquared(std::numeric_limits<float>::max());
533
534 for (const CaloHit *const pCaloHit : matchedHits)
535 {
536 const float distanceSquared((pCaloHit->GetPositionVector() - projectedPosition).GetMagnitudeSquared());
537
538 if (distanceSquared < closestDistanceSquared)
539 closestDistanceSquared = distanceSquared;
540 }
541
542 if (closestDistanceSquared < m_maxPointDisplacementSquared)
543 {
544 ++nMatchedSamplingPoints;
545 chi2Sum += closestDistanceSquared;
546 }
547 }
548
549 fragmentOverlapResult = FragmentOverlapResult(nMatchedSamplingPoints, projectedPositions.size(), chi2Sum, matchedHits, matchedClusters);
550}
551
552//------------------------------------------------------------------------------------------------------------------------------------------
553
554bool ThreeViewTrackFragmentsAlgorithm::CheckMatchedClusters(const CartesianPointVector &projectedPositions, const ClusterList &matchedClusters) const
555{
556 if (projectedPositions.empty() || matchedClusters.empty())
557 return false;
558
559 // Calculate X and Z span of projected positions
560 float minXproj(+std::numeric_limits<float>::max());
561 float maxXproj(-std::numeric_limits<float>::max());
562 float minZproj(+std::numeric_limits<float>::max());
563 float maxZproj(-std::numeric_limits<float>::max());
564
565 for (const CartesianVector &projectedPosition : projectedPositions)
566 {
567 minXproj = std::min(minXproj, projectedPosition.GetX());
568 maxXproj = std::max(maxXproj, projectedPosition.GetX());
569 minZproj = std::min(minZproj, projectedPosition.GetZ());
570 maxZproj = std::max(maxZproj, projectedPosition.GetZ());
571 }
572
573 const float dXproj(maxXproj - minXproj);
574 const float dZproj(maxZproj - minZproj);
575 const float projectedLengthSquared(dXproj * dXproj + dZproj * dZproj);
576
577 // Calculate X and Z span of matched clusters
578 float minXcluster(+std::numeric_limits<float>::max());
579 float maxXcluster(-std::numeric_limits<float>::max());
580 float minZcluster(+std::numeric_limits<float>::max());
581 float maxZcluster(-std::numeric_limits<float>::max());
582
583 for (const Cluster *const pCluster : matchedClusters)
584 {
585 CartesianVector minPosition(0.f, 0.f, 0.f);
586 CartesianVector maxPosition(0.f, 0.f, 0.f);
587
588 LArClusterHelper::GetClusterBoundingBox(pCluster, minPosition, maxPosition);
589
590 minXcluster = std::min(minXcluster, minPosition.GetX());
591 maxXcluster = std::max(maxXcluster, maxPosition.GetX());
592 minZcluster = std::min(minZcluster, minPosition.GetZ());
593 maxZcluster = std::max(maxZcluster, maxPosition.GetZ());
594 }
595
596 const float dXcluster(maxXcluster - minXcluster);
597 const float dZcluster(maxZcluster - minZcluster);
598 const float clusterLengthSquared(dXcluster * dXcluster + dZcluster * dZcluster);
599
600 // Require that the span of the matched clusters is no larger than twice the span of the projected positions
601 if (clusterLengthSquared > 4.f * projectedLengthSquared)
602 return false;
603
604 return true;
605}
606
607//------------------------------------------------------------------------------------------------------------------------------------------
608
610{
611 // ATTN This method is currently mirrored in ClearTrackFragments tool
613 return false;
614
615 if (overlapResult.GetFragmentCaloHitList().size() < m_minMatchedHits)
616 return false;
617
618 return true;
619}
620
621//------------------------------------------------------------------------------------------------------------------------------------------
622
624{
625 unsigned int repeatCounter(0);
626
627 for (TensorToolVector::const_iterator iter = m_algorithmToolVector.begin(), iterEnd = m_algorithmToolVector.end(); iter != iterEnd;)
628 {
629 if ((*iter)->Run(this, this->GetMatchingControl().GetOverlapTensor()))
630 {
631 iter = m_algorithmToolVector.begin();
632
633 if (++repeatCounter > m_nMaxTensorToolRepeats)
634 break;
635 }
636 else
637 {
638 ++iter;
639 }
640 }
641}
642
643//------------------------------------------------------------------------------------------------------------------------------------------
644
646{
647 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ProcessAlgorithm(*this, xmlHandle, "ClusterRebuilding", m_reclusteringAlgorithmName));
648
649 AlgorithmToolVector algorithmToolVector;
650 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ProcessAlgorithmToolList(*this, xmlHandle, "TrackTools", algorithmToolVector));
651
652 for (AlgorithmToolVector::const_iterator iter = algorithmToolVector.begin(), iterEnd = algorithmToolVector.end(); iter != iterEnd; ++iter)
653 {
654 FragmentTensorTool *const pFragmentTensorTool(dynamic_cast<FragmentTensorTool *>(*iter));
655
656 if (!pFragmentTensorTool)
657 return STATUS_CODE_INVALID_PARAMETER;
658
659 m_algorithmToolVector.push_back(pFragmentTensorTool);
660 }
661
663 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NMaxTensorToolRepeats", m_nMaxTensorToolRepeats));
664
665 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinXOverlap", m_minXOverlap));
666
668 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinXOverlapFraction", m_minXOverlapFraction));
669
670 float maxPointDisplacement = std::sqrt(m_maxPointDisplacementSquared);
672 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxPointDisplacement", maxPointDisplacement));
673 m_maxPointDisplacementSquared = maxPointDisplacement * maxPointDisplacement;
674
675 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
676 XmlHelper::ReadValue(xmlHandle, "MinMatchedSamplingPointFraction", m_minMatchedSamplingPointFraction));
677
678 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinMatchedHits", m_minMatchedHits));
679
680 return BaseAlgorithm::ReadSettings(xmlHandle);
681}
682
683} // namespace lar_content
Grouping of header files for many classes of use in particle flow algorithms.
Header file for the cluster helper class.
Header file for the geometry helper class.
#define PANDORA_THROW_RESULT_IF(StatusCode1, Operator, Command)
Definition StatusCodes.h:43
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:31
#define PANDORA_RETURN_RESULT_IF(StatusCode1, Operator, Command)
Definition StatusCodes.h:19
Header file for the three view fragments algorithm base class.
static pandora::StatusCode RunClusteringAlgorithm(const pandora::Algorithm &algorithm, const std::string &clusteringAlgorithmName, const pandora::ClusterList *&pNewClusterList, std::string &newClusterListName)
Run a clustering algorithm (an algorithm that will create new cluster objects)
static pandora::StatusCode EndReclustering(const pandora::Algorithm &algorithm, const std::string &selectedClusterListName)
End reclustering operations on clusters in the algorithm input list.
static pandora::StatusCode InitializeReclustering(const pandora::Algorithm &algorithm, const pandora::TrackList &inputTrackList, const pandora::ClusterList &inputClusterList, std::string &originalClustersListName)
Initialize reclustering operations on clusters in the algorithm input list. This allows hits in a lis...
const pandora::CaloHitList & GetFragmentCaloHitList() const
Get the list of fragment-associated hits.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
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 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 GetClusterBoundingBox(const pandora::Cluster *const pCluster, pandora::CartesianVector &minimumCoordinate, pandora::CartesianVector &maximumCoordinate)
Get minimum and maximum X, Y and Z positions of the calo hits in a cluster.
static float MergeTwoPositions(const pandora::Pandora &pandora, const pandora::HitType view1, const pandora::HitType view2, const float position1, const float position2)
Merge two views (U,V) to give a third view (Z).
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
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.
const pandora::ClusterList & GetInputClusterList(const pandora::HitType hitType) const
Get the input cluster list corresponding to a specified hit type.
MatchingType & GetMatchingControl()
Get the matching control.
const pandora::ClusterList & GetSelectedClusterList(const pandora::HitType hitType) const
Get the selected cluster list corresponding to a specified hit type.
void AddToSlidingFitCache(const pandora::Cluster *const pCluster)
Add a new sliding fit result, for the specified cluster, to the algorithm cache.
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
void PerformMainLoop()
Main loop over cluster combinations in order to populate the overlap container. Responsible for calli...
TensorToolVector m_algorithmToolVector
The algorithm tool list.
std::unordered_map< const pandora::CaloHit *, const pandora::Cluster * > HitToClusterMap
void GetFragmentOverlapResult(const pandora::CartesianPointVector &projectedPositions, const pandora::CaloHitList &matchedHits, const pandora::ClusterList &matchedClusters, FragmentOverlapResult &fragmentOverlapResult) const
Get the populated fragment overlap result.
void UpdateForNewCluster(const pandora::Cluster *const pNewCluster)
Update to reflect addition of a new cluster to the problem space.
void ExamineOverlapContainer()
Examine contents of overlap container, collect together best-matching 2D particles and modify cluster...
void RebuildClusters(const pandora::ClusterList &rebuildList, pandora::ClusterList &newClusters) const
Rebuild clusters after fragmentation.
float m_maxPointDisplacementSquared
maximum allowed distance (squared) between projected points and associated hits
unsigned int m_nMaxTensorToolRepeats
The maximum number of repeat loops over tensor tools.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
pandora::StatusCode GetMatchedClusters(const pandora::CaloHitList &matchedHits, const HitToClusterMap &hitToClusterMap, pandora::ClusterList &matchedClusters, const pandora::Cluster *&pBestMatchedCluster) const
Get the list of the relevant clusters and the address of the single best matched cluster.
void CalculateOverlapResult(const pandora::Cluster *const pClusterU, const pandora::Cluster *const pClusterV, const pandora::Cluster *const pClusterW)
Calculate cluster overlap result and store in container.
bool CheckMatchedClusters(const pandora::CartesianPointVector &projectedPositions, const pandora::ClusterList &matchedClusters) const
Whether the matched clusters are consistent with the projected positions.
float m_minMatchedSamplingPointFraction
minimum fraction of matched sampling points
float m_minXOverlap
requirement on minimum X overlap for associated clusters
bool CheckOverlapResult(const FragmentOverlapResult &overlapResult) const
Whether the matched clusters and hits pass the algorithm quality cuts.
std::string m_reclusteringAlgorithmName
Name of daughter algorithm to use for cluster re-building.
unsigned int m_minMatchedHits
minimum number of matched calo hits
float m_minXOverlapFraction
requirement on minimum X overlap fraction for associated clusters
std::unordered_map< const pandora::Cluster *, unsigned int > ClusterToMatchedHitsMap
pandora::StatusCode GetMatchedHits(const pandora::ClusterList &inputClusterList, const pandora::CartesianPointVector &projectedPositions, HitToClusterMap &hitToClusterMap, pandora::CaloHitList &matchedCaloHits) const
Get the list of hits associated with the projected positions and a useful hit to cluster map.
pandora::StatusCode GetProjectedPositions(const TwoDSlidingFitResult &fitResult1, const TwoDSlidingFitResult &fitResult2, pandora::CartesianPointVector &projectedPositions) const
Get the list of projected positions, in the third view, corresponding to a pair of sliding fit result...
bool IsInitialized() const
Whether the track overlap result has been initialized.
float GetMatchedFraction() const
Get the fraction of sampling points resulting in a match.
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::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
pandora::StatusCode GetTransverseProjection(const float x, const FitSegment &fitSegment, pandora::CartesianVector &position) const
Get projected position for a given input x coordinate and fit segment.
const FitSegment & GetFitSegment(const float rL) const
Get fit segment for a given longitudinal coordinate.
pandora::StatusCode GetGlobalFitProjection(const pandora::CartesianVector &inputPosition, pandora::CartesianVector &projectedPosition) const
Get projected position on global fit for a given position vector.
CaloHit class.
Definition CaloHit.h:26
float GetHadronicEnergy() const
Get the calibrated hadronic energy measure.
Definition CaloHit.h:490
CartesianVector class.
float GetX() const
Get the cartesian x coordinate.
float GetZ() const
Get the cartesian z coordinate.
Cluster class.
Definition Cluster.h:31
bool IsAvailable() const
Whether the cluster is available to be added to a particle flow object.
Definition Cluster.h:582
float GetHadronicEnergy() const
Get the sum of hadronic energy measures of all constituent calo hits, units GeV.
Definition Cluster.h:526
const OrderedCaloHitList & GetOrderedCaloHitList() const
Get the ordered calo hit list.
Definition Cluster.h:470
void GetClusterSpanX(float &xmin, float &xmax) const
Get minimum and maximum X positions of the calo hits in this cluster.
Definition Cluster.cc:169
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.
Definition Process.h:116
StatusCodeException class.
StatusCode GetStatusCode() const
Get status code.
static StatusCode ProcessAlgorithm(const Algorithm &algorithm, const TiXmlHandle &xmlHandle, const std::string &description, std::string &algorithmName)
Process an algorithm described in an xml element with a matching "description = .....
Definition XmlHelper.cc:16
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
Definition XmlHelper.h:136
static StatusCode ProcessAlgorithmToolList(const Algorithm &algorithm, const TiXmlHandle &xmlHandle, const std::string &listName, AlgorithmToolVector &algorithmToolVector)
Process a list of algorithms tools in an xml file.
Definition XmlHelper.cc:101
HitType
Calorimeter hit type enum.
std::vector< const CaloHit * > CaloHitVector
std::vector< const Cluster * > ClusterVector
MANAGED_CONTAINER< const Cluster * > ClusterList
std::vector< CartesianVector > CartesianPointVector
std::vector< AlgorithmTool * > AlgorithmToolVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList
MANAGED_CONTAINER< const Track * > TrackList
StatusCode
The StatusCode enum.