LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
StitchingCosmicRayMergingTool.cc
Go to the documentation of this file.
1 
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
264  : (1.f - pX1 * pX1 > std::numeric_limits<float>::epsilon()) ? pX1 / std::sqrt(1.f - pX1 * pX1)
265  : minL);
266  const float dXdL2(m_useXcoordinate ? pX2
267  : (1.f - pX2 * pX2 > std::numeric_limits<float>::epsilon()) ? pX2 / std::sqrt(1.f - pX2 * pX2)
268  : minL);
269  const float maxL1(maxLongitudinalDisplacementX / dXdL1);
270  const float maxL2(maxLongitudinalDisplacementX / dXdL2);
271 
272  if (rL1 < minL || rL1 > maxL1 || rL2 < minL || rL2 > maxL2)
273  return;
274 
275  // Selection cuts on transverse impact parameters
276  const bool minPass(std::min(rT1, rT2) < m_relaxTransverseDisplacement && cosRelativeAngle > m_relaxCosRelativeAngle);
277  const bool maxPass(std::max(rT1, rT2) < m_maxTransverseDisplacement && cosRelativeAngle > m_minCosRelativeAngle);
278 
279  if (!minPass && !maxPass)
280  return;
281 
282  // Store this association
285 
286  const float particleLength1(pointingCluster1.GetLengthSquared());
287  const float particleLength2(pointingCluster2.GetLengthSquared());
288 
289  pfoAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pPfo2, PfoAssociation(vertexType1, vertexType2, particleLength2)));
290  pfoAssociationMatrix[pPfo2].insert(PfoAssociationMap::value_type(pPfo1, PfoAssociation(vertexType2, vertexType1, particleLength1)));
291 }
292 
293 //------------------------------------------------------------------------------------------------------------------------------------------
294 
295 void StitchingCosmicRayMergingTool::SelectPfoMatches(const PfoAssociationMatrix &pfoAssociationMatrix, PfoMergeMap &pfoMatches) const
296 {
297  // First step: loop over association matrix and find best associations A -> X and B -> Y
298  // =====================================================================================
299  PfoAssociationMatrix bestAssociationMatrix;
300 
301  PfoVector pfoVector1;
302  for (const auto &mapEntry : pfoAssociationMatrix)
303  pfoVector1.push_back(mapEntry.first);
304  std::sort(pfoVector1.begin(), pfoVector1.end(), LArPfoHelper::SortByNHits);
305 
306  for (const ParticleFlowObject *const pPfo1 : pfoVector1)
307  {
308  const PfoAssociationMap &pfoAssociationMap(pfoAssociationMatrix.at(pPfo1));
309 
310  const ParticleFlowObject *pBestPfoInner(nullptr);
312 
313  const ParticleFlowObject *pBestPfoOuter(nullptr);
315 
316  PfoVector pfoVector2;
317  for (const auto &mapEntry : pfoAssociationMap)
318  pfoVector2.push_back(mapEntry.first);
319  std::sort(pfoVector2.begin(), pfoVector2.end(), LArPfoHelper::SortByNHits);
320 
321  for (const ParticleFlowObject *const pPfo2 : pfoVector2)
322  {
323  const PfoAssociation &pfoAssociation(pfoAssociationMap.at(pPfo2));
324 
325  // Inner associations
326  if (pfoAssociation.GetParent() == PfoAssociation::INNER)
327  {
328  if (pfoAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
329  {
330  bestAssociationInner = pfoAssociation;
331  pBestPfoInner = pPfo2;
332  }
333  }
334 
335  // Outer associations
336  if (pfoAssociation.GetParent() == PfoAssociation::OUTER)
337  {
338  if (pfoAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
339  {
340  bestAssociationOuter = pfoAssociation;
341  pBestPfoOuter = pPfo2;
342  }
343  }
344  }
345 
346  if (pBestPfoInner)
347  (void)bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoInner, bestAssociationInner));
348 
349  if (pBestPfoOuter)
350  (void)bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoOuter, bestAssociationOuter));
351  }
352 
353  // Second step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
354  // =============================================================================
355  PfoVector pfoVector3;
356  for (const auto &mapEntry : bestAssociationMatrix)
357  pfoVector3.push_back(mapEntry.first);
358  std::sort(pfoVector3.begin(), pfoVector3.end(), LArPfoHelper::SortByNHits);
359 
360  for (const ParticleFlowObject *const pParentPfo : pfoVector3)
361  {
362  const PfoAssociationMap &parentAssociationMap(bestAssociationMatrix.at(pParentPfo));
363 
364  PfoVector pfoVector4;
365  for (const auto &mapEntry : parentAssociationMap)
366  pfoVector4.push_back(mapEntry.first);
367  std::sort(pfoVector4.begin(), pfoVector4.end(), LArPfoHelper::SortByNHits);
368 
369  for (const ParticleFlowObject *const pDaughterPfo : pfoVector4)
370  {
371  const PfoAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterPfo));
372  PfoAssociationMatrix::const_iterator iter5 = bestAssociationMatrix.find(pDaughterPfo);
373 
374  if (bestAssociationMatrix.end() == iter5)
375  continue;
376 
377  const PfoAssociationMap &daughterAssociationMap(iter5->second);
378 
379  PfoAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentPfo);
380  if (daughterAssociationMap.end() == iter6)
381  continue;
382 
383  const PfoAssociation &daughterToParentAssociation(iter6->second);
384 
385  if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
386  parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
387  {
388  pfoMatches[pParentPfo].push_back(pDaughterPfo);
389  }
390  }
391  }
392 }
393 
394 //------------------------------------------------------------------------------------------------------------------------------------------
395 
397 {
398  PfoSet vetoSet;
399 
400  PfoVector inputPfoVector;
401  for (const auto &mapEntry : pfoMatches)
402  inputPfoVector.push_back(mapEntry.first);
403  std::sort(inputPfoVector.begin(), inputPfoVector.end(), LArPfoHelper::SortByNHits);
404 
405  for (const ParticleFlowObject *const pInputPfo : inputPfoVector)
406  {
407  const PfoList &pfoList(pfoMatches.at(pInputPfo));
408 
409  for (const ParticleFlowObject *const pSeedPfo : pfoList)
410  {
411  if (vetoSet.count(pSeedPfo))
412  continue;
413 
414  PfoList mergeList;
415  this->CollectAssociatedPfos(pSeedPfo, pSeedPfo, pfoMatches, vetoSet, mergeList);
416 
417  vetoSet.insert(pSeedPfo);
418  PfoList &selectedPfoList(pfoMerges[pSeedPfo]);
419  selectedPfoList.push_back(pSeedPfo);
420 
421  for (const ParticleFlowObject *const pAssociatedPfo : mergeList)
422  {
423  // Check if particle has already been counted
424  if (vetoSet.count(pAssociatedPfo) || (selectedPfoList.end() != std::find(selectedPfoList.begin(), selectedPfoList.end(), pAssociatedPfo)))
425  throw StatusCodeException(STATUS_CODE_FAILURE);
426 
427  vetoSet.insert(pAssociatedPfo);
428  selectedPfoList.push_back(pAssociatedPfo);
429  }
430  }
431  }
432 }
433 
434 //------------------------------------------------------------------------------------------------------------------------------------------
435 
436 void StitchingCosmicRayMergingTool::CollectAssociatedPfos(const ParticleFlowObject *const pSeedPfo,
437  const ParticleFlowObject *const pCurrentPfo, const PfoMergeMap &pfoMergeMap, const PfoSet &vetoSet, PfoList &associatedList) const
438 {
439  if (vetoSet.count(pCurrentPfo))
440  return;
441 
442  PfoMergeMap::const_iterator iter1 = pfoMergeMap.find(pCurrentPfo);
443 
444  if (pfoMergeMap.end() == iter1)
445  return;
446 
447  for (PfoList::const_iterator iter2 = iter1->second.begin(), iterEnd2 = iter1->second.end(); iter2 != iterEnd2; ++iter2)
448  {
449  const ParticleFlowObject *const pAssociatedPfo = *iter2;
450 
451  if (pAssociatedPfo == pSeedPfo)
452  continue;
453 
454  if (associatedList.end() != std::find(associatedList.begin(), associatedList.end(), pAssociatedPfo))
455  continue;
456 
457  associatedList.push_back(pAssociatedPfo);
458 
459  this->CollectAssociatedPfos(pSeedPfo, pAssociatedPfo, pfoMergeMap, vetoSet, associatedList);
460  }
461 }
462 
463 //------------------------------------------------------------------------------------------------------------------------------------------
464 
465 void StitchingCosmicRayMergingTool::OrderPfoMerges(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap,
466  const PfoMergeMap &inputPfoMerges, PfoMergeMap &outputPfoMerges) const
467 {
468  PfoVector inputPfoVector;
469  for (const auto &mapEntry : inputPfoMerges)
470  inputPfoVector.push_back(mapEntry.first);
471  std::sort(inputPfoVector.begin(), inputPfoVector.end(), LArPfoHelper::SortByNHits);
472 
473  for (const ParticleFlowObject *const pInputPfo : inputPfoVector)
474  {
475  const PfoList &pfoList(inputPfoMerges.at(pInputPfo));
476 
477  float bestLength(0.f);
478  const ParticleFlowObject *pVertexPfo = nullptr;
479 
480  for (PfoList::const_iterator iter1 = pfoList.begin(), iterEnd = pfoList.end(); iter1 != iterEnd; ++iter1)
481  {
482  const ParticleFlowObject *const pPfo1(*iter1);
483  PfoToLArTPCMap::const_iterator tpcIter1 = pfoToLArTPCMap.find(pPfo1);
484  ThreeDPointingClusterMap::const_iterator pointingIter1 = pointingClusterMap.find(pPfo1);
485 
486  if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
487  throw StatusCodeException(STATUS_CODE_FAILURE);
488 
489  const LArTPC *const pLArTPC1(tpcIter1->second);
490  const LArPointingCluster &pointingCluster1(pointingIter1->second);
491 
492  for (PfoList::const_iterator iter2 = iter1; iter2 != iterEnd; ++iter2)
493  {
494  const ParticleFlowObject *const pPfo2(*iter2);
495  PfoToLArTPCMap::const_iterator tpcIter2 = pfoToLArTPCMap.find(pPfo2);
496  ThreeDPointingClusterMap::const_iterator pointingIter2 = pointingClusterMap.find(pPfo2);
497 
498  if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
499  throw StatusCodeException(STATUS_CODE_FAILURE);
500 
501  const LArTPC *const pLArTPC2(tpcIter2->second);
502  const LArPointingCluster &pointingCluster2(pointingIter2->second);
503 
504  if (pLArTPC1 == pLArTPC2)
505  continue;
506 
507  const float thisLength(LArStitchingHelper::GetTPCDisplacement(*pLArTPC1, *pLArTPC2));
508 
509  if (thisLength < bestLength)
510  continue;
511 
512  bestLength = thisLength;
513 
514  try
515  {
516  pVertexPfo = nullptr;
517 
518  LArPointingCluster::Vertex nearVertex1, nearVertex2;
519  LArStitchingHelper::GetClosestVertices(*pLArTPC1, *pLArTPC2, pointingCluster1, pointingCluster2, nearVertex1, nearVertex2);
520 
521  const LArPointingCluster::Vertex &farVertex1(
522  nearVertex1.IsInnerVertex() ? pointingCluster1.GetOuterVertex() : pointingCluster1.GetInnerVertex());
523  const LArPointingCluster::Vertex &farVertex2(
524  nearVertex2.IsInnerVertex() ? pointingCluster2.GetOuterVertex() : pointingCluster2.GetInnerVertex());
525  const float deltaY(farVertex1.GetPosition().GetY() - farVertex2.GetPosition().GetY());
526 
527  if (std::fabs(deltaY) < std::numeric_limits<float>::epsilon())
528  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
529 
530  pVertexPfo = ((deltaY > 0.f) ? pPfo1 : pPfo2);
531  }
532  catch (const pandora::StatusCodeException &)
533  {
534  }
535  }
536  }
537 
538  if (pVertexPfo)
539  outputPfoMerges[pVertexPfo].insert(outputPfoMerges[pVertexPfo].begin(), pfoList.begin(), pfoList.end());
540  }
541 }
542 
543 //------------------------------------------------------------------------------------------------------------------------------------------
544 
545 void StitchingCosmicRayMergingTool::StitchPfos(const MasterAlgorithm *const pAlgorithm, const ThreeDPointingClusterMap &pointingClusterMap,
546  const PfoMergeMap &pfoMerges, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map) const
547 {
548  PfoVector pfoVectorToEnlarge;
549  for (const auto &mapEntry : pfoMerges)
550  pfoVectorToEnlarge.push_back(mapEntry.first);
551  std::sort(pfoVectorToEnlarge.begin(), pfoVectorToEnlarge.end(), LArPfoHelper::SortByNHits);
552 
553  for (const ParticleFlowObject *const pPfoToEnlarge : pfoVectorToEnlarge)
554  {
555  const PfoList &pfoList(pfoMerges.at(pPfoToEnlarge));
556  const PfoVector pfoVector(pfoList.begin(), pfoList.end());
557  PfoToPointingVertexMatrix pfoToPointingVertexMatrix;
558  float x0(0.f);
559 
561  {
562  try
563  {
564  // If stitching contributions are inconsistent, abort
565  if (!this->CalculateX0(pfoToLArTPCMap, pointingClusterMap, pfoVector, x0, pfoToPointingVertexMatrix))
566  continue;
567  }
568  catch (const pandora::StatusCodeException &)
569  {
570  continue;
571  }
572  }
573 
574  // ATTN: shift the pfos one at a time
575  PfoSet shiftedPfos;
576  for (PfoVector::const_iterator iterI = pfoVector.begin(); iterI != pfoVector.end(); ++iterI)
577  {
578  const ParticleFlowObject *const pPfoI(*iterI);
579  const LArTPC *const pLArTPCI(pfoToLArTPCMap.at(pPfoI));
580 
581  for (PfoVector::const_iterator iterJ = std::next(iterI); iterJ != pfoVector.end(); ++iterJ)
582  {
583  const ParticleFlowObject *const pPfoJ(*iterJ);
584  const LArTPC *const pLArTPCJ(pfoToLArTPCMap.at(pPfoJ));
585 
586  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPCI, *pLArTPCJ))
587  continue;
588 
589  if (std::find(shiftedPfos.begin(), shiftedPfos.end(), pPfoI) == shiftedPfos.end())
590  {
592  this->ShiftPfo(pAlgorithm, pPfoI, pPfoJ, x0, pfoToLArTPCMap, pfoToPointingVertexMatrix);
593 
594  shiftedPfos.insert(pPfoI);
595  }
596 
597  if (std::find(shiftedPfos.begin(), shiftedPfos.end(), pPfoJ) == shiftedPfos.end())
598  {
600  this->ShiftPfo(pAlgorithm, pPfoJ, pPfoI, x0, pfoToLArTPCMap, pfoToPointingVertexMatrix);
601 
602  shiftedPfos.insert(pPfoJ);
603  }
604  }
605  }
606 
607  // now merge all pfos
608  for (const ParticleFlowObject *const pPfoToDelete : shiftedPfos)
609  {
610  if (pPfoToDelete == pPfoToEnlarge)
611  continue;
612 
613  pAlgorithm->StitchPfos(pPfoToEnlarge, pPfoToDelete, pfoToLArTPCMap);
614  }
615 
616  stitchedPfosToX0Map.insert(PfoToFloatMap::value_type(pPfoToEnlarge, x0));
617  }
618 }
619 
620 //------------------------------------------------------------------------------------------------------------------------------------------
621 
622 void StitchingCosmicRayMergingTool::ShiftPfo(const MasterAlgorithm *const pAlgorithm, const ParticleFlowObject *const pPfoToShift,
623  const ParticleFlowObject *const pMatchedPfo, const float x0, const PfoToLArTPCMap &pfoToLArTPCMap,
624  const PfoToPointingVertexMatrix &pfoToPointingVertexMatrix) const
625 {
626  // get stitching vertex for the pfo to be shifted
627  const PfoToPointingVertexMatrix::const_iterator pfoToPointingVertexMatrixIter(pfoToPointingVertexMatrix.find(pPfoToShift));
628  const LArPointingCluster::Vertex stitchingVertex(pfoToPointingVertexMatrixIter->second.at(pMatchedPfo));
629 
630  const LArTPC *const pShiftLArTPC(pfoToLArTPCMap.at(pPfoToShift));
631  const LArTPC *const pMatchedLArTPC(pfoToLArTPCMap.at(pMatchedPfo));
632 
633  // determine shift sign from the relative position of stitching vertex and the relevant TPC boundary position
634  const float tpcBoundaryCenterX(LArStitchingHelper::GetTPCBoundaryCenterX(*pShiftLArTPC, *pMatchedLArTPC));
635  float tpcBoundaryX(0.f);
636 
637  if (pShiftLArTPC->GetCenterX() < tpcBoundaryCenterX)
638  {
639  tpcBoundaryX = pShiftLArTPC->GetCenterX() + (pShiftLArTPC->GetWidthX() / 2.f);
640  }
641  else
642  {
643  tpcBoundaryX = pShiftLArTPC->GetCenterX() - (pShiftLArTPC->GetWidthX() / 2.f);
644  }
645 
646  const float positionShiftSign = stitchingVertex.GetPosition().GetX() < tpcBoundaryX ? 1.f : -1.f;
647 
648  // ATTN: No CPA/APA sign needed since x0 calculation corresponds to an APA
649  object_creation::ParticleFlowObject::Metadata metadata;
650  metadata.m_propertiesToAdd["X0"] = x0;
651 
652  // ATTN: Set the X0 shift for all particles in hierarchy
653  PfoList downstreamPfoList;
654  LArPfoHelper::GetAllDownstreamPfos(pPfoToShift, downstreamPfoList);
655 
656  for (const ParticleFlowObject *const pHierarchyPfo : downstreamPfoList)
657  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pHierarchyPfo, metadata));
658 
659  const float signedX0(std::fabs(x0) * positionShiftSign);
660 
661  pAlgorithm->ShiftPfoHierarchy(pPfoToShift, pfoToLArTPCMap, signedX0);
662 }
663 
664 //------------------------------------------------------------------------------------------------------------------------------------------
665 
666 bool StitchingCosmicRayMergingTool::CalculateX0(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap,
667  const PfoVector &pfoVector, float &x0, PfoToPointingVertexMatrix &pfoToPointingVertexMatrix) const
668 {
669  float sumX(0.f), sumN(0.f);
670 
671  for (PfoVector::const_iterator iter1 = pfoVector.begin(), iterEnd = pfoVector.end(); iter1 != iterEnd; ++iter1)
672  {
673  const ParticleFlowObject *const pPfo1(*iter1);
674  PfoToLArTPCMap::const_iterator tpcIter1 = pfoToLArTPCMap.find(pPfo1);
675  ThreeDPointingClusterMap::const_iterator pointingIter1 = pointingClusterMap.find(pPfo1);
676 
677  if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
678  throw StatusCodeException(STATUS_CODE_FAILURE);
679 
680  const LArTPC *const pLArTPC1(tpcIter1->second);
681  const LArPointingCluster &pointingCluster1(pointingIter1->second);
682 
683  for (PfoVector::const_iterator iter2 = std::next(iter1); iter2 != iterEnd; ++iter2)
684  {
685  const ParticleFlowObject *const pPfo2(*iter2);
686  PfoToLArTPCMap::const_iterator tpcIter2 = pfoToLArTPCMap.find(pPfo2);
687  ThreeDPointingClusterMap::const_iterator pointingIter2 = pointingClusterMap.find(pPfo2);
688 
689  if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
690  throw StatusCodeException(STATUS_CODE_FAILURE);
691 
692  const LArTPC *const pLArTPC2(tpcIter2->second);
693  const LArPointingCluster &pointingCluster2(pointingIter2->second);
694 
695  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPC1, *pLArTPC2))
696  continue;
697 
698  // Calculate X0 for the closest pair of vertices
699  LArPointingCluster::Vertex pointingVertex1, pointingVertex2;
700  try
701  {
702  LArStitchingHelper::GetClosestVertices(*pLArTPC1, *pLArTPC2, pointingCluster1, pointingCluster2, pointingVertex1, pointingVertex2);
703 
704  // Record pfo1 stitching vertex for pfo1<->pfo2 match, used to determine shifting direction in later step
705  const PfoToPointingVertexMatrix::iterator pfoToPointingVertexMatrixIter1(pfoToPointingVertexMatrix.find(pPfo1));
706  if (pfoToPointingVertexMatrixIter1 == pfoToPointingVertexMatrix.end())
707  {
708  // No matches present in map, add pfo1<->pfo2 match
709  const PfoToPointingVertexMap pfoToPointingVertexMap({{pPfo2, pointingVertex1}});
710  (void)pfoToPointingVertexMatrix.insert(PfoToPointingVertexMatrix::value_type(pPfo1, pfoToPointingVertexMap));
711  }
712  else
713  {
714  // ATTN: another match for a different TPC boundary may be present, add pfo1<->pfo2 match
715  PfoToPointingVertexMap &pfoToPointingVertexMap(pfoToPointingVertexMatrixIter1->second);
716  const PfoToPointingVertexMap::iterator pfoToPointingVertexMapIter(pfoToPointingVertexMap.find(pPfo2));
717  if (pfoToPointingVertexMapIter == pfoToPointingVertexMap.end())
718  {
719  (void)pfoToPointingVertexMap.insert(PfoToPointingVertexMap::value_type(pPfo2, pointingVertex1));
720  }
721  else
722  {
723  if ((pfoToPointingVertexMapIter->second.GetPosition() - pointingVertex1.GetPosition()).GetMagnitude() >
724  std::numeric_limits<float>::epsilon())
725  throw StatusCodeException(STATUS_CODE_FAILURE);
726  }
727  }
728 
729  // Record pfo2 stitching vertex for pfo1<->pfo2 match, used to determine shifting direction in later step
730  const PfoToPointingVertexMatrix::iterator pfoToPointingVertexMatrixIter2(pfoToPointingVertexMatrix.find(pPfo2));
731  if (pfoToPointingVertexMatrixIter2 == pfoToPointingVertexMatrix.end())
732  {
733  // No matches present in map, add pfo1<->pfo2 match
734  const PfoToPointingVertexMap pfoToPointingVertexMap({{pPfo1, pointingVertex2}});
735  (void)pfoToPointingVertexMatrix.insert(PfoToPointingVertexMatrix::value_type(pPfo2, pfoToPointingVertexMap));
736  }
737  else
738  {
739  // ATTN: another match for a different TPC boundary may be present, add pfo1<->pfo2 match
740  PfoToPointingVertexMap &pfoToPointingVertexMap(pfoToPointingVertexMatrixIter2->second);
741  const PfoToPointingVertexMap::iterator pfoToPointingVertexMapIter(pfoToPointingVertexMap.find(pPfo1));
742  if (pfoToPointingVertexMapIter == pfoToPointingVertexMap.end())
743  {
744  (void)pfoToPointingVertexMap.insert(PfoToPointingVertexMap::value_type(pPfo1, pointingVertex2));
745  }
746  else
747  {
748  if ((pfoToPointingVertexMapIter->second.GetPosition() - pointingVertex2.GetPosition()).GetMagnitude() >
749  std::numeric_limits<float>::epsilon())
750  throw StatusCodeException(STATUS_CODE_FAILURE);
751  }
752  }
753 
754  const float tpcBoundaryCenterX(LArStitchingHelper::GetTPCBoundaryCenterX(*pLArTPC1, *pLArTPC2));
755  const bool isCPAStitch(pLArTPC1->GetCenterX() < tpcBoundaryCenterX ? !pLArTPC1->IsDriftInPositiveX() : !pLArTPC2->IsDriftInPositiveX());
756  float thisX0(LArStitchingHelper::CalculateX0(*pLArTPC1, *pLArTPC2, pointingVertex1, pointingVertex2));
757 
758  thisX0 *= isCPAStitch ? -1.f : 1.f;
759 
760  // If multiple boundaries identified, check if stitching contribution is consistent
761  if ((sumN > std::numeric_limits<float>::epsilon()) && (sumX > std::numeric_limits<float>::epsilon()))
762  {
763  const float fractionalDiff(std::fabs((sumX - (thisX0 * sumN)) / sumX));
764 
765  if ((fractionalDiff > m_maxX0FractionalDeviation) && (std::fabs(sumX / sumN) > m_boundaryToleranceWidth))
766  return false;
767  }
768 
769  sumX += thisX0;
770  sumN += 1.f;
771  }
772  catch (const pandora::StatusCodeException &statusCodeException)
773  {
774  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
775  std::cout << "StitchingCosmicRayMergingTool: Attempting to stitch a pfo with multiple vertices for the same match" << std::endl;
776  }
777  }
778  }
779 
780  if ((sumN < std::numeric_limits<float>::epsilon()) || (std::fabs(sumX) < std::numeric_limits<float>::epsilon()))
781  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
782 
783  x0 = (sumX / sumN);
784 
785  return true;
786 }
787 
788 //------------------------------------------------------------------------------------------------------------------------------------------
789 //------------------------------------------------------------------------------------------------------------------------------------------
790 
792  m_parent(parent),
793  m_daughter(daughter),
794  m_fom(fom)
795 {
796 }
797 
798 //------------------------------------------------------------------------------------------------------------------------------------------
799 
801 {
802  return m_parent;
803 }
804 
805 //------------------------------------------------------------------------------------------------------------------------------------------
806 
808 {
809  return m_daughter;
810 }
811 
812 //------------------------------------------------------------------------------------------------------------------------------------------
813 
815 {
816  return m_fom;
817 }
818 
819 //------------------------------------------------------------------------------------------------------------------------------------------
820 //------------------------------------------------------------------------------------------------------------------------------------------
821 
822 StatusCode StitchingCosmicRayMergingTool::ReadSettings(const TiXmlHandle xmlHandle)
823 {
824  PANDORA_RETURN_RESULT_IF_AND_IF(
825  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ThreeDStitchingMode", m_useXcoordinate));
826 
827  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
828  XmlHelper::ReadValue(xmlHandle, "AlwaysApplyT0Calculation", m_alwaysApplyT0Calculation));
829 
830  PANDORA_RETURN_RESULT_IF_AND_IF(
831  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HalfWindowLayers", m_halfWindowLayers));
832 
833  float minLength(std::sqrt(m_minLengthSquared));
834  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinPfoLength", minLength));
835  m_minLengthSquared = minLength * minLength;
836 
837  PANDORA_RETURN_RESULT_IF_AND_IF(
838  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCosRelativeAngle", m_minCosRelativeAngle));
839 
840  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
841  XmlHelper::ReadValue(xmlHandle, "RelaxMinLongitudinalDisplacement", m_relaxMinLongitudinalDisplacement));
842 
843  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
844  XmlHelper::ReadValue(xmlHandle, "MaxLongitudinalDisplacementX", m_maxLongitudinalDisplacementX));
845 
846  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
847  XmlHelper::ReadValue(xmlHandle, "MaxTransverseDisplacement", m_maxTransverseDisplacement));
848 
849  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
850  XmlHelper::ReadValue(xmlHandle, "LooserMinCosRelativeAngle", m_relaxCosRelativeAngle));
851 
852  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
853  XmlHelper::ReadValue(xmlHandle, "LooserMaxTransverseDisplacement", m_relaxTransverseDisplacement));
854 
855  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinNCaloHits3D", m_minNCaloHits3D));
856 
857  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
858  XmlHelper::ReadValue(xmlHandle, "MaxX0FractionalDeviation", m_maxX0FractionalDeviation));
859 
860  PANDORA_RETURN_RESULT_IF_AND_IF(
861  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "BoundaryToleranceWidth", m_boundaryToleranceWidth));
862 
863  return STATUS_CODE_SUCCESS;
864 }
865 
866 } // namespace lar_content
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.
TFile f
Definition: plotHisto.C:6
std::unordered_map< const pandora::ParticleFlowObject *, const pandora::LArTPC * > PfoToLArTPCMap
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:101
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.
std::unordered_map< const pandora::ParticleFlowObject *, float > PfoToFloatMap
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.
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.
Header file for the helper class for multiple drift volumes.
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:69
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.
std::unordered_map< const pandora::ParticleFlowObject *, LArPointingCluster > ThreeDPointingClusterMap