LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
TwoDSlidingFitSplittingAndSwitchingAlgorithm.cc
Go to the documentation of this file.
1 
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  for (ClusterVector::const_iterator iter = clusterVector.begin(), iterEnd = clusterVector.end(); iter != iterEnd; ++iter)
136  {
137  if (slidingFitResultMap.end() == slidingFitResultMap.find(*iter))
138  {
139  try
140  {
141  const float slidingFitPitch(LArGeometryHelper::GetWirePitch(this->GetPandora(), LArClusterHelper::GetClusterHitType(*iter)));
142  const TwoDSlidingFitResult slidingFitResult(*iter, m_halfWindowLayers, slidingFitPitch);
143 
144  if (!slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(*iter, slidingFitResult)).second)
145  throw StatusCodeException(STATUS_CODE_FAILURE);
146  }
147  catch (StatusCodeException &statusCodeException)
148  {
149  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
150  throw statusCodeException;
151  }
152  }
153  }
154 }
155 
156 //------------------------------------------------------------------------------------------------------------------------------------------
157 
158 void TwoDSlidingFitSplittingAndSwitchingAlgorithm::SplitCluster(const Cluster *const pCluster, const CartesianVector &splitPosition,
159  const CartesianVector &splitDirection, CaloHitList &firstCaloHitList, CaloHitList &secondCaloHitList) const
160 {
161  CaloHitList caloHitsToDistribute;
162  pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitsToDistribute);
163 
164  for (CaloHitList::const_iterator iter = caloHitsToDistribute.begin(), iterEnd = caloHitsToDistribute.end(); iter != iterEnd; ++iter)
165  {
166  const CaloHit *const pCaloHit = *iter;
167 
168  if (splitDirection.GetDotProduct((pCaloHit->GetPositionVector() - splitPosition)) > 0.f)
169  {
170  firstCaloHitList.push_back(pCaloHit);
171  }
172  else
173  {
174  secondCaloHitList.push_back(pCaloHit);
175  }
176  }
177 }
178 
179 //------------------------------------------------------------------------------------------------------------------------------------------
180 
181 StatusCode TwoDSlidingFitSplittingAndSwitchingAlgorithm::ReplaceClusters(const Cluster *const pCluster1, const Cluster *const pCluster2,
182  const CartesianVector &splitPosition, const CartesianVector &firstDirection, const CartesianVector &secondDirection) const
183 {
184  // Split cluster into two hit lists (note the convention for 'firstDirection' and 'secondDirection')
185  PandoraContentApi::Cluster::Parameters firstParameters, secondParameters;
186 
187  this->SplitCluster(pCluster1, splitPosition, firstDirection, firstParameters.m_caloHitList, secondParameters.m_caloHitList);
188  this->SplitCluster(pCluster2, splitPosition, secondDirection, secondParameters.m_caloHitList, firstParameters.m_caloHitList);
189 
190  if (firstParameters.m_caloHitList.empty() || secondParameters.m_caloHitList.empty())
191  return STATUS_CODE_NOT_ALLOWED;
192 
193  // Begin cluster fragmentation operations
194  ClusterList clusterList;
195  clusterList.push_back(pCluster1);
196  clusterList.push_back(pCluster2);
197 
198  std::string clusterListToSaveName, clusterListToDeleteName;
199  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
200  PandoraContentApi::InitializeFragmentation(*this, clusterList, clusterListToDeleteName, clusterListToSaveName));
201 
202  // Create new clusters
203  const Cluster *pFirstCluster(NULL), *pSecondCluster(NULL);
204  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, firstParameters, pFirstCluster));
205  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*this, secondParameters, pSecondCluster));
206 
207  // End cluster fragmentation operations
208  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*this, clusterListToSaveName, clusterListToDeleteName));
209 
210  return STATUS_CODE_SUCCESS;
211 }
212 
213 //------------------------------------------------------------------------------------------------------------------------------------------
214 
215 StatusCode TwoDSlidingFitSplittingAndSwitchingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
216 {
217  PANDORA_RETURN_RESULT_IF_AND_IF(
218  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HalfWindowLayers", m_halfWindowLayers));
219 
220  PANDORA_RETURN_RESULT_IF_AND_IF(
221  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterLength", m_minClusterLength));
222 
223  return STATUS_CODE_SUCCESS;
224 }
225 
226 } // 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
intermediate_table::const_iterator const_iterator
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
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.
TFile f
Definition: plotHisto.C:6
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.
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
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...