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