StitchingCosmicRayMergingTool.cc
Go to the documentation of this file.
1 /**
2  * @file LArContent/src/LArControlFlow/StitchingCosmicRayMergingTool.cc
3  *
4  * @brief Implementation of the stitching cosmic ray merging tool class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
15 
17 
19 
20 using namespace pandora;
21 
22 namespace lar_content
23 {
24 
25 StitchingCosmicRayMergingTool::StitchingCosmicRayMergingTool() :
26  m_useXcoordinate(false),
27  m_alwaysApplyT0Calculation(true),
28  m_halfWindowLayers(30),
29  m_minLengthSquared(50.f),
30  m_minCosRelativeAngle(0.966),
31  m_relaxMinLongitudinalDisplacement(-5.f),
32  m_maxLongitudinalDisplacementX(15.f),
33  m_maxTransverseDisplacement(5.f),
34  m_relaxCosRelativeAngle(0.906),
35  m_relaxTransverseDisplacement(2.5f),
36  m_minNCaloHits3D(0),
37  m_maxX0FractionalDeviation(0.3f),
38  m_boundaryToleranceWidth(10.f)
39 {
40 }
41 
42 void StitchingCosmicRayMergingTool::Run(const MasterAlgorithm *const pAlgorithm, const PfoList *const pMultiPfoList,
43  PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map)
44 {
45  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
46  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
47 
48  if (this->GetPandora().GetGeometry()->GetLArTPCMap().size() < 2)
49  return;
50 
51  if (pfoToLArTPCMap.empty())
52  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
53 
54  PfoList primaryPfos;
55  this->SelectPrimaryPfos(pMultiPfoList, pfoToLArTPCMap, primaryPfos);
56 
57  ThreeDPointingClusterMap pointingClusterMap;
58  this->BuildPointingClusterMaps(primaryPfos, pfoToLArTPCMap, pointingClusterMap);
59 
60  LArTPCToPfoMap larTPCToPfoMap;
61  this->BuildTPCMaps(primaryPfos, pfoToLArTPCMap, larTPCToPfoMap);
62 
63  PfoAssociationMatrix pfoAssociationMatrix;
64  this->CreatePfoMatches(larTPCToPfoMap, pointingClusterMap, pfoAssociationMatrix);
65 
66  PfoMergeMap pfoSelectedMatches;
67  this->SelectPfoMatches(pfoAssociationMatrix, pfoSelectedMatches);
68 
69  PfoMergeMap pfoSelectedMerges;
70  this->SelectPfoMerges(pfoSelectedMatches, pfoSelectedMerges);
71 
72  PfoMergeMap pfoOrderedMerges;
73  this->OrderPfoMerges(pfoToLArTPCMap, pointingClusterMap, pfoSelectedMerges, pfoOrderedMerges);
74 
75  this->StitchPfos(pAlgorithm, pointingClusterMap, pfoOrderedMerges, pfoToLArTPCMap, stitchedPfosToX0Map);
76 }
77 
78 //------------------------------------------------------------------------------------------------------------------------------------------
79 
80 void StitchingCosmicRayMergingTool::SelectPrimaryPfos(const PfoList *pInputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, PfoList &outputPfoList) const
81 {
82  for (const ParticleFlowObject *const pPfo : *pInputPfoList)
83  {
85  continue;
86 
87  if (!pfoToLArTPCMap.count(pPfo))
88  continue;
89 
90  outputPfoList.push_back(pPfo);
91  }
92 
93  outputPfoList.sort(LArPfoHelper::SortByNHits);
94 }
95 
96 //------------------------------------------------------------------------------------------------------------------------------------------
97 
99  const PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, ThreeDPointingClusterMap &pointingClusterMap) const
100 {
101  for (const ParticleFlowObject *const pPfo : inputPfoList)
102  {
103  try
104  {
105  PfoToLArTPCMap::const_iterator tpcIter(pfoToLArTPCMap.find(pPfo));
106 
107  if (pfoToLArTPCMap.end() == tpcIter)
108  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
109 
110  const float slidingFitPitch(tpcIter->second->GetWirePitchW());
111 
112  ClusterList clusterList;
113  LArPfoHelper::GetThreeDClusterList(pPfo, clusterList);
114 
115  if (1 != clusterList.size())
116  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
117 
118  const ThreeDSlidingFitResult slidingFitResult(clusterList.front(), m_halfWindowLayers, slidingFitPitch);
119  (void)pointingClusterMap.insert(ThreeDPointingClusterMap::value_type(pPfo, LArPointingCluster(slidingFitResult)));
120  }
121  catch (const StatusCodeException &)
122  {
123  }
124  }
125 }
126 
127 //------------------------------------------------------------------------------------------------------------------------------------------
128 
129 void StitchingCosmicRayMergingTool::BuildTPCMaps(const PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, LArTPCToPfoMap &larTPCToPfoMap) const
130 {
131  for (const ParticleFlowObject *const pPfo : inputPfoList)
132  {
133  PfoToLArTPCMap::const_iterator iter(pfoToLArTPCMap.find(pPfo));
134 
135  if (pfoToLArTPCMap.end() != iter)
136  larTPCToPfoMap[iter->second].push_back(pPfo);
137  }
138 }
139 
140 //------------------------------------------------------------------------------------------------------------------------------------------
141 
143  const ThreeDPointingClusterMap &pointingClusterMap, PfoAssociationMatrix &pfoAssociationMatrix) const
144 {
145  LArTPCVector larTPCVector;
146  for (const auto &mapEntry : larTPCToPfoMap)
147  larTPCVector.push_back(mapEntry.first);
148  std::sort(larTPCVector.begin(), larTPCVector.end(), LArStitchingHelper::SortTPCs);
149 
150  for (LArTPCVector::const_iterator tpcIter1 = larTPCVector.begin(), tpcIterEnd = larTPCVector.end(); tpcIter1 != tpcIterEnd; ++tpcIter1)
151  {
152  const LArTPC *const pLArTPC1(*tpcIter1);
153  const PfoList &pfoList1(larTPCToPfoMap.at(pLArTPC1));
154 
155  for (LArTPCVector::const_iterator tpcIter2 = tpcIter1; tpcIter2 != tpcIterEnd; ++tpcIter2)
156  {
157  const LArTPC *const pLArTPC2(*tpcIter2);
158  const PfoList &pfoList2(larTPCToPfoMap.at(pLArTPC2));
159 
160  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPC1, *pLArTPC2))
161  continue;
162 
163  for (const ParticleFlowObject *const pPfo1 : pfoList1)
164  {
165  for (const ParticleFlowObject *const pPfo2 : pfoList2)
166  this->CreatePfoMatches(*pLArTPC1, *pLArTPC2, pPfo1, pPfo2, pointingClusterMap, pfoAssociationMatrix);
167  }
168  }
169  }
170 }
171 
172 //------------------------------------------------------------------------------------------------------------------------------------------
173 
174 void StitchingCosmicRayMergingTool::CreatePfoMatches(const LArTPC &larTPC1, const LArTPC &larTPC2, const ParticleFlowObject *const pPfo1,
175  const ParticleFlowObject *const pPfo2, const ThreeDPointingClusterMap &pointingClusterMap, PfoAssociationMatrix &pfoAssociationMatrix) const
176 {
177  // Get centre and width of boundary between tpcs
178  const float boundaryCenterX(LArStitchingHelper::GetTPCBoundaryCenterX(larTPC1, larTPC2));
179  const float boundaryWidthX(LArStitchingHelper::GetTPCBoundaryWidthX(larTPC1, larTPC2));
180  const float maxLongitudinalDisplacementX(m_maxLongitudinalDisplacementX + boundaryWidthX);
181 
182  // Get the pointing cluster corresponding to each of these Pfos
183  ThreeDPointingClusterMap::const_iterator iter1 = pointingClusterMap.find(pPfo1);
184  ThreeDPointingClusterMap::const_iterator iter2 = pointingClusterMap.find(pPfo2);
185 
186  if (pointingClusterMap.end() == iter1 || pointingClusterMap.end() == iter2)
187  return;
188 
189  const LArPointingCluster &pointingCluster1(iter1->second);
190  const LArPointingCluster &pointingCluster2(iter2->second);
191 
192  // Check length of pointing clusters
193  if (pointingCluster1.GetLengthSquared() < m_minLengthSquared || pointingCluster2.GetLengthSquared() < m_minLengthSquared)
194  return;
195 
196  // Get number of 3D hits in each of the pfos
197  CaloHitList caloHitList3D1;
198  LArPfoHelper::GetCaloHits(pPfo1, TPC_3D, caloHitList3D1);
199 
200  CaloHitList caloHitList3D2;
201  LArPfoHelper::GetCaloHits(pPfo2, TPC_3D, caloHitList3D2);
202 
203  // Check number of 3D hits in each of the pfos
204  if (caloHitList3D1.size() < m_minNCaloHits3D || caloHitList3D2.size() < m_minNCaloHits3D)
205  return;
206 
207  // Get closest pair of vertices
208  LArPointingCluster::Vertex pointingVertex1, pointingVertex2;
209 
210  try
211  {
212  LArStitchingHelper::GetClosestVertices(larTPC1, larTPC2, pointingCluster1, pointingCluster2, pointingVertex1, pointingVertex2);
213  }
214  catch (const pandora::StatusCodeException &)
215  {
216  return;
217  }
218 
219  // Pointing clusters must have a parallel direction
220  const float cosRelativeAngle(-pointingVertex1.GetDirection().GetDotProduct(pointingVertex2.GetDirection()));
221 
222  if (cosRelativeAngle < m_relaxCosRelativeAngle)
223  return;
224 
225  // Pointing clusters must have a non-zero X direction (so that they point across drift volume boundary)
226  const float pX1(std::fabs(pointingVertex1.GetDirection().GetX()));
227  const float pX2(std::fabs(pointingVertex2.GetDirection().GetX()));
228 
229  if (pX1 < std::numeric_limits<float>::epsilon() || pX2 < std::numeric_limits<float>::epsilon())
230  return;
231 
232  // Pointing clusters must intersect at a drift volume boundary
233  const float intersectX(0.5 * (pointingVertex1.GetPosition().GetX() + pointingVertex2.GetPosition().GetX()));
234 
235  if (std::fabs(intersectX - boundaryCenterX) > maxLongitudinalDisplacementX)
236  return;
237 
238  // Impact parameters
239  float rT1(0.f), rL1(0.f), rT2(0.f), rL2(0.f);
240 
241  try
242  {
243  if (m_useXcoordinate)
244  {
245  LArPointingClusterHelper::GetImpactParameters(pointingVertex1, pointingVertex2, rL1, rT1);
246  LArPointingClusterHelper::GetImpactParameters(pointingVertex2, pointingVertex1, rL2, rT2);
247  }
248  else
249  {
250  LArPointingClusterHelper::GetImpactParametersInYZ(pointingVertex1, pointingVertex2, rL1, rT1);
251  LArPointingClusterHelper::GetImpactParametersInYZ(pointingVertex2, pointingVertex1, rL2, rT2);
252  }
253  }
254  catch (const pandora::StatusCodeException &)
255  {
256  return;
257  }
258 
259  const float minL((!LArGeometryHelper::IsInGap(this->GetPandora(), pointingVertex1.GetPosition(), TPC_3D) ||
260  !LArGeometryHelper::IsInGap(this->GetPandora(), pointingVertex2.GetPosition(), TPC_3D))
261  ? -1.f
263  const float dXdL1(m_useXcoordinate ? pX1 : (1.f - pX1 * pX1 > std::numeric_limits<float>::epsilon()) ? pX1 / std::sqrt(1.f - pX1 * pX1) : minL);
264  const float dXdL2(m_useXcoordinate ? pX2 : (1.f - pX2 * pX2 > std::numeric_limits<float>::epsilon()) ? pX2 / std::sqrt(1.f - pX2 * pX2) : minL);
265  const float maxL1(maxLongitudinalDisplacementX / dXdL1);
266  const float maxL2(maxLongitudinalDisplacementX / dXdL2);
267 
268  if (rL1 < minL || rL1 > maxL1 || rL2 < minL || rL2 > maxL2)
269  return;
270 
271  // Selection cuts on transverse impact parameters
272  const bool minPass(std::min(rT1, rT2) < m_relaxTransverseDisplacement && cosRelativeAngle > m_relaxCosRelativeAngle);
273  const bool maxPass(std::max(rT1, rT2) < m_maxTransverseDisplacement && cosRelativeAngle > m_minCosRelativeAngle);
274 
275  if (!minPass && !maxPass)
276  return;
277 
278  // Store this association
281 
282  const float particleLength1(pointingCluster1.GetLengthSquared());
283  const float particleLength2(pointingCluster2.GetLengthSquared());
284 
285  pfoAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pPfo2, PfoAssociation(vertexType1, vertexType2, particleLength2)));
286  pfoAssociationMatrix[pPfo2].insert(PfoAssociationMap::value_type(pPfo1, PfoAssociation(vertexType2, vertexType1, particleLength1)));
287 }
288 
289 //------------------------------------------------------------------------------------------------------------------------------------------
290 
291 void StitchingCosmicRayMergingTool::SelectPfoMatches(const PfoAssociationMatrix &pfoAssociationMatrix, PfoMergeMap &pfoMatches) const
292 {
293  // First step: loop over association matrix and find best associations A -> X and B -> Y
294  // =====================================================================================
295  PfoAssociationMatrix bestAssociationMatrix;
296 
297  PfoVector pfoVector1;
298  for (const auto &mapEntry : pfoAssociationMatrix)
299  pfoVector1.push_back(mapEntry.first);
300  std::sort(pfoVector1.begin(), pfoVector1.end(), LArPfoHelper::SortByNHits);
301 
302  for (const ParticleFlowObject *const pPfo1 : pfoVector1)
303  {
304  const PfoAssociationMap &pfoAssociationMap(pfoAssociationMatrix.at(pPfo1));
305 
306  const ParticleFlowObject *pBestPfoInner(nullptr);
308 
309  const ParticleFlowObject *pBestPfoOuter(nullptr);
311 
312  PfoVector pfoVector2;
313  for (const auto &mapEntry : pfoAssociationMap)
314  pfoVector2.push_back(mapEntry.first);
315  std::sort(pfoVector2.begin(), pfoVector2.end(), LArPfoHelper::SortByNHits);
316 
317  for (const ParticleFlowObject *const pPfo2 : pfoVector2)
318  {
319  const PfoAssociation &pfoAssociation(pfoAssociationMap.at(pPfo2));
320 
321  // Inner associations
322  if (pfoAssociation.GetParent() == PfoAssociation::INNER)
323  {
324  if (pfoAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
325  {
326  bestAssociationInner = pfoAssociation;
327  pBestPfoInner = pPfo2;
328  }
329  }
330 
331  // Outer associations
332  if (pfoAssociation.GetParent() == PfoAssociation::OUTER)
333  {
334  if (pfoAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
335  {
336  bestAssociationOuter = pfoAssociation;
337  pBestPfoOuter = pPfo2;
338  }
339  }
340  }
341 
342  if (pBestPfoInner)
343  (void)bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoInner, bestAssociationInner));
344 
345  if (pBestPfoOuter)
346  (void)bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoOuter, bestAssociationOuter));
347  }
348 
349  // Second step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
350  // =============================================================================
351  PfoVector pfoVector3;
352  for (const auto &mapEntry : bestAssociationMatrix)
353  pfoVector3.push_back(mapEntry.first);
354  std::sort(pfoVector3.begin(), pfoVector3.end(), LArPfoHelper::SortByNHits);
355 
356  for (const ParticleFlowObject *const pParentPfo : pfoVector3)
357  {
358  const PfoAssociationMap &parentAssociationMap(bestAssociationMatrix.at(pParentPfo));
359 
360  PfoVector pfoVector4;
361  for (const auto &mapEntry : parentAssociationMap)
362  pfoVector4.push_back(mapEntry.first);
363  std::sort(pfoVector4.begin(), pfoVector4.end(), LArPfoHelper::SortByNHits);
364 
365  for (const ParticleFlowObject *const pDaughterPfo : pfoVector4)
366  {
367  const PfoAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterPfo));
368  PfoAssociationMatrix::const_iterator iter5 = bestAssociationMatrix.find(pDaughterPfo);
369 
370  if (bestAssociationMatrix.end() == iter5)
371  continue;
372 
373  const PfoAssociationMap &daughterAssociationMap(iter5->second);
374 
375  PfoAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentPfo);
376  if (daughterAssociationMap.end() == iter6)
377  continue;
378 
379  const PfoAssociation &daughterToParentAssociation(iter6->second);
380 
381  if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
382  parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
383  {
384  pfoMatches[pParentPfo].push_back(pDaughterPfo);
385  }
386  }
387  }
388 }
389 
390 //------------------------------------------------------------------------------------------------------------------------------------------
391 
393 {
394  PfoSet vetoSet;
395 
396  PfoVector inputPfoVector;
397  for (const auto &mapEntry : pfoMatches)
398  inputPfoVector.push_back(mapEntry.first);
399  std::sort(inputPfoVector.begin(), inputPfoVector.end(), LArPfoHelper::SortByNHits);
400 
401  for (const ParticleFlowObject *const pInputPfo : inputPfoVector)
402  {
403  const PfoList &pfoList(pfoMatches.at(pInputPfo));
404 
405  for (const ParticleFlowObject *const pSeedPfo : pfoList)
406  {
407  if (vetoSet.count(pSeedPfo))
408  continue;
409 
410  PfoList mergeList;
411  this->CollectAssociatedPfos(pSeedPfo, pSeedPfo, pfoMatches, vetoSet, mergeList);
412 
413  vetoSet.insert(pSeedPfo);
414  PfoList &selectedPfoList(pfoMerges[pSeedPfo]);
415  selectedPfoList.push_back(pSeedPfo);
416 
417  for (const ParticleFlowObject *const pAssociatedPfo : mergeList)
418  {
419  // Check if particle has already been counted
420  if (vetoSet.count(pAssociatedPfo) || (selectedPfoList.end() != std::find(selectedPfoList.begin(), selectedPfoList.end(), pAssociatedPfo)))
421  throw StatusCodeException(STATUS_CODE_FAILURE);
422 
423  vetoSet.insert(pAssociatedPfo);
424  selectedPfoList.push_back(pAssociatedPfo);
425  }
426  }
427  }
428 }
429 
430 //------------------------------------------------------------------------------------------------------------------------------------------
431 
432 void StitchingCosmicRayMergingTool::CollectAssociatedPfos(const ParticleFlowObject *const pSeedPfo,
433  const ParticleFlowObject *const pCurrentPfo, const PfoMergeMap &pfoMergeMap, const PfoSet &vetoSet, PfoList &associatedList) const
434 {
435  if (vetoSet.count(pCurrentPfo))
436  return;
437 
438  PfoMergeMap::const_iterator iter1 = pfoMergeMap.find(pCurrentPfo);
439 
440  if (pfoMergeMap.end() == iter1)
441  return;
442 
443  for (PfoList::const_iterator iter2 = iter1->second.begin(), iterEnd2 = iter1->second.end(); iter2 != iterEnd2; ++iter2)
444  {
445  const ParticleFlowObject *const pAssociatedPfo = *iter2;
446 
447  if (pAssociatedPfo == pSeedPfo)
448  continue;
449 
450  if (associatedList.end() != std::find(associatedList.begin(), associatedList.end(), pAssociatedPfo))
451  continue;
452 
453  associatedList.push_back(pAssociatedPfo);
454 
455  this->CollectAssociatedPfos(pSeedPfo, pAssociatedPfo, pfoMergeMap, vetoSet, associatedList);
456  }
457 }
458 
459 //------------------------------------------------------------------------------------------------------------------------------------------
460 
461 void StitchingCosmicRayMergingTool::OrderPfoMerges(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap,
462  const PfoMergeMap &inputPfoMerges, PfoMergeMap &outputPfoMerges) const
463 {
464  PfoVector inputPfoVector;
465  for (const auto &mapEntry : inputPfoMerges)
466  inputPfoVector.push_back(mapEntry.first);
467  std::sort(inputPfoVector.begin(), inputPfoVector.end(), LArPfoHelper::SortByNHits);
468 
469  for (const ParticleFlowObject *const pInputPfo : inputPfoVector)
470  {
471  const PfoList &pfoList(inputPfoMerges.at(pInputPfo));
472 
473  float bestLength(0.f);
474  const ParticleFlowObject *pVertexPfo = nullptr;
475 
476  for (PfoList::const_iterator iter1 = pfoList.begin(), iterEnd = pfoList.end(); iter1 != iterEnd; ++iter1)
477  {
478  const ParticleFlowObject *const pPfo1(*iter1);
479  PfoToLArTPCMap::const_iterator tpcIter1 = pfoToLArTPCMap.find(pPfo1);
480  ThreeDPointingClusterMap::const_iterator pointingIter1 = pointingClusterMap.find(pPfo1);
481 
482  if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
483  throw StatusCodeException(STATUS_CODE_FAILURE);
484 
485  const LArTPC *const pLArTPC1(tpcIter1->second);
486  const LArPointingCluster &pointingCluster1(pointingIter1->second);
487 
488  for (PfoList::const_iterator iter2 = iter1; iter2 != iterEnd; ++iter2)
489  {
490  const ParticleFlowObject *const pPfo2(*iter2);
491  PfoToLArTPCMap::const_iterator tpcIter2 = pfoToLArTPCMap.find(pPfo2);
492  ThreeDPointingClusterMap::const_iterator pointingIter2 = pointingClusterMap.find(pPfo2);
493 
494  if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
495  throw StatusCodeException(STATUS_CODE_FAILURE);
496 
497  const LArTPC *const pLArTPC2(tpcIter2->second);
498  const LArPointingCluster &pointingCluster2(pointingIter2->second);
499 
500  if (pLArTPC1 == pLArTPC2)
501  continue;
502 
503  const float thisLength(LArStitchingHelper::GetTPCDisplacement(*pLArTPC1, *pLArTPC2));
504 
505  if (thisLength < bestLength)
506  continue;
507 
508  bestLength = thisLength;
509 
510  try
511  {
512  pVertexPfo = nullptr;
513 
514  LArPointingCluster::Vertex nearVertex1, nearVertex2;
515  LArStitchingHelper::GetClosestVertices(*pLArTPC1, *pLArTPC2, pointingCluster1, pointingCluster2, nearVertex1, nearVertex2);
516 
517  const LArPointingCluster::Vertex &farVertex1(
518  nearVertex1.IsInnerVertex() ? pointingCluster1.GetOuterVertex() : pointingCluster1.GetInnerVertex());
519  const LArPointingCluster::Vertex &farVertex2(
520  nearVertex2.IsInnerVertex() ? pointingCluster2.GetOuterVertex() : pointingCluster2.GetInnerVertex());
521  const float deltaY(farVertex1.GetPosition().GetY() - farVertex2.GetPosition().GetY());
522 
523  if (std::fabs(deltaY) < std::numeric_limits<float>::epsilon())
524  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
525 
526  pVertexPfo = ((deltaY > 0.f) ? pPfo1 : pPfo2);
527  }
528  catch (const pandora::StatusCodeException &)
529  {
530  }
531  }
532  }
533 
534  if (pVertexPfo)
535  outputPfoMerges[pVertexPfo].insert(outputPfoMerges[pVertexPfo].begin(), pfoList.begin(), pfoList.end());
536  }
537 }
538 
539 //------------------------------------------------------------------------------------------------------------------------------------------
540 
541 void StitchingCosmicRayMergingTool::StitchPfos(const MasterAlgorithm *const pAlgorithm, const ThreeDPointingClusterMap &pointingClusterMap,
542  const PfoMergeMap &pfoMerges, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map) const
543 {
544  PfoVector pfoVectorToEnlarge;
545  for (const auto &mapEntry : pfoMerges)
546  pfoVectorToEnlarge.push_back(mapEntry.first);
547  std::sort(pfoVectorToEnlarge.begin(), pfoVectorToEnlarge.end(), LArPfoHelper::SortByNHits);
548 
549  for (const ParticleFlowObject *const pPfoToEnlarge : pfoVectorToEnlarge)
550  {
551  const PfoList &pfoList(pfoMerges.at(pPfoToEnlarge));
552  const PfoVector pfoVector(pfoList.begin(), pfoList.end());
553  PfoToPointingVertexMatrix pfoToPointingVertexMatrix;
554  float x0(0.f);
555 
557  {
558  try
559  {
560  // If stitching contributions are inconsistent, abort
561  if (!this->CalculateX0(pfoToLArTPCMap, pointingClusterMap, pfoVector, x0, pfoToPointingVertexMatrix))
562  continue;
563  }
564  catch (const pandora::StatusCodeException &)
565  {
566  continue;
567  }
568  }
569 
570  // ATTN: shift the pfos one at a time
571  PfoSet shiftedPfos;
572  for (PfoVector::const_iterator iterI = pfoVector.begin(); iterI != pfoVector.end(); ++iterI)
573  {
574  const ParticleFlowObject *const pPfoI(*iterI);
575  const LArTPC *const pLArTPCI(pfoToLArTPCMap.at(pPfoI));
576 
577  for (PfoVector::const_iterator iterJ = std::next(iterI); iterJ != pfoVector.end(); ++iterJ)
578  {
579  const ParticleFlowObject *const pPfoJ(*iterJ);
580  const LArTPC *const pLArTPCJ(pfoToLArTPCMap.at(pPfoJ));
581 
582  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPCI, *pLArTPCJ))
583  continue;
584 
585  if (std::find(shiftedPfos.begin(), shiftedPfos.end(), pPfoI) == shiftedPfos.end())
586  {
588  this->ShiftPfo(pAlgorithm, pPfoI, pPfoJ, x0, pfoToLArTPCMap, pfoToPointingVertexMatrix);
589 
590  shiftedPfos.insert(pPfoI);
591  }
592 
593  if (std::find(shiftedPfos.begin(), shiftedPfos.end(), pPfoJ) == shiftedPfos.end())
594  {
596  this->ShiftPfo(pAlgorithm, pPfoJ, pPfoI, x0, pfoToLArTPCMap, pfoToPointingVertexMatrix);
597 
598  shiftedPfos.insert(pPfoJ);
599  }
600  }
601  }
602 
603  // now merge all pfos
604  for (const ParticleFlowObject *const pPfoToDelete : shiftedPfos)
605  {
606  if (pPfoToDelete == pPfoToEnlarge)
607  continue;
608 
609  pAlgorithm->StitchPfos(pPfoToEnlarge, pPfoToDelete, pfoToLArTPCMap);
610  }
611 
612  stitchedPfosToX0Map.insert(PfoToFloatMap::value_type(pPfoToEnlarge, x0));
613  }
614 }
615 
616 //------------------------------------------------------------------------------------------------------------------------------------------
617 
618 void StitchingCosmicRayMergingTool::ShiftPfo(const MasterAlgorithm *const pAlgorithm, const ParticleFlowObject *const pPfoToShift,
619  const ParticleFlowObject *const pMatchedPfo, const float x0, const PfoToLArTPCMap &pfoToLArTPCMap,
620  const PfoToPointingVertexMatrix &pfoToPointingVertexMatrix) const
621 {
622  // get stitching vertex for the pfo to be shifted
623  const PfoToPointingVertexMatrix::const_iterator pfoToPointingVertexMatrixIter(pfoToPointingVertexMatrix.find(pPfoToShift));
624  const LArPointingCluster::Vertex stitchingVertex(pfoToPointingVertexMatrixIter->second.at(pMatchedPfo));
625 
626  const LArTPC *const pShiftLArTPC(pfoToLArTPCMap.at(pPfoToShift));
627  const LArTPC *const pMatchedLArTPC(pfoToLArTPCMap.at(pMatchedPfo));
628 
629  // determine shift sign from the relative position of stitching vertex and the relevant TPC boundary position
630  const float tpcBoundaryCenterX(LArStitchingHelper::GetTPCBoundaryCenterX(*pShiftLArTPC, *pMatchedLArTPC));
631  float tpcBoundaryX(0.f);
632 
633  if (pShiftLArTPC->GetCenterX() < tpcBoundaryCenterX)
634  {
635  tpcBoundaryX = pShiftLArTPC->GetCenterX() + (pShiftLArTPC->GetWidthX() / 2.f);
636  }
637  else
638  {
639  tpcBoundaryX = pShiftLArTPC->GetCenterX() - (pShiftLArTPC->GetWidthX() / 2.f);
640  }
641 
642  const float positionShiftSign = stitchingVertex.GetPosition().GetX() < tpcBoundaryX ? 1.f : -1.f;
643 
644  // ATTN: No CPA/APA sign needed since x0 calculation corresponds to an APA
645  object_creation::ParticleFlowObject::Metadata metadata;
646  metadata.m_propertiesToAdd["X0"] = x0;
647 
648  // ATTN: Set the X0 shift for all particles in hierarchy
649  PfoList downstreamPfoList;
650  LArPfoHelper::GetAllDownstreamPfos(pPfoToShift, downstreamPfoList);
651 
652  for (const ParticleFlowObject *const pHierarchyPfo : downstreamPfoList)
653  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pHierarchyPfo, metadata));
654 
655  const float signedX0(std::fabs(x0) * positionShiftSign);
656 
657  pAlgorithm->ShiftPfoHierarchy(pPfoToShift, pfoToLArTPCMap, signedX0);
658 }
659 
660 //------------------------------------------------------------------------------------------------------------------------------------------
661 
662 bool StitchingCosmicRayMergingTool::CalculateX0(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap,
663  const PfoVector &pfoVector, float &x0, PfoToPointingVertexMatrix &pfoToPointingVertexMatrix) const
664 {
665  float sumX(0.f), sumN(0.f);
666 
667  for (PfoVector::const_iterator iter1 = pfoVector.begin(), iterEnd = pfoVector.end(); iter1 != iterEnd; ++iter1)
668  {
669  const ParticleFlowObject *const pPfo1(*iter1);
670  PfoToLArTPCMap::const_iterator tpcIter1 = pfoToLArTPCMap.find(pPfo1);
671  ThreeDPointingClusterMap::const_iterator pointingIter1 = pointingClusterMap.find(pPfo1);
672 
673  if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
674  throw StatusCodeException(STATUS_CODE_FAILURE);
675 
676  const LArTPC *const pLArTPC1(tpcIter1->second);
677  const LArPointingCluster &pointingCluster1(pointingIter1->second);
678 
679  for (PfoVector::const_iterator iter2 = std::next(iter1); iter2 != iterEnd; ++iter2)
680  {
681  const ParticleFlowObject *const pPfo2(*iter2);
682  PfoToLArTPCMap::const_iterator tpcIter2 = pfoToLArTPCMap.find(pPfo2);
683  ThreeDPointingClusterMap::const_iterator pointingIter2 = pointingClusterMap.find(pPfo2);
684 
685  if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
686  throw StatusCodeException(STATUS_CODE_FAILURE);
687 
688  const LArTPC *const pLArTPC2(tpcIter2->second);
689  const LArPointingCluster &pointingCluster2(pointingIter2->second);
690 
691  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPC1, *pLArTPC2))
692  continue;
693 
694  // Calculate X0 for the closest pair of vertices
695  LArPointingCluster::Vertex pointingVertex1, pointingVertex2;
696  try
697  {
698  LArStitchingHelper::GetClosestVertices(*pLArTPC1, *pLArTPC2, pointingCluster1, pointingCluster2, pointingVertex1, pointingVertex2);
699 
700  // Record pfo1 stitching vertex for pfo1<->pfo2 match, used to determine shifting direction in later step
701  const PfoToPointingVertexMatrix::iterator pfoToPointingVertexMatrixIter1(pfoToPointingVertexMatrix.find(pPfo1));
702  if (pfoToPointingVertexMatrixIter1 == pfoToPointingVertexMatrix.end())
703  {
704  // No matches present in map, add pfo1<->pfo2 match
705  const PfoToPointingVertexMap pfoToPointingVertexMap({{pPfo2, pointingVertex1}});
706  (void)pfoToPointingVertexMatrix.insert(PfoToPointingVertexMatrix::value_type(pPfo1, pfoToPointingVertexMap));
707  }
708  else
709  {
710  // ATTN: another match for a different TPC boundary may be present, add pfo1<->pfo2 match
711  PfoToPointingVertexMap &pfoToPointingVertexMap(pfoToPointingVertexMatrixIter1->second);
712  const PfoToPointingVertexMap::iterator pfoToPointingVertexMapIter(pfoToPointingVertexMap.find(pPfo2));
713  if (pfoToPointingVertexMapIter == pfoToPointingVertexMap.end())
714  {
715  (void)pfoToPointingVertexMap.insert(PfoToPointingVertexMap::value_type(pPfo2, pointingVertex1));
716  }
717  else
718  {
719  if ((pfoToPointingVertexMapIter->second.GetPosition() - pointingVertex1.GetPosition()).GetMagnitude() >
720  std::numeric_limits<float>::epsilon())
721  throw StatusCodeException(STATUS_CODE_FAILURE);
722  }
723  }
724 
725  // Record pfo2 stitching vertex for pfo1<->pfo2 match, used to determine shifting direction in later step
726  const PfoToPointingVertexMatrix::iterator pfoToPointingVertexMatrixIter2(pfoToPointingVertexMatrix.find(pPfo2));
727  if (pfoToPointingVertexMatrixIter2 == pfoToPointingVertexMatrix.end())
728  {
729  // No matches present in map, add pfo1<->pfo2 match
730  const PfoToPointingVertexMap pfoToPointingVertexMap({{pPfo1, pointingVertex2}});
731  (void)pfoToPointingVertexMatrix.insert(PfoToPointingVertexMatrix::value_type(pPfo2, pfoToPointingVertexMap));
732  }
733  else
734  {
735  // ATTN: another match for a different TPC boundary may be present, add pfo1<->pfo2 match
736  PfoToPointingVertexMap &pfoToPointingVertexMap(pfoToPointingVertexMatrixIter2->second);
737  const PfoToPointingVertexMap::iterator pfoToPointingVertexMapIter(pfoToPointingVertexMap.find(pPfo1));
738  if (pfoToPointingVertexMapIter == pfoToPointingVertexMap.end())
739  {
740  (void)pfoToPointingVertexMap.insert(PfoToPointingVertexMap::value_type(pPfo1, pointingVertex2));
741  }
742  else
743  {
744  if ((pfoToPointingVertexMapIter->second.GetPosition() - pointingVertex2.GetPosition()).GetMagnitude() >
745  std::numeric_limits<float>::epsilon())
746  throw StatusCodeException(STATUS_CODE_FAILURE);
747  }
748  }
749 
750  const float tpcBoundaryCenterX(LArStitchingHelper::GetTPCBoundaryCenterX(*pLArTPC1, *pLArTPC2));
751  const bool isCPAStitch(pLArTPC1->GetCenterX() < tpcBoundaryCenterX ? !pLArTPC1->IsDriftInPositiveX() : !pLArTPC2->IsDriftInPositiveX());
752  float thisX0(LArStitchingHelper::CalculateX0(*pLArTPC1, *pLArTPC2, pointingVertex1, pointingVertex2));
753 
754  thisX0 *= isCPAStitch ? -1.f : 1.f;
755 
756  // If multiple boundaries identified, check if stitching contribution is consistent
757  if ((sumN > std::numeric_limits<float>::epsilon()) && (sumX > std::numeric_limits<float>::epsilon()))
758  {
759  const float fractionalDiff(std::fabs((sumX - (thisX0 * sumN)) / sumX));
760 
761  if ((fractionalDiff > m_maxX0FractionalDeviation) && (std::fabs(sumX / sumN) > m_boundaryToleranceWidth))
762  return false;
763  }
764 
765  sumX += thisX0;
766  sumN += 1.f;
767  }
768  catch (const pandora::StatusCodeException &statusCodeException)
769  {
770  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
771  std::cout << "StitchingCosmicRayMergingTool: Attempting to stitch a pfo with multiple vertices for the same match" << std::endl;
772  }
773  }
774  }
775 
776  if ((sumN < std::numeric_limits<float>::epsilon()) || (std::fabs(sumX) < std::numeric_limits<float>::epsilon()))
777  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
778 
779  x0 = (sumX / sumN);
780 
781  return true;
782 }
783 
784 //------------------------------------------------------------------------------------------------------------------------------------------
785 //------------------------------------------------------------------------------------------------------------------------------------------
786 
788  m_parent(parent),
789  m_daughter(daughter),
790  m_fom(fom)
791 {
792 }
793 
794 //------------------------------------------------------------------------------------------------------------------------------------------
795 
797 {
798  return m_parent;
799 }
800 
801 //------------------------------------------------------------------------------------------------------------------------------------------
802 
804 {
805  return m_daughter;
806 }
807 
808 //------------------------------------------------------------------------------------------------------------------------------------------
809 
811 {
812  return m_fom;
813 }
814 
815 //------------------------------------------------------------------------------------------------------------------------------------------
816 //------------------------------------------------------------------------------------------------------------------------------------------
817 
818 StatusCode StitchingCosmicRayMergingTool::ReadSettings(const TiXmlHandle xmlHandle)
819 {
820  PANDORA_RETURN_RESULT_IF_AND_IF(
821  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ThreeDStitchingMode", m_useXcoordinate));
822 
823  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
824  XmlHelper::ReadValue(xmlHandle, "AlwaysApplyT0Calculation", m_alwaysApplyT0Calculation));
825 
826  PANDORA_RETURN_RESULT_IF_AND_IF(
827  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HalfWindowLayers", m_halfWindowLayers));
828 
829  float minLength(std::sqrt(m_minLengthSquared));
830  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinPfoLength", minLength));
831  m_minLengthSquared = minLength * minLength;
832 
833  PANDORA_RETURN_RESULT_IF_AND_IF(
834  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCosRelativeAngle", m_minCosRelativeAngle));
835 
836  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
837  XmlHelper::ReadValue(xmlHandle, "RelaxMinLongitudinalDisplacement", m_relaxMinLongitudinalDisplacement));
838 
839  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
840  XmlHelper::ReadValue(xmlHandle, "MaxLongitudinalDisplacementX", m_maxLongitudinalDisplacementX));
841 
842  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
843  XmlHelper::ReadValue(xmlHandle, "MaxTransverseDisplacement", m_maxTransverseDisplacement));
844 
845  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
846  XmlHelper::ReadValue(xmlHandle, "LooserMinCosRelativeAngle", m_relaxCosRelativeAngle));
847 
848  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
849  XmlHelper::ReadValue(xmlHandle, "LooserMaxTransverseDisplacement", m_relaxTransverseDisplacement));
850 
851  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinNCaloHits3D", m_minNCaloHits3D));
852 
853  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
854  XmlHelper::ReadValue(xmlHandle, "MaxX0FractionalDeviation", m_maxX0FractionalDeviation));
855 
856  PANDORA_RETURN_RESULT_IF_AND_IF(
857  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "BoundaryToleranceWidth", m_boundaryToleranceWidth));
858 
859  return STATUS_CODE_SUCCESS;
860 }
861 
862 } // namespace lar_content
std::unordered_map< const pandora::ParticleFlowObject *, float > PfoToFloatMap
intermediate_table::iterator iterator
void SelectPrimaryPfos(const pandora::PfoList *pInputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, pandora::PfoList &outputPfoList) const
Select primary Pfos from the input list of Pfos.
std::unordered_map< const pandora::ParticleFlowObject *, PfoToPointingVertexMap > PfoToPointingVertexMatrix
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
Header file for the pfo helper class.
static float CalculateX0(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC, const LArPointingCluster::Vertex &firstVertex, const LArPointingCluster::Vertex &secondVertex)
Calculate X0 for a pair of vertices.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
PfoAssociation(const VertexType parent, const VertexType daughter, const float fom)
Constructor.
void CollectAssociatedPfos(const pandora::ParticleFlowObject *const pSeedPfo, const pandora::ParticleFlowObject *const pCurrentPfo, const PfoMergeMap &pfoMerges, const pandora::PfoSet &vetoSet, pandora::PfoList &associatedList) const
Collect up associations between Pfos.
static void GetImpactParametersInYZ(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices using yz-coordinates.
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
bool CalculateX0(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap, const pandora::PfoVector &pfoVector, float &x0, PfoToPointingVertexMatrix &pfoToPointingVertexMatrix) const
Calculate x0 shift for a group of associated Pfos.
intermediate_table::const_iterator const_iterator
LArPointingCluster class.
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
void CreatePfoMatches(const LArTPCToPfoMap &larTPCToPfoMap, const ThreeDPointingClusterMap &pointingClusterMap, PfoAssociationMatrix &pfoAssociationMatrix) const
Create associations between Pfos using 3D pointing clusters.
std::unordered_map< const pandora::ParticleFlowObject *, pandora::PfoList > PfoMergeMap
std::unordered_map< const pandora::ParticleFlowObject *, PfoAssociationMap > PfoAssociationMatrix
void BuildTPCMaps(const pandora::PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, LArTPCToPfoMap &larTPCToPfoMap) const
Build a list of Pfos for each tpc.
float m_boundaryToleranceWidth
The distance from the APA/CPA boundary inside which the deviation consideration is ignored...
void OrderPfoMerges(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap, const PfoMergeMap &inputPfoMerges, PfoMergeMap &outputPfoMerges) const
Identify the vertex Pfo and then re-order the map of merges so that the vertex Pfo will be enlarged...
static bool IsInGap(const pandora::Pandora &pandora, const pandora::CartesianVector &testPoint2D, const pandora::HitType hitType, const float gapTolerance=0.f)
Whether a 2D test point lies in a registered gap with the associated hit type.
float m_maxX0FractionalDeviation
The maximum allowed fractional difference of an X0 contribution for matches to be stitched...
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
void ShiftPfo(const MasterAlgorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pPfoToShift, const pandora::ParticleFlowObject *const pMatchedPfo, const float x0, const PfoToLArTPCMap &pfoToLArTPCMap, const PfoToPointingVertexMatrix &pfoToPointingVertexMatrix) const
Shift a pfo given its pfo stitching pair.
Header file for the geometry helper class.
static bool CanTPCsBeStitched(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Whether particles from a given pair of tpcs can be stitched together.
const Vertex & GetOuterVertex() const
Get the outer vertex.
static float GetTPCDisplacement(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Calculate distance between central positions of a pair of tpcs.
static float GetTPCBoundaryCenterX(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Determine centre in X at the boundary between a pair of tpcs.
const Vertex & GetInnerVertex() const
Get the inner vertex.
void ShiftPfoHierarchy(const pandora::ParticleFlowObject *const pParentPfo, const PfoToLArTPCMap &pfoToLArTPCMap, const float x0) const
Shift a Pfo hierarchy by a specified x0 value.
static int max(int a, int b)
void StitchPfos(const pandora::ParticleFlowObject *const pPfoToEnlarge, const pandora::ParticleFlowObject *const pPfoToDelete, PfoToLArTPCMap &pfoToLArTPCMap) const
Stitch together a pair of pfos.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
float GetLengthSquared() const
Get length squared of pointing cluster.
static float GetTPCBoundaryWidthX(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Determine width in X at the boundary between a pair of tpcs.
void StitchPfos(const MasterAlgorithm *const pAlgorithm, const ThreeDPointingClusterMap &pointingClusterMap, const PfoMergeMap &pfoMerges, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map) const
Apply X0 corrections, and then stitch together Pfos.
Header file for the lar three dimensional sliding fit result class.
const pandora::CartesianVector & GetDirection() const
Get the vertex direction.
void BuildPointingClusterMaps(const pandora::PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, ThreeDPointingClusterMap &pointingClusterMap) const
Build a 3D pointing cluster for each Pfo.
std::unordered_map< const pandora::ParticleFlowObject *, const pandora::LArTPC * > PfoToLArTPCMap
Header file for the helper class for multiple drift volumes.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
void SelectPfoMatches(const PfoAssociationMatrix &pfoAssociationMatrix, PfoMergeMap &pfoSelectedMatches) const
Select the best associations between Pfos; create a mapping between associated Pfos, handling any ambiguities.
std::unordered_map< const pandora::ParticleFlowObject *, LArPointingCluster::Vertex > PfoToPointingVertexMap
MasterAlgorithm class.
static bool IsFinalState(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a primary parent particle.
std::unordered_map< const pandora::ParticleFlowObject *, PfoAssociation > PfoAssociationMap
float m_relaxMinLongitudinalDisplacement
The minimum value of the longitudinal impact parameter for association if both verticies fall in the ...
static void GetAllDownstreamPfos(const pandora::PfoList &inputPfoList, pandora::PfoList &outputPfoList)
Get a flat list of all pfos, recursively, of all daughters associated with those pfos in an input lis...
void Run(const MasterAlgorithm *const pAlgorithm, const pandora::PfoList *const pMultiPfoList, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map)
Run the algorithm tool.
static bool SortTPCs(const pandora::LArTPC *const pLhs, const pandora::LArTPC *const pRhs)
Sort tpcs by central positions.
std::unordered_map< const pandora::LArTPC *, pandora::PfoList > LArTPCToPfoMap
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
bool IsInnerVertex() const
Is this the inner vertex.
void SelectPfoMerges(const PfoMergeMap &pfoMatches, PfoMergeMap &pfoMerges) const
Create an initial map of Pfo merges to be made.
static void GetClosestVertices(const pandora::LArTPC &larTPC1, const pandora::LArTPC &larTPC2, const LArPointingCluster &pointingCluster1, const LArPointingCluster &pointingCluster2, LArPointingCluster::Vertex &closestVertex1, LArPointingCluster::Vertex &closestVertex2)
Given a pair of pointing clusters, find the pair of vertices with smallest yz-separation.
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
def parent(G, child, parent_type)
Definition: graph.py:67
QTextStream & endl(QTextStream &s)
std::unordered_map< const pandora::ParticleFlowObject *, LArPointingCluster > ThreeDPointingClusterMap
GeomAnalyzerI * GetGeometry(void)
Definition: gAtmoEvGen.cxx:433