LArSoft  v07_13_02
Liquid Argon Software toolkit - http://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 : (TPC_VIEW_V == hitType) ? inputClusterListV : inputClusterListW);
89  clusterList.push_back(pCluster);
90  }
91  }
92 }
93 
94 //------------------------------------------------------------------------------------------------------------------------------------------
95 
96 void ParticleRecoveryAlgorithm::SelectInputClusters(const ClusterList &inputClusterList, ClusterList &selectedClusterList) const
97 {
99  {
100  ClusterList vertexClusterList;
101  this->VertexClusterSelection(inputClusterList, vertexClusterList);
102  this->StandardClusterSelection(vertexClusterList, selectedClusterList);
103  }
104  else
105  {
106  this->StandardClusterSelection(inputClusterList, selectedClusterList);
107  }
108 }
109 
110 //------------------------------------------------------------------------------------------------------------------------------------------
111 
112 void ParticleRecoveryAlgorithm::StandardClusterSelection(const ClusterList &inputClusterList, ClusterList &selectedClusterList) const
113 {
114  for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
115  {
116  const Cluster *const pCluster = *iter;
117 
118  if (!pCluster->IsAvailable())
119  continue;
120 
121  if (pCluster->GetNCaloHits() < m_minClusterCaloHits)
122  continue;
123 
125  continue;
126 
127  float xMin(0.f), xMax(0.f);
128  LArClusterHelper::GetClusterSpanX(pCluster, xMin, xMax);
129 
130  if ((xMax - xMin) < m_minClusterXSpan)
131  continue;
132 
133  selectedClusterList.push_back(pCluster);
134  }
135 }
136 
137 //------------------------------------------------------------------------------------------------------------------------------------------
138 
139 void ParticleRecoveryAlgorithm::VertexClusterSelection(const ClusterList &inputClusterList, ClusterList &selectedClusterList) const
140 {
141  CartesianPointVector vertexList;
142 
143  for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
144  {
145  try
146  {
147  if (!(*iter)->IsAvailable())
148  {
149  const LArPointingCluster pointingCluster(*iter);
150  vertexList.push_back(pointingCluster.GetInnerVertex().GetPosition());
151  vertexList.push_back(pointingCluster.GetOuterVertex().GetPosition());
152  }
153  }
154  catch (StatusCodeException &) {}
155  }
156 
157  for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
158  {
159  try
160  {
161  const Cluster *const pCluster = *iter;
162 
163  if (!pCluster->IsAvailable())
164  continue;
165 
166  const LArPointingCluster pointingCluster(pCluster);
167 
168  for (CartesianPointVector::const_iterator vIter = vertexList.begin(), vIterEnd = vertexList.end(); vIter != vIterEnd; ++vIter)
169  {
172  {
173  selectedClusterList.push_back(pCluster);
174  break;
175  }
176  }
177  }
178  catch (StatusCodeException &) {}
179  }
180 }
181 
182 //------------------------------------------------------------------------------------------------------------------------------------------
183 
184 void ParticleRecoveryAlgorithm::FindOverlaps(const ClusterList &clusterList1, const ClusterList &clusterList2, SimpleOverlapTensor &overlapTensor) const
185 {
186  for (ClusterList::const_iterator iter1 = clusterList1.begin(), iter1End = clusterList1.end(); iter1 != iter1End; ++iter1)
187  {
188  for (ClusterList::const_iterator iter2 = clusterList2.begin(), iter2End = clusterList2.end(); iter2 != iter2End; ++iter2)
189  {
190  if (this->IsOverlap(*iter1, *iter2))
191  overlapTensor.AddAssociation(*iter1, *iter2);
192  }
193  }
194 }
195 
196 //------------------------------------------------------------------------------------------------------------------------------------------
197 
198 bool ParticleRecoveryAlgorithm::IsOverlap(const Cluster *const pCluster1, const Cluster *const pCluster2) const
199 {
201  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
202 
203  if ((0 == pCluster1->GetNCaloHits()) || (0 == pCluster2->GetNCaloHits()))
204  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
205 
206  float xMin1(0.f), xMax1(0.f), xMin2(0.f), xMax2(0.f);
207  LArClusterHelper::GetClusterSpanX(pCluster1, xMin1, xMax1);
208  LArClusterHelper::GetClusterSpanX(pCluster2, xMin2, xMax2);
209 
210  const float xSpan1(xMax1 - xMin1), xSpan2(xMax2 - xMin2);
211 
212  if ((xSpan1 < std::numeric_limits<float>::epsilon()) || (xSpan2 < std::numeric_limits<float>::epsilon()))
213  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
214 
215  const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
216 
217  float xOverlapFraction1(xOverlap / xSpan1), xOverlapFraction2(xOverlap / xSpan2);
218 
219  if (m_checkGaps)
220  this->CalculateEffectiveOverlapFractions(pCluster1, xMin1, xMax1, pCluster2, xMin2, xMax2, xOverlapFraction1, xOverlapFraction2);
221 
222  if ((xOverlapFraction1 < m_minXOverlapFraction) || (xOverlapFraction2 < m_minXOverlapFraction))
223  return false;
224 
225  return true;
226 }
227 
228 //------------------------------------------------------------------------------------------------------------------------------------------
229 
230 void ParticleRecoveryAlgorithm::CalculateEffectiveOverlapFractions(const Cluster *const pCluster1, const float xMin1, const float xMax1,
231  const Cluster *const pCluster2, const float xMin2, const float xMax2, float &xOverlapFraction1, float &xOverlapFraction2) const
232 {
233  if (PandoraContentApi::GetGeometry(*this)->GetDetectorGapList().empty())
234  return;
235 
236  const float xMin(std::min(xMin1, xMin2));
237  const float xMax(std::max(xMax1, xMax2));
238  float xMinEff1(xMin1), xMaxEff1(xMax1), xMinEff2(xMin2), xMaxEff2(xMax2);
239 
240  this->CalculateEffectiveSpan(pCluster1, xMin, xMax, xMinEff1, xMaxEff1);
241  this->CalculateEffectiveSpan(pCluster2, xMin, xMax, xMinEff2, xMaxEff2);
242 
243  const float effectiveXSpan1(xMaxEff1 - xMinEff1), effectiveXSpan2(xMaxEff2 - xMinEff2);
244  const float effectiveXOverlapSpan(std::min(xMaxEff1, xMaxEff2) - std::max(xMinEff1, xMinEff2));
245 
246  if ((effectiveXSpan1 > std::numeric_limits<float>::epsilon()) && (effectiveXSpan2 > std::numeric_limits<float>::epsilon()))
247  {
248  xOverlapFraction1 = std::min(1.f, (effectiveXOverlapSpan / effectiveXSpan1));
249  xOverlapFraction2 = std::min(1.f, (effectiveXOverlapSpan / effectiveXSpan2));
250  }
251 }
252 
253 //------------------------------------------------------------------------------------------------------------------------------------------
254 
255 void ParticleRecoveryAlgorithm::CalculateEffectiveSpan(const pandora::Cluster *const pCluster, const float xMin, const float xMax, float &xMinEff, float &xMaxEff) const
256 {
257  // TODO cache sliding linear fit results and optimise protection against exceptions from TwoDSlidingFitResult and IsXSamplingPointInGap
258  try
259  {
260  const float slidingFitPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
261 
262  const TwoDSlidingFitResult slidingFitResult(pCluster, m_slidingFitHalfWindow, slidingFitPitch);
263 
264  const int nSamplingPointsLeft(1 + static_cast<int>((xMinEff - xMin) / m_sampleStepSize));
265  const int nSamplingPointsRight(1 + static_cast<int>((xMax - xMaxEff) / m_sampleStepSize));
266  float dxMin(0.f), dxMax(0.f);
267 
268  for (int iSample = 1; iSample <= nSamplingPointsLeft; ++iSample)
269  {
270  const float xSample(std::max(xMin, xMinEff - static_cast<float>(iSample) * m_sampleStepSize));
271 
272  if (!LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult, m_sampleStepSize))
273  break;
274 
275  dxMin = xMinEff - xSample;
276  }
277 
278  for (int iSample = 1; iSample <= nSamplingPointsRight; ++iSample)
279  {
280  const float xSample(std::min(xMax, xMaxEff + static_cast<float>(iSample) * m_sampleStepSize));
281 
282  if (!LArGeometryHelper::IsXSamplingPointInGap(this->GetPandora(), xSample, slidingFitResult, m_sampleStepSize))
283  break;
284 
285  dxMax = xSample - xMaxEff;
286  }
287 
288  xMinEff = xMinEff - dxMin;
289  xMaxEff = xMaxEff + dxMax;
290  }
291  catch (StatusCodeException &) {}
292 }
293 
294 //------------------------------------------------------------------------------------------------------------------------------------------
295 
297 {
298  ClusterVector sortedKeyClusters(overlapTensor.GetKeyClusters().begin(), overlapTensor.GetKeyClusters().end());
299  std::sort(sortedKeyClusters.begin(), sortedKeyClusters.end(), LArClusterHelper::SortByNHits);
300 
301  for (const Cluster *const pKeyCluster : sortedKeyClusters)
302  {
303  ClusterList clusterListU, clusterListV, clusterListW;
304 
305  overlapTensor.GetConnectedElements(pKeyCluster, true, clusterListU, clusterListV, clusterListW);
306  const unsigned int nU(clusterListU.size()), nV(clusterListV.size()), nW(clusterListW.size());
307 
308  if ((0 == nU * nV) && (0 == nV * nW) && (0 == nW * nU))
309  continue;
310 
311  ClusterList clusterListAll;
312  clusterListAll.insert(clusterListAll.end(), clusterListU.begin(), clusterListU.end());
313  clusterListAll.insert(clusterListAll.end(), clusterListV.begin(), clusterListV.end());
314  clusterListAll.insert(clusterListAll.end(), clusterListW.begin(), clusterListW.end());
315 
316  if ((1 == nU * nV * nW) && this->CheckConsistency(*(clusterListU.begin()), *(clusterListV.begin()), *(clusterListW.begin())))
317  {
318  this->CreateTrackParticle(clusterListAll);
319  }
320  else if ((0 == nU * nV * nW) && ((1 == nU && 1 == nV) || (1 == nV && 1 == nW) || (1 == nW && 1 == nU)))
321  {
322  this->CreateTrackParticle(clusterListAll);
323  }
324  else
325  {
326  // TODO - check here whether there is a gap in the 2 in one view when 1:2:0
327  // May later choose to resolve simple ambiguities, e.g. of form nU:nV:nW == 1:2:0
328  }
329  }
330 }
331 
332 //------------------------------------------------------------------------------------------------------------------------------------------
333 
334 bool ParticleRecoveryAlgorithm::CheckConsistency(const Cluster *const pClusterU, const Cluster *const pClusterV, const Cluster *const pClusterW) const
335 {
336  // Requirements on X matching
337  float xMinU(0.f), xMinV(0.f), xMinW(0.f), xMaxU(0.f), xMaxV(0.f), xMaxW(0.f);
338  LArClusterHelper::GetClusterSpanX(pClusterU, xMinU, xMaxU);
339  LArClusterHelper::GetClusterSpanX(pClusterV, xMinV, xMaxV);
340  LArClusterHelper::GetClusterSpanX(pClusterW, xMinW, xMaxW);
341 
342  const float xMin(std::max(xMinU, std::max(xMinV, xMinW)));
343  const float xMax(std::min(xMaxU, std::min(xMaxV, xMaxW)));
344  const float xOverlap(xMax - xMin);
345 
346  if (xOverlap < std::numeric_limits<float>::epsilon())
347  return false;
348 
349  // Requirements on 3D matching
351 
352  if ((STATUS_CODE_SUCCESS != LArClusterHelper::GetAverageZ(pClusterU, xMin, xMax, u)) ||
353  (STATUS_CODE_SUCCESS != LArClusterHelper::GetAverageZ(pClusterV, xMin, xMax, v)) ||
354  (STATUS_CODE_SUCCESS != LArClusterHelper::GetAverageZ(pClusterW, xMin, xMax, w)))
355  {
356  return false;
357  }
358 
359  const float uv2w(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), TPC_VIEW_U, TPC_VIEW_V, u, v));
360  const float vw2u(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), TPC_VIEW_V, TPC_VIEW_W, v, w));
361  const float wu2v(LArGeometryHelper::MergeTwoPositions(this->GetPandora(), TPC_VIEW_W, TPC_VIEW_U, w, u));
362 
363  const float pseudoChi2(((u - vw2u) * (u - vw2u) + (v - wu2v) * (v - wu2v) + (w - uv2w) * (w - uv2w)) / 3.f);
364 
365  if (pseudoChi2 > m_pseudoChi2Cut)
366  return false;
367 
368  return true;
369 }
370 
371 //------------------------------------------------------------------------------------------------------------------------------------------
372 
373 void ParticleRecoveryAlgorithm::CreateTrackParticle(const ClusterList &clusterList) const
374 {
375  if (clusterList.size() < 2)
376  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
377 
378  const PfoList *pPfoList = NULL; std::string pfoListName;
379  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pPfoList, pfoListName));
380 
381  // TODO Correct these placeholder parameters
382  PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
383  pfoParameters.m_particleId = MU_MINUS;
384  pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
385  pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
386  pfoParameters.m_energy = 0.f;
387  pfoParameters.m_momentum = CartesianVector(0.f, 0.f, 0.f);
388  pfoParameters.m_clusterList = clusterList;
389 
390  const ParticleFlowObject *pPfo(NULL);
391  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*this, pfoParameters, pPfo));
392 
393  if (!pPfoList->empty())
394  {
395  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*this, m_outputPfoListName));
396  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Pfo>(*this, m_outputPfoListName));
397  }
398 }
399 
400 //------------------------------------------------------------------------------------------------------------------------------------------
401 //------------------------------------------------------------------------------------------------------------------------------------------
402 
403 void ParticleRecoveryAlgorithm::SimpleOverlapTensor::AddAssociation(const Cluster *const pCluster1, const Cluster *const pCluster2)
404 {
405  const HitType hitType1(LArClusterHelper::GetClusterHitType(pCluster1));
406  const HitType hitType2(LArClusterHelper::GetClusterHitType(pCluster2));
407 
408  const Cluster *const pClusterU((TPC_VIEW_U == hitType1) ? pCluster1 : (TPC_VIEW_U == hitType2) ? pCluster2 : NULL);
409  const Cluster *const pClusterV((TPC_VIEW_V == hitType1) ? pCluster1 : (TPC_VIEW_V == hitType2) ? pCluster2 : NULL);
410  const Cluster *const pClusterW((TPC_VIEW_W == hitType1) ? pCluster1 : (TPC_VIEW_W == hitType2) ? pCluster2 : NULL);
411 
412  if (pClusterU && pClusterV && !pClusterW)
413  {
414  m_clusterNavigationMapUV[pClusterU].push_back(pClusterV);
415 
416  if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterU))
417  m_keyClusters.push_back(pClusterU);
418  }
419  else if (!pClusterU && pClusterV && pClusterW)
420  {
421  m_clusterNavigationMapVW[pClusterV].push_back(pClusterW);
422 
423  if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterV))
424  m_keyClusters.push_back(pClusterV);
425  }
426  else if (pClusterU && !pClusterV && pClusterW)
427  {
428  m_clusterNavigationMapWU[pClusterW].push_back(pClusterU);
429 
430  if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterW))
431  m_keyClusters.push_back(pClusterW);
432  }
433  else
434  {
435  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
436  }
437 }
438 
439 //------------------------------------------------------------------------------------------------------------------------------------------
440 
441 void ParticleRecoveryAlgorithm::SimpleOverlapTensor::GetConnectedElements(const Cluster *const pCluster, const bool ignoreUnavailable,
442  ClusterList &clusterListU, ClusterList &clusterListV, ClusterList &clusterListW) const
443 {
444  if (ignoreUnavailable && !pCluster->IsAvailable())
445  return;
446 
447  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
448 
449  if (!((TPC_VIEW_U == hitType) || (TPC_VIEW_V == hitType) || (TPC_VIEW_W == hitType)))
450  throw StatusCodeException(STATUS_CODE_FAILURE);
451 
452  ClusterList &clusterList((TPC_VIEW_U == hitType) ? clusterListU : (TPC_VIEW_V == hitType) ? clusterListV : clusterListW);
453  const ClusterNavigationMap &navigationMap((TPC_VIEW_U == hitType) ? m_clusterNavigationMapUV : (TPC_VIEW_V == hitType) ? m_clusterNavigationMapVW : m_clusterNavigationMapWU);
454 
455  if (clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pCluster))
456  return;
457 
458  clusterList.push_back(pCluster);
459 
460  ClusterNavigationMap::const_iterator iter = navigationMap.find(pCluster);
461 
462  if (navigationMap.end() == iter)
463  return;
464 
465  for (ClusterList::const_iterator cIter = iter->second.begin(), cIterEnd = iter->second.end(); cIter != cIterEnd; ++cIter)
466  this->GetConnectedElements(*cIter, ignoreUnavailable, clusterListU, clusterListV, clusterListW);
467 }
468 
469 //------------------------------------------------------------------------------------------------------------------------------------------
470 //------------------------------------------------------------------------------------------------------------------------------------------
471 
472 StatusCode ParticleRecoveryAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
473 {
474  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputClusterListNames", m_inputClusterListNames));
475  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "OutputPfoListName", m_outputPfoListName));
476 
477  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
478  "MinClusterCaloHits", m_minClusterCaloHits));
479 
480  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
481  "CheckGaps", m_checkGaps));
482 
483  float minClusterLength = std::sqrt(m_minClusterLengthSquared);
484  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
485  "MinClusterLength", minClusterLength));
486  m_minClusterLengthSquared = minClusterLength * minClusterLength;
487 
488  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
489  "MinClusterXSpan", m_minClusterXSpan));
490 
491  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
492  "VertexClusterMode", m_vertexClusterMode));
493 
494  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
495  "MinVertexLongitudinalDistance", m_minVertexLongitudinalDistance));
496 
497  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
498  "MaxVertexTransverseDistance", m_maxVertexTransverseDistance));
499 
500  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
501  "MinXOverlapFraction", m_minXOverlapFraction));
502 
503  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
504  "MinXOverlapFractionGaps", m_minXOverlapFractionGaps));
505 
506  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
507  "SampleStepSize", m_sampleStepSize));
508 
509  if (m_sampleStepSize < std::numeric_limits<float>::epsilon())
510  {
511  std::cout << "ParticleRecoveryAlgorithm: Invalid value for SampleStepSize " << m_sampleStepSize << std::endl;
512  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
513  }
514 
515  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
516  "SlidingFitHalfWindow", m_slidingFitHalfWindow));
517 
518  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
519  "PseudoChi2Cut", m_pseudoChi2Cut));
520 
521  return STATUS_CODE_SUCCESS;
522 }
523 
524 } // 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.
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...
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.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
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.
Int_t max
Definition: plot.C:27
void CreateTrackParticle(const pandora::ClusterList &clusterList) const
Create and save a track particle containing the provided clusters.
intermediate_table::const_iterator const_iterator
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).
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 ...
std::vector< art::Ptr< recob::Cluster > > ClusterVector
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.
Int_t min
Definition: plot.C:26
Header file for the track recovery algorithm class.
std::string m_outputPfoListName
The output pfo list name.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterNavigationMap
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.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
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:23
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.