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