LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
ParticleRecoveryAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
14 
16 
18 
19 #include <algorithm>
20 
21 using namespace pandora;
22 
23 namespace lar_content
24 {
25 
26 ParticleRecoveryAlgorithm::ParticleRecoveryAlgorithm() :
27  m_checkGaps(true),
28  m_minClusterCaloHits(20),
29  m_minClusterLengthSquared(5.f * 5.f),
30  m_minClusterXSpan(0.25f),
31  m_vertexClusterMode(false),
32  m_minVertexLongitudinalDistance(-2.5f),
33  m_maxVertexTransverseDistance(1.5f),
34  m_minXOverlapFraction(0.75f),
35  m_minXOverlapFractionGaps(0.75f),
36  m_sampleStepSize(0.5f),
37  m_slidingFitHalfWindow(10),
38  m_pseudoChi2Cut(5.f)
39 {
40 }
41 
42 //------------------------------------------------------------------------------------------------------------------------------------------
43 
45 {
46  ClusterList inputClusterListU, inputClusterListV, inputClusterListW;
47  this->GetInputClusters(inputClusterListU, inputClusterListV, inputClusterListW);
48 
49  ClusterList selectedClusterListU, selectedClusterListV, selectedClusterListW;
50  this->SelectInputClusters(inputClusterListU, selectedClusterListU);
51  this->SelectInputClusters(inputClusterListV, selectedClusterListV);
52  this->SelectInputClusters(inputClusterListW, selectedClusterListW);
53 
54  SimpleOverlapTensor overlapTensor;
55  this->FindOverlaps(selectedClusterListU, selectedClusterListV, overlapTensor);
56  this->FindOverlaps(selectedClusterListV, selectedClusterListW, overlapTensor);
57  this->FindOverlaps(selectedClusterListW, selectedClusterListU, overlapTensor);
58  this->ExamineTensor(overlapTensor);
59 
60  return STATUS_CODE_SUCCESS;
61 }
62 
63 //------------------------------------------------------------------------------------------------------------------------------------------
64 
65 void ParticleRecoveryAlgorithm::GetInputClusters(ClusterList &inputClusterListU, ClusterList &inputClusterListV, ClusterList &inputClusterListW) const
66 {
67  for (StringVector::const_iterator iter = m_inputClusterListNames.begin(), iterEnd = m_inputClusterListNames.end(); iter != iterEnd; ++iter)
68  {
69  const ClusterList *pClusterList(NULL);
70  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, *iter, pClusterList));
71 
72  if (!pClusterList || pClusterList->empty())
73  {
74  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
75  std::cout << "ParticleRecoveryAlgorithm: unable to find cluster list " << *iter << std::endl;
76 
77  continue;
78  }
79 
80  for (ClusterList::const_iterator cIter = pClusterList->begin(), cIterEnd = pClusterList->end(); cIter != cIterEnd; ++cIter)
81  {
82  const Cluster *const pCluster(*cIter);
83  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
84 
85  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
86  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
87 
88  ClusterList &clusterList((TPC_VIEW_U == hitType) ? inputClusterListU
89  : (TPC_VIEW_V == hitType) ? inputClusterListV
90  : inputClusterListW);
91  clusterList.push_back(pCluster);
92  }
93  }
94 }
95 
96 //------------------------------------------------------------------------------------------------------------------------------------------
97 
98 void ParticleRecoveryAlgorithm::SelectInputClusters(const ClusterList &inputClusterList, ClusterList &selectedClusterList) const
99 {
101  {
102  ClusterList vertexClusterList;
103  this->VertexClusterSelection(inputClusterList, vertexClusterList);
104  this->StandardClusterSelection(vertexClusterList, selectedClusterList);
105  }
106  else
107  {
108  this->StandardClusterSelection(inputClusterList, selectedClusterList);
109  }
110 }
111 
112 //------------------------------------------------------------------------------------------------------------------------------------------
113 
114 void ParticleRecoveryAlgorithm::StandardClusterSelection(const ClusterList &inputClusterList, ClusterList &selectedClusterList) const
115 {
116  for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
117  {
118  const Cluster *const pCluster = *iter;
119 
120  if (!pCluster->IsAvailable())
121  continue;
122 
123  if (pCluster->GetNCaloHits() < m_minClusterCaloHits)
124  continue;
125 
127  continue;
128 
129  float xMin(0.f), xMax(0.f);
130  pCluster->GetClusterSpanX(xMin, xMax);
131 
132  if ((xMax - xMin) < m_minClusterXSpan)
133  continue;
134 
135  selectedClusterList.push_back(pCluster);
136  }
137 }
138 
139 //------------------------------------------------------------------------------------------------------------------------------------------
140 
141 void ParticleRecoveryAlgorithm::VertexClusterSelection(const ClusterList &inputClusterList, ClusterList &selectedClusterList) const
142 {
143  CartesianPointVector vertexList;
144 
145  for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
146  {
147  try
148  {
149  if (!(*iter)->IsAvailable())
150  {
151  const LArPointingCluster pointingCluster(*iter);
152  vertexList.push_back(pointingCluster.GetInnerVertex().GetPosition());
153  vertexList.push_back(pointingCluster.GetOuterVertex().GetPosition());
154  }
155  }
156  catch (StatusCodeException &)
157  {
158  }
159  }
160 
161  for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
162  {
163  try
164  {
165  const Cluster *const pCluster = *iter;
166 
167  if (!pCluster->IsAvailable())
168  continue;
169 
170  const LArPointingCluster pointingCluster(pCluster);
171 
172  for (CartesianPointVector::const_iterator vIter = vertexList.begin(), vIterEnd = vertexList.end(); vIter != vIterEnd; ++vIter)
173  {
176  {
177  selectedClusterList.push_back(pCluster);
178  break;
179  }
180  }
181  }
182  catch (StatusCodeException &)
183  {
184  }
185  }
186 }
187 
188 //------------------------------------------------------------------------------------------------------------------------------------------
189 
190 void ParticleRecoveryAlgorithm::FindOverlaps(const ClusterList &clusterList1, const ClusterList &clusterList2, SimpleOverlapTensor &overlapTensor) const
191 {
192  for (ClusterList::const_iterator iter1 = clusterList1.begin(), iter1End = clusterList1.end(); iter1 != iter1End; ++iter1)
193  {
194  for (ClusterList::const_iterator iter2 = clusterList2.begin(), iter2End = clusterList2.end(); iter2 != iter2End; ++iter2)
195  {
196  if (this->IsOverlap(*iter1, *iter2))
197  overlapTensor.AddAssociation(*iter1, *iter2);
198  }
199  }
200 }
201 
202 //------------------------------------------------------------------------------------------------------------------------------------------
203 
204 bool ParticleRecoveryAlgorithm::IsOverlap(const Cluster *const pCluster1, const Cluster *const pCluster2) const
205 {
207  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
208 
209  if ((0 == pCluster1->GetNCaloHits()) || (0 == pCluster2->GetNCaloHits()))
210  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
211 
212  float xMin1(0.f), xMax1(0.f), xMin2(0.f), xMax2(0.f);
213  pCluster1->GetClusterSpanX(xMin1, xMax1);
214  pCluster2->GetClusterSpanX(xMin2, xMax2);
215 
216  const float xSpan1(xMax1 - xMin1), xSpan2(xMax2 - xMin2);
217 
218  if ((xSpan1 < std::numeric_limits<float>::epsilon()) || (xSpan2 < std::numeric_limits<float>::epsilon()))
219  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
220 
221  const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
222 
223  float xOverlapFraction1(xOverlap / xSpan1), xOverlapFraction2(xOverlap / xSpan2);
224 
225  if (m_checkGaps)
226  this->CalculateEffectiveOverlapFractions(pCluster1, xMin1, xMax1, pCluster2, xMin2, xMax2, xOverlapFraction1, xOverlapFraction2);
227 
228  if ((xOverlapFraction1 < m_minXOverlapFraction) || (xOverlapFraction2 < m_minXOverlapFraction))
229  return false;
230 
231  return true;
232 }
233 
234 //------------------------------------------------------------------------------------------------------------------------------------------
235 
236 void ParticleRecoveryAlgorithm::CalculateEffectiveOverlapFractions(const Cluster *const pCluster1, const float xMin1, const float xMax1,
237  const Cluster *const pCluster2, const float xMin2, const float xMax2, float &xOverlapFraction1, float &xOverlapFraction2) const
238 {
239  if (PandoraContentApi::GetGeometry(*this)->GetDetectorGapList().empty())
240  return;
241 
242  const float xMin(std::min(xMin1, xMin2));
243  const float xMax(std::max(xMax1, xMax2));
244  float xMinEff1(xMin1), xMaxEff1(xMax1), xMinEff2(xMin2), xMaxEff2(xMax2);
245 
246  this->CalculateEffectiveSpan(pCluster1, xMin, xMax, xMinEff1, xMaxEff1);
247  this->CalculateEffectiveSpan(pCluster2, xMin, xMax, xMinEff2, xMaxEff2);
248 
249  const float effectiveXSpan1(xMaxEff1 - xMinEff1), effectiveXSpan2(xMaxEff2 - xMinEff2);
250  const float effectiveXOverlapSpan(std::min(xMaxEff1, xMaxEff2) - std::max(xMinEff1, xMinEff2));
251 
252  if ((effectiveXSpan1 > std::numeric_limits<float>::epsilon()) && (effectiveXSpan2 > std::numeric_limits<float>::epsilon()))
253  {
254  xOverlapFraction1 = std::min(1.f, (effectiveXOverlapSpan / effectiveXSpan1));
255  xOverlapFraction2 = std::min(1.f, (effectiveXOverlapSpan / effectiveXSpan2));
256  }
257 }
258 
259 //------------------------------------------------------------------------------------------------------------------------------------------
260 
262  const pandora::Cluster *const pCluster, const float xMin, const float xMax, float &xMinEff, float &xMaxEff) const
263 {
264  // TODO cache sliding linear fit results and optimise protection against exceptions from TwoDSlidingFitResult and IsXSamplingPointInGap
265  try
266  {
267  const float slidingFitPitch(LArGeometryHelper::GetWirePitch(this->GetPandora(), LArClusterHelper::GetClusterHitType(pCluster)));
268 
269  const TwoDSlidingFitResult slidingFitResult(pCluster, m_slidingFitHalfWindow, slidingFitPitch);
270 
271  const int nSamplingPointsLeft(1 + static_cast<int>((xMinEff - xMin) / m_sampleStepSize));
272  const int nSamplingPointsRight(1 + static_cast<int>((xMax - xMaxEff) / m_sampleStepSize));
273  float dxMin(0.f), dxMax(0.f);
274 
275  for (int iSample = 1; iSample <= nSamplingPointsLeft; ++iSample)
276  {
277  const float xSample(std::max(xMin, xMinEff - static_cast<float>(iSample) * m_sampleStepSize));
278 
279  if (!LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult, m_sampleStepSize))
280  break;
281 
282  dxMin = xMinEff - xSample;
283  }
284 
285  for (int iSample = 1; iSample <= nSamplingPointsRight; ++iSample)
286  {
287  const float xSample(std::min(xMax, xMaxEff + static_cast<float>(iSample) * m_sampleStepSize));
288 
289  if (!LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult, m_sampleStepSize))
290  break;
291 
292  dxMax = xSample - xMaxEff;
293  }
294 
295  xMinEff = xMinEff - dxMin;
296  xMaxEff = xMaxEff + dxMax;
297  }
298  catch (StatusCodeException &)
299  {
300  }
301 }
302 
303 //------------------------------------------------------------------------------------------------------------------------------------------
304 
306 {
307  ClusterVector sortedKeyClusters(overlapTensor.GetKeyClusters().begin(), overlapTensor.GetKeyClusters().end());
308  std::sort(sortedKeyClusters.begin(), sortedKeyClusters.end(), LArClusterHelper::SortByNHits);
309 
310  for (const Cluster *const pKeyCluster : sortedKeyClusters)
311  {
312  ClusterList clusterListU, clusterListV, clusterListW;
313 
314  overlapTensor.GetConnectedElements(pKeyCluster, true, clusterListU, clusterListV, clusterListW);
315  const unsigned int nU(clusterListU.size()), nV(clusterListV.size()), nW(clusterListW.size());
316 
317  if ((0 == nU * nV) && (0 == nV * nW) && (0 == nW * nU))
318  continue;
319 
320  ClusterList clusterListAll;
321  clusterListAll.insert(clusterListAll.end(), clusterListU.begin(), clusterListU.end());
322  clusterListAll.insert(clusterListAll.end(), clusterListV.begin(), clusterListV.end());
323  clusterListAll.insert(clusterListAll.end(), clusterListW.begin(), clusterListW.end());
324 
325  if ((1 == nU * nV * nW) && this->CheckConsistency(*(clusterListU.begin()), *(clusterListV.begin()), *(clusterListW.begin())))
326  {
327  this->CreateTrackParticle(clusterListAll);
328  }
329  else if ((0 == nU * nV * nW) && ((1 == nU && 1 == nV) || (1 == nV && 1 == nW) || (1 == nW && 1 == nU)))
330  {
331  this->CreateTrackParticle(clusterListAll);
332  }
333  else
334  {
335  // TODO - check here whether there is a gap in the 2 in one view when 1:2:0
336  // May later choose to resolve simple ambiguities, e.g. of form nU:nV:nW == 1:2:0
337  }
338  }
339 }
340 
341 //------------------------------------------------------------------------------------------------------------------------------------------
342 
343 bool ParticleRecoveryAlgorithm::CheckConsistency(const Cluster *const pClusterU, const Cluster *const pClusterV, const Cluster *const pClusterW) const
344 {
345  // Requirements on X matching
346  float xMinU(0.f), xMinV(0.f), xMinW(0.f), xMaxU(0.f), xMaxV(0.f), xMaxW(0.f);
347  pClusterU->GetClusterSpanX(xMinU, xMaxU);
348  pClusterV->GetClusterSpanX(xMinV, xMaxV);
349  pClusterW->GetClusterSpanX(xMinW, xMaxW);
350 
351  const float xMin(std::max(xMinU, std::max(xMinV, xMinW)));
352  const float xMax(std::min(xMaxU, std::min(xMaxV, xMaxW)));
353  const float xOverlap(xMax - xMin);
354 
355  if (xOverlap < std::numeric_limits<float>::epsilon())
356  return false;
357 
358  // Requirements on 3D matching
359  float u(std::numeric_limits<float>::max()), v(std::numeric_limits<float>::max()), w(std::numeric_limits<float>::max());
360 
361  if ((STATUS_CODE_SUCCESS != LArClusterHelper::GetAverageZ(pClusterU, xMin, xMax, u)) ||
362  (STATUS_CODE_SUCCESS != LArClusterHelper::GetAverageZ(pClusterV, xMin, xMax, v)) ||
363  (STATUS_CODE_SUCCESS != LArClusterHelper::GetAverageZ(pClusterW, xMin, xMax, w)))
364  {
365  return false;
366  }
367 
368  const float uv2w(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), TPC_VIEW_U, TPC_VIEW_V, u, v));
369  const float vw2u(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), TPC_VIEW_V, TPC_VIEW_W, v, w));
370  const float wu2v(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), TPC_VIEW_W, TPC_VIEW_U, w, u));
371 
372  const float pseudoChi2(((u - vw2u) * (u - vw2u) + (v - wu2v) * (v - wu2v) + (w - uv2w) * (w - uv2w)) / 3.f);
373 
374  if (pseudoChi2 > m_pseudoChi2Cut)
375  return false;
376 
377  return true;
378 }
379 
380 //------------------------------------------------------------------------------------------------------------------------------------------
381 
382 void ParticleRecoveryAlgorithm::CreateTrackParticle(const ClusterList &clusterList) const
383 {
384  if (clusterList.size() < 2)
385  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
386 
387  const PfoList *pPfoList = NULL;
388  std::string pfoListName;
389  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pPfoList, pfoListName));
390 
391  // TODO Correct these placeholder parameters
392  PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
393  pfoParameters.m_particleId = MU_MINUS;
394  pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
395  pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
396  pfoParameters.m_energy = 0.f;
397  pfoParameters.m_momentum = CartesianVector(0.f, 0.f, 0.f);
398  pfoParameters.m_clusterList = clusterList;
399 
400  const ParticleFlowObject *pPfo(NULL);
401  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*this, pfoParameters, pPfo));
402 
403  if (!pPfoList->empty())
404  {
405  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*this, m_outputPfoListName));
406  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Pfo>(*this, m_outputPfoListName));
407  }
408 }
409 
410 //------------------------------------------------------------------------------------------------------------------------------------------
411 //------------------------------------------------------------------------------------------------------------------------------------------
412 
413 void ParticleRecoveryAlgorithm::SimpleOverlapTensor::AddAssociation(const Cluster *const pCluster1, const Cluster *const pCluster2)
414 {
415  const HitType hitType1(LArClusterHelper::GetClusterHitType(pCluster1));
416  const HitType hitType2(LArClusterHelper::GetClusterHitType(pCluster2));
417 
418  const Cluster *const pClusterU((TPC_VIEW_U == hitType1) ? pCluster1 : (TPC_VIEW_U == hitType2) ? pCluster2 : NULL);
419  const Cluster *const pClusterV((TPC_VIEW_V == hitType1) ? pCluster1 : (TPC_VIEW_V == hitType2) ? pCluster2 : NULL);
420  const Cluster *const pClusterW((TPC_VIEW_W == hitType1) ? pCluster1 : (TPC_VIEW_W == hitType2) ? pCluster2 : NULL);
421 
422  if (pClusterU && pClusterV && !pClusterW)
423  {
424  m_clusterNavigationMapUV[pClusterU].push_back(pClusterV);
425 
426  if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterU))
427  m_keyClusters.push_back(pClusterU);
428  }
429  else if (!pClusterU && pClusterV && pClusterW)
430  {
431  m_clusterNavigationMapVW[pClusterV].push_back(pClusterW);
432 
433  if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterV))
434  m_keyClusters.push_back(pClusterV);
435  }
436  else if (pClusterU && !pClusterV && pClusterW)
437  {
438  m_clusterNavigationMapWU[pClusterW].push_back(pClusterU);
439 
440  if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterW))
441  m_keyClusters.push_back(pClusterW);
442  }
443  else
444  {
445  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
446  }
447 }
448 
449 //------------------------------------------------------------------------------------------------------------------------------------------
450 
451 void ParticleRecoveryAlgorithm::SimpleOverlapTensor::GetConnectedElements(const Cluster *const pCluster, const bool ignoreUnavailable,
452  ClusterList &clusterListU, ClusterList &clusterListV, ClusterList &clusterListW) const
453 {
454  if (ignoreUnavailable && !pCluster->IsAvailable())
455  return;
456 
457  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
458 
459  if (!((TPC_VIEW_U == hitType) || (TPC_VIEW_V == hitType) || (TPC_VIEW_W == hitType)))
460  throw StatusCodeException(STATUS_CODE_FAILURE);
461 
462  ClusterList &clusterList((TPC_VIEW_U == hitType) ? clusterListU : (TPC_VIEW_V == hitType) ? clusterListV : clusterListW);
463  const ClusterNavigationMap &navigationMap((TPC_VIEW_U == hitType) ? m_clusterNavigationMapUV
464  : (TPC_VIEW_V == hitType) ? m_clusterNavigationMapVW
465  : m_clusterNavigationMapWU);
466 
467  if (clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pCluster))
468  return;
469 
470  clusterList.push_back(pCluster);
471 
472  ClusterNavigationMap::const_iterator iter = navigationMap.find(pCluster);
473 
474  if (navigationMap.end() == iter)
475  return;
476 
477  for (ClusterList::const_iterator cIter = iter->second.begin(), cIterEnd = iter->second.end(); cIter != cIterEnd; ++cIter)
478  this->GetConnectedElements(*cIter, ignoreUnavailable, clusterListU, clusterListV, clusterListW);
479 }
480 
481 //------------------------------------------------------------------------------------------------------------------------------------------
482 //------------------------------------------------------------------------------------------------------------------------------------------
483 
484 StatusCode ParticleRecoveryAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
485 {
486  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputClusterListNames", m_inputClusterListNames));
487  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "OutputPfoListName", m_outputPfoListName));
488 
489  PANDORA_RETURN_RESULT_IF_AND_IF(
490  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterCaloHits", m_minClusterCaloHits));
491 
492  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "CheckGaps", m_checkGaps));
493 
494  float minClusterLength = std::sqrt(m_minClusterLengthSquared);
495  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterLength", minClusterLength));
496  m_minClusterLengthSquared = minClusterLength * minClusterLength;
497 
498  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterXSpan", m_minClusterXSpan));
499 
500  PANDORA_RETURN_RESULT_IF_AND_IF(
501  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "VertexClusterMode", m_vertexClusterMode));
502 
503  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
504  XmlHelper::ReadValue(xmlHandle, "MinVertexLongitudinalDistance", m_minVertexLongitudinalDistance));
505 
506  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
507  XmlHelper::ReadValue(xmlHandle, "MaxVertexTransverseDistance", m_maxVertexTransverseDistance));
508 
509  PANDORA_RETURN_RESULT_IF_AND_IF(
510  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinXOverlapFraction", m_minXOverlapFraction));
511 
512  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
513  XmlHelper::ReadValue(xmlHandle, "MinXOverlapFractionGaps", m_minXOverlapFractionGaps));
514 
515  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SampleStepSize", m_sampleStepSize));
516 
517  if (m_sampleStepSize < std::numeric_limits<float>::epsilon())
518  {
519  std::cout << "ParticleRecoveryAlgorithm: Invalid value for SampleStepSize " << m_sampleStepSize << std::endl;
520  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
521  }
522 
523  PANDORA_RETURN_RESULT_IF_AND_IF(
524  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingFitHalfWindow", m_slidingFitHalfWindow));
525 
526  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "PseudoChi2Cut", m_pseudoChi2Cut));
527 
528  return STATUS_CODE_SUCCESS;
529 }
530 
531 } // namespace lar_content
pandora::StringVector m_inputClusterListNames
The list of cluster list names.
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.
unsigned int m_minClusterCaloHits
The min number of hits in base cluster selection method.
void GetInputClusters(pandora::ClusterList &inputClusterListU, pandora::ClusterList &inputClusterListV, pandora::ClusterList &inputClusterListW) const
Get the input cluster lists for processing in this algorithm.
const pandora::ClusterList & GetKeyClusters() const
Get the list of key clusters.
Header file for the lar pointing cluster class.
float m_minClusterLengthSquared
The min length (squared) in base cluster selection method.
void ExamineTensor(const SimpleOverlapTensor &overlapTensor) const
Identify unambiguous cluster overlaps and resolve ambiguous overlaps, creating new track particles...
float m_maxVertexTransverseDistance
Vertex association check: max transverse distance cut.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterNavigationMap
bool CheckConsistency(const pandora::Cluster *const pClusterU, const pandora::Cluster *const pClusterV, const pandora::Cluster *const pClusterW) const
Whether a trio of clusters are consistent with representing projections of the same 3d trajectory...
intermediate_table::const_iterator const_iterator
LArPointingCluster class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static pandora::StatusCode GetAverageZ(const pandora::Cluster *const pCluster, const float xmin, const float xmax, float &averageZ)
Get average Z positions of the calo hits in a cluster in range xmin to xmax.
float m_minXOverlapFractionGaps
The min x overlap fraction when there are gaps involved.
void SelectInputClusters(const pandora::ClusterList &inputClusterList, pandora::ClusterList &selectedClusterList) const
Select a subset of input clusters for processing in this algorithm.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
void CalculateEffectiveSpan(const pandora::Cluster *const pCluster, const float xMin, const float xMax, float &xMinEff, float &xMaxEff) const
Calculate effective span for a given clsuter taking gaps into account.
void CreateTrackParticle(const pandora::ClusterList &clusterList) const
Create and save a track particle containing the provided clusters.
bool IsOverlap(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2) const
Whether two clusters overlap convincingly in x.
void AddAssociation(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2)
Add an association between two clusters to the simple overlap tensor.
Header file for the cluster helper class.
void FindOverlaps(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2, SimpleOverlapTensor &overlapTensor) const
Find cluster overlaps and record these in the overlap tensor.
const Vertex & GetOuterVertex() const
Get the outer vertex.
const Vertex & GetInnerVertex() const
Get the inner vertex.
float m_minVertexLongitudinalDistance
Vertex association check: min longitudinal distance cut.
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 GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
float m_minClusterXSpan
The min x span required in order to consider a cluster.
float m_pseudoChi2Cut
The selection cut on the matched chi2.
void CalculateEffectiveOverlapFractions(const pandora::Cluster *const pCluster1, const float xMin1, const float xMax1, const pandora::Cluster *const pCluster2, const float xMin2, const float xMax2, float &xOverlapFraction1, float &xOverlapFraction2) const
Calculate effective overlap fractions taking into account gaps.
static bool IsXSamplingPointInGap(const pandora::Pandora &pandora, const float xSample, const TwoDSlidingFitResult &slidingFitResult, const float gapTolerance=0.f)
Whether there is a gap in a cluster (described via its sliding fit result) at a specified x sampling ...
unsigned int m_slidingFitHalfWindow
The half window for the fit sliding result constructor.
float m_minXOverlapFraction
The min x overlap fraction required in order to id overlapping clusters.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
bool m_checkGaps
Whether to check for gaps in the calculation of the overlap.
bool m_vertexClusterMode
Whether to demand clusters are associated with vertices of existing particles.
HitType
Definition: HitType.h:12
Header file for the track recovery algorithm class.
std::string m_outputPfoListName
The output pfo list name.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
void StandardClusterSelection(const pandora::ClusterList &inputClusterList, pandora::ClusterList &selectedClusterList) const
Select a subset of input clusters for processing in this algorithm.
float m_sampleStepSize
The sampling step size used in association checks, units cm.
void VertexClusterSelection(const pandora::ClusterList &inputClusterList, pandora::ClusterList &selectedClusterList) const
Select a subset of input clusters nodally associated with the vertices of existing particles...
Float_t w
Definition: plot.C:20
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
static bool IsNode(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxTransverseDistance)
Whether pointing vertex is adjacent to a given position.
void GetConnectedElements(const pandora::Cluster *const pCluster, const bool ignoreUnavailable, pandora::ClusterList &clusterListU, pandora::ClusterList &clusterListV, pandora::ClusterList &clusterListW) const
Get elements connected to a specified cluster.