LArSoft  v09_90_00
Liquid Argon Software toolkit - https://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 mapIterFwd = clusterAssociationMap.find(pCluster);
67 
68  if (clusterAssociationMap.end() == mapIterFwd)
69  continue;
70 
71  if (mapIterFwd->second.m_backwardAssociations.empty() && !mapIterFwd->second.m_forwardAssociations.empty())
72  this->AmbiguousPropagation(pCluster, true, clusterAssociationMap);
73 
74  ClusterAssociationMap::const_iterator mapIterBwd = clusterAssociationMap.find(pCluster);
75 
76  if (clusterAssociationMap.end() == mapIterBwd)
77  continue;
78 
79  if (mapIterBwd->second.m_forwardAssociations.empty() && !mapIterBwd->second.m_backwardAssociations.empty())
80  this->AmbiguousPropagation(pCluster, false, clusterAssociationMap);
81  }
82  }
83 
84  return STATUS_CODE_SUCCESS;
85 }
86 
87 //------------------------------------------------------------------------------------------------------------------------------------------
88 
89 void ClusterAssociationAlgorithm::UnambiguousPropagation(const Cluster *const pCluster, const bool isForward, ClusterAssociationMap &clusterAssociationMap) const
90 {
91  const Cluster *const pClusterToEnlarge = pCluster;
92  ClusterAssociationMap::iterator iterEnlarge = clusterAssociationMap.find(pClusterToEnlarge);
93 
94  if (clusterAssociationMap.end() == iterEnlarge)
95  return;
96 
97  ClusterSet &clusterSetEnlarge(isForward ? iterEnlarge->second.m_forwardAssociations : iterEnlarge->second.m_backwardAssociations);
98 
99  if (clusterSetEnlarge.size() != 1)
100  return;
101 
102  const Cluster *const pClusterToDelete = *(clusterSetEnlarge.begin());
103  ClusterAssociationMap::iterator iterDelete = clusterAssociationMap.find(pClusterToDelete);
104 
105  if (clusterAssociationMap.end() == iterDelete)
106  return;
107 
108  ClusterSet &clusterSetDelete(isForward ? iterDelete->second.m_backwardAssociations : iterDelete->second.m_forwardAssociations);
109 
110  if (clusterSetDelete.size() != 1)
111  return;
112 
113  this->UpdateForUnambiguousMerge(pClusterToEnlarge, pClusterToDelete, isForward, clusterAssociationMap);
114 
115  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pClusterToEnlarge, pClusterToDelete));
116  m_mergeMade = true;
117 
118  this->UnambiguousPropagation(pClusterToEnlarge, isForward, clusterAssociationMap);
119 }
120 
121 //------------------------------------------------------------------------------------------------------------------------------------------
122 
123 void ClusterAssociationAlgorithm::AmbiguousPropagation(const Cluster *const pCluster, const bool isForward, ClusterAssociationMap &clusterAssociationMap) const
124 {
125  ClusterAssociationMap::iterator cIter = clusterAssociationMap.find(pCluster);
126 
127  if (clusterAssociationMap.end() == cIter)
128  throw StatusCodeException(STATUS_CODE_FAILURE);
129 
130  const Cluster *pExtremalCluster = pCluster;
131 
132  ClusterSet firstClusterSet;
133  this->NavigateAlongAssociations(clusterAssociationMap, pCluster, isForward, pExtremalCluster, firstClusterSet);
134 
135  ClusterSet secondClusterSet;
136  this->NavigateAlongAssociations(clusterAssociationMap, pExtremalCluster, !isForward, pExtremalCluster, secondClusterSet);
137 
138  ClusterVector daughterClusterVector;
139 
140  if (pCluster == pExtremalCluster)
141  {
142  for (const Cluster *const pFirstCluster : firstClusterSet)
143  {
144  if ((pCluster != pFirstCluster) && (secondClusterSet.count(pFirstCluster)) &&
145  (daughterClusterVector.end() == std::find(daughterClusterVector.begin(), daughterClusterVector.end(), pFirstCluster)))
146  {
147  daughterClusterVector.push_back(pFirstCluster);
148  }
149  }
150  }
151 
152  std::sort(daughterClusterVector.begin(), daughterClusterVector.end(), LArClusterHelper::SortByNHits);
153 
154  for (ClusterVector::iterator dIter = daughterClusterVector.begin(), dIterEnd = daughterClusterVector.end(); dIter != dIterEnd; ++dIter)
155  {
156  this->UpdateForAmbiguousMerge(*dIter, clusterAssociationMap);
157 
158  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*this, pCluster, *dIter));
159  m_mergeMade = true;
160  *dIter = NULL;
161  }
162 
163  this->UpdateForAmbiguousMerge(pCluster, clusterAssociationMap);
164 }
165 
166 //------------------------------------------------------------------------------------------------------------------------------------------
167 
168 void ClusterAssociationAlgorithm::UpdateForUnambiguousMerge(const Cluster *const pClusterToEnlarge, const Cluster *const pClusterToDelete,
169  const bool isForwardMerge, ClusterAssociationMap &clusterAssociationMap) const
170 {
171  ClusterAssociationMap::iterator iterEnlarge = clusterAssociationMap.find(pClusterToEnlarge);
172  ClusterAssociationMap::iterator iterDelete = clusterAssociationMap.find(pClusterToDelete);
173 
174  if ((clusterAssociationMap.end() == iterEnlarge) || (clusterAssociationMap.end() == iterDelete))
175  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
176 
177  ClusterSet &clusterSetToMove(isForwardMerge ? iterDelete->second.m_forwardAssociations : iterDelete->second.m_backwardAssociations);
178  ClusterSet &clusterSetToReplace(isForwardMerge ? iterEnlarge->second.m_forwardAssociations : iterEnlarge->second.m_backwardAssociations);
179  clusterSetToReplace = clusterSetToMove;
180  clusterAssociationMap.erase(iterDelete);
181 
182  for (ClusterAssociationMap::iterator iter = clusterAssociationMap.begin(), iterEnd = clusterAssociationMap.end(); iter != iterEnd; ++iter)
183  {
184  ClusterSet &forwardClusters = iter->second.m_forwardAssociations;
185  ClusterSet &backwardClusters = iter->second.m_backwardAssociations;
186 
187  ClusterSet::iterator forwardIter = forwardClusters.find(pClusterToDelete);
188  ClusterSet::iterator backwardIter = backwardClusters.find(pClusterToDelete);
189 
190  if (forwardClusters.end() != forwardIter)
191  {
192  forwardClusters.erase(forwardIter);
193  forwardClusters.insert(pClusterToEnlarge);
194  }
195 
196  if (backwardClusters.end() != backwardIter)
197  {
198  backwardClusters.erase(backwardIter);
199  backwardClusters.insert(pClusterToEnlarge);
200  }
201  }
202 }
203 
204 //------------------------------------------------------------------------------------------------------------------------------------------
205 
206 void ClusterAssociationAlgorithm::UpdateForAmbiguousMerge(const Cluster *const pCluster, ClusterAssociationMap &clusterAssociationMap) const
207 {
208  ClusterAssociationMap::iterator cIter = clusterAssociationMap.find(pCluster);
209 
210  if (clusterAssociationMap.end() == cIter)
211  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
212 
213  for (ClusterAssociationMap::iterator mIter = clusterAssociationMap.begin(), mIterEnd = clusterAssociationMap.end(); mIter != mIterEnd; ++mIter)
214  {
215  ClusterSet &forwardClusters = mIter->second.m_forwardAssociations;
216  ClusterSet &backwardClusters = mIter->second.m_backwardAssociations;
217 
218  ClusterSet::iterator fIter = forwardClusters.find(pCluster);
219  ClusterSet::iterator bIter = backwardClusters.find(pCluster);
220 
221  if (forwardClusters.end() != fIter)
222  forwardClusters.erase(fIter);
223 
224  if (backwardClusters.end() != bIter)
225  backwardClusters.erase(bIter);
226  }
227 
228  clusterAssociationMap.erase(pCluster);
229 }
230 
231 //------------------------------------------------------------------------------------------------------------------------------------------
232 
234  const Cluster *const pCluster, const bool isForward, const Cluster *&pExtremalCluster, ClusterSet &clusterSet) const
235 {
236  ClusterAssociationMap::const_iterator iterAssociation = clusterAssociationMap.find(pCluster);
237 
238  if (clusterAssociationMap.end() == iterAssociation)
239  throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
240 
241  (void)clusterSet.insert(pCluster);
242 
243  if ((pCluster != pExtremalCluster) && this->IsExtremalCluster(isForward, pExtremalCluster, pCluster))
244  pExtremalCluster = pCluster;
245 
246  const ClusterSet &associatedClusterSet(isForward ? iterAssociation->second.m_forwardAssociations : iterAssociation->second.m_backwardAssociations);
247 
248  for (ClusterSet::const_iterator iter = associatedClusterSet.begin(), iterEnd = associatedClusterSet.end(); iter != iterEnd; ++iter)
249  {
250  this->NavigateAlongAssociations(clusterAssociationMap, *iter, isForward, pExtremalCluster, clusterSet);
251  }
252 }
253 
254 //------------------------------------------------------------------------------------------------------------------------------------------
255 
256 StatusCode ClusterAssociationAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
257 {
258  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
259  XmlHelper::ReadValue(xmlHandle, "ResolveAmbiguousAssociations", m_resolveAmbiguousAssociations));
260 
261  return STATUS_CODE_SUCCESS;
262 }
263 
264 } // 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.