LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
ClusterAssociationAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
14 
15 using namespace pandora;
16 
17 namespace lar_content
18 {
19 
20 ClusterAssociationAlgorithm::ClusterAssociationAlgorithm() :
21  m_mergeMade(false),
22  m_resolveAmbiguousAssociations(true)
23 {
24 }
25 
26 //------------------------------------------------------------------------------------------------------------------------------------------
27 
29 {
30  const ClusterList *pClusterList = NULL;
31  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pClusterList));
32 
33  ClusterVector clusterVector;
34  this->GetListOfCleanClusters(pClusterList, clusterVector);
35 
36  ClusterAssociationMap clusterAssociationMap;
37  this->PopulateClusterAssociationMap(clusterVector, clusterAssociationMap);
38 
39  m_mergeMade = true;
40 
41  while (m_mergeMade)
42  {
43  // Unambiguous propagation
44  while (m_mergeMade)
45  {
46  m_mergeMade = false;
47 
48  for (const Cluster *const pCluster : clusterVector)
49  {
50  // ATTN The clusterVector may end up with dangling pointers; only protected by this check against managed cluster list
51  if (pClusterList->end() == std::find(pClusterList->begin(), pClusterList->end(), pCluster))
52  continue;
53 
54  this->UnambiguousPropagation(pCluster, true, clusterAssociationMap);
55  this->UnambiguousPropagation(pCluster, false, clusterAssociationMap);
56  }
57  }
58 
60  continue;
61 
62  // Propagation with ambiguities
63  for (const Cluster *const pCluster : clusterVector)
64  {
65  // ATTN The clusterVector may end up with dangling pointers; only protected by this check against up-to-date association list
66  ClusterAssociationMap::const_iterator mapIter = clusterAssociationMap.find(pCluster);
67 
68  if (clusterAssociationMap.end() == mapIter)
69  continue;
70 
71  if (mapIter->second.m_backwardAssociations.empty() && !mapIter->second.m_forwardAssociations.empty())
72  this->AmbiguousPropagation(pCluster, true, clusterAssociationMap);
73 
74  if (mapIter->second.m_forwardAssociations.empty() && !mapIter->second.m_backwardAssociations.empty())
75  this->AmbiguousPropagation(pCluster, false, clusterAssociationMap);
76  }
77  }
78 
79  return STATUS_CODE_SUCCESS;
80 }
81 
82 //------------------------------------------------------------------------------------------------------------------------------------------
83 
84 void ClusterAssociationAlgorithm::UnambiguousPropagation(const Cluster *const pCluster, const bool isForward, ClusterAssociationMap &clusterAssociationMap) const
85 {
86  const Cluster *const pClusterToEnlarge = pCluster;
87  ClusterAssociationMap::iterator iterEnlarge = clusterAssociationMap.find(pClusterToEnlarge);
88 
89  if (clusterAssociationMap.end() == iterEnlarge)
90  return;
91 
92  ClusterSet &clusterSetEnlarge(isForward ? iterEnlarge->second.m_forwardAssociations : iterEnlarge->second.m_backwardAssociations);
93 
94  if (clusterSetEnlarge.size() != 1)
95  return;
96 
97  const Cluster *const pClusterToDelete = *(clusterSetEnlarge.begin());
98  ClusterAssociationMap::iterator iterDelete = clusterAssociationMap.find(pClusterToDelete);
99 
100  if (clusterAssociationMap.end() == iterDelete)
101  return;
102 
103  ClusterSet &clusterSetDelete(isForward ? iterDelete->second.m_backwardAssociations : iterDelete->second.m_forwardAssociations);
104 
105  if (clusterSetDelete.size() != 1)
106  return;
107 
108  this->UpdateForUnambiguousMerge(pClusterToEnlarge, pClusterToDelete, isForward, clusterAssociationMap);
109  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pClusterToEnlarge, pClusterToDelete));
110  m_mergeMade = true;
111 
112  this->UnambiguousPropagation(pClusterToEnlarge, isForward, clusterAssociationMap);
113 }
114 
115 //------------------------------------------------------------------------------------------------------------------------------------------
116 
117 void ClusterAssociationAlgorithm::AmbiguousPropagation(const Cluster *const pCluster, const bool isForward, ClusterAssociationMap &clusterAssociationMap) const
118 {
119  ClusterAssociationMap::iterator cIter = clusterAssociationMap.find(pCluster);
120 
121  if (clusterAssociationMap.end() == cIter)
122  throw StatusCodeException(STATUS_CODE_FAILURE);
123 
124  const Cluster *pExtremalCluster = pCluster;
125 
126  ClusterSet firstClusterSet;
127  this->NavigateAlongAssociations(clusterAssociationMap, pCluster, isForward, pExtremalCluster, firstClusterSet);
128 
129  ClusterSet secondClusterSet;
130  this->NavigateAlongAssociations(clusterAssociationMap, pExtremalCluster, !isForward, pExtremalCluster, secondClusterSet);
131 
132  ClusterVector daughterClusterVector;
133 
134  if (pCluster == pExtremalCluster)
135  {
136  for (const Cluster *const pFirstCluster : firstClusterSet)
137  {
138  if ((pCluster != pFirstCluster) && (secondClusterSet.count(pFirstCluster)) &&
139  (daughterClusterVector.end() == std::find(daughterClusterVector.begin(), daughterClusterVector.end(), pFirstCluster)))
140  {
141  daughterClusterVector.push_back(pFirstCluster);
142  }
143  }
144  }
145 
146  std::sort(daughterClusterVector.begin(), daughterClusterVector.end(), LArClusterHelper::SortByNHits);
147 
148  for (ClusterVector::iterator dIter = daughterClusterVector.begin(), dIterEnd = daughterClusterVector.end(); dIter != dIterEnd; ++dIter)
149  {
150  this->UpdateForAmbiguousMerge(pCluster, *dIter, isForward, clusterAssociationMap);
151  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pCluster, *dIter));
152  m_mergeMade = true;
153  *dIter = NULL;
154  }
155 }
156 
157 //------------------------------------------------------------------------------------------------------------------------------------------
158 
159 void ClusterAssociationAlgorithm::UpdateForUnambiguousMerge(const Cluster *const pClusterToEnlarge, const Cluster *const pClusterToDelete, const bool isForwardMerge,
160  ClusterAssociationMap &clusterAssociationMap) const
161 {
162  ClusterAssociationMap::iterator iterEnlarge = clusterAssociationMap.find(pClusterToEnlarge);
163  ClusterAssociationMap::iterator iterDelete = clusterAssociationMap.find(pClusterToDelete);
164 
165  if ((clusterAssociationMap.end() == iterEnlarge) || (clusterAssociationMap.end() == iterDelete))
166  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
167 
168  ClusterSet &clusterSetToMove(isForwardMerge ? iterDelete->second.m_forwardAssociations : iterDelete->second.m_backwardAssociations);
169  ClusterSet &clusterSetToReplace(isForwardMerge ? iterEnlarge->second.m_forwardAssociations : iterEnlarge->second.m_backwardAssociations);
170  clusterSetToReplace = clusterSetToMove;
171  clusterAssociationMap.erase(iterDelete);
172 
173  for (ClusterAssociationMap::iterator iter = clusterAssociationMap.begin(), iterEnd = clusterAssociationMap.end(); iter != iterEnd; ++iter)
174  {
175  ClusterSet &forwardClusters = iter->second.m_forwardAssociations;
176  ClusterSet &backwardClusters = iter->second.m_backwardAssociations;
177 
178  ClusterSet::iterator forwardIter = forwardClusters.find(pClusterToDelete);
179  ClusterSet::iterator backwardIter = backwardClusters.find(pClusterToDelete);
180 
181  if (forwardClusters.end() != forwardIter)
182  {
183  forwardClusters.erase(forwardIter);
184  forwardClusters.insert(pClusterToEnlarge);
185  }
186 
187  if (backwardClusters.end() != backwardIter)
188  {
189  backwardClusters.erase(backwardIter);
190  backwardClusters.insert(pClusterToEnlarge);
191  }
192  }
193 }
194 
195 //------------------------------------------------------------------------------------------------------------------------------------------
196 
197 void ClusterAssociationAlgorithm::UpdateForAmbiguousMerge(const Cluster *const pClusterToEnlarge, const Cluster *const pClusterToDelete, const bool isForwardMerge,
198  ClusterAssociationMap &clusterAssociationMap) const
199 {
200  ClusterAssociationMap::iterator iterEnlarge = clusterAssociationMap.find(pClusterToEnlarge);
201  ClusterAssociationMap::iterator iterDelete = clusterAssociationMap.find(pClusterToDelete);
202 
203  if ((clusterAssociationMap.end() == iterEnlarge) || (clusterAssociationMap.end() == iterDelete))
204  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
205 
206  ClusterSet &clusterSetEnlarge(isForwardMerge ? iterEnlarge->second.m_forwardAssociations : iterEnlarge->second.m_backwardAssociations);
207  ClusterSet &clusterSetDelete(isForwardMerge ? iterDelete->second.m_backwardAssociations : iterDelete->second.m_forwardAssociations);
208 
209  for (ClusterSet::iterator iter = clusterSetEnlarge.begin(); iter != clusterSetEnlarge.end();)
210  {
211  if ((*iter) != pClusterToDelete)
212  {
213  ClusterAssociationMap::iterator iterAssociation = clusterAssociationMap.find(*iter);
214 
215  if (clusterAssociationMap.end() == iterAssociation)
216  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
217 
218  ClusterSet &associatedClusterSet(isForwardMerge ? iterAssociation->second.m_backwardAssociations : iterAssociation->second.m_forwardAssociations);
219 
220  ClusterSet::iterator enlargeIter = associatedClusterSet.find(pClusterToEnlarge);
221 
222  if (associatedClusterSet.end() == enlargeIter)
223  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
224 
225  associatedClusterSet.erase(enlargeIter);
226  clusterSetEnlarge.erase(iter++);
227  }
228  else
229  {
230  ++iter;
231  }
232  }
233 
234  for (ClusterSet::iterator iter = clusterSetDelete.begin(); iter != clusterSetDelete.end();)
235  {
236  if ((*iter) != pClusterToEnlarge)
237  {
238  ClusterAssociationMap::iterator iterAssociation = clusterAssociationMap.find(*iter);
239 
240  if (clusterAssociationMap.end() == iterAssociation)
241  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
242 
243  ClusterSet &associatedClusterSet(isForwardMerge ? iterAssociation->second.m_forwardAssociations : iterAssociation->second.m_backwardAssociations);
244 
245  ClusterSet::iterator deleteIter = associatedClusterSet.find(pClusterToDelete);
246 
247  if (associatedClusterSet.end() == deleteIter)
248  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
249 
250  associatedClusterSet.erase(deleteIter);
251  clusterSetDelete.erase(iter++);
252  }
253  else
254  {
255  ++iter;
256  }
257  }
258 
259  return this->UpdateForUnambiguousMerge(pClusterToEnlarge, pClusterToDelete, isForwardMerge, clusterAssociationMap);
260 }
261 
262 //------------------------------------------------------------------------------------------------------------------------------------------
263 
264 void ClusterAssociationAlgorithm::NavigateAlongAssociations(const ClusterAssociationMap &clusterAssociationMap, const Cluster *const pCluster,
265  const bool isForward, const Cluster *&pExtremalCluster, ClusterSet &clusterSet) const
266 {
267  ClusterAssociationMap::const_iterator iterAssociation = clusterAssociationMap.find(pCluster);
268 
269  if (clusterAssociationMap.end() == iterAssociation)
270  throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
271 
272  (void) clusterSet.insert(pCluster);
273 
274  if ((pCluster != pExtremalCluster) && this->IsExtremalCluster(isForward, pExtremalCluster, pCluster))
275  pExtremalCluster = pCluster;
276 
277  const ClusterSet &associatedClusterSet(isForward ? iterAssociation->second.m_forwardAssociations : iterAssociation->second.m_backwardAssociations);
278 
279  for (ClusterSet::const_iterator iter = associatedClusterSet.begin(), iterEnd = associatedClusterSet.end(); iter != iterEnd; ++iter)
280  {
281  this->NavigateAlongAssociations(clusterAssociationMap, *iter, isForward, pExtremalCluster, clusterSet);
282  }
283 }
284 
285 //------------------------------------------------------------------------------------------------------------------------------------------
286 
287 StatusCode ClusterAssociationAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
288 {
289  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
290  "ResolveAmbiguousAssociations", m_resolveAmbiguousAssociations));
291 
292  return STATUS_CODE_SUCCESS;
293 }
294 
295 } // 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.
intermediate_table::iterator iterator
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void UpdateForAmbiguousMerge(const pandora::Cluster *const pClusterToEnlarge, const pandora::Cluster *const pClusterToDelete, const bool isForwardMerge, ClusterAssociationMap &clusterAssociationMap) const
Update cluster association map to reflect an ambiguous cluster merge.
bool m_resolveAmbiguousAssociations
Whether to resolve ambiguous associations.
void NavigateAlongAssociations(const ClusterAssociationMap &clusterAssociationMap, const pandora::Cluster *const pCluster, const bool isForward, const pandora::Cluster *&pExtremalCluster, pandora::ClusterSet &clusterSet) const
Navigate along cluster associations, from specified cluster, in specified direction.
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
Header file for the cluster association algorithm class.
void AmbiguousPropagation(const pandora::Cluster *const pCluster, const bool isForward, ClusterAssociationMap &clusterAssociationMap) const
Ambiguous propagation.
virtual void PopulateClusterAssociationMap(const pandora::ClusterVector &clusterVector, ClusterAssociationMap &clusterAssociationMap) const =0
Populate the cluster association map.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
void UnambiguousPropagation(const pandora::Cluster *const pCluster, const bool isForward, ClusterAssociationMap &clusterAssociationMap) const
Unambiguous propagation.
void UpdateForUnambiguousMerge(const pandora::Cluster *const pClusterToEnlarge, const pandora::Cluster *const pClusterToDelete, const bool isForwardMerge, ClusterAssociationMap &clusterAssociationMap) const
Update cluster association map to reflect an unambiguous cluster merge.
std::unordered_map< const pandora::Cluster *, ClusterAssociation > ClusterAssociationMap
virtual void GetListOfCleanClusters(const pandora::ClusterList *const pClusterList, pandora::ClusterVector &clusterVector) const =0
Populate cluster vector with subset of cluster list, containing clusters judged to be clean...
virtual bool IsExtremalCluster(const bool isForward, const pandora::Cluster *const pCurrentCluster, const pandora::Cluster *const pTestCluster) const =0
Determine which of two clusters is extremal.