LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
CosmicRayExtensionAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
13 
15 
16 using namespace pandora;
17 
18 namespace lar_content
19 {
20 
21 CosmicRayExtensionAlgorithm::CosmicRayExtensionAlgorithm() :
22  m_minClusterLength(3.f),
23  m_minSeedClusterLength(6.f),
24  m_maxLongitudinalDisplacement(30.f),
25  m_maxTransverseDisplacement(2.f),
26  m_minCosRelativeAngle(0.966f),
27  m_maxAverageRms(1.f)
28 {
29 }
30 
31 //------------------------------------------------------------------------------------------------------------------------------------------
32 
33 void CosmicRayExtensionAlgorithm::GetListOfCleanClusters(const ClusterList *const pClusterList, ClusterVector &clusterVector) const
34 {
35  for (ClusterList::const_iterator iter = pClusterList->begin(), iterEnd = pClusterList->end(); iter != iterEnd; ++iter)
36  {
37  const Cluster *const pCluster = *iter;
38 
40  continue;
41 
42  clusterVector.push_back(pCluster);
43  }
44 
45  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
46 }
47 
48 //------------------------------------------------------------------------------------------------------------------------------------------
49 
50 void CosmicRayExtensionAlgorithm::FillClusterAssociationMatrix(const ClusterVector &clusterVector, ClusterAssociationMatrix &clusterAssociationMatrix) const
51 {
52  // Convert each input cluster into a pointing cluster
53  LArPointingClusterList pointingClusterList;
54 
55  for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
56  {
57  try
58  {
59  pointingClusterList.push_back(LArPointingCluster(*iter));
60  }
61  catch (StatusCodeException &)
62  {
63  }
64  }
65 
66  // Form associations between pairs of pointing clusters
67  for (LArPointingClusterList::const_iterator iterI = pointingClusterList.begin(), iterEndI = pointingClusterList.end(); iterI != iterEndI; ++iterI)
68  {
69  const LArPointingCluster &clusterI = *iterI;
70 
71  for (LArPointingClusterList::const_iterator iterJ = iterI, iterEndJ = pointingClusterList.end(); iterJ != iterEndJ; ++iterJ)
72  {
73  const LArPointingCluster &clusterJ = *iterJ;
74 
75  if (clusterI.GetCluster() == clusterJ.GetCluster())
76  continue;
77 
78  this->FillClusterAssociationMatrix(clusterI, clusterJ, clusterAssociationMatrix);
79  }
80  }
81 }
82 
83 //------------------------------------------------------------------------------------------------------------------------------------------
84 
86  ClusterAssociationMatrix &clusterAssociationMatrix) const
87 {
88  const Cluster *const pClusterI(clusterI.GetCluster());
89  const Cluster *const pClusterJ(clusterJ.GetCluster());
90 
91  if (pClusterI == pClusterJ)
92  return;
93 
94  // Get closest pair of vertices
95  LArPointingCluster::Vertex clusterVertexI, clusterVertexJ;
96 
97  try
98  {
99  LArPointingClusterHelper::GetClosestVertices(clusterI, clusterJ, clusterVertexI, clusterVertexJ);
100  }
101  catch (StatusCodeException &)
102  {
103  return;
104  }
105 
106  // (Just in case...)
107  if (!(clusterVertexI.IsInitialized() && clusterVertexJ.IsInitialized()))
108  throw StatusCodeException(STATUS_CODE_FAILURE);
109 
110  const CartesianVector vertexI(clusterVertexI.GetPosition());
111  const CartesianVector vertexJ(clusterVertexJ.GetPosition());
112 
113  const CartesianVector endI(clusterVertexI.IsInnerVertex() ? clusterI.GetOuterVertex().GetPosition() : clusterI.GetInnerVertex().GetPosition());
114  const CartesianVector endJ(clusterVertexJ.IsInnerVertex() ? clusterJ.GetOuterVertex().GetPosition() : clusterJ.GetInnerVertex().GetPosition());
115 
116  // Requirements on length
117  const float lengthSquaredI(LArPointingClusterHelper::GetLengthSquared(clusterI));
118  const float lengthSquaredJ(LArPointingClusterHelper::GetLengthSquared(clusterJ));
119 
120  if (std::max(lengthSquaredI, lengthSquaredJ) < m_minSeedClusterLength * m_minSeedClusterLength)
121  return;
122 
123  // Requirements on proximity
124  const float distanceSquaredIJ((vertexI - vertexJ).GetMagnitudeSquared());
125 
127  return;
128 
129  // Requirements on pointing information
130  const CartesianVector directionI((endI - vertexI).GetUnitVector());
131  const CartesianVector directionJ((endJ - vertexJ).GetUnitVector());
132 
133  const float cosTheta(-directionI.GetDotProduct(directionJ));
134  const float cosThetaCut(-1.f + 2.f * m_minCosRelativeAngle);
135 
136  if (cosTheta < cosThetaCut)
137  return;
138 
139  // Requirements on overlap between clusters
140  const CartesianVector directionIJ((endJ - endI).GetUnitVector());
141  const CartesianVector directionJI((endI - endJ).GetUnitVector());
142 
143  const float overlapL(directionIJ.GetDotProduct(vertexJ - vertexI));
144  const float overlapT(directionIJ.GetCrossProduct(vertexJ - vertexI).GetMagnitude());
145 
146  if (overlapL < -1.f || overlapL * overlapL > 2.f * std::min(lengthSquaredI, lengthSquaredJ) ||
147  overlapT > m_maxTransverseDisplacement + std::fabs(overlapL) * std::tan(5.f * M_PI / 180.f))
148  return;
149 
150  // Calculate RMS deviations on composite cluster
151  const float rms1(this->CalculateRms(pClusterI, endI, directionIJ));
152  const float rms2(this->CalculateRms(pClusterJ, endJ, directionJI));
153 
154  const float rms(0.5f * (rms1 + rms2));
155  const float rmsCut(2.f * m_maxAverageRms * (cosTheta - cosThetaCut) / (1.0 - cosThetaCut));
156 
157  if (rms > rmsCut)
158  return;
159 
160  // Record the association
164 
165  (void) clusterAssociationMatrix[pClusterI].insert(ClusterAssociationMap::value_type(pClusterJ,
166  ClusterAssociation(vertexTypeI, vertexTypeJ, associationType, lengthSquaredJ)));
167 
168  (void) clusterAssociationMatrix[pClusterJ].insert(ClusterAssociationMap::value_type(pClusterI,
169  ClusterAssociation(vertexTypeJ, vertexTypeI, associationType, lengthSquaredI)));
170 }
171 
172 //------------------------------------------------------------------------------------------------------------------------------------------
173 
174 void CosmicRayExtensionAlgorithm::FillClusterMergeMap(const ClusterAssociationMatrix &inputAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
175 {
176  // Decide which associations will become merges
177  // To make the merge A <-> B, both A -> B and B -> A must be strong associations
178  // with the largest figures of merit of all the A -> X and B -> Y associations
179 
180  // First step: remove double-counting from the map of associations
181  // i.e. if the map has A <-> B, B <-> C, A <-> C, then remove A <-> C
182  ClusterAssociationMatrix clusterAssociationMatrix;
183 
184  ClusterVector sortedInputClusters;
185  for (const auto &mapEntry : inputAssociationMatrix) sortedInputClusters.push_back(mapEntry.first);
186  std::sort(sortedInputClusters.begin(), sortedInputClusters.end(), LArClusterHelper::SortByNHits);
187 
188  for (const Cluster *const pCluster1 : sortedInputClusters)
189  {
190  const ClusterAssociationMap &associationMap1(inputAssociationMatrix.at(pCluster1));
191 
192  for (const Cluster *const pCluster2 : sortedInputClusters)
193  {
194  if (pCluster1 == pCluster2)
195  continue;
196 
197  const ClusterAssociationMap &associationMap2(inputAssociationMatrix.at(pCluster2));
198 
199  ClusterAssociationMap::const_iterator iter12 = associationMap1.find(pCluster2);
200  if (associationMap1.end() == iter12)
201  continue;
202 
203  ClusterAssociationMap::const_iterator iter21 = associationMap2.find(pCluster1);
204  if (associationMap2.end() == iter21)
205  continue;
206 
207  const ClusterAssociation &association12(iter12->second);
208  const ClusterAssociation &association21(iter21->second);
209 
210  bool isAssociated(true);
211 
212  ClusterVector sortedAssociationClusters;
213  for (const auto &mapEntry : associationMap1) sortedAssociationClusters.push_back(mapEntry.first);
214  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
215 
216  for (const Cluster *const pCluster3 : sortedAssociationClusters)
217  {
218  const ClusterAssociation &association13(associationMap1.at(pCluster3));
219 
220  ClusterAssociationMap::const_iterator iter23 = associationMap2.find(pCluster3);
221  if (associationMap2.end() == iter23)
222  continue;
223 
224  const ClusterAssociation &association23(iter23->second);
225 
226  if (association12.GetParent() == association13.GetParent() &&
227  association23.GetParent() == association21.GetParent() &&
228  association13.GetDaughter() != association23.GetDaughter())
229  {
230  isAssociated = false;
231  break;
232  }
233  }
234 
235  if (isAssociated)
236  {
237  (void) clusterAssociationMatrix[pCluster1].insert(ClusterAssociationMap::value_type(pCluster2, association12));
238  (void) clusterAssociationMatrix[pCluster2].insert(ClusterAssociationMap::value_type(pCluster1, association21));
239  }
240  }
241  }
242 
243 
244  // Second step: find the best associations A -> X and B -> Y
245  ClusterAssociationMatrix intermediateAssociationMatrix;
246 
247  ClusterVector sortedClusters;
248  for (const auto &mapEntry : clusterAssociationMatrix) sortedClusters.push_back(mapEntry.first);
249  std::sort(sortedClusters.begin(), sortedClusters.end(), LArClusterHelper::SortByNHits);
250 
251  for (const Cluster *const pParentCluster : sortedClusters)
252  {
253  const ClusterAssociationMap &clusterAssociationMap(clusterAssociationMatrix.at(pParentCluster));
254 
255  const Cluster *pBestClusterInner(nullptr);
257 
258  const Cluster *pBestClusterOuter(nullptr);
260 
261  ClusterVector sortedAssociationClusters;
262  for (const auto &mapEntry : clusterAssociationMap) sortedAssociationClusters.push_back(mapEntry.first);
263  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
264 
265  for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
266  {
267  const ClusterAssociation &clusterAssociation(clusterAssociationMap.at(pDaughterCluster));
268 
269  // Inner associations
270  if (clusterAssociation.GetParent() == ClusterAssociation::INNER)
271  {
272  if (clusterAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
273  {
274  bestAssociationInner = clusterAssociation;
275  pBestClusterInner = pDaughterCluster;
276  }
277  }
278 
279  // Outer associations
280  if (clusterAssociation.GetParent() == ClusterAssociation::OUTER)
281  {
282  if (clusterAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
283  {
284  bestAssociationOuter = clusterAssociation;
285  pBestClusterOuter = pDaughterCluster;
286  }
287  }
288  }
289 
290  if (pBestClusterInner)
291  (void) intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterInner, bestAssociationInner));
292 
293  if (pBestClusterOuter)
294  (void) intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterOuter, bestAssociationOuter));
295  }
296 
297 
298  // Third step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
299  ClusterVector intermediateSortedClusters;
300  for (const auto &mapEntry : intermediateAssociationMatrix) intermediateSortedClusters.push_back(mapEntry.first);
301  std::sort(intermediateSortedClusters.begin(), intermediateSortedClusters.end(), LArClusterHelper::SortByNHits);
302 
303  for (const Cluster *const pParentCluster : intermediateSortedClusters)
304  {
305  const ClusterAssociationMap &parentAssociationMap(intermediateAssociationMatrix.at(pParentCluster));
306 
307  ClusterVector sortedAssociationClusters;
308  for (const auto &mapEntry : parentAssociationMap) sortedAssociationClusters.push_back(mapEntry.first);
309  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
310 
311  for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
312  {
313  const ClusterAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterCluster));
314 
315  ClusterAssociationMatrix::const_iterator iter5 = intermediateAssociationMatrix.find(pDaughterCluster);
316 
317  if (intermediateAssociationMatrix.end() == iter5)
318  continue;
319 
320  const ClusterAssociationMap &daughterAssociationMap(iter5->second);
321 
322  ClusterAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentCluster);
323 
324  if (daughterAssociationMap.end() == iter6)
325  continue;
326 
327  const ClusterAssociation &daughterToParentAssociation(iter6->second);
328 
329  if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
330  parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
331  {
332  ClusterList &parentList(clusterMergeMap[pParentCluster]);
333 
334  if (parentList.end() == std::find(parentList.begin(), parentList.end(), pDaughterCluster))
335  parentList.push_back(pDaughterCluster);
336  }
337  }
338  }
339 }
340 
341 //------------------------------------------------------------------------------------------------------------------------------------------
342 
343 float CosmicRayExtensionAlgorithm::CalculateRms(const Cluster *const pCluster, const CartesianVector &position, const CartesianVector &direction) const
344 {
345  float totalChi2(0.f);
346  float totalHits(0.f);
347 
348  CaloHitList caloHitList;
349  pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
350 
351  for (CaloHitList::const_iterator iter = caloHitList.begin(), iterEnd = caloHitList.end(); iter != iterEnd; ++iter)
352  {
353  const CaloHit *const pCaloHit = *iter;
354 
355  const CartesianVector hitPosition(pCaloHit->GetPositionVector());
356  const CartesianVector predictedPosition(position + direction * direction.GetDotProduct(hitPosition - position));
357 
358  totalChi2 += (predictedPosition - hitPosition).GetMagnitudeSquared();
359  totalHits += 1.f;
360  }
361 
362  if (totalHits > 0.f)
363  return std::sqrt(totalChi2/totalHits);
364 
365  return 0.f;
366 }
367 
368 //------------------------------------------------------------------------------------------------------------------------------------------
369 
370 StatusCode CosmicRayExtensionAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
371 {
372  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
373  "MinClusterLength", m_minClusterLength));
374 
375  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
376  "MinSeedClusterLength", m_minSeedClusterLength));
377 
378  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
379  "MaxLongitudinalDisplacement", m_maxLongitudinalDisplacement));
380 
381  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
382  "MaxTransverseDisplacement", m_maxTransverseDisplacement));
383 
384  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
385  "MinCosRelativeAngle", m_minCosRelativeAngle));
386 
387  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
388  "MaxAverageRms", m_maxAverageRms));
389 
390  return ClusterExtensionAlgorithm::ReadSettings(xmlHandle);
391 }
392 
393 } // 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.
std::unordered_map< const pandora::Cluster *, ClusterAssociationMap > ClusterAssociationMatrix
std::vector< LArPointingCluster > LArPointingClusterList
Header file for the cosmic-ray extension algorithm class.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
LArPointingCluster class.
const pandora::Cluster * GetCluster() const
Get the address of the cluster.
static void GetClosestVertices(const bool useX, const bool useY, const bool useZ, const LArPointingCluster &pointingClusterI, const LArPointingCluster &pointingClusterJ, LArPointingCluster::Vertex &closestVertexI, LArPointingCluster::Vertex &closestVertexJ)
Given a pair of pointing clusters, receive the closest or farthest pair of vertices.
TFile f
Definition: plotHisto.C:6
Int_t max
Definition: plot.C:27
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
bool IsInitialized() const
Whether the vertex has been initialized.
const Vertex & GetOuterVertex() const
Get the outer vertex.
const Vertex & GetInnerVertex() const
Get the inner vertex.
float CalculateRms(const pandora::Cluster *const pCluster, const pandora::CartesianVector &position, const pandora::CartesianVector &direction) const
Calculate RMS deviation of a cluster with respect to the reference line.
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...
std::vector< art::Ptr< recob::Cluster > > ClusterVector
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
void FillClusterAssociationMatrix(const pandora::ClusterVector &clusterVector, ClusterAssociationMatrix &clusterAssociationMatrix) const
Fill the cluster association matrix.
Int_t min
Definition: plot.C:26
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
bool IsInnerVertex() const
Is this the inner vertex.
static float GetLengthSquared(const LArPointingCluster &pointingCluster)
Calculate distance squared between inner and outer vertices of pointing cluster.
void FillClusterMergeMap(const ClusterAssociationMatrix &clusterAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
Fill the cluster merge map.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::Cluster *, ClusterAssociation > ClusterAssociationMap