LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
CrossGapsExtensionAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
14 
16 
17 using namespace pandora;
18 
19 namespace lar_content
20 {
21 
22 CrossGapsExtensionAlgorithm::CrossGapsExtensionAlgorithm() :
23  m_minClusterLength(5.f),
24  m_minGapFraction(0.5f),
25  m_maxGapTolerance(2.f),
26  m_maxTransverseDisplacement(2.5f),
27  m_maxRelativeAngle(10.f)
28 {
29 }
30 
31 //------------------------------------------------------------------------------------------------------------------------------------------
32 
33 void CrossGapsExtensionAlgorithm::GetListOfCleanClusters(const ClusterList *const pClusterList, ClusterVector &clusterVector) const
34 {
35  // ATTN May want to opt-out completely if no gap information available
36  // if (PandoraContentApi::GetGeometry(*this)->GetDetectorGapList().empty())
37  // return;
38 
39  for (const Cluster *const pCluster : *pClusterList)
40  {
42  continue;
43 
44  clusterVector.push_back(pCluster);
45  }
46 
47  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
48 }
49 
50 //------------------------------------------------------------------------------------------------------------------------------------------
51 
53 {
54  // Build lists of pointing clusters in proximity to gaps
55  LArPointingClusterList innerPointingClusterList, outerPointingClusterList;
56  this->BuildPointingClusterList(clusterVector, innerPointingClusterList, outerPointingClusterList);
57 
58  // Form associations between pairs of pointing clusters
59  for (const LArPointingCluster &pointingClusterInner : innerPointingClusterList)
60  {
61  const LArPointingCluster::Vertex &pointingVertexInner(pointingClusterInner.GetInnerVertex());
62  const float zInner(pointingVertexInner.GetPosition().GetZ());
63 
64  for (const LArPointingCluster &pointingClusterOuter : outerPointingClusterList)
65  {
66  const LArPointingCluster::Vertex &pointingVertexOuter(pointingClusterOuter.GetOuterVertex());
67  const float zOuter(pointingVertexOuter.GetPosition().GetZ());
68 
69  if (!this->IsAcrossGap(zOuter, zInner, LArClusterHelper::GetClusterHitType(pointingClusterInner.GetCluster())))
70  continue;
71 
72  if (!this->IsAssociated(pointingVertexInner, pointingVertexOuter))
73  continue;
74 
75  const Cluster *const pClusterInner(pointingClusterInner.GetCluster());
76  const Cluster *const pClusterOuter(pointingClusterOuter.GetCluster());
77 
78  const float lengthSquaredInner(LArClusterHelper::GetLengthSquared(pClusterInner));
79  const float lengthSquaredOuter(LArClusterHelper::GetLengthSquared(pClusterOuter));
80 
81  (void) clusterAssociationMatrix[pClusterInner].insert(ClusterAssociationMap::value_type(pClusterOuter,
83  (void) clusterAssociationMatrix[pClusterOuter].insert(ClusterAssociationMap::value_type(pClusterInner,
85  }
86  }
87 }
88 
89 //------------------------------------------------------------------------------------------------------------------------------------------
90 
91 void CrossGapsExtensionAlgorithm::BuildPointingClusterList(const ClusterVector &clusterVector, LArPointingClusterList &innerPointingClusterList,
92  LArPointingClusterList &outerPointingClusterList) const
93 {
94  // Convert each input cluster into a pointing cluster
95  LArPointingClusterList pointingClusterList;
96 
97  for (const Cluster *const pCluster : clusterVector)
98  {
99  try {pointingClusterList.push_back(LArPointingCluster(pCluster));}
100  catch (StatusCodeException &) {}
101  }
102 
103  // Identify clusters adjacent to detector gaps
104  this->BuildPointingClusterList(true, pointingClusterList, innerPointingClusterList);
105  this->BuildPointingClusterList(false, pointingClusterList, outerPointingClusterList);
106 }
107 
108 //------------------------------------------------------------------------------------------------------------------------------------------
109 
110 void CrossGapsExtensionAlgorithm::BuildPointingClusterList(const bool useInner, const LArPointingClusterList &inputPointingClusterList,
111  LArPointingClusterList &outputPointingClusterList) const
112 {
113  for (const LArPointingCluster &pointingCluster : inputPointingClusterList)
114  {
115  const LArPointingCluster::Vertex &pointingVertex(useInner ? pointingCluster.GetInnerVertex() : pointingCluster.GetOuterVertex());
116  const HitType hitType(LArClusterHelper::GetClusterHitType(pointingCluster.GetCluster()));
117 
118  if (LArGeometryHelper::IsInGap(this->GetPandora(), pointingVertex.GetPosition(), hitType, m_maxGapTolerance))
119  outputPointingClusterList.push_back(pointingCluster);
120  }
121 }
122 
123 //------------------------------------------------------------------------------------------------------------------------------------------
124 
126 {
127  const float maxLongitudinalDisplacement((pointingVertex2.GetPosition() - pointingVertex1.GetPosition()).GetMagnitude());
128 
129  const bool isAssociated1(LArPointingClusterHelper::IsEmission(pointingVertex1.GetPosition(), pointingVertex2, -1.f,
130  maxLongitudinalDisplacement + 1.f, m_maxTransverseDisplacement, m_maxRelativeAngle));
131  const bool isAssociated2(LArPointingClusterHelper::IsEmission(pointingVertex2.GetPosition(), pointingVertex1, -1.f,
132  maxLongitudinalDisplacement + 1.f, m_maxTransverseDisplacement, m_maxRelativeAngle));
133 
134  return (isAssociated1 && isAssociated2);
135 }
136 
137 //------------------------------------------------------------------------------------------------------------------------------------------
138 
139 bool CrossGapsExtensionAlgorithm::IsAcrossGap(const float minZ, const float maxZ, const HitType hitType) const
140 {
141  if (maxZ - minZ < std::numeric_limits<float>::epsilon())
142  return false;
143 
144  const float gapDeltaZ(LArGeometryHelper::CalculateGapDeltaZ(this->GetPandora(), minZ, maxZ, hitType));
145 
146  if (gapDeltaZ / (maxZ - minZ) < m_minGapFraction)
147  return false;
148 
149  return true;
150 }
151 
152 //------------------------------------------------------------------------------------------------------------------------------------------
153 
154 void CrossGapsExtensionAlgorithm::FillClusterMergeMap(const ClusterAssociationMatrix &inputAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
155 {
156  // Decide which associations will become merges
157  // To make the merge A <-> B, both A -> B and B -> A must be strong associations
158  // with the largest figures of merit of all the A -> X and B -> Y associations
159 
160  // First step: remove double-counting from the map of associations
161  // i.e. if the map has A <-> B, B <-> C, A <-> C, then remove A <-> C
162  ClusterAssociationMatrix clusterAssociationMatrix;
163 
164  ClusterVector sortedInputClusters;
165  for (const auto &mapEntry : inputAssociationMatrix) sortedInputClusters.push_back(mapEntry.first);
166  std::sort(sortedInputClusters.begin(), sortedInputClusters.end(), LArClusterHelper::SortByNHits);
167 
168  for (const Cluster *const pCluster1 : sortedInputClusters)
169  {
170  const ClusterAssociationMap &associationMap1(inputAssociationMatrix.at(pCluster1));
171 
172  for (const Cluster *const pCluster2 : sortedInputClusters)
173  {
174  if (pCluster1 == pCluster2)
175  continue;
176 
177  const ClusterAssociationMap &associationMap2(inputAssociationMatrix.at(pCluster2));
178 
179  ClusterAssociationMap::const_iterator iter12 = associationMap1.find(pCluster2);
180  if (associationMap1.end() == iter12)
181  continue;
182 
183  ClusterAssociationMap::const_iterator iter21 = associationMap2.find(pCluster1);
184  if (associationMap2.end() == iter21)
185  continue;
186 
187  const ClusterAssociation &association12(iter12->second);
188  const ClusterAssociation &association21(iter21->second);
189 
190  bool isAssociated(true);
191 
192  ClusterVector sortedAssociationClusters;
193  for (const auto &mapEntry : associationMap1) sortedAssociationClusters.push_back(mapEntry.first);
194  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
195 
196  for (const Cluster *const pCluster3 : sortedAssociationClusters)
197  {
198  const ClusterAssociation &association13(associationMap1.at(pCluster3));
199 
200  ClusterAssociationMap::const_iterator iter23 = associationMap2.find(pCluster3);
201  if (associationMap2.end() == iter23)
202  continue;
203 
204  const ClusterAssociation &association23(iter23->second);
205 
206  if (association12.GetParent() == association13.GetParent() &&
207  association23.GetParent() == association21.GetParent() &&
208  association13.GetDaughter() != association23.GetDaughter())
209  {
210  isAssociated = false;
211  break;
212  }
213  }
214 
215  if (isAssociated)
216  {
217  (void) clusterAssociationMatrix[pCluster1].insert(ClusterAssociationMap::value_type(pCluster2, association12));
218  (void) clusterAssociationMatrix[pCluster2].insert(ClusterAssociationMap::value_type(pCluster1, association21));
219  }
220  }
221  }
222 
223 
224  // Second step: find the best associations A -> X and B -> Y
225  ClusterAssociationMatrix intermediateAssociationMatrix;
226 
227  ClusterVector sortedClusters;
228  for (const auto &mapEntry : clusterAssociationMatrix) sortedClusters.push_back(mapEntry.first);
229  std::sort(sortedClusters.begin(), sortedClusters.end(), LArClusterHelper::SortByNHits);
230 
231  for (const Cluster *const pParentCluster : sortedClusters)
232  {
233  const ClusterAssociationMap &clusterAssociationMap(clusterAssociationMatrix.at(pParentCluster));
234 
235  const Cluster *pBestClusterInner(nullptr);
237 
238  const Cluster *pBestClusterOuter(nullptr);
240 
241  ClusterVector sortedAssociationClusters;
242  for (const auto &mapEntry : clusterAssociationMap) sortedAssociationClusters.push_back(mapEntry.first);
243  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
244 
245  for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
246  {
247  const ClusterAssociation &clusterAssociation(clusterAssociationMap.at(pDaughterCluster));
248 
249  // Inner associations
250  if (clusterAssociation.GetParent() == ClusterAssociation::INNER)
251  {
252  if (clusterAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
253  {
254  bestAssociationInner = clusterAssociation;
255  pBestClusterInner = pDaughterCluster;
256  }
257  }
258 
259  // Outer associations
260  if (clusterAssociation.GetParent() == ClusterAssociation::OUTER)
261  {
262  if (clusterAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
263  {
264  bestAssociationOuter = clusterAssociation;
265  pBestClusterOuter = pDaughterCluster;
266  }
267  }
268  }
269 
270  if (pBestClusterInner)
271  (void) intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterInner, bestAssociationInner));
272 
273  if (pBestClusterOuter)
274  (void) intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterOuter, bestAssociationOuter));
275  }
276 
277 
278  // Third step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
279  ClusterVector intermediateSortedClusters;
280  for (const auto &mapEntry : intermediateAssociationMatrix) intermediateSortedClusters.push_back(mapEntry.first);
281  std::sort(intermediateSortedClusters.begin(), intermediateSortedClusters.end(), LArClusterHelper::SortByNHits);
282 
283  for (const Cluster *const pParentCluster : intermediateSortedClusters)
284  {
285  const ClusterAssociationMap &parentAssociationMap(intermediateAssociationMatrix.at(pParentCluster));
286 
287  ClusterVector sortedAssociationClusters;
288  for (const auto &mapEntry : parentAssociationMap) sortedAssociationClusters.push_back(mapEntry.first);
289  std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
290 
291  for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
292  {
293  const ClusterAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterCluster));
294 
295  ClusterAssociationMatrix::const_iterator iter5 = intermediateAssociationMatrix.find(pDaughterCluster);
296 
297  if (intermediateAssociationMatrix.end() == iter5)
298  continue;
299 
300  const ClusterAssociationMap &daughterAssociationMap(iter5->second);
301 
302  ClusterAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentCluster);
303 
304  if (daughterAssociationMap.end() == iter6)
305  continue;
306 
307  const ClusterAssociation &daughterToParentAssociation(iter6->second);
308 
309  if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
310  parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
311  {
312  ClusterList &parentList(clusterMergeMap[pParentCluster]);
313 
314  if (parentList.end() == std::find(parentList.begin(), parentList.end(), pDaughterCluster))
315  parentList.push_back(pDaughterCluster);
316  }
317  }
318  }
319 }
320 
321 //------------------------------------------------------------------------------------------------------------------------------------------
322 
323 StatusCode CrossGapsExtensionAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
324 {
325  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
326  "MinClusterLength", m_minClusterLength));
327 
328  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
329  "MinGapFraction", m_minGapFraction));
330 
331  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
332  "MaxGapTolerance", m_maxGapTolerance));
333 
334  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
335  "MaxTransverseDisplacement", m_maxTransverseDisplacement));
336 
337  float maxCosRelativeAngle(std::cos(m_maxRelativeAngle * M_PI / 180.0));
338  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
339  "MaxCosRelativeAngle", maxCosRelativeAngle));
340  m_maxRelativeAngle = (180.0 / M_PI) * std::acos(maxCosRelativeAngle);
341 
342  return ClusterExtensionAlgorithm::ReadSettings(xmlHandle);
343 }
344 
345 } // 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
static bool IsEmission(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxLongitudinalDistance, const float maxTransverseDistance, const float angularAllowance)
Whether pointing vertex is emitted from a given position.
void BuildPointingClusterList(const pandora::ClusterVector &clusterVector, LArPointingClusterList &innerPointingClusterList, LArPointingClusterList &outerPointingClusterList) const
Build lists of pointing clusters that are adjacent to a detector gap.
std::vector< LArPointingCluster > LArPointingClusterList
static float CalculateGapDeltaZ(const pandora::Pandora &pandora, const float minZ, const float maxZ, const pandora::HitType hitType)
Calculate the total distance within a given 2D region that is composed of detector gaps...
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 FillClusterMergeMap(const ClusterAssociationMatrix &clusterAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
Fill the cluster merge map.
LArPointingCluster class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static bool IsInGap(const pandora::Pandora &pandora, const pandora::CartesianVector &testPoint2D, const pandora::HitType hitType, const float gapTolerance=0.f)
Whether a 2D test point lies in a registered gap with the associated hit type.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
void FillClusterAssociationMatrix(const pandora::ClusterVector &clusterVector, ClusterAssociationMatrix &clusterAssociationMatrix) const
Fill the cluster association matrix.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::vector< art::Ptr< recob::Cluster > > ClusterVector
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
bool IsAcrossGap(const float minZ, const float maxZ, const pandora::HitType hitType) const
Determine whether a start and end position sit either side of a gap.
bool IsAssociated(const LArPointingCluster::Vertex &pointingVertex1, const LArPointingCluster::Vertex &pointingVertex2) const
Use pointing information to determine whether two clusters are associated.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
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
Header file for the cross gaps extension algorithm class.