LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
LongitudinalExtensionAlgorithm.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 LongitudinalExtensionAlgorithm::LongitudinalExtensionAlgorithm() :
22  m_clusterMinLength(5.f),
23  m_clusterMinLayerOccupancy(0.75f),
24  m_nodeMaxDisplacement(1.5f),
25  m_nodeMaxCosRelativeAngle(0.906f),
26  m_emissionMaxLongitudinalDisplacement(15.f),
27  m_emissionMaxTransverseDisplacement(2.5f),
28  m_emissionMaxCosRelativeAngle(0.985f)
29 {
30 }
31 
32 //------------------------------------------------------------------------------------------------------------------------------------------
33 
34 void LongitudinalExtensionAlgorithm::GetListOfCleanClusters(const ClusterList *const pClusterList, ClusterVector &clusterVector) const
35 {
36  for (ClusterList::const_iterator iter = pClusterList->begin(), iterEnd = pClusterList->end(); iter != iterEnd; ++iter)
37  {
38  const Cluster *const pCluster = *iter;
39 
41  continue;
42 
44  continue;
45 
46  clusterVector.push_back(pCluster);
47  }
48 
49  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
50 }
51 
52 //------------------------------------------------------------------------------------------------------------------------------------------
53 
54 void LongitudinalExtensionAlgorithm::FillClusterAssociationMatrix(const ClusterVector &clusterVector, ClusterAssociationMatrix &clusterAssociationMatrix) const
55 {
56  // Convert each input cluster into a pointing cluster
57  LArPointingClusterList pointingClusterList;
58 
59  for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
60  {
61  try
62  {
63  pointingClusterList.push_back(LArPointingCluster(*iter));
64  }
65  catch (StatusCodeException &)
66  {
67  }
68  }
69 
70  // Form associations between pairs of pointing clusters
71  for (LArPointingClusterList::const_iterator iterI = pointingClusterList.begin(), iterEndI = pointingClusterList.end(); iterI != iterEndI; ++iterI)
72  {
73  const LArPointingCluster &clusterI = *iterI;
74 
75  for (LArPointingClusterList::const_iterator iterJ = iterI, iterEndJ = pointingClusterList.end(); iterJ != iterEndJ; ++iterJ)
76  {
77  const LArPointingCluster &clusterJ = *iterJ;
78 
79  if (clusterI.GetCluster() == clusterJ.GetCluster())
80  continue;
81 
82  this->FillClusterAssociationMatrix(clusterI, clusterJ, clusterAssociationMatrix);
83  }
84  }
85 }
86 
87 //------------------------------------------------------------------------------------------------------------------------------------------
88 
90  ClusterAssociationMatrix &clusterAssociationMatrix) const
91 {
92  const Cluster *const pClusterI(clusterI.GetCluster());
93  const Cluster *const pClusterJ(clusterJ.GetCluster());
94 
95  if (pClusterI == pClusterJ)
96  return;
97 
98  // Check that new layer occupancy would be reasonable
100  return;
101 
102  // Identify closest pair of vertices
103  LArPointingCluster::Vertex targetVertexI, targetVertexJ;
104 
105  try
106  {
107  LArPointingClusterHelper::GetClosestVertices(clusterI, clusterJ, targetVertexI, targetVertexJ);
108  }
109  catch (StatusCodeException &)
110  {
111  return;
112  }
113 
114  // (Just in case...)
115  if (!(targetVertexI.IsInitialized() && targetVertexJ.IsInitialized()))
116  throw StatusCodeException(STATUS_CODE_FAILURE);
117 
118  const CartesianVector &vertexPositionI(targetVertexI.GetPosition());
119  const CartesianVector &vertexPositionJ(targetVertexJ.GetPosition());
120  const CartesianVector &vertexDirectionI(targetVertexI.GetDirection());
121  const CartesianVector &vertexDirectionJ(targetVertexJ.GetDirection());
122 
123  // Check for reasonable proximity between vertices
124  const float distanceSquared((vertexPositionI - vertexPositionJ).GetMagnitudeSquared());
125 
127  return;
128 
129  // Check that vertices have a reasonable linear fit
130  if (targetVertexI.GetRms() > 1.f || targetVertexJ.GetRms() > 1.f)
131  return;
132 
133  // Association type
135 
136  // Requirements for Nodes
137  if (distanceSquared < 2.f * m_nodeMaxDisplacement * m_nodeMaxDisplacement)
138  {
139  associationType = ClusterAssociation::WEAK;
140 
141  if (distanceSquared < m_nodeMaxDisplacement * m_nodeMaxDisplacement)
142  {
143  const float cosTheta(-vertexDirectionI.GetDotProduct(vertexDirectionJ));
144 
145  if (cosTheta > m_nodeMaxCosRelativeAngle)
146  {
147  associationType = ClusterAssociation::STRONG;
148  }
149  }
150  }
151 
152  // Requirements for Emissions
153  const float clusterLengthI(LArPointingClusterHelper::GetLength(clusterI));
154  const float clusterLengthJ(LArPointingClusterHelper::GetLength(clusterJ));
155 
156  if (associationType < ClusterAssociation::STRONG)
157  {
158  const float cosTheta(-vertexDirectionI.GetDotProduct(vertexDirectionJ));
159  const float cosThetaI((vertexPositionI - vertexPositionJ).GetUnitVector().GetDotProduct(vertexDirectionI));
160  const float cosThetaJ((vertexPositionJ - vertexPositionI).GetUnitVector().GetDotProduct(vertexDirectionJ));
161 
162  float rT1(0.f), rL1(0.f), rT2(0.f), rL2(0.f);
163  LArPointingClusterHelper::GetImpactParameters(vertexPositionI, vertexDirectionI, vertexPositionJ, rL1, rT1);
164  LArPointingClusterHelper::GetImpactParameters(vertexPositionJ, vertexDirectionJ, vertexPositionI, rL2, rT2);
165 
166  if ((rL1 > -2.5f && rL1 < std::min(0.66f * clusterLengthJ, m_emissionMaxLongitudinalDisplacement)) &&
167  (rL2 > -2.5f && rL2 < std::min(0.66f * clusterLengthI, m_emissionMaxLongitudinalDisplacement)) &&
169  (targetVertexI.GetRms() < 0.5f && targetVertexJ.GetRms() < 0.5f) &&
170  (cosTheta > m_emissionMaxCosRelativeAngle) && (std::fabs(cosThetaI) > 0.25f) && (std::fabs(cosThetaJ) > 0.25f))
171  {
172  associationType = ClusterAssociation::STRONG;
173  }
174  }
175 
176  // Record the association
177  if (ClusterAssociation::NONE != associationType)
178  {
181  (void) clusterAssociationMatrix[pClusterI].insert(ClusterAssociationMap::value_type(pClusterJ, ClusterAssociation(vertexTypeI, vertexTypeJ, associationType, clusterLengthJ)));
182  (void) clusterAssociationMatrix[pClusterJ].insert(ClusterAssociationMap::value_type(pClusterI, ClusterAssociation(vertexTypeJ, vertexTypeI, associationType, clusterLengthI)));
183  return;
184  }
185 }
186 
187 //------------------------------------------------------------------------------------------------------------------------------------------
188 
189 void LongitudinalExtensionAlgorithm::FillClusterMergeMap(const ClusterAssociationMatrix &inputAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
190 {
191  // Decide which associations will become merges
192  // To make the merge A <-> B, both A -> B and B -> A must be strong associations
193  // with the largest figures of merit of all the A -> X and B -> Y associations
194 
195  // First step: remove double-counting from the map of associations
196  // i.e. if the map has A <-> B, B <-> C, A <-> C, then remove A <-> C
197  ClusterAssociationMatrix clusterAssociationMatrix;
198 
199  ClusterVector sortedInputClusters;
200  for (const auto &mapEntry : inputAssociationMatrix) sortedInputClusters.push_back(mapEntry.first);
201  std::sort(sortedInputClusters.begin(), sortedInputClusters.end(), LArClusterHelper::SortByNHits);
202 
203  for (const Cluster *const pCluster1 : sortedInputClusters)
204  {
205  const ClusterAssociationMap &associationMap1(inputAssociationMatrix.at(pCluster1));
206 
207  for (const Cluster *const pCluster2 : sortedInputClusters)
208  {
209  if (pCluster1 == pCluster2)
210  continue;
211 
212  const ClusterAssociationMap &associationMap2(inputAssociationMatrix.at(pCluster2));
213 
214  ClusterAssociationMap::const_iterator iter12 = associationMap1.find(pCluster2);
215  if (associationMap1.end() == iter12)
216  continue;
217 
218  ClusterAssociationMap::const_iterator iter21 = associationMap2.find(pCluster1);
219  if (associationMap2.end() == iter21)
220  continue;
221 
222  const ClusterAssociation &association12(iter12->second);
223  const ClusterAssociation &association21(iter21->second);
224 
225  bool isAssociated(true);
226 
227  ClusterVector sortedAssociationClusters;
228  for (const auto &mapEntry : associationMap1) sortedAssociationClusters.push_back(mapEntry.first);
229  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
230 
231  for (const Cluster *const pCluster3 : sortedAssociationClusters)
232  {
233  const ClusterAssociation &association13(associationMap1.at(pCluster3));
234 
235  ClusterAssociationMap::const_iterator iter23 = associationMap2.find(pCluster3);
236  if (associationMap2.end() == iter23)
237  continue;
238 
239  const ClusterAssociation &association23(iter23->second);
240 
241  if (association12.GetParent() == association13.GetParent() &&
242  association23.GetParent() == association21.GetParent() &&
243  association13.GetDaughter() != association23.GetDaughter())
244  {
245  isAssociated = false;
246  break;
247  }
248  }
249 
250  if (isAssociated)
251  {
252  (void) clusterAssociationMatrix[pCluster1].insert(ClusterAssociationMap::value_type(pCluster2, association12));
253  (void) clusterAssociationMatrix[pCluster2].insert(ClusterAssociationMap::value_type(pCluster1, association21));
254  }
255  }
256  }
257 
258 
259  // Second step: find the best associations A -> X and B -> Y
260  ClusterAssociationMatrix intermediateAssociationMatrix;
261 
262  ClusterVector sortedClusters;
263  for (const auto &mapEntry : clusterAssociationMatrix) sortedClusters.push_back(mapEntry.first);
264  std::sort(sortedClusters.begin(), sortedClusters.end(), LArClusterHelper::SortByNHits);
265 
266  for (const Cluster *const pParentCluster : sortedClusters)
267  {
268  const ClusterAssociationMap &clusterAssociationMap(clusterAssociationMatrix.at(pParentCluster));
269 
270  const Cluster *pBestClusterInner(nullptr);
272 
273  const Cluster *pBestClusterOuter(nullptr);
275 
276  ClusterVector sortedAssociationClusters;
277  for (const auto &mapEntry : clusterAssociationMap) sortedAssociationClusters.push_back(mapEntry.first);
278  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
279 
280  for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
281  {
282  const ClusterAssociation &clusterAssociation(clusterAssociationMap.at(pDaughterCluster));
283 
284  // Inner associations
285  if (clusterAssociation.GetParent() == ClusterAssociation::INNER)
286  {
287  if (clusterAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
288  {
289  bestAssociationInner = clusterAssociation;
290 
291  if (clusterAssociation.GetAssociation() == ClusterAssociation::STRONG)
292  pBestClusterInner = pDaughterCluster;
293  else
294  pBestClusterInner = nullptr;
295  }
296  }
297 
298  // Outer associations
299  if (clusterAssociation.GetParent() == ClusterAssociation::OUTER)
300  {
301  if (clusterAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
302  {
303  bestAssociationOuter = clusterAssociation;
304 
305  if (clusterAssociation.GetAssociation() == ClusterAssociation::STRONG)
306  pBestClusterOuter = pDaughterCluster;
307  else
308  pBestClusterOuter = nullptr;
309  }
310  }
311  }
312 
313  if (pBestClusterInner)
314  (void) intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterInner, bestAssociationInner));
315 
316  if (pBestClusterOuter)
317  (void) intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterOuter, bestAssociationOuter));
318  }
319 
320 
321  // Third step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
322  ClusterVector intermediateSortedClusters;
323  for (const auto &mapEntry : intermediateAssociationMatrix) intermediateSortedClusters.push_back(mapEntry.first);
324  std::sort(intermediateSortedClusters.begin(), intermediateSortedClusters.end(), LArClusterHelper::SortByNHits);
325 
326  for (const Cluster *const pParentCluster : intermediateSortedClusters)
327  {
328  const ClusterAssociationMap &parentAssociationMap(intermediateAssociationMatrix.at(pParentCluster));
329 
330  ClusterVector sortedAssociationClusters;
331  for (const auto &mapEntry : parentAssociationMap) sortedAssociationClusters.push_back(mapEntry.first);
332  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
333 
334  for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
335  {
336  const ClusterAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterCluster));
337 
338  ClusterAssociationMatrix::const_iterator iter5 = intermediateAssociationMatrix.find(pDaughterCluster);
339 
340  if (intermediateAssociationMatrix.end() == iter5)
341  continue;
342 
343  const ClusterAssociationMap &daughterAssociationMap(iter5->second);
344 
345  ClusterAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentCluster);
346 
347  if (daughterAssociationMap.end() == iter6)
348  continue;
349 
350  const ClusterAssociation &daughterToParentAssociation(iter6->second);
351 
352  if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
353  parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
354  {
355  ClusterList &parentList(clusterMergeMap[pParentCluster]);
356 
357  if (parentList.end() == std::find(parentList.begin(), parentList.end(), pDaughterCluster))
358  parentList.push_back(pDaughterCluster);
359  }
360  }
361  }
362 }
363 
364 //------------------------------------------------------------------------------------------------------------------------------------------
365 
366 StatusCode LongitudinalExtensionAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
367 {
368  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
369  "ClusterMinLength", m_clusterMinLength));
370 
371  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
372  "ClusterMinLayerOccupancy", m_clusterMinLayerOccupancy));
373 
374  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
375  "NodeMaxDisplacement", m_nodeMaxDisplacement));
376 
377  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
378  "NodeMaxCosRelativeAngle", m_nodeMaxCosRelativeAngle));
379 
380  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
381  "EmissionMaxLongitudinalDisplacement", m_emissionMaxLongitudinalDisplacement));
382 
383  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
384  "EmissionMaxTransverseDisplacement", m_emissionMaxTransverseDisplacement));
385 
386  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
387  "EmissionMaxCosRelativeAngle", m_emissionMaxCosRelativeAngle));
388 
389  return ClusterExtensionAlgorithm::ReadSettings(xmlHandle);
390 }
391 
392 } // 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.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::Cluster *, ClusterAssociationMap > ClusterAssociationMatrix
void FillClusterAssociationMatrix(const pandora::ClusterVector &clusterVector, ClusterAssociationMatrix &clusterAssociationMatrix) const
Fill the cluster association matrix.
std::vector< LArPointingCluster > LArPointingClusterList
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
static float GetLength(const LArPointingCluster &pointingCluster)
Calculate distance squared between inner and outer vertices of pointing cluster.
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
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
bool IsInitialized() const
Whether the vertex has been initialized.
static float GetLayerOccupancy(const pandora::Cluster *const pCluster)
Fraction of occupied layers in cluster.
const pandora::CartesianVector & GetDirection() const
Get the vertex direction.
float GetRms() const
Get rms from vertex fit.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
Int_t min
Definition: plot.C:26
void FillClusterMergeMap(const ClusterAssociationMatrix &clusterAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
Fill the cluster merge map.
Header file for the longitudinal extension algorithm class.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
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...
bool IsInnerVertex() const
Is this the inner vertex.
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