TwoDSlidingFitSplittingAndSwitchingAlgorithm.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArTwoDReco/ClusterSplitting/TwoDSlidingFitSplittingAndSwitchingAlgorithm.cc
3  *
4  * @brief Implementation of the two dimensional sliding fit splitting and splicing algorithm class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
13 
15 
16 using namespace pandora;
17 
18 namespace lar_content
19 {
20 
21 TwoDSlidingFitSplittingAndSwitchingAlgorithm::TwoDSlidingFitSplittingAndSwitchingAlgorithm() :
22  m_halfWindowLayers(25),
23  m_minClusterLength(10.f)
24 {
25 }
26 
27 //------------------------------------------------------------------------------------------------------------------------------------------
28 
30 {
31  const ClusterList *pClusterList = NULL;
32  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pClusterList));
33 
34  // Get ordered list of clean clusters
35  ClusterVector clusterVector;
36  this->GetListOfCleanClusters(pClusterList, clusterVector);
37 
38  // Calculate sliding fit results for clean clusters
39  TwoDSlidingFitResultMap slidingFitResultMap;
40  this->BuildSlidingFitResultMap(clusterVector, slidingFitResultMap);
41 
42  // May choose to cache information here, for subsequent expensive calculations
43  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->PreparationStep(clusterVector));
44 
45  // Loop over clusters, identify split positions, perform splits
46  for (ClusterVector::iterator iter1 = clusterVector.begin(), iterEnd1 = clusterVector.end(); iter1 != iterEnd1; ++iter1)
47  {
48  if (NULL == *iter1)
49  continue;
50 
51  TwoDSlidingFitResultMap::iterator sIter1 = slidingFitResultMap.find(*iter1);
52 
53  if (slidingFitResultMap.end() == sIter1)
54  continue;
55 
56  const TwoDSlidingFitResult &slidingFitResult1(sIter1->second);
57 
58  for (ClusterVector::iterator iter2 = iter1, iterEnd2 = iterEnd1; iter2 != iterEnd2; ++iter2)
59  {
60  if (NULL == *iter2)
61  continue;
62 
63  TwoDSlidingFitResultMap::iterator sIter2 = slidingFitResultMap.find(*iter2);
64 
65  if (slidingFitResultMap.end() == sIter2)
66  continue;
67 
68  const TwoDSlidingFitResult &slidingFitResult2(sIter2->second);
69 
70  if (slidingFitResult1.GetCluster() == slidingFitResult2.GetCluster())
71  continue;
72 
73  CartesianVector splitPosition(0.f, 0.f, 0.f);
74  CartesianVector firstDirection(0.f, 0.f, 0.f);
75  CartesianVector secondDirection(0.f, 0.f, 0.f);
76 
77  if (STATUS_CODE_SUCCESS != this->FindBestSplitPosition(slidingFitResult1, slidingFitResult2, splitPosition, firstDirection, secondDirection))
78  continue;
79 
80  const Cluster *const pCluster1 = slidingFitResult1.GetCluster();
81  const Cluster *const pCluster2 = slidingFitResult2.GetCluster();
82 
83  if (STATUS_CODE_SUCCESS != this->ReplaceClusters(pCluster1, pCluster2, splitPosition, firstDirection, secondDirection))
84  continue;
85 
86  slidingFitResultMap.erase(sIter1);
87  slidingFitResultMap.erase(sIter2);
88 
89  *iter1 = NULL;
90  *iter2 = NULL;
91 
92  break;
93  }
94  }
95 
96  return this->TidyUpStep();
97 }
98 
99 //------------------------------------------------------------------------------------------------------------------------------------------
100 
102 {
103  return STATUS_CODE_SUCCESS;
104 }
105 
106 //------------------------------------------------------------------------------------------------------------------------------------------
107 
109 {
110  return STATUS_CODE_SUCCESS;
111 }
112 
113 //------------------------------------------------------------------------------------------------------------------------------------------
114 
115 void TwoDSlidingFitSplittingAndSwitchingAlgorithm::GetListOfCleanClusters(const ClusterList *const pClusterList, ClusterVector &clusterVector) const
116 {
117  for (ClusterList::const_iterator iter = pClusterList->begin(), iterEnd = pClusterList->end(); iter != iterEnd; ++iter)
118  {
119  const Cluster *const pCluster = *iter;
120 
122  continue;
123 
124  clusterVector.push_back(pCluster);
125  }
126 
127  std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
128 }
129 
130 //------------------------------------------------------------------------------------------------------------------------------------------
131 
133  const ClusterVector &clusterVector, TwoDSlidingFitResultMap &slidingFitResultMap) const
134 {
135  const float slidingFitPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
136 
137  for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
138  {
139  if (slidingFitResultMap.end() == slidingFitResultMap.find(*iter))
140  {
141  try
142  {
143  const TwoDSlidingFitResult slidingFitResult(*iter, m_halfWindowLayers, slidingFitPitch);
144 
145  if (!slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(*iter, slidingFitResult)).second)
146  throw StatusCodeException(STATUS_CODE_FAILURE);
147  }
148  catch (StatusCodeException &statusCodeException)
149  {
150  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
151  throw statusCodeException;
152  }
153  }
154  }
155 }
156 
157 //------------------------------------------------------------------------------------------------------------------------------------------
158 
159 void TwoDSlidingFitSplittingAndSwitchingAlgorithm::SplitCluster(const Cluster *const pCluster, const CartesianVector &splitPosition,
160  const CartesianVector &splitDirection, CaloHitList &firstCaloHitList, CaloHitList &secondCaloHitList) const
161 {
162  CaloHitList caloHitsToDistribute;
163  pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitsToDistribute);
164 
165  for (CaloHitList::const_iterator iter = caloHitsToDistribute.begin(), iterEnd = caloHitsToDistribute.end(); iter != iterEnd; ++iter)
166  {
167  const CaloHit *const pCaloHit = *iter;
168 
169  if (splitDirection.GetDotProduct((pCaloHit->GetPositionVector() - splitPosition)) > 0.f)
170  {
171  firstCaloHitList.push_back(pCaloHit);
172  }
173  else
174  {
175  secondCaloHitList.push_back(pCaloHit);
176  }
177  }
178 }
179 
180 //------------------------------------------------------------------------------------------------------------------------------------------
181 
182 StatusCode TwoDSlidingFitSplittingAndSwitchingAlgorithm::ReplaceClusters(const Cluster *const pCluster1, const Cluster *const pCluster2,
183  const CartesianVector &splitPosition, const CartesianVector &firstDirection, const CartesianVector &secondDirection) const
184 {
185  // Split cluster into two hit lists (note the convention for 'firstDirection' and 'secondDirection')
186  PandoraContentApi::Cluster::Parameters firstParameters, secondParameters;
187 
188  this->SplitCluster(pCluster1, splitPosition, firstDirection, firstParameters.m_caloHitList, secondParameters.m_caloHitList);
189  this->SplitCluster(pCluster2, splitPosition, secondDirection, secondParameters.m_caloHitList, firstParameters.m_caloHitList);
190 
191  if (firstParameters.m_caloHitList.empty() || secondParameters.m_caloHitList.empty())
192  return STATUS_CODE_NOT_ALLOWED;
193 
194  // Begin cluster fragmentation operations
195  ClusterList clusterList;
196  clusterList.push_back(pCluster1);
197  clusterList.push_back(pCluster2);
198 
199  std::string clusterListToSaveName, clusterListToDeleteName;
200  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
201  PandoraContentApi::InitializeFragmentation(*this, clusterList, clusterListToDeleteName, clusterListToSaveName));
202 
203  // Create new clusters
204  const Cluster *pFirstCluster(NULL), *pSecondCluster(NULL);
205  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, firstParameters, pFirstCluster));
206  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, secondParameters, pSecondCluster));
207 
208  // End cluster fragmentation operations
209  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, clusterListToSaveName, clusterListToDeleteName));
210 
211  return STATUS_CODE_SUCCESS;
212 }
213 
214 //------------------------------------------------------------------------------------------------------------------------------------------
215 
216 StatusCode TwoDSlidingFitSplittingAndSwitchingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
217 {
218  PANDORA_RETURN_RESULT_IF_AND_IF(
219  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HalfWindowLayers", m_halfWindowLayers));
220 
221  PANDORA_RETURN_RESULT_IF_AND_IF(
222  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterLength", m_minClusterLength));
223 
224  return STATUS_CODE_SUCCESS;
225 }
226 
227 } // 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.
unsigned int m_halfWindowLayers
half window layers for sliding linear fot
std::string string
Definition: nybbler.cc:12
intermediate_table::const_iterator const_iterator
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
virtual pandora::StatusCode FindBestSplitPosition(const TwoDSlidingFitResult &slidingFit1, const TwoDSlidingFitResult &slidingFit2, pandora::CartesianVector &splitPosition, pandora::CartesianVector &direction1, pandora::CartesianVector &direction2) const =0
Find the best split position and direction for a pair of clusters.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the geometry helper class.
virtual pandora::StatusCode TidyUpStep()
Tidy up any information cached in e.g. the preparation step.
pandora::StatusCode ReplaceClusters(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &firstDirection, const pandora::CartesianVector &secondDirection) const
Replace crossed clusters with un-crossed clusters.
Header file for the cluster helper class.
void SplitCluster(const pandora::Cluster *const pCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection, pandora::CaloHitList &firstCaloHitList, pandora::CaloHitList &secondCaloHitList) const
Split cluster at a given position and direction.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
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...
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
virtual pandora::StatusCode PreparationStep(const pandora::ClusterVector &clusterVector)
Perform any preparatory actions, such as caching information for subsequent expensive calculations...
void BuildSlidingFitResultMap(const pandora::ClusterVector &clusterVector, TwoDSlidingFitResultMap &slidingFitResultMap) const
Build the map of sliding fit results.
Header file for the two dimensional sliding fit splitting and switching algorithm class...