LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
CosmicRaySplittingAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
16 
17 using namespace pandora;
18 
19 namespace lar_content
20 {
21 
22 CosmicRaySplittingAlgorithm::CosmicRaySplittingAlgorithm() :
23  m_clusterMinLength(10.f),
24  m_halfWindowLayers(30),
25  m_samplingPitch(1.f),
26  m_maxCosSplittingAngle(0.9925f),
27  m_minCosMergingAngle(0.94f),
28  m_maxTransverseDisplacement(5.f),
29  m_maxLongitudinalDisplacement(30.f),
30  m_maxLongitudinalDisplacementSquared(m_maxLongitudinalDisplacement * m_maxLongitudinalDisplacement)
31 {
32 }
33 
34 //------------------------------------------------------------------------------------------------------------------------------------------
35 
37 {
38  const ClusterList *pClusterList = NULL;
39  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pClusterList));
40 
41  // Get ordered list of clean clusters
42  ClusterVector clusterVector;
43  this->GetListOfCleanClusters(pClusterList, clusterVector);
44 
45  // Calculate sliding fit results for clean clusters
46  TwoDSlidingFitResultMap slidingFitResultMap;
47  this->BuildSlidingFitResultMap(clusterVector, slidingFitResultMap);
48 
49  // Loop over clusters, identify and perform splits
50  ClusterSet splitClusters;
51 
52  for (ClusterVector::const_iterator bIter = clusterVector.begin(), bIterEnd1 = clusterVector.end(); bIter != bIterEnd1; ++bIter)
53  {
54  if (splitClusters.count(*bIter) > 0)
55  continue;
56 
57  TwoDSlidingFitResultMap::const_iterator bFitIter = slidingFitResultMap.find(*bIter);
58 
59  if (slidingFitResultMap.end() == bFitIter)
60  continue;
61 
62  const TwoDSlidingFitResult &branchSlidingFitResult(bFitIter->second);
63 
64  // Find best split position for candidate branch cluster
65  CartesianVector splitPosition(0.f,0.f,0.f);
66  CartesianVector splitDirection1(0.f,0.f,0.f);
67  CartesianVector splitDirection2(0.f,0.f,0.f);
68 
69  if (STATUS_CODE_SUCCESS != this->FindBestSplitPosition(branchSlidingFitResult, splitPosition, splitDirection1, splitDirection2))
70  continue;
71 
72  // Find candidate replacement clusters to merge into branch cluster at the split position
73  TwoDSlidingFitResultMap::const_iterator bestReplacementIter1(slidingFitResultMap.end());
74  TwoDSlidingFitResultMap::const_iterator bestReplacementIter2(slidingFitResultMap.end());
75 
76  float bestLengthSquared1(m_maxLongitudinalDisplacementSquared);
77  float bestLengthSquared2(m_maxLongitudinalDisplacementSquared);
78 
79  for (ClusterVector::const_iterator rIter = clusterVector.begin(), rIterEnd = clusterVector.end(); rIter != rIterEnd; ++rIter)
80  {
81  if (splitClusters.count(*rIter) > 0)
82  continue;
83 
84  TwoDSlidingFitResultMap::const_iterator rFitIter = slidingFitResultMap.find(*rIter);
85 
86  if (slidingFitResultMap.end() == rFitIter)
87  continue;
88 
89  const TwoDSlidingFitResult &replacementSlidingFitResult(rFitIter->second);
90 
91  if (branchSlidingFitResult.GetCluster() == replacementSlidingFitResult.GetCluster())
92  continue;
93 
94  float lengthSquared1(std::numeric_limits<float>::max());
95  float lengthSquared2(std::numeric_limits<float>::max());
96 
97  if (STATUS_CODE_SUCCESS != this->ConfirmSplitPosition(branchSlidingFitResult, replacementSlidingFitResult,
98  splitPosition, splitDirection1, splitDirection2, lengthSquared1, lengthSquared2))
99  continue;
100 
101  if (lengthSquared1 < bestLengthSquared1)
102  {
103  bestLengthSquared1 = lengthSquared1;
104  bestReplacementIter1 = rFitIter;
105  }
106 
107  if (lengthSquared2 < bestLengthSquared2)
108  {
109  bestLengthSquared2 = lengthSquared2;
110  bestReplacementIter2 = rFitIter;
111  }
112  }
113 
114  const Cluster *pReplacementCluster1 = NULL;
115  const Cluster *pReplacementCluster2 = NULL;
116 
117  if (slidingFitResultMap.end() != bestReplacementIter1)
118  pReplacementCluster1 = bestReplacementIter1->first;
119 
120  if (slidingFitResultMap.end() != bestReplacementIter2)
121  pReplacementCluster2 = bestReplacementIter2->first;
122 
123  if (NULL == pReplacementCluster1 && NULL == pReplacementCluster2)
124  continue;
125 
126  const Cluster *const pBranchCluster = branchSlidingFitResult.GetCluster();
127 
128  // Crossed tracks
129  if (pReplacementCluster1 && pReplacementCluster2)
130  {
131  if (!(this->IdentifyCrossedTracks(pBranchCluster, pReplacementCluster1, pReplacementCluster2, splitPosition)))
132  continue;
133 
134  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->PerformDoubleSplit(pBranchCluster, pReplacementCluster1,
135  pReplacementCluster2, splitPosition, splitDirection1, splitDirection2));
136  }
137  // Single scatter
138  else if (pReplacementCluster1)
139  {
140  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->PerformSingleSplit(pBranchCluster, pReplacementCluster1,
141  splitPosition, splitDirection1, splitDirection2));
142  }
143  else if (pReplacementCluster2)
144  {
145  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->PerformSingleSplit(pBranchCluster, pReplacementCluster2,
146  splitPosition, splitDirection2, splitDirection1));
147  }
148 
149  // Choose not to re-use clusters (for now)
150  if (pReplacementCluster1)
151  splitClusters.insert(pReplacementCluster1);
152 
153  if (pReplacementCluster2)
154  splitClusters.insert(pReplacementCluster2);
155 
156  splitClusters.insert(pBranchCluster);
157  }
158 
159  return STATUS_CODE_SUCCESS;
160 }
161 
162 //------------------------------------------------------------------------------------------------------------------------------------------
163 
164 void CosmicRaySplittingAlgorithm::GetListOfCleanClusters(const ClusterList *const pClusterList, ClusterVector &clusterVector) const
165 {
166  for (ClusterList::const_iterator iter = pClusterList->begin(), iterEnd = pClusterList->end(); iter != iterEnd; ++iter)
167  {
168  const Cluster *const pCluster = *iter;
169 
171  continue;
172 
173  clusterVector.push_back(pCluster);
174  }
175 
176  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
177 }
178 
179 //------------------------------------------------------------------------------------------------------------------------------------------
180 
182  TwoDSlidingFitResultMap &slidingFitResultMap) const
183 {
184  const float slidingFitPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
185 
186  for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
187  {
188  if (slidingFitResultMap.end() == slidingFitResultMap.find(*iter))
189  {
190  try
191  {
192  const TwoDSlidingFitResult slidingFitResult(*iter, m_halfWindowLayers, slidingFitPitch);
193 
194  if (!slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(*iter, slidingFitResult)).second)
195  throw StatusCodeException(STATUS_CODE_FAILURE);
196  }
197  catch (StatusCodeException &statusCodeException)
198  {
199  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
200  throw statusCodeException;
201  }
202  }
203  }
204 }
205 
206 //------------------------------------------------------------------------------------------------------------------------------------------
207 
208 StatusCode CosmicRaySplittingAlgorithm::FindBestSplitPosition(const TwoDSlidingFitResult &branchSlidingFitResult, CartesianVector &splitPosition,
209  CartesianVector &splitDirection1, CartesianVector &splitDirection2) const
210 {
211  // Find position of greatest scatter for this cluster
212  float splitCosTheta(m_maxCosSplittingAngle);
213  bool foundSplit(false);
214 
215  const CartesianVector &minPosition(branchSlidingFitResult.GetGlobalMinLayerPosition());
216  const CartesianVector &maxPosition(branchSlidingFitResult.GetGlobalMaxLayerPosition());
217  const float halfWindowLength(branchSlidingFitResult.GetLayerFitHalfWindowLength());
218 
219  float minL(0.f), maxL(0.f), minT(0.f), maxT(0.f);
220  branchSlidingFitResult.GetLocalPosition(minPosition, minL, minT);
221  branchSlidingFitResult.GetLocalPosition(maxPosition, maxL, maxT);
222 
223  const unsigned int nSamplingPoints = static_cast<unsigned int>((maxL - minL)/ m_samplingPitch);
224 
225  for (unsigned int n = 0; n < nSamplingPoints; ++n)
226  {
227  const float alpha((0.5f + static_cast<float>(n)) / static_cast<float>(nSamplingPoints));
228  const float rL(minL + (maxL - minL) * alpha);
229 
230  CartesianVector centralPosition(0.f,0.f,0.f), forwardDirection(0.f,0.f,0.f), backwardDirection(0.f,0.f,0.f);
231 
232  if ((STATUS_CODE_SUCCESS != branchSlidingFitResult.GetGlobalFitPosition(rL, centralPosition)) ||
233  (STATUS_CODE_SUCCESS != branchSlidingFitResult.GetGlobalFitDirection(rL + halfWindowLength, forwardDirection)) ||
234  (STATUS_CODE_SUCCESS != branchSlidingFitResult.GetGlobalFitDirection(rL - halfWindowLength, backwardDirection)))
235  {
236  continue;
237  }
238 
239  const float cosTheta(forwardDirection.GetDotProduct(backwardDirection));
240 
241  if (cosTheta < splitCosTheta)
242  {
243  CartesianVector forwardPosition(0.f,0.f,0.f);
244  CartesianVector backwardPosition(0.f,0.f,0.f);
245 
246  if ((STATUS_CODE_SUCCESS != branchSlidingFitResult.GetGlobalFitPosition(rL + halfWindowLength, forwardPosition)) ||
247  (STATUS_CODE_SUCCESS != branchSlidingFitResult.GetGlobalFitPosition(rL - halfWindowLength, backwardPosition)))
248  {
249  continue;
250  }
251 
252  CartesianVector forwardVectorOutwards(forwardPosition - centralPosition);
253  CartesianVector backwardVectorOutwards(backwardPosition - centralPosition);
254 
255  splitPosition = centralPosition;
256  splitDirection1 = (forwardDirection.GetDotProduct(forwardVectorOutwards) > 0.f) ? forwardDirection : forwardDirection * -1.f;
257  splitDirection2 = (backwardDirection.GetDotProduct(backwardVectorOutwards) > 0.f) ? backwardDirection : backwardDirection * -1.f;
258  splitCosTheta = cosTheta;
259  foundSplit = true;
260  }
261  }
262 
263  if (!foundSplit)
264  return STATUS_CODE_NOT_FOUND;
265 
266  return STATUS_CODE_SUCCESS;
267 }
268 
269 //------------------------------------------------------------------------------------------------------------------------------------------
270 
272  const TwoDSlidingFitResult &replacementSlidingFitResult, const CartesianVector &splitPosition, const CartesianVector &splitDirection1,
273  const CartesianVector &splitDirection2, float &bestLengthSquared1, float &bestLengthSquared2) const
274 {
275  // Check if the replacement cluster points to the split position on the branch cluster
276  bestLengthSquared1 = std::numeric_limits<float>::max();
277  bestLengthSquared2 = std::numeric_limits<float>::max();
278 
279  bool foundMatch(false);
280 
281  const CartesianVector minPosition(replacementSlidingFitResult.GetGlobalMinLayerPosition());
282  const CartesianVector maxPosition(replacementSlidingFitResult.GetGlobalMaxLayerPosition());
283  const CartesianVector minDirection(replacementSlidingFitResult.GetGlobalMinLayerDirection());
284  const CartesianVector maxDirection(replacementSlidingFitResult.GetGlobalMaxLayerDirection());
285 
286  const CartesianVector branchVertex1(branchSlidingFitResult.GetGlobalMinLayerPosition());
287  const CartesianVector branchVertex2(branchSlidingFitResult.GetGlobalMaxLayerPosition());
288  const CartesianVector branchDirection1(splitDirection1 * -1.f);
289  const CartesianVector branchDirection2(splitDirection2 * -1.f);
290 
291  const float cosSplittingAngle(-splitDirection1.GetDotProduct(splitDirection2));
292  const float branchLengthSquared((branchVertex2 - branchVertex1).GetMagnitudeSquared());
293  const float replacementLengthSquared((maxPosition - minPosition).GetMagnitudeSquared());
294 
295  // Loop over each end of the replacement cluster
296  for (unsigned int iFwd = 0; iFwd < 2; ++iFwd)
297  {
298  const CartesianVector pAxis((0 == iFwd) ? (maxPosition - minPosition) : (minPosition - maxPosition));
299  const CartesianVector vtxPosition((0 == iFwd) ? minPosition : maxPosition);
300  const CartesianVector endPosition((0 == iFwd) ? maxPosition : minPosition);
301  const CartesianVector vtxDirection((0 == iFwd) ? (pAxis.GetDotProduct(minDirection) > 0 ? minDirection : minDirection * -1.f) :
302  (pAxis.GetDotProduct(maxDirection) > 0 ? maxDirection : maxDirection * -1.f));
303 
304  // Choose the correct end of the replacement cluster and require proximity to the branch cluster
305  const float vtxDisplacement(LArClusterHelper::GetClosestDistance(vtxPosition, branchSlidingFitResult.GetCluster()));
306  const float endDisplacement(LArClusterHelper::GetClosestDistance(endPosition, branchSlidingFitResult.GetCluster()));
307 
308  const float lengthSquared((vtxPosition - splitPosition).GetMagnitudeSquared());
309  const float lengthSquared1((vtxPosition - branchVertex1).GetMagnitudeSquared());
310  const float lengthSquared2((vtxPosition - branchVertex2).GetMagnitudeSquared());
311 
312  if (vtxDisplacement > endDisplacement)
313  continue;
314 
315  if (std::min(lengthSquared,std::min(lengthSquared1,lengthSquared2)) > std::min(branchLengthSquared, replacementLengthSquared))
316  continue;
317 
318  // Require good pointing information between replacement cluster and candidate split position
319  float impactL(0.f), impactT(0.f);
320  LArPointingClusterHelper::GetImpactParameters(vtxPosition, vtxDirection, splitPosition, impactL, impactT);
321 
322  if (impactT > m_maxTransverseDisplacement || impactL > m_maxLongitudinalDisplacement ||
323  impactL < -1.f || impactT > std::max(1.5f, 0.577f * (1.f + impactL)))
324  continue;
325 
326  // Check the segment of the branch cluster above the split position
327  if (vtxDirection.GetDotProduct(branchDirection1) > std::max(m_minCosMergingAngle,cosSplittingAngle))
328  {
329  if (lengthSquared < bestLengthSquared1)
330  {
331  bestLengthSquared1 = lengthSquared;
332  foundMatch = true;
333  }
334  }
335 
336  // Check the segment of the branch cluster below the split position
337  if (vtxDirection.GetDotProduct(branchDirection2) > std::max(m_minCosMergingAngle,cosSplittingAngle))
338  {
339  if (lengthSquared < bestLengthSquared2)
340  {
341  bestLengthSquared2 = lengthSquared;
342  foundMatch = true;
343  }
344  }
345  }
346 
347  if (!foundMatch)
348  return STATUS_CODE_NOT_FOUND;
349 
350  return STATUS_CODE_SUCCESS;
351 }
352 
353 //------------------------------------------------------------------------------------------------------------------------------------------
354 
355 StatusCode CosmicRaySplittingAlgorithm::PerformSingleSplit(const Cluster *const pBranchCluster, const Cluster *const pReplacementCluster,
356  const CartesianVector &splitPosition, const CartesianVector &forwardDirection, const CartesianVector &backwardDirection) const
357 {
358  CaloHitList caloHitListToMove;
359  this->GetCaloHitListToMove(pBranchCluster, pReplacementCluster, splitPosition, forwardDirection, backwardDirection, caloHitListToMove);
360 
361  CaloHitList caloHitListToKeep;
362  this->GetCaloHitListToKeep(pBranchCluster, caloHitListToMove, caloHitListToKeep);
363 
364  if (caloHitListToKeep.empty())
365  return PandoraContentApi::MergeAndDeleteClusters(*this, pReplacementCluster, pBranchCluster);
366 
367  return this->SplitCluster(pBranchCluster, pReplacementCluster, caloHitListToMove);
368 }
369 
370 //------------------------------------------------------------------------------------------------------------------------------------------
371 
372 StatusCode CosmicRaySplittingAlgorithm::PerformDoubleSplit(const Cluster *const pBranchCluster, const Cluster *const pReplacementCluster1, const Cluster *const pReplacementCluster2,
373  const CartesianVector &splitPosition, const CartesianVector &splitDirection1, const CartesianVector &splitDirection2) const
374 {
375  CaloHitList caloHitListToMove1, caloHitListToMove2;
376  this->GetCaloHitListsToMove(pBranchCluster, splitPosition, splitDirection1, splitDirection2, caloHitListToMove1, caloHitListToMove2);
377 
378  CaloHitList caloHitListToKeep1;
379  this->GetCaloHitListToKeep(pBranchCluster, caloHitListToMove1, caloHitListToKeep1);
380 
381  if (caloHitListToKeep1.empty())
382  return STATUS_CODE_FAILURE;
383 
384  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->SplitCluster(pBranchCluster, pReplacementCluster1, caloHitListToMove1));
385 
386  CaloHitList caloHitListToKeep2;
387  this->GetCaloHitListToKeep(pBranchCluster, caloHitListToMove2, caloHitListToKeep2);
388 
389  if (caloHitListToKeep2.empty())
390  return PandoraContentApi::MergeAndDeleteClusters(*this, pReplacementCluster2, pBranchCluster);
391 
392  return this->SplitCluster(pBranchCluster, pReplacementCluster2, caloHitListToMove2);
393 }
394 
395 //------------------------------------------------------------------------------------------------------------------------------------------
396 
397 void CosmicRaySplittingAlgorithm::GetCaloHitListToMove(const Cluster *const pBranchCluster, const Cluster *const pReplacementCluster,
398  const CartesianVector &splitPosition, const CartesianVector &forwardDirection, const CartesianVector &backwardDirection,
399  CaloHitList &caloHitListToMove) const
400 {
401  const CartesianVector forwardPosition(LArClusterHelper::GetClosestPosition(splitPosition,pBranchCluster));
402  const CartesianVector vtxPosition(LArClusterHelper::GetClosestPosition(splitPosition,pReplacementCluster));
403  const CartesianVector vtxDirection((forwardPosition - vtxPosition).GetUnitVector());
404 
405  CaloHitList caloHitListToSort, caloHitListToCheck;
406  pBranchCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitListToSort);
407 
408  for (CaloHitList::const_iterator iter = caloHitListToSort.begin(), iterEnd = caloHitListToSort.end(); iter != iterEnd; ++iter)
409  {
410  const CaloHit *const pCaloHit = *iter;
411 
412  if (forwardDirection.GetDotProduct(pCaloHit->GetPositionVector() - forwardPosition) > 0.f)
413  {
414  caloHitListToMove.push_back(pCaloHit);
415  }
416  else if(forwardDirection.GetDotProduct(pCaloHit->GetPositionVector() - vtxPosition) > -1.25f)
417  {
418  caloHitListToCheck.push_back(pCaloHit);
419  }
420  }
421 
422  float closestLengthSquared(std::numeric_limits<float>::max());
423 
424  for (CaloHitList::const_iterator iter = caloHitListToCheck.begin(), iterEnd = caloHitListToCheck.end(); iter != iterEnd; ++iter)
425  {
426  const CaloHit *const pCaloHit = *iter;
427 
428  if (vtxDirection.GetCrossProduct(pCaloHit->GetPositionVector() - forwardPosition).GetMagnitude() >
429  backwardDirection.GetCrossProduct(pCaloHit->GetPositionVector() - forwardPosition).GetMagnitude())
430  continue;
431 
432  const float lengthSquared((pCaloHit->GetPositionVector() - vtxPosition).GetMagnitudeSquared());
433 
434  if (lengthSquared < closestLengthSquared)
435  closestLengthSquared = lengthSquared;
436  }
437 
438  for (CaloHitList::const_iterator iter = caloHitListToCheck.begin(), iterEnd = caloHitListToCheck.end(); iter != iterEnd; ++iter)
439  {
440  const CaloHit *const pCaloHit = *iter;
441 
442  if ((pCaloHit->GetPositionVector() - vtxPosition).GetMagnitudeSquared() >= closestLengthSquared)
443  caloHitListToMove.push_back(pCaloHit);
444  }
445 }
446 
447 //------------------------------------------------------------------------------------------------------------------------------------------
448 
449 void CosmicRaySplittingAlgorithm::GetCaloHitListsToMove(const Cluster *const pBranchCluster, const CartesianVector &splitPosition,
450  const CartesianVector &splitDirection1, const CartesianVector &splitDirection2, CaloHitList &caloHitListToMove1, CaloHitList &caloHitListToMove2) const
451 {
452  CaloHitList caloHitListToSort;
453  pBranchCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitListToSort);
454 
455  for (CaloHitList::const_iterator iter = caloHitListToSort.begin(), iterEnd = caloHitListToSort.end(); iter != iterEnd; ++iter)
456  {
457  const CaloHit *const pCaloHit = *iter;
458 
459  const float displacement1(splitDirection1.GetDotProduct(pCaloHit->GetPositionVector() - splitPosition));
460  const float displacement2(splitDirection2.GetDotProduct(pCaloHit->GetPositionVector() - splitPosition));
461 
462  if (displacement1 > displacement2)
463  {
464  caloHitListToMove1.push_back(pCaloHit);
465  }
466  else
467  {
468  caloHitListToMove2.push_back(pCaloHit);
469  }
470  }
471 }
472 //------------------------------------------------------------------------------------------------------------------------------------------
473 
474 bool CosmicRaySplittingAlgorithm::IdentifyCrossedTracks(const Cluster *const pBranchCluster, const Cluster *const pReplacementCluster1,
475  const Cluster *const pReplacementCluster2, const pandora::CartesianVector &splitPosition) const
476 {
477  CartesianVector branchVertex1(0.f,0.f,0.f), branchVertex2(0.f,0.f,0.f);
478  LArClusterHelper::GetExtremalCoordinates(pBranchCluster,branchVertex1,branchVertex2);
479 
480  const CartesianVector replacementVertex1(LArClusterHelper::GetClosestPosition(splitPosition,pReplacementCluster1));
481  const CartesianVector replacementVertex2(LArClusterHelper::GetClosestPosition(splitPosition,pReplacementCluster2));
482 
483  if ((replacementVertex2 - replacementVertex1).GetMagnitudeSquared() > (branchVertex2 - branchVertex1).GetMagnitudeSquared())
484  return false;
485 
486  return true;
487 }
488 
489 //------------------------------------------------------------------------------------------------------------------------------------------
490 
491 StatusCode CosmicRaySplittingAlgorithm::GetCaloHitListToKeep(const Cluster *const pBranchCluster, const CaloHitList &caloHitListToMove,
492  CaloHitList &caloHitListToKeep) const
493 {
494  if (caloHitListToMove.empty())
495  return STATUS_CODE_FAILURE;
496 
497  CaloHitList caloHitList;
498  pBranchCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
499 
500  for (CaloHitList::const_iterator iter = caloHitList.begin(), iterEnd = caloHitList.end(); iter != iterEnd; ++iter)
501  {
502  const CaloHit *const pCaloHit = *iter;
503 
504  if (caloHitListToMove.end() == std::find(caloHitListToMove.begin(), caloHitListToMove.end(), pCaloHit))
505  caloHitListToKeep.push_back(pCaloHit);
506  }
507 
508  return STATUS_CODE_SUCCESS;
509 }
510 
511 //------------------------------------------------------------------------------------------------------------------------------------------
512 
513 StatusCode CosmicRaySplittingAlgorithm::SplitCluster(const Cluster *const pBranchCluster, const Cluster *const pReplacementCluster, const CaloHitList &caloHitListToMove) const
514 {
515  if (caloHitListToMove.empty())
516  return STATUS_CODE_FAILURE;
517 
518  for (CaloHitList::const_iterator iter = caloHitListToMove.begin(), iterEnd = caloHitListToMove.end(); iter != iterEnd; ++iter)
519  {
520  const CaloHit *const pCaloHit = *iter;
521  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::RemoveFromCluster(*this, pBranchCluster, pCaloHit));
522  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*this, pReplacementCluster, pCaloHit));
523  }
524 
525  return STATUS_CODE_SUCCESS;
526 }
527 
528 //------------------------------------------------------------------------------------------------------------------------------------------
529 
530 StatusCode CosmicRaySplittingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
531 {
532  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
533  "ClusterMinLength", m_clusterMinLength));
534 
535  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
536  "SlidingFitHalfWindow", m_halfWindowLayers));
537 
538  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
539  "SamplingPitch", m_samplingPitch));
540 
541  if (m_samplingPitch < std::numeric_limits<float>::epsilon())
542  return STATUS_CODE_INVALID_PARAMETER;
543 
544  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
545  "MaxCosSplittingAngle", m_maxCosSplittingAngle));
546 
547  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
548  "MinCosMergingAngle", m_minCosMergingAngle));
549 
550  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
551  "MaxTransverseDisplacement", m_maxTransverseDisplacement));
552 
553  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
554  "MaxLongitudinalDisplacement", m_maxLongitudinalDisplacement));
556 
557  return STATUS_CODE_SUCCESS;
558 }
559 
560 } // namespace lar_content
static bool SortByNHits(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by number of hits, then layer span, then inner layer, then position, then pulse-height.
void GetListOfCleanClusters(const pandora::ClusterList *const pClusterList, pandora::ClusterVector &clusterVector) const
Populate cluster vector with subset of cluster list, containing clusters judged to be clean...
void GetCaloHitListsToMove(const pandora::Cluster *const pBranchCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection1, const pandora::CartesianVector &splitDirection2, pandora::CaloHitList &caloHitList1, pandora::CaloHitList &caloHitList2) const
Get lists of calo hits to move in order to split a branch cluster into two segments for case of two r...
bool IdentifyCrossedTracks(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster1, const pandora::Cluster *const pReplacementCluster2, const pandora::CartesianVector &splitPosition) const
Identify crossed tracks formed from the branch cluster and its replacement cluster.
Header file for the cosmic ray splitting algorithm class.
float m_maxLongitudinalDisplacement
maximum longitudinal displacement of associated clusters
void GetCaloHitListToMove(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &forwardDirection, const pandora::CartesianVector &backwardDirection, pandora::CaloHitList &caloHitList) const
Get list of calo hits to move in order to split a branch cluster into two segments for case of one re...
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
float GetLayerFitHalfWindowLength() const
Get the layer fit half window length.
pandora::CartesianVector GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
float m_clusterMinLength
minimum length of clusters for this algorithm
TFile f
Definition: plotHisto.C:6
pandora::StatusCode SplitCluster(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CaloHitList &caloHitListToMove) const
Split the branch cluster and add hits to the replacement cluster.
Header file for the geometry helper class.
pandora::StatusCode PerformSingleSplit(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &forwardDirection, const pandora::CartesianVector &backwardDirection) const
Split a branch cluster for case of one replacement cluster.
Int_t max
Definition: plot.C:27
float m_minCosMergingAngle
largest relative angle allowed when merging clusters
if(nlines<=0)
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
pandora::StatusCode GetCaloHitListToKeep(const pandora::Cluster *const pBranchCluster, const pandora::CaloHitList &caloHitListToMove, pandora::CaloHitList &caloHitListToKeep) const
Split the branch cluster and add hits to the replacement cluster.
pandora::StatusCode GetGlobalFitPosition(const float rL, pandora::CartesianVector &position) const
Get global fit position for a given longitudinal coordinate.
float m_maxCosSplittingAngle
smallest scatter angle allowed when splitting cluster
float m_maxLongitudinalDisplacementSquared
longitudinal displacement squared
pandora::StatusCode PerformDoubleSplit(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster1, const pandora::Cluster *const pReplacementCluster2, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection1, const pandora::CartesianVector &splitDirection2) const
Split a branch cluster for case of two replacement clusters.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
static void GetExtremalCoordinates(const pandora::ClusterList &clusterList, pandora::CartesianVector &innerCoordinate, pandora::CartesianVector &outerCoordinate)
Get positions of the two most distant calo hits in a list of cluster (ordered by Z) ...
void BuildSlidingFitResultMap(const pandora::ClusterVector &clusterVector, TwoDSlidingFitResultMap &slidingFitResultMap) const
Build the map of sliding fit results.
float m_maxTransverseDisplacement
maximum transverse displacement of associated clusters
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
pandora::StatusCode GetGlobalFitDirection(const float rL, pandora::CartesianVector &direction) const
Get global fit direction for a given longitudinal coordinate.
Int_t min
Definition: plot.C:26
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
pandora::StatusCode ConfirmSplitPosition(const TwoDSlidingFitResult &branchSlidingFitResult, const TwoDSlidingFitResult &replacementSlidingFitResult, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection1, const pandora::CartesianVector &splitDirection2, float &lengthSquared1, float &lengthSquared2) const
Find a second replacement cluster that aligns with the scatter of the first branch cluster...
pandora::CartesianVector GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
Char_t n[5]
pandora::StatusCode FindBestSplitPosition(const TwoDSlidingFitResult &slidingFitResult, pandora::CartesianVector &splitPosition, pandora::CartesianVector &splitDirection1, pandora::CartesianVector &splitDirection2) const
Find the position of greatest scatter along a sliding linear fit.
unsigned int m_halfWindowLayers
number of layers to use for half-window of sliding fit
static pandora::CartesianVector GetClosestPosition(const pandora::CartesianVector &position, const pandora::ClusterList &clusterList)
Get closest position in a list of clusters to a specified input position vector.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
float m_samplingPitch
sampling pitch for walking along sliding linear fit
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.