LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
StitchingCosmicRayMergingTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
16 
18 
19 using namespace pandora;
20 
21 namespace lar_content
22 {
23 
24 StitchingCosmicRayMergingTool::StitchingCosmicRayMergingTool() :
25  m_useXcoordinate(false),
26  m_halfWindowLayers(30),
27  m_minLengthSquared(50.f),
28  m_minCosRelativeAngle(0.966),
29  m_maxLongitudinalDisplacementX(15.f),
30  m_maxTransverseDisplacement(5.f),
31  m_relaxCosRelativeAngle(0.906),
32  m_relaxTransverseDisplacement(2.5f)
33 {
34 }
35 
36 //------------------------------------------------------------------------------------------------------------------------------------------
37 
38 void StitchingCosmicRayMergingTool::Run(const MasterAlgorithm *const pAlgorithm, const PfoList *const pMultiPfoList, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map)
39 {
40  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
41  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
42 
43  if (this->GetPandora().GetGeometry()->GetLArTPCMap().size() < 2)
44  return;
45 
46  if (pfoToLArTPCMap.empty())
47  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
48 
49  PfoList primaryPfos;
50  this->SelectPrimaryPfos(pMultiPfoList, pfoToLArTPCMap, primaryPfos);
51 
52  ThreeDPointingClusterMap pointingClusterMap;
53  this->BuildPointingClusterMaps(primaryPfos, pfoToLArTPCMap, pointingClusterMap);
54 
55  LArTPCToPfoMap larTPCToPfoMap;
56  this->BuildTPCMaps(primaryPfos, pfoToLArTPCMap, larTPCToPfoMap);
57 
58  PfoAssociationMatrix pfoAssociationMatrix;
59  this->CreatePfoMatches(larTPCToPfoMap, pointingClusterMap, pfoAssociationMatrix);
60 
61  PfoMergeMap pfoSelectedMatches;
62  this->SelectPfoMatches(pfoAssociationMatrix, pfoSelectedMatches);
63 
64  PfoMergeMap pfoSelectedMerges;
65  this->SelectPfoMerges(pfoSelectedMatches, pfoSelectedMerges);
66 
67  PfoMergeMap pfoOrderedMerges;
68  this->OrderPfoMerges(pfoToLArTPCMap, pointingClusterMap, pfoSelectedMerges, pfoOrderedMerges);
69 
70  this->StitchPfos(pAlgorithm, pointingClusterMap, pfoOrderedMerges, pfoToLArTPCMap, stitchedPfosToX0Map);
71 }
72 
73 //------------------------------------------------------------------------------------------------------------------------------------------
74 
75 void StitchingCosmicRayMergingTool::SelectPrimaryPfos(const PfoList *pInputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, PfoList &outputPfoList) const
76 {
77  for (const ParticleFlowObject *const pPfo : *pInputPfoList)
78  {
80  continue;
81 
82  if (!pfoToLArTPCMap.count(pPfo))
83  continue;
84 
85  outputPfoList.push_back(pPfo);
86  }
87 
88  outputPfoList.sort(LArPfoHelper::SortByNHits);
89 }
90 
91 //------------------------------------------------------------------------------------------------------------------------------------------
92 
93 void StitchingCosmicRayMergingTool::BuildPointingClusterMaps(const PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, ThreeDPointingClusterMap &pointingClusterMap) const
94 {
95  for (const ParticleFlowObject *const pPfo : inputPfoList)
96  {
97  try
98  {
99  PfoToLArTPCMap::const_iterator tpcIter(pfoToLArTPCMap.find(pPfo));
100 
101  if (pfoToLArTPCMap.end() == tpcIter)
102  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
103 
104  const float slidingFitPitch(tpcIter->second->GetWirePitchW());
105 
106  ClusterList clusterList;
107  LArPfoHelper::GetThreeDClusterList(pPfo, clusterList);
108 
109  if (1 != clusterList.size())
110  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
111 
112  const ThreeDSlidingFitResult slidingFitResult(clusterList.front(), m_halfWindowLayers, slidingFitPitch);
113  (void) pointingClusterMap.insert(ThreeDPointingClusterMap::value_type(pPfo, LArPointingCluster(slidingFitResult)));
114  }
115  catch (const StatusCodeException &) {}
116  }
117 }
118 
119 //------------------------------------------------------------------------------------------------------------------------------------------
120 
121 void StitchingCosmicRayMergingTool::BuildTPCMaps(const PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, LArTPCToPfoMap &larTPCToPfoMap) const
122 {
123  for (const ParticleFlowObject *const pPfo : inputPfoList)
124  {
125  PfoToLArTPCMap::const_iterator iter(pfoToLArTPCMap.find(pPfo));
126 
127  if (pfoToLArTPCMap.end() != iter)
128  larTPCToPfoMap[iter->second].push_back(pPfo);
129  }
130 }
131 
132 //------------------------------------------------------------------------------------------------------------------------------------------
133 
135  PfoAssociationMatrix &pfoAssociationMatrix) const
136 {
137  LArTPCVector larTPCVector;
138  for (const auto &mapEntry : larTPCToPfoMap) larTPCVector.push_back(mapEntry.first);
139  std::sort(larTPCVector.begin(), larTPCVector.end(), LArStitchingHelper::SortTPCs);
140 
141  for (LArTPCVector::const_iterator tpcIter1 = larTPCVector.begin(), tpcIterEnd = larTPCVector.end(); tpcIter1 != tpcIterEnd; ++tpcIter1)
142  {
143  const LArTPC *const pLArTPC1(*tpcIter1);
144  const PfoList &pfoList1(larTPCToPfoMap.at(pLArTPC1));
145 
146  for (LArTPCVector::const_iterator tpcIter2 = tpcIter1; tpcIter2 != tpcIterEnd; ++tpcIter2)
147  {
148  const LArTPC *const pLArTPC2(*tpcIter2);
149  const PfoList &pfoList2(larTPCToPfoMap.at(pLArTPC2));
150 
151  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPC1, *pLArTPC2))
152  continue;
153 
154  for (const ParticleFlowObject *const pPfo1 : pfoList1)
155  {
156  for (const ParticleFlowObject *const pPfo2 : pfoList2)
157  this->CreatePfoMatches(*pLArTPC1, *pLArTPC2, pPfo1, pPfo2, pointingClusterMap, pfoAssociationMatrix);
158  }
159  }
160  }
161 }
162 
163 //------------------------------------------------------------------------------------------------------------------------------------------
164 
165 void StitchingCosmicRayMergingTool::CreatePfoMatches(const LArTPC &larTPC1, const LArTPC &larTPC2,
166  const ParticleFlowObject *const pPfo1, const ParticleFlowObject *const pPfo2,
167  const ThreeDPointingClusterMap &pointingClusterMap, PfoAssociationMatrix &pfoAssociationMatrix) const
168 {
169  // Get centre and width of boundary between tpcs
170  const float boundaryCenterX(LArStitchingHelper::GetTPCBoundaryCenterX(larTPC1, larTPC2));
171  const float boundaryWidthX(LArStitchingHelper::GetTPCBoundaryWidthX(larTPC1, larTPC2));
172  const float maxLongitudinalDisplacementX(m_maxLongitudinalDisplacementX + boundaryWidthX);
173 
174  // Get the pointing cluster corresponding to each of these Pfos
175  ThreeDPointingClusterMap::const_iterator iter1 = pointingClusterMap.find(pPfo1);
176  ThreeDPointingClusterMap::const_iterator iter2 = pointingClusterMap.find(pPfo2);
177 
178  if (pointingClusterMap.end() == iter1 || pointingClusterMap.end() == iter2)
179  return;
180 
181  const LArPointingCluster &pointingCluster1(iter1->second);
182  const LArPointingCluster &pointingCluster2(iter2->second);
183 
184  // Check length of pointing clusters
185  if (pointingCluster1.GetLengthSquared() < m_minLengthSquared || pointingCluster2.GetLengthSquared() < m_minLengthSquared)
186  return;
187 
188  // Get closest pair of vertices
189  LArPointingCluster::Vertex pointingVertex1, pointingVertex2;
190 
191  try
192  {
193  LArStitchingHelper::GetClosestVertices(larTPC1, larTPC2, pointingCluster1, pointingCluster2, pointingVertex1, pointingVertex2);
194  }
195  catch (const pandora::StatusCodeException &)
196  {
197  return;
198  }
199 
200  // Pointing clusters must have a parallel direction
201  const float cosRelativeAngle(-pointingVertex1.GetDirection().GetDotProduct(pointingVertex2.GetDirection()));
202 
203  if (cosRelativeAngle < m_relaxCosRelativeAngle)
204  return;
205 
206  // Pointing clusters must have a non-zero X direction (so that they point across drift volume boundary)
207  const float pX1(std::fabs(pointingVertex1.GetDirection().GetX()));
208  const float pX2(std::fabs(pointingVertex2.GetDirection().GetX()));
209 
210  if (pX1 < std::numeric_limits<float>::epsilon() || pX2 < std::numeric_limits<float>::epsilon())
211  return;
212 
213  // Pointing clusters must intersect at a drift volume boundary
214  const float intersectX(0.5 * (pointingVertex1.GetPosition().GetX() + pointingVertex2.GetPosition().GetX()));
215 
216  if (std::fabs(intersectX - boundaryCenterX) > maxLongitudinalDisplacementX)
217  return;
218 
219  // Impact parameters
220  float rT1(0.f), rL1(0.f), rT2(0.f), rL2(0.f);
221 
222  try
223  {
224  if (m_useXcoordinate)
225  {
226  LArPointingClusterHelper::GetImpactParameters(pointingVertex1, pointingVertex2, rL1, rT1);
227  LArPointingClusterHelper::GetImpactParameters(pointingVertex2, pointingVertex1, rL2, rT2);
228  }
229  else
230  {
231  LArPointingClusterHelper::GetImpactParametersInYZ(pointingVertex1, pointingVertex2, rL1, rT1);
232  LArPointingClusterHelper::GetImpactParametersInYZ(pointingVertex2, pointingVertex1, rL2, rT2);
233  }
234  }
235  catch (const pandora::StatusCodeException &)
236  {
237  return;
238  }
239 
240  // Selection cuts on longitudinal impact parameters
241  const float minL(-1.f);
242  const float dXdL1(m_useXcoordinate ? pX1 :
243  (1.f - pX1 * pX1 > std::numeric_limits<float>::epsilon()) ? pX1 / std::sqrt(1.f - pX1 * pX1) : minL);
244  const float dXdL2(m_useXcoordinate ? pX2 :
245  (1.f - pX2 * pX2 > std::numeric_limits<float>::epsilon()) ? pX2 / std::sqrt(1.f - pX2 * pX2) : minL);
246  const float maxL1(maxLongitudinalDisplacementX / dXdL1);
247  const float maxL2(maxLongitudinalDisplacementX / dXdL2);
248 
249  if (rL1 < minL || rL1 > maxL1 || rL2 < minL || rL2 > maxL2)
250  return;
251 
252  // Selection cuts on transverse impact parameters
253  const bool minPass(std::min(rT1, rT2) < m_relaxTransverseDisplacement && cosRelativeAngle > m_relaxCosRelativeAngle);
254  const bool maxPass(std::max(rT1, rT2) < m_maxTransverseDisplacement && cosRelativeAngle > m_minCosRelativeAngle);
255 
256  if (!minPass && !maxPass)
257  return;
258 
259  // Store this association
262 
263  const float particleLength1(pointingCluster1.GetLengthSquared());
264  const float particleLength2(pointingCluster2.GetLengthSquared());
265 
266  pfoAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pPfo2, PfoAssociation(vertexType1, vertexType2, particleLength2)));
267  pfoAssociationMatrix[pPfo2].insert(PfoAssociationMap::value_type(pPfo1, PfoAssociation(vertexType2, vertexType1, particleLength1)));
268 }
269 
270 //------------------------------------------------------------------------------------------------------------------------------------------
271 
272 void StitchingCosmicRayMergingTool::SelectPfoMatches(const PfoAssociationMatrix &pfoAssociationMatrix, PfoMergeMap &pfoMatches) const
273 {
274  // First step: loop over association matrix and find best associations A -> X and B -> Y
275  // =====================================================================================
276  PfoAssociationMatrix bestAssociationMatrix;
277 
278  PfoVector pfoVector1;
279  for (const auto &mapEntry : pfoAssociationMatrix) pfoVector1.push_back(mapEntry.first);
280  std::sort(pfoVector1.begin(), pfoVector1.end(), LArPfoHelper::SortByNHits);
281 
282  for (const ParticleFlowObject *const pPfo1 : pfoVector1)
283  {
284  const PfoAssociationMap &pfoAssociationMap(pfoAssociationMatrix.at(pPfo1));
285 
286  const ParticleFlowObject *pBestPfoInner(nullptr);
288 
289  const ParticleFlowObject *pBestPfoOuter(nullptr);
291 
292  PfoVector pfoVector2;
293  for (const auto &mapEntry : pfoAssociationMap) pfoVector2.push_back(mapEntry.first);
294  std::sort(pfoVector2.begin(), pfoVector2.end(), LArPfoHelper::SortByNHits);
295 
296  for (const ParticleFlowObject *const pPfo2 : pfoVector2)
297  {
298  const PfoAssociation &pfoAssociation(pfoAssociationMap.at(pPfo2));
299 
300  // Inner associations
301  if (pfoAssociation.GetParent() == PfoAssociation::INNER)
302  {
303  if (pfoAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
304  {
305  bestAssociationInner = pfoAssociation;
306  pBestPfoInner = pPfo2;
307  }
308  }
309 
310  // Outer associations
311  if (pfoAssociation.GetParent() == PfoAssociation::OUTER)
312  {
313  if (pfoAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
314  {
315  bestAssociationOuter = pfoAssociation;
316  pBestPfoOuter = pPfo2;
317  }
318  }
319  }
320 
321  if (pBestPfoInner)
322  (void) bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoInner, bestAssociationInner));
323 
324  if (pBestPfoOuter)
325  (void) bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoOuter, bestAssociationOuter));
326  }
327 
328  // Second step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
329  // =============================================================================
330  PfoVector pfoVector3;
331  for (const auto &mapEntry : bestAssociationMatrix) pfoVector3.push_back(mapEntry.first);
332  std::sort(pfoVector3.begin(), pfoVector3.end(), LArPfoHelper::SortByNHits);
333 
334  for (const ParticleFlowObject *const pParentPfo : pfoVector3)
335  {
336  const PfoAssociationMap &parentAssociationMap(bestAssociationMatrix.at(pParentPfo));
337 
338  PfoVector pfoVector4;
339  for (const auto &mapEntry : parentAssociationMap) pfoVector4.push_back(mapEntry.first);
340  std::sort(pfoVector4.begin(), pfoVector4.end(), LArPfoHelper::SortByNHits);
341 
342  for (const ParticleFlowObject *const pDaughterPfo : pfoVector4)
343  {
344  const PfoAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterPfo));
345  PfoAssociationMatrix::const_iterator iter5 = bestAssociationMatrix.find(pDaughterPfo);
346 
347  if (bestAssociationMatrix.end() == iter5)
348  continue;
349 
350  const PfoAssociationMap &daughterAssociationMap(iter5->second);
351 
352  PfoAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentPfo);
353  if (daughterAssociationMap.end() == iter6)
354  continue;
355 
356  const PfoAssociation &daughterToParentAssociation(iter6->second);
357 
358  if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
359  parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
360  {
361  pfoMatches[pParentPfo].push_back(pDaughterPfo);
362  }
363  }
364  }
365 }
366 
367 //------------------------------------------------------------------------------------------------------------------------------------------
368 
370 {
371  PfoSet vetoSet;
372 
373  PfoVector inputPfoVector;
374  for (const auto &mapEntry : pfoMatches) inputPfoVector.push_back(mapEntry.first);
375  std::sort(inputPfoVector.begin(), inputPfoVector.end(), LArPfoHelper::SortByNHits);
376 
377  for (const ParticleFlowObject *const pInputPfo : inputPfoVector)
378  {
379  const PfoList &pfoList(pfoMatches.at(pInputPfo));
380 
381  for (const ParticleFlowObject *const pSeedPfo : pfoList)
382  {
383  if (vetoSet.count(pSeedPfo))
384  continue;
385 
386  PfoList mergeList;
387  this->CollectAssociatedPfos(pSeedPfo, pSeedPfo, pfoMatches, vetoSet, mergeList);
388 
389  vetoSet.insert(pSeedPfo);
390  PfoList &selectedPfoList(pfoMerges[pSeedPfo]);
391  selectedPfoList.push_back(pSeedPfo);
392 
393  for (const ParticleFlowObject *const pAssociatedPfo : mergeList)
394  {
395  // Check if particle has already been counted
396  if (vetoSet.count(pAssociatedPfo) || (selectedPfoList.end() != std::find(selectedPfoList.begin(), selectedPfoList.end(), pAssociatedPfo)))
397  throw StatusCodeException(STATUS_CODE_FAILURE);
398 
399  vetoSet.insert(pAssociatedPfo);
400  selectedPfoList.push_back(pAssociatedPfo);
401  }
402  }
403  }
404 }
405 
406 //------------------------------------------------------------------------------------------------------------------------------------------
407 
408 void StitchingCosmicRayMergingTool::CollectAssociatedPfos(const ParticleFlowObject *const pSeedPfo, const ParticleFlowObject *const pCurrentPfo,
409  const PfoMergeMap &pfoMergeMap, const PfoSet &vetoSet, PfoList &associatedList) const
410 {
411  if (vetoSet.count(pCurrentPfo))
412  return;
413 
414  PfoMergeMap::const_iterator iter1 = pfoMergeMap.find(pCurrentPfo);
415 
416  if (pfoMergeMap.end() == iter1)
417  return;
418 
419  for (PfoList::const_iterator iter2 = iter1->second.begin(), iterEnd2 = iter1->second.end(); iter2 != iterEnd2; ++iter2)
420  {
421  const ParticleFlowObject *const pAssociatedPfo = *iter2;
422 
423  if (pAssociatedPfo == pSeedPfo)
424  continue;
425 
426  if (associatedList.end() != std::find(associatedList.begin(), associatedList.end(), pAssociatedPfo))
427  continue;
428 
429  associatedList.push_back(pAssociatedPfo);
430 
431  this->CollectAssociatedPfos(pSeedPfo, pAssociatedPfo, pfoMergeMap, vetoSet, associatedList);
432  }
433 }
434 
435 //------------------------------------------------------------------------------------------------------------------------------------------
436 
437 void StitchingCosmicRayMergingTool::OrderPfoMerges(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap,
438  const PfoMergeMap &inputPfoMerges, PfoMergeMap &outputPfoMerges) const
439 {
440  PfoVector inputPfoVector;
441  for (const auto &mapEntry : inputPfoMerges) inputPfoVector.push_back(mapEntry.first);
442  std::sort(inputPfoVector.begin(), inputPfoVector.end(), LArPfoHelper::SortByNHits);
443 
444  for (const ParticleFlowObject *const pInputPfo : inputPfoVector)
445  {
446  const PfoList &pfoList(inputPfoMerges.at(pInputPfo));
447 
448  float bestLength(0.f);
449  const ParticleFlowObject *pVertexPfo = nullptr;
450 
451  for (PfoList::const_iterator iter1 = pfoList.begin(), iterEnd = pfoList.end(); iter1 != iterEnd; ++iter1)
452  {
453  const ParticleFlowObject *const pPfo1(*iter1);
454  PfoToLArTPCMap::const_iterator tpcIter1 = pfoToLArTPCMap.find(pPfo1);
455  ThreeDPointingClusterMap::const_iterator pointingIter1 = pointingClusterMap.find(pPfo1);
456 
457  if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
458  throw StatusCodeException(STATUS_CODE_FAILURE);
459 
460  const LArTPC *const pLArTPC1(tpcIter1->second);
461  const LArPointingCluster &pointingCluster1(pointingIter1->second);
462 
463  for (PfoList::const_iterator iter2 = iter1; iter2 != iterEnd; ++iter2)
464  {
465  const ParticleFlowObject *const pPfo2(*iter2);
466  PfoToLArTPCMap::const_iterator tpcIter2 = pfoToLArTPCMap.find(pPfo2);
467  ThreeDPointingClusterMap::const_iterator pointingIter2 = pointingClusterMap.find(pPfo2);
468 
469  if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
470  throw StatusCodeException(STATUS_CODE_FAILURE);
471 
472  const LArTPC *const pLArTPC2(tpcIter2->second);
473  const LArPointingCluster &pointingCluster2(pointingIter2->second);
474 
475  if (pLArTPC1 == pLArTPC2)
476  continue;
477 
478  const float thisLength(LArStitchingHelper::GetTPCDisplacement(*pLArTPC1, *pLArTPC2));
479 
480  if (thisLength < bestLength)
481  continue;
482 
483  bestLength = thisLength;
484 
485  try
486  {
487  pVertexPfo = nullptr;
488 
489  LArPointingCluster::Vertex nearVertex1, nearVertex2;
490  LArStitchingHelper::GetClosestVertices(*pLArTPC1, *pLArTPC2, pointingCluster1, pointingCluster2, nearVertex1, nearVertex2);
491 
492  const LArPointingCluster::Vertex &farVertex1(nearVertex1.IsInnerVertex() ? pointingCluster1.GetOuterVertex() : pointingCluster1.GetInnerVertex());
493  const LArPointingCluster::Vertex &farVertex2(nearVertex2.IsInnerVertex() ? pointingCluster2.GetOuterVertex() : pointingCluster2.GetInnerVertex());
494  const float deltaY(farVertex1.GetPosition().GetY() - farVertex2.GetPosition().GetY());
495 
496  if (std::fabs(deltaY) < std::numeric_limits<float>::epsilon())
497  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
498 
499  pVertexPfo = ((deltaY > 0.f) ? pPfo1 : pPfo2);
500  }
501  catch (const pandora::StatusCodeException &) {}
502  }
503  }
504 
505  if (pVertexPfo)
506  outputPfoMerges[pVertexPfo].insert(outputPfoMerges[pVertexPfo].begin(), pfoList.begin(), pfoList.end());
507  }
508 }
509 
510 //------------------------------------------------------------------------------------------------------------------------------------------
511 
512 void StitchingCosmicRayMergingTool::StitchPfos(const MasterAlgorithm *const pAlgorithm, const ThreeDPointingClusterMap &pointingClusterMap,
513  const PfoMergeMap &pfoMerges, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map) const
514 {
515  PfoVector pfoVectorToEnlarge;
516  for (const auto &mapEntry : pfoMerges) pfoVectorToEnlarge.push_back(mapEntry.first);
517  std::sort(pfoVectorToEnlarge.begin(), pfoVectorToEnlarge.end(), LArPfoHelper::SortByNHits);
518 
519  for (const ParticleFlowObject *const pPfoToEnlarge : pfoVectorToEnlarge)
520  {
521  const PfoList &pfoList(pfoMerges.at(pPfoToEnlarge));
522 
523  PfoVector pfoVector;
524  for (const ParticleFlowObject *const pPfo : pfoList) pfoVector.push_back(pPfo);
525  std::sort(pfoVector.begin(), pfoVector.end(), LArPfoHelper::SortByNHits);
526 
527  float x0(0.f);
528 
529  if (!m_useXcoordinate)
530  {
531  try
532  {
533  this->CalculateX0(pfoToLArTPCMap, pointingClusterMap, pfoVector, x0);
534  }
535  catch (const pandora::StatusCodeException &)
536  {
537  continue;
538  }
539 
540  for (const ParticleFlowObject *const pPfoToShift : pfoVector)
541  pAlgorithm->ShiftPfoHierarchy(pPfoToShift, pfoToLArTPCMap, x0);
542  }
543 
544  for (const ParticleFlowObject *const pPfoToDelete : pfoVector)
545  {
546  if (pPfoToEnlarge == pPfoToDelete)
547  continue;
548 
549  pAlgorithm->StitchPfos(pPfoToEnlarge, pPfoToDelete, pfoToLArTPCMap);
550  stitchedPfosToX0Map.insert(PfoToFloatMap::value_type(pPfoToEnlarge, x0));
551  }
552  }
553 }
554 
555 //------------------------------------------------------------------------------------------------------------------------------------------
556 
557 void StitchingCosmicRayMergingTool::CalculateX0(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap,
558  const PfoVector &pfoVector, float &x0) const
559 {
560  float sumX(0.f), sumN(0.f);
561 
562  for (PfoVector::const_iterator iter1 = pfoVector.begin(), iterEnd = pfoVector.end(); iter1 != iterEnd; ++iter1)
563  {
564  const ParticleFlowObject *const pPfo1(*iter1);
565  PfoToLArTPCMap::const_iterator tpcIter1 = pfoToLArTPCMap.find(pPfo1);
566  ThreeDPointingClusterMap::const_iterator pointingIter1 = pointingClusterMap.find(pPfo1);
567 
568  if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
569  throw StatusCodeException(STATUS_CODE_FAILURE);
570 
571  const LArTPC *const pLArTPC1(tpcIter1->second);
572  const LArPointingCluster &pointingCluster1(pointingIter1->second);
573 
574  for (PfoVector::const_iterator iter2 = iter1; iter2 != iterEnd; ++iter2)
575  {
576  const ParticleFlowObject *const pPfo2(*iter2);
577  PfoToLArTPCMap::const_iterator tpcIter2 = pfoToLArTPCMap.find(pPfo2);
578  ThreeDPointingClusterMap::const_iterator pointingIter2 = pointingClusterMap.find(pPfo2);
579 
580  if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
581  throw StatusCodeException(STATUS_CODE_FAILURE);
582 
583  const LArTPC *const pLArTPC2(tpcIter2->second);
584  const LArPointingCluster &pointingCluster2(pointingIter2->second);
585 
586  if (!LArStitchingHelper::CanTPCsBeStitched(*pLArTPC1, *pLArTPC2))
587  continue;
588 
589  // Calculate X0 for the closest pair of vertices
590  LArPointingCluster::Vertex pointingVertex1, pointingVertex2;
591 
592  try
593  {
594  LArStitchingHelper::GetClosestVertices(*pLArTPC1, *pLArTPC2, pointingCluster1, pointingCluster2,
595  pointingVertex1, pointingVertex2);
596 
597  const float thisX0(LArStitchingHelper::CalculateX0(*pLArTPC1, *pLArTPC2, pointingVertex1, pointingVertex2));
598  sumX += thisX0; sumN += 1.f;
599  }
600  catch (const pandora::StatusCodeException &) {}
601  }
602  }
603 
604  if ((sumN < std::numeric_limits<float>::epsilon()) || (std::fabs(sumX) < std::numeric_limits<float>::epsilon()))
605  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
606 
607  x0 = (sumX / sumN);
608 }
609 
610 //------------------------------------------------------------------------------------------------------------------------------------------
611 //------------------------------------------------------------------------------------------------------------------------------------------
612 
614  m_parent(parent),
615  m_daughter(daughter),
616  m_fom(fom)
617 {
618 }
619 
620 //------------------------------------------------------------------------------------------------------------------------------------------
621 
623 {
624  return m_parent;
625 }
626 
627 //------------------------------------------------------------------------------------------------------------------------------------------
628 
630 {
631  return m_daughter;
632 }
633 
634 //------------------------------------------------------------------------------------------------------------------------------------------
635 
637 {
638  return m_fom;
639 }
640 
641 //------------------------------------------------------------------------------------------------------------------------------------------
642 //------------------------------------------------------------------------------------------------------------------------------------------
643 
644 StatusCode StitchingCosmicRayMergingTool::ReadSettings(const TiXmlHandle xmlHandle)
645 {
646  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
647  "ThreeDStitchingMode", m_useXcoordinate));
648 
649  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
650  "HalfWindowLayers", m_halfWindowLayers));
651 
652  float minLength(std::sqrt(m_minLengthSquared));
653  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
654  "MinPfoLength", minLength));
655  m_minLengthSquared = minLength * minLength;
656 
657  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
658  "MinCosRelativeAngle", m_minCosRelativeAngle));
659 
660  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
661  "MaxLongitudinalDisplacementX", m_maxLongitudinalDisplacementX));
662 
663  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
664  "MaxTransverseDisplacement", m_maxTransverseDisplacement));
665 
666  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
667  "LooserMinCosRelativeAngle", m_relaxCosRelativeAngle));
668 
669  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
670  "LooserMaxTransverseDisplacement", m_relaxTransverseDisplacement));
671 
672  return STATUS_CODE_SUCCESS;
673 }
674 
675 } // namespace lar_content
std::unordered_map< const pandora::ParticleFlowObject *, LArPointingCluster > ThreeDPointingClusterMap
void SelectPrimaryPfos(const pandora::PfoList *pInputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, pandora::PfoList &outputPfoList) const
Select primary Pfos from the input list of Pfos.
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)
std::unordered_map< const pandora::ParticleFlowObject *, pandora::PfoList > PfoMergeMap
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.
std::unordered_map< const pandora::LArTPC *, pandora::PfoList > LArTPCToPfoMap
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.
LArPointingCluster class.
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
std::unordered_map< const pandora::ParticleFlowObject *, float > PfoToFloatMap
void CreatePfoMatches(const LArTPCToPfoMap &larTPCToPfoMap, const ThreeDPointingClusterMap &pointingClusterMap, PfoAssociationMatrix &pfoAssociationMatrix) const
Create associations between Pfos using 3D pointing clusters.
void BuildTPCMaps(const pandora::PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, LArTPCToPfoMap &larTPCToPfoMap) const
Build a list of Pfos for each tpc.
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...
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
Int_t max
Definition: plot.C:27
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
void CalculateX0(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap, const pandora::PfoVector &pfoVector, float &x0) const
Calculate x0 shift for a group of associated Pfos.
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.
std::unordered_map< const pandora::ParticleFlowObject *, PfoAssociation > PfoAssociationMap
static float GetTPCDisplacement(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Calculate distance between central positions of a pair of tpcs.
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
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.
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.
Int_t min
Definition: plot.C:26
MasterAlgorithm class.
static bool IsFinalState(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a primary parent particle.
std::unordered_map< const pandora::ParticleFlowObject *, const pandora::LArTPC * > PfoToLArTPCMap
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.
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.
std::unordered_map< const pandora::ParticleFlowObject *, PfoAssociationMap > PfoAssociationMatrix
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.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.