LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
CandidateVertexCreationAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
13 
15 
16 #include <utility>
17 
18 using namespace pandora;
19 
20 namespace lar_content
21 {
22 
23 CandidateVertexCreationAlgorithm::CandidateVertexCreationAlgorithm() :
24  m_replaceCurrentVertexList(true),
25  m_slidingFitWindow(20),
26  m_minClusterCaloHits(5),
27  m_minClusterLengthSquared(3.f * 3.f),
28  m_chiSquaredCut(2.f),
29  m_enableEndpointCandidates(true),
30  m_maxEndpointXDiscrepancy(4.f),
31  m_enableCrossingCandidates(false),
32  m_nMaxCrossingCandidates(500),
33  m_maxCrossingXDiscrepancy(0.5f),
34  m_extrapolationNSteps(200),
35  m_extrapolationStepSize(0.1f),
36  m_maxCrossingSeparationSquared(2.f * 2.f),
37  m_minNearbyCrossingDistanceSquared(0.5f * 0.5f),
38  m_reducedCandidates(false),
39  m_selectionCutFactorMax(2.f),
40  m_nClustersPassingMaxCutsPar(26.f)
41 {
42 }
43 
44 //------------------------------------------------------------------------------------------------------------------------------------------
45 
47 {
48  try
49  {
50  // INFO: See if there is already a vertex, and quit early if there is.
51  // The vertex has likely already been defined by another algorithm.
52  const VertexList *pVertexList(nullptr);
53  PandoraContentApi::GetCurrentList(*this, pVertexList);
54  if (pVertexList != nullptr && !pVertexList->empty())
55  {
56  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
57  std::cout << "CandidateVertexCreationAlgorithm: Vertex already defined, skipping" << std::endl;
58 
59  return STATUS_CODE_SUCCESS;
60  }
61 
62  ClusterVector clusterVectorU, clusterVectorV, clusterVectorW;
63  this->SelectClusters(clusterVectorU, clusterVectorV, clusterVectorW);
64 
65  std::string temporaryListName;
66  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pVertexList, temporaryListName));
67 
69  {
70  this->CreateEndpointCandidates(clusterVectorU, clusterVectorV);
71  this->CreateEndpointCandidates(clusterVectorU, clusterVectorW);
72  this->CreateEndpointCandidates(clusterVectorV, clusterVectorW);
73  }
74 
76  this->CreateCrossingCandidates(clusterVectorU, clusterVectorV, clusterVectorW);
77 
78  if (!m_inputVertexListName.empty())
79  this->AddInputVertices();
80 
81  if (!pVertexList->empty())
82  {
83  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*this, m_outputVertexListName));
84 
86  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*this, m_outputVertexListName));
87  }
88  }
89  catch (StatusCodeException &statusCodeException)
90  {
91  this->TidyUp();
92  throw statusCodeException;
93  }
94 
95  this->TidyUp();
96 
97  return STATUS_CODE_SUCCESS;
98 }
99 
100 //------------------------------------------------------------------------------------------------------------------------------------------
101 
102 void CandidateVertexCreationAlgorithm::SelectClusters(ClusterVector &clusterVectorU, ClusterVector &clusterVectorV, ClusterVector &clusterVectorW)
103 {
104  for (const std::string &clusterListName : m_inputClusterListNames)
105  {
106  const ClusterList *pClusterList(NULL);
107  PANDORA_THROW_RESULT_IF_AND_IF(
108  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, clusterListName, pClusterList));
109 
110  if (!pClusterList || pClusterList->empty())
111  {
112  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
113  std::cout << "CandidateVertexCreationAlgorithm: unable to find cluster list " << clusterListName << std::endl;
114 
115  continue;
116  }
117 
118  const HitType hitType(LArClusterHelper::GetClusterHitType(*(pClusterList->begin())));
119 
120  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
121  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
122 
123  ClusterVector &selectedClusterVector((TPC_VIEW_U == hitType) ? clusterVectorU
124  : (TPC_VIEW_V == hitType) ? clusterVectorV
125  : clusterVectorW);
126 
127  if (!selectedClusterVector.empty())
128  throw StatusCodeException(STATUS_CODE_FAILURE);
129 
130  ClusterVector sortedClusters(pClusterList->begin(), pClusterList->end());
131  std::sort(sortedClusters.begin(), sortedClusters.end(), LArClusterHelper::SortByNHits);
132 
133  unsigned int nClustersPassingMaxCuts(0);
135  {
136  for (const Cluster *const pCluster : sortedClusters)
137  {
138  float selectionCutFactor(1.f);
139 
140  if (pCluster->GetParticleId() == E_MINUS)
141  selectionCutFactor = m_selectionCutFactorMax;
142 
143  if (pCluster->GetNCaloHits() < m_minClusterCaloHits * selectionCutFactor)
144  continue;
145 
146  if (LArClusterHelper::GetLengthSquared(pCluster) < m_minClusterLengthSquared * selectionCutFactor * selectionCutFactor)
147  continue;
148 
149  nClustersPassingMaxCuts++;
150  }
151  }
152 
153  for (const Cluster *const pCluster : sortedClusters)
154  {
155  float selectionCutFactor(1.f);
156 
157  if (pCluster->GetParticleId() == E_MINUS && m_reducedCandidates)
158  {
159  selectionCutFactor = (m_selectionCutFactorMax + 1.f) * 0.5f +
160  (m_selectionCutFactorMax - 1.f) * 0.5f * std::tanh(static_cast<float>(nClustersPassingMaxCuts) - m_nClustersPassingMaxCutsPar);
161  }
162 
163  if (pCluster->GetNCaloHits() < m_minClusterCaloHits * selectionCutFactor)
164  continue;
165 
166  if (LArClusterHelper::GetLengthSquared(pCluster) < m_minClusterLengthSquared * selectionCutFactor * selectionCutFactor)
167  continue;
168 
169  try
170  {
171  this->AddToSlidingFitCache(pCluster);
172  selectedClusterVector.push_back(pCluster);
173  }
174  catch (StatusCodeException &statusCodeException)
175  {
176  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
177  throw statusCodeException;
178  }
179  }
180  }
181 }
182 
183 //------------------------------------------------------------------------------------------------------------------------------------------
184 
185 void CandidateVertexCreationAlgorithm::CreateEndpointCandidates(const ClusterVector &clusterVector1, const ClusterVector &clusterVector2) const
186 {
187  for (const Cluster *const pCluster1 : clusterVector1)
188  {
189  const HitType hitType1(LArClusterHelper::GetClusterHitType(pCluster1));
190 
191  const TwoDSlidingFitResult &fitResult1(this->GetCachedSlidingFitResult(pCluster1));
192  const CartesianVector minLayerPosition1(fitResult1.GetGlobalMinLayerPosition());
193  const CartesianVector maxLayerPosition1(fitResult1.GetGlobalMaxLayerPosition());
194 
195  for (const Cluster *const pCluster2 : clusterVector2)
196  {
197  const HitType hitType2(LArClusterHelper::GetClusterHitType(pCluster2));
198 
199  const TwoDSlidingFitResult &fitResult2(this->GetCachedSlidingFitResult(pCluster2));
200  const CartesianVector minLayerPosition2(fitResult2.GetGlobalMinLayerPosition());
201  const CartesianVector maxLayerPosition2(fitResult2.GetGlobalMaxLayerPosition());
202 
203  this->CreateEndpointVertex(maxLayerPosition1, hitType1, fitResult2);
204  this->CreateEndpointVertex(minLayerPosition1, hitType1, fitResult2);
205  this->CreateEndpointVertex(maxLayerPosition2, hitType2, fitResult1);
206  this->CreateEndpointVertex(minLayerPosition2, hitType2, fitResult1);
207  }
208  }
209 }
210 
211 //------------------------------------------------------------------------------------------------------------------------------------------
212 
214  const CartesianVector &position1, const HitType hitType1, const TwoDSlidingFitResult &fitResult2) const
215 {
216  const CartesianVector minLayerPosition2(fitResult2.GetGlobalMinLayerPosition());
217  const CartesianVector maxLayerPosition2(fitResult2.GetGlobalMaxLayerPosition());
218 
219  if ((((position1.GetX() < minLayerPosition2.GetX()) && (position1.GetX() < maxLayerPosition2.GetX())) ||
220  ((position1.GetX() > minLayerPosition2.GetX()) && (position1.GetX() > maxLayerPosition2.GetX()))) &&
221  (std::fabs(position1.GetX() - minLayerPosition2.GetX()) > m_maxEndpointXDiscrepancy) &&
222  (std::fabs(position1.GetX() - maxLayerPosition2.GetX()) > m_maxEndpointXDiscrepancy))
223  {
224  return;
225  }
226 
227  CartesianVector position2(0.f, 0.f, 0.f);
228  if (STATUS_CODE_SUCCESS != fitResult2.GetExtrapolatedPositionAtX(position1.GetX(), position2))
229  return;
230 
231  const HitType hitType2(LArClusterHelper::GetClusterHitType(fitResult2.GetCluster()));
232 
233  float chiSquared(0.f);
234  CartesianVector position3D(0.f, 0.f, 0.f);
235  LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), hitType1, hitType2, position1, position2, position3D, chiSquared);
236 
237  if (chiSquared > m_chiSquaredCut)
238  return;
239 
240  PandoraContentApi::Vertex::Parameters parameters;
241  parameters.m_position = position3D;
242  parameters.m_vertexLabel = VERTEX_INTERACTION;
243  parameters.m_vertexType = VERTEX_3D;
244 
245  const Vertex *pVertex(NULL);
246  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*this, parameters, pVertex));
247 }
248 
249 //------------------------------------------------------------------------------------------------------------------------------------------
250 
252  const ClusterVector &clusterVectorU, const ClusterVector &clusterVectorV, const ClusterVector &clusterVectorW) const
253 {
254  CartesianPointVector crossingsU, crossingsV, crossingsW;
255  this->FindCrossingPoints(clusterVectorU, crossingsU);
256  this->FindCrossingPoints(clusterVectorV, crossingsV);
257  this->FindCrossingPoints(clusterVectorW, crossingsW);
258 
259  unsigned int nCrossingCandidates(0);
260  this->CreateCrossingVertices(crossingsU, crossingsV, TPC_VIEW_U, TPC_VIEW_V, nCrossingCandidates);
261  this->CreateCrossingVertices(crossingsU, crossingsW, TPC_VIEW_U, TPC_VIEW_W, nCrossingCandidates);
262  this->CreateCrossingVertices(crossingsV, crossingsW, TPC_VIEW_V, TPC_VIEW_W, nCrossingCandidates);
263 }
264 
265 //------------------------------------------------------------------------------------------------------------------------------------------
266 
267 void CandidateVertexCreationAlgorithm::FindCrossingPoints(const ClusterVector &clusterVector, CartesianPointVector &crossingPoints) const
268 {
269  ClusterToSpacepointsMap clusterToSpacepointsMap;
270 
271  for (const Cluster *const pCluster : clusterVector)
272  {
273  ClusterToSpacepointsMap::iterator mapIter(clusterToSpacepointsMap.emplace(pCluster, CartesianPointVector()).first);
274  this->GetSpacepoints(pCluster, mapIter->second);
275  }
276 
277  for (const Cluster *const pCluster1 : clusterVector)
278  {
279  for (const Cluster *const pCluster2 : clusterVector)
280  {
281  if (pCluster1 == pCluster2)
282  continue;
283 
284  this->FindCrossingPoints(clusterToSpacepointsMap.at(pCluster1), clusterToSpacepointsMap.at(pCluster2), crossingPoints);
285  }
286  }
287 }
288 
289 //------------------------------------------------------------------------------------------------------------------------------------------
290 
291 void CandidateVertexCreationAlgorithm::GetSpacepoints(const Cluster *const pCluster, CartesianPointVector &spacepoints) const
292 {
293  LArClusterHelper::GetCoordinateVector(pCluster, spacepoints);
294 
295  const TwoDSlidingFitResult &fitResult(this->GetCachedSlidingFitResult(pCluster));
296  const float minLayerRL(fitResult.GetL(fitResult.GetMinLayer()));
297  const float maxLayerRL(fitResult.GetL(fitResult.GetMaxLayer()));
298 
299  for (unsigned int iStep = 0; iStep < m_extrapolationNSteps; ++iStep)
300  {
301  const float deltaRL(static_cast<float>(iStep) * m_extrapolationStepSize);
302 
303  CartesianVector positionPositive(0.f, 0.f, 0.f), positionNegative(0.f, 0.f, 0.f);
304  fitResult.GetExtrapolatedPosition(maxLayerRL + deltaRL, positionPositive);
305  fitResult.GetExtrapolatedPosition(minLayerRL - deltaRL, positionNegative);
306 
307  spacepoints.push_back(positionPositive);
308  spacepoints.push_back(positionNegative);
309  }
310 
311  std::sort(spacepoints.begin(), spacepoints.end(), LArClusterHelper::SortCoordinatesByPosition);
312 }
313 
314 //------------------------------------------------------------------------------------------------------------------------------------------
315 
317  const CartesianPointVector &spacepoints1, const CartesianPointVector &spacepoints2, CartesianPointVector &crossingPoints) const
318 {
319  bool bestCrossingFound(false);
320  float bestSeparationSquared(m_maxCrossingSeparationSquared);
321  CartesianVector bestPosition1(0.f, 0.f, 0.f), bestPosition2(0.f, 0.f, 0.f);
322 
323  for (const CartesianVector &position1 : spacepoints1)
324  {
325  for (const CartesianVector &position2 : spacepoints2)
326  {
327  const float separationSquared((position1 - position2).GetMagnitudeSquared());
328 
329  if (separationSquared < bestSeparationSquared)
330  {
331  bestCrossingFound = true;
332  bestSeparationSquared = separationSquared;
333  bestPosition1 = position1;
334  bestPosition2 = position2;
335  }
336  }
337  }
338 
339  if (bestCrossingFound)
340  {
341  bool alreadyPopulated(false);
342 
343  for (const CartesianVector &existingPosition : crossingPoints)
344  {
345  if (((existingPosition - bestPosition1).GetMagnitudeSquared() < m_minNearbyCrossingDistanceSquared) ||
346  ((existingPosition - bestPosition2).GetMagnitudeSquared() < m_minNearbyCrossingDistanceSquared))
347  {
348  alreadyPopulated = true;
349  break;
350  }
351  }
352 
353  if (!alreadyPopulated)
354  {
355  crossingPoints.push_back(bestPosition1);
356  crossingPoints.push_back(bestPosition2);
357  }
358  }
359 }
360 
361 //------------------------------------------------------------------------------------------------------------------------------------------
362 
363 void CandidateVertexCreationAlgorithm::CreateCrossingVertices(const CartesianPointVector &crossingPoints1,
364  const CartesianPointVector &crossingPoints2, const HitType hitType1, const HitType hitType2, unsigned int &nCrossingCandidates) const
365 {
366 
367  for (const CartesianVector &position1 : crossingPoints1)
368  {
369  for (const CartesianVector &position2 : crossingPoints2)
370  {
371  if (nCrossingCandidates > m_nMaxCrossingCandidates)
372  return;
373 
374  if (std::fabs(position1.GetX() - position2.GetX()) > m_maxCrossingXDiscrepancy)
375  continue;
376 
377  float chiSquared(0.f);
378  CartesianVector position3D(0.f, 0.f, 0.f);
379  LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), hitType1, hitType2, position1, position2, position3D, chiSquared);
380 
381  if (chiSquared > m_chiSquaredCut)
382  continue;
383 
384  PandoraContentApi::Vertex::Parameters parameters;
385  parameters.m_position = position3D;
386  parameters.m_vertexLabel = VERTEX_INTERACTION;
387  parameters.m_vertexType = VERTEX_3D;
388 
389  const Vertex *pVertex(NULL);
390  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*this, parameters, pVertex));
391  ++nCrossingCandidates;
392  }
393  }
394 }
395 
396 //------------------------------------------------------------------------------------------------------------------------------------------
397 
399 {
400  const VertexList *pInputVertexList{nullptr};
401  try
402  { // ATTN - No guarantee the list has been initialised, but silent failure here is ok
403  PandoraContentApi::GetList(*this, m_inputVertexListName, pInputVertexList);
404  if (!pInputVertexList)
405  return;
406 
407  for (const Vertex *pInputVertex : *pInputVertexList)
408  {
409  PandoraContentApi::Vertex::Parameters parameters;
410  parameters.m_position = pInputVertex->GetPosition();
411  parameters.m_vertexLabel = VERTEX_INTERACTION;
412  parameters.m_vertexType = VERTEX_3D;
413 
414  const Vertex *pVertex(nullptr);
415  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*this, parameters, pVertex));
416  }
417  }
418  catch (const StatusCodeException &)
419  {
420  return;
421  }
422 }
423 
424 //------------------------------------------------------------------------------------------------------------------------------------------
425 
427 {
428  const float slidingFitPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
429  const TwoDSlidingFitResult slidingFitResult(pCluster, m_slidingFitWindow, slidingFitPitch);
430 
431  if (!m_slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(pCluster, slidingFitResult)).second)
432  throw StatusCodeException(STATUS_CODE_FAILURE);
433 }
434 
435 //------------------------------------------------------------------------------------------------------------------------------------------
436 
438 {
440 
441  if (m_slidingFitResultMap.end() == iter)
442  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
443 
444  return iter->second;
445 }
446 
447 //------------------------------------------------------------------------------------------------------------------------------------------
448 
450 {
451  m_slidingFitResultMap.clear();
452 }
453 
454 //------------------------------------------------------------------------------------------------------------------------------------------
455 
456 StatusCode CandidateVertexCreationAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
457 {
458  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputClusterListNames", m_inputClusterListNames));
459 
460  PANDORA_RETURN_RESULT_IF_AND_IF(
461  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "InputVertexListName", m_inputVertexListName));
462 
463  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "OutputVertexListName", m_outputVertexListName));
464 
465  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
466  XmlHelper::ReadValue(xmlHandle, "ReplaceCurrentVertexList", m_replaceCurrentVertexList));
467 
468  PANDORA_RETURN_RESULT_IF_AND_IF(
469  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingFitWindow", m_slidingFitWindow));
470 
471  PANDORA_RETURN_RESULT_IF_AND_IF(
472  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterCaloHits", m_minClusterCaloHits));
473 
474  float minClusterLength = std::sqrt(m_minClusterLengthSquared);
475  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterLength", minClusterLength));
476  m_minClusterLengthSquared = minClusterLength * minClusterLength;
477 
478  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ChiSquaredCut", m_chiSquaredCut));
479 
480  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
481  XmlHelper::ReadValue(xmlHandle, "EnableEndpointCandidates", m_enableEndpointCandidates));
482 
483  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
484  XmlHelper::ReadValue(xmlHandle, "MaxEndpointXDiscrepancy", m_maxEndpointXDiscrepancy));
485 
486  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
487  XmlHelper::ReadValue(xmlHandle, "EnableCrossingCandidates", m_enableCrossingCandidates));
488 
489  PANDORA_RETURN_RESULT_IF_AND_IF(
490  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NMaxCrossingCandidates", m_nMaxCrossingCandidates));
491 
492  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
493  XmlHelper::ReadValue(xmlHandle, "MaxCrossingXDiscrepancy", m_maxCrossingXDiscrepancy));
494 
495  PANDORA_RETURN_RESULT_IF_AND_IF(
496  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ExtrapolationNSteps", m_extrapolationNSteps));
497 
498  PANDORA_RETURN_RESULT_IF_AND_IF(
499  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ExtrapolationStepSize", m_extrapolationStepSize));
500 
501  PANDORA_RETURN_RESULT_IF_AND_IF(
502  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ReducedCandidates", m_reducedCandidates));
503 
504  PANDORA_RETURN_RESULT_IF_AND_IF(
505  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SelectionCutFactorMax", m_selectionCutFactorMax));
506 
507  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
508  XmlHelper::ReadValue(xmlHandle, "NClustersPassingMaxCutsPar", m_nClustersPassingMaxCutsPar));
509 
510  float maxCrossingSeparation = std::sqrt(m_maxCrossingSeparationSquared);
511  PANDORA_RETURN_RESULT_IF_AND_IF(
512  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxCrossingSeparation", maxCrossingSeparation));
513  m_maxCrossingSeparationSquared = maxCrossingSeparation * maxCrossingSeparation;
514 
515  float minNearbyCrossingDistance = std::sqrt(m_minNearbyCrossingDistanceSquared);
516  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
517  XmlHelper::ReadValue(xmlHandle, "MinNearbyCrossingDistance", minNearbyCrossingDistance));
518  m_minNearbyCrossingDistanceSquared = minNearbyCrossingDistance * minNearbyCrossingDistance;
519 
520  return STATUS_CODE_SUCCESS;
521 }
522 
523 } // namespace lar_content
bool m_reducedCandidates
Whether to reduce the number of candidates.
intermediate_table::iterator iterator
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_minClusterLengthSquared
The min length (squared) in base cluster selection method.
void CreateEndpointVertex(const pandora::CartesianVector &position1, const pandora::HitType hitType1, const TwoDSlidingFitResult &fitResult2) const
Create a candidate vertex position, using an end-point position from one cluster and sliding fit to a...
void CreateCrossingCandidates(const pandora::ClusterVector &clusterVectorU, const pandora::ClusterVector &clusterVectorV, const pandora::ClusterVector &clusterVectorW) const
Extrapolate 2D clusters, find where they cross, and match crossing points between views to create ver...
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.
void GetSpacepoints(const pandora::Cluster *const pCluster, pandora::CartesianPointVector &spacePoints) const
Get a list of spacepoints representing cluster 2D hit positions and extrapolated positions.
float m_extrapolationStepSize
The extrapolation step size in cm.
float m_maxCrossingSeparationSquared
The separation (squared) between spacepoints below which a crossing can be identified.
pandora::StatusCode GetExtrapolatedPositionAtX(const float x, pandora::CartesianVector &position) const
Get extrapolated position (beyond span) for a given input x coordinate.
bool m_enableEndpointCandidates
Whether to create endpoint-based candidates.
void AddToSlidingFitCache(const pandora::Cluster *const pCluster)
Creates a 2D sliding fit of a cluster and stores it for later use.
intermediate_table::const_iterator const_iterator
bool m_replaceCurrentVertexList
Whether to replace the current vertex list with the output list.
float m_maxEndpointXDiscrepancy
The max cluster endpoint discrepancy.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
void FindCrossingPoints(const pandora::ClusterVector &clusterVector, pandora::CartesianPointVector &crossingPoints) const
Identify where (extrapolated) clusters plausibly cross in 2D.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
TFile f
Definition: plotHisto.C:6
static bool SortCoordinatesByPosition(const pandora::CartesianVector &lhs, const pandora::CartesianVector &rhs)
Sort cartesian vectors by their position (use Z, followed by X, followed by Y)
Header file for the geometry helper class.
Header file for the candidate vertex creation algorithm class.
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
std::string m_inputVertexListName
The list name for existing candidate vertices.
Header file for the cluster helper class.
bool m_enableCrossingCandidates
Whether to create crossing vertex candidates.
float m_maxCrossingXDiscrepancy
The max cluster endpoint discrepancy.
TwoDSlidingFitResultMap m_slidingFitResultMap
The sliding fit result map.
void CreateEndpointCandidates(const pandora::ClusterVector &clusterVector1, const pandora::ClusterVector &clusterVector2) const
Create candidate vertex positions by comparing pairs of cluster end positions.
float m_nClustersPassingMaxCutsPar
Parameter for number of clusters passing the max base cluster selection cuts.
pandora::StatusCode GetExtrapolatedPosition(const float rL, pandora::CartesianVector &position) const
Get extrapolated position (beyond span) for a given input coordinate.
float m_minNearbyCrossingDistanceSquared
The minimum allowed distance between identified crossing positions.
unsigned int m_minClusterCaloHits
The min number of hits in base cluster selection method.
void TidyUp()
Clear relevant algorithm member variables between events.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
unsigned int m_extrapolationNSteps
Number of extrapolation steps, at each end of cluster, of specified size.
std::string m_outputVertexListName
The name under which to save the output vertex list.
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
pandora::StringVector m_inputClusterListNames
The list of cluster list names.
unsigned int m_nMaxCrossingCandidates
The max number of crossing candidates to create.
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
std::unordered_map< const pandora::Cluster *, pandora::CartesianPointVector > ClusterToSpacepointsMap
float m_selectionCutFactorMax
Maximum factor to multiply the base cluster selection cuts.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
HitType
Definition: HitType.h:12
void SelectClusters(pandora::ClusterVector &clusterVectorU, pandora::ClusterVector &clusterVectorV, pandora::ClusterVector &clusterVectorW)
Select a subset of input clusters (contained in the input list names) for processing in this algorith...
float m_chiSquaredCut
The chi squared cut (accept only 3D vertex positions with values below cut)
float GetL(const int layer) const
Get longitudinal coordinate for a given sliding linear fit layer number.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
static void GetCoordinateVector(const pandora::Cluster *const pCluster, pandora::CartesianPointVector &coordinateVector)
Get vector of hit coordinates from an input cluster.
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
Definition: ModuleGraph.h:25
std::vector< art::Ptr< recob::Cluster > > ClusterVector
void AddInputVertices() const
Add candidate vertices from any input vertices.
void CreateCrossingVertices(const pandora::CartesianPointVector &crossingPoints1, const pandora::CartesianPointVector &crossingPoints2, const pandora::HitType hitType1, const pandora::HitType hitType2, unsigned int &nCrossingCandidates) const
Attempt to create candidate vertex positions, using 2D crossing points in 2 views.
std::list< Vertex > VertexList
Definition: DCEL.h:169
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
unsigned int m_slidingFitWindow
The layer window for the sliding linear fits.