ThreeDKinkBaseTool.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArThreeDReco/LArTransverseTrackMatching/ThreeDKinkBaseTool.cc
3  *
4  * @brief Implementation of the three d kink base tool class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
14 
16 
17 using namespace pandora;
18 
19 namespace lar_content
20 {
21 
22 ThreeDKinkBaseTool::ThreeDKinkBaseTool(const unsigned int nCommonClusters) :
23  m_nCommonClusters(nCommonClusters),
24  m_majorityRulesMode(false),
25  m_minMatchedFraction(0.75f),
26  m_minMatchedSamplingPoints(10),
27  m_minLongitudinalImpactParameter(-1.f),
28  m_nLayersForKinkSearch(10),
29  m_additionalXStepForKinkSearch(0.01f)
30 {
31  if (!((1 == m_nCommonClusters) || (2 == m_nCommonClusters)))
32  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
33 }
34 
35 //------------------------------------------------------------------------------------------------------------------------------------------
36 
38 {
39 }
40 
41 //------------------------------------------------------------------------------------------------------------------------------------------
42 
43 bool ThreeDKinkBaseTool::PassesElementCuts(TensorType::ElementList::const_iterator eIter, const ClusterSet &usedClusters) const
44 {
45  if (usedClusters.count(eIter->GetClusterU()) || usedClusters.count(eIter->GetClusterV()) || usedClusters.count(eIter->GetClusterW()))
46  return false;
47 
48  if (eIter->GetOverlapResult().GetMatchedFraction() < m_minMatchedFraction)
49  return false;
50 
51  if (eIter->GetOverlapResult().GetNMatchedSamplingPoints() < m_minMatchedSamplingPoints)
52  return false;
53 
54  return true;
55 }
56 
57 //------------------------------------------------------------------------------------------------------------------------------------------
58 
59 float ThreeDKinkBaseTool::GetXSamplingPoint(const CartesianVector &splitPosition1, const bool isForwardInX,
60  const TwoDSlidingFitResult &fitResult1, const TwoDSlidingFitResult &fitResult2, const TwoDSlidingFitResult &fitResult3) const
61 {
62  // Nearest common x position
66  fitResult1.GetMinAndMaxX(xMin1, xMax1);
67  fitResult2.GetMinAndMaxX(xMin2, xMax2);
68  fitResult3.GetMinAndMaxX(xMin3, xMax3);
69 
70  const float commonX(isForwardInX ? std::max(xMin1, std::max(xMin2, xMin3)) : std::min(xMax1, std::min(xMax2, xMax3)));
71 
72  if (isForwardInX && ((commonX > xMax1) || (commonX > xMax2) || (commonX > xMax3)))
73  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
74 
75  if (!isForwardInX && ((commonX < xMin1) || (commonX < xMin2) || (commonX < xMin3)))
76  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
77 
78  // Layer step x position
79  float rL1(0.f), rT1(0.f);
80  fitResult1.GetLocalPosition(splitPosition1, rL1, rT1);
81  const int splitLayer(fitResult1.GetLayer(rL1));
82 
83  const int lowLayer(std::max(fitResult1.GetMinLayer(), std::min(fitResult1.GetMaxLayer(), splitLayer - m_nLayersForKinkSearch)));
84  const int highLayer(std::max(fitResult1.GetMinLayer(), std::min(fitResult1.GetMaxLayer(), splitLayer + m_nLayersForKinkSearch)));
85 
86  CartesianVector minus(0.f, 0.f, 0.f), plus(0.f, 0.f, 0.f);
87  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, fitResult1.GetGlobalFitPosition(fitResult1.GetL(lowLayer), minus));
88  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, fitResult1.GetGlobalFitPosition(fitResult1.GetL(highLayer), plus));
89 
90  if (minus.GetX() > plus.GetX())
91  {
92  CartesianVector temporary(minus);
93  minus = plus;
94  plus = temporary;
95  }
96 
97  const float layerStepX(isForwardInX ? plus.GetX() : minus.GetX());
98 
99  // Final x position selection
100  const float chosenX(isForwardInX ? std::max(layerStepX, commonX) : std::min(layerStepX, commonX));
101  const float finalX(isForwardInX ? chosenX + m_additionalXStepForKinkSearch : chosenX - m_additionalXStepForKinkSearch);
102  return finalX;
103 }
104 
105 //------------------------------------------------------------------------------------------------------------------------------------------
106 
107 bool ThreeDKinkBaseTool::IsALowestInX(const LArPointingCluster &pointingClusterA, const LArPointingCluster &pointingClusterB)
108 {
109  if ((pointingClusterA.GetInnerVertex().GetPosition().GetX() < pointingClusterB.GetInnerVertex().GetPosition().GetX()) &&
110  (pointingClusterA.GetInnerVertex().GetPosition().GetX() < pointingClusterB.GetOuterVertex().GetPosition().GetX()))
111  {
112  return true;
113  }
114 
115  if ((pointingClusterA.GetOuterVertex().GetPosition().GetX() < pointingClusterB.GetInnerVertex().GetPosition().GetX()) &&
116  (pointingClusterA.GetOuterVertex().GetPosition().GetX() < pointingClusterB.GetOuterVertex().GetPosition().GetX()))
117  {
118  return true;
119  }
120 
121  return false;
122 }
123 
124 //------------------------------------------------------------------------------------------------------------------------------------------
125 
127 {
128  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
129  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
130 
131  ModificationList modificationList;
132  this->GetModifications(pAlgorithm, overlapTensor, modificationList);
133  const bool changesMade(this->ApplyChanges(pAlgorithm, modificationList));
134 
135  return changesMade;
136 }
137 
138 //------------------------------------------------------------------------------------------------------------------------------------------
139 
141  ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType &overlapTensor, ModificationList &modificationList) const
142 {
143  ClusterSet usedClusters;
144  ClusterVector sortedKeyClusters;
145  overlapTensor.GetSortedKeyClusters(sortedKeyClusters);
146 
147  for (const Cluster *const pKeyCluster : sortedKeyClusters)
148  {
149  if (!pKeyCluster->IsAvailable())
150  continue;
151 
152  unsigned int nU(0), nV(0), nW(0);
153  TensorType::ElementList elementList;
154  overlapTensor.GetConnectedElements(pKeyCluster, true, elementList, nU, nV, nW);
155 
156  if (nU * nV * nW < 2)
157  continue;
158 
159  for (TensorType::ElementList::const_iterator eIter = elementList.begin(); eIter != elementList.end(); ++eIter)
160  {
161  if (!this->PassesElementCuts(eIter, usedClusters))
162  continue;
163 
164  IteratorList iteratorList;
165  this->SelectTensorElements(eIter, elementList, usedClusters, iteratorList);
166 
167  if (iteratorList.size() < 2)
168  continue;
169 
170  ModificationList localModificationList;
171  this->GetIteratorListModifications(pAlgorithm, iteratorList, localModificationList);
172 
173  if (localModificationList.empty())
174  continue;
175 
176  for (ModificationList::const_iterator mIter = localModificationList.begin(), mIterEnd = localModificationList.end(); mIter != mIterEnd; ++mIter)
177  {
178  usedClusters.insert(mIter->m_affectedClusters.begin(), mIter->m_affectedClusters.end());
179  }
180 
181  modificationList.insert(modificationList.end(), localModificationList.begin(), localModificationList.end());
182  }
183  }
184 }
185 
186 //------------------------------------------------------------------------------------------------------------------------------------------
187 
188 bool ThreeDKinkBaseTool::ApplyChanges(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const ModificationList &modificationList) const
189 {
190  ClusterMergeMap consolidatedMergeMap;
191  SplitPositionMap consolidatedSplitMap;
192 
193  for (const Modification &modification : modificationList)
194  {
195  ClusterList parentClusters;
196  for (const auto &mapEntry : modification.m_clusterMergeMap)
197  parentClusters.push_back(mapEntry.first);
198  parentClusters.sort(LArClusterHelper::SortByNHits);
199 
200  for (const Cluster *const pParentCluster : parentClusters)
201  {
202  const ClusterList &daughterClusters(modification.m_clusterMergeMap.at(pParentCluster));
203 
204  for (const Cluster *const pDaughterCluster : daughterClusters)
205  {
206  if (consolidatedMergeMap.count(pDaughterCluster))
207  throw StatusCodeException(STATUS_CODE_FAILURE);
208  }
209 
210  ClusterList &targetClusterList(consolidatedMergeMap[pParentCluster]);
211  targetClusterList.insert(targetClusterList.end(), daughterClusters.begin(), daughterClusters.end());
212  }
213 
214  ClusterList splitClusters;
215  for (const auto &mapEntry : modification.m_splitPositionMap)
216  splitClusters.push_back(mapEntry.first);
217  splitClusters.sort(LArClusterHelper::SortByNHits);
218 
219  for (const Cluster *const pSplitCluster : splitClusters)
220  {
221  const CartesianPointVector &splitPositions(modification.m_splitPositionMap.at(pSplitCluster));
222 
223  CartesianPointVector &cartesianPointVector(consolidatedSplitMap[pSplitCluster]);
224  cartesianPointVector.insert(cartesianPointVector.end(), splitPositions.begin(), splitPositions.end());
225  }
226  }
227 
228  bool changesMade(false);
229  changesMade |= pAlgorithm->MakeClusterMerges(consolidatedMergeMap);
230  changesMade |= pAlgorithm->MakeClusterSplits(consolidatedSplitMap);
231 
232  return changesMade;
233 }
234 
235 //------------------------------------------------------------------------------------------------------------------------------------------
236 
238  const ClusterSet &usedClusters, IteratorList &iteratorList) const
239 {
240  iteratorList.push_back(eIter);
241 
242  for (TensorType::ElementList::const_iterator eIter2 = elementList.begin(); eIter2 != elementList.end(); ++eIter2)
243  {
244  if (eIter == eIter2)
245  continue;
246 
247  if (!this->PassesElementCuts(eIter2, usedClusters))
248  continue;
249 
250  for (IteratorList::const_iterator iIter = iteratorList.begin(); iIter != iteratorList.end(); ++iIter)
251  {
252  if ((*iIter) == eIter2)
253  continue;
254 
255  unsigned int nMatchedClusters(0);
256 
257  if ((*iIter)->GetClusterU() == eIter2->GetClusterU())
258  ++nMatchedClusters;
259 
260  if ((*iIter)->GetClusterV() == eIter2->GetClusterV())
261  ++nMatchedClusters;
262 
263  if ((*iIter)->GetClusterW() == eIter2->GetClusterW())
264  ++nMatchedClusters;
265 
266  if (m_nCommonClusters == nMatchedClusters)
267  {
268  iteratorList.push_back(eIter2);
269  return;
270  }
271  }
272  }
273 }
274 
275 //------------------------------------------------------------------------------------------------------------------------------------------
276 
277 StatusCode ThreeDKinkBaseTool::ReadSettings(const TiXmlHandle xmlHandle)
278 {
279  PANDORA_RETURN_RESULT_IF_AND_IF(
280  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MajorityRulesMode", m_majorityRulesMode));
281 
282  PANDORA_RETURN_RESULT_IF_AND_IF(
283  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinMatchedFraction", m_minMatchedFraction));
284 
285  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
286  XmlHelper::ReadValue(xmlHandle, "MinMatchedSamplingPoints", m_minMatchedSamplingPoints));
287 
288  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
289  XmlHelper::ReadValue(xmlHandle, "MinLongitudinalImpactParameter", m_minLongitudinalImpactParameter));
290 
291  PANDORA_RETURN_RESULT_IF_AND_IF(
292  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NLayersForKinkSearch", m_nLayersForKinkSearch));
293 
294  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
295  XmlHelper::ReadValue(xmlHandle, "AdditionalXStepForKinkSearch", m_additionalXStepForKinkSearch));
296 
297  return STATUS_CODE_SUCCESS;
298 }
299 
300 } // 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.
std::vector< Modification > ModificationList
bool ApplyChanges(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const ModificationList &modificationList) const
Apply the changes cached in a modification list and update the tensor accordingly.
float GetXSamplingPoint(const pandora::CartesianVector &splitPosition1, const bool isForwardInX, const TwoDSlidingFitResult &fitResult1, const TwoDSlidingFitResult &fitResult2, const TwoDSlidingFitResult &fitResult3) const
Get a sampling point in x that is common to sliding linear fit objects in three views.
virtual bool MakeClusterSplits(const SplitPositionMap &splitPositionMap)
Make cluster splits.
Header file for the lar pointing cluster class.
void GetMinAndMaxX(float &minX, float &maxX) const
Get the minimum and maximum x coordinates associated with the sliding fit.
std::vector< TensorType::ElementList::const_iterator > IteratorList
unsigned int m_nCommonClusters
The number of common clusters.
void GetConnectedElements(const pandora::Cluster *const pCluster, const bool ignoreUnavailable, ElementList &elementList) const
Get a list of elements connected to a specified cluster.
virtual void GetIteratorListModifications(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const IteratorList &iteratorList, ModificationList &modificationList) const =0
Get modification objects for a specific elements of the tensor, identifying required splits and merge...
intermediate_table::const_iterator const_iterator
LArPointingCluster class.
virtual ~ThreeDKinkBaseTool()
Destructor.
Header file for the three d kink base tool.
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
int m_nLayersForKinkSearch
The number of sliding fit layers to step in the kink search.
Header file for the cluster helper class.
pandora::StatusCode GetGlobalFitPosition(const float rL, pandora::CartesianVector &position) const
Get global fit position for a given longitudinal coordinate.
const Vertex & GetOuterVertex() const
Get the outer vertex.
std::unordered_map< const pandora::Cluster *, pandora::CartesianPointVector > SplitPositionMap
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
const Vertex & GetInnerVertex() const
Get the inner vertex.
void GetModifications(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const TensorType &overlapTensor, ModificationList &modificationList) const
Get modification objects, identifying required splits and merges for clusters.
void SelectTensorElements(TensorType::ElementList::const_iterator eIter, const TensorType::ElementList &elementList, const pandora::ClusterSet &usedClusters, IteratorList &iteratorList) const
Select elements representing possible components of interest due to overshoots or undershoots in clus...
virtual bool PassesElementCuts(TensorType::ElementList::const_iterator eIter, const pandora::ClusterSet &usedClusters) const
Whether a provided (iterator to a) tensor element passes the selection cuts for overshoot identificat...
static int max(int a, int b)
void GetSortedKeyClusters(pandora::ClusterVector &sortedKeyClusters) const
Get a sorted vector of key clusters (U clusters with current implementation)
virtual bool MakeClusterMerges(const ClusterMergeMap &clusterMergeMap)
Merge clusters together.
bool Run(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, TensorType &overlapTensor)
Run the algorithm tool.
static bool IsALowestInX(const LArPointingCluster &pointingClusterA, const LArPointingCluster &pointingClusterB)
Whether pointing cluster labelled A extends to lowest x positions (as opposed to that labelled B) ...
float m_additionalXStepForKinkSearch
An additional (safety) step to tack-on when choosing x sampling points.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
unsigned int m_minMatchedSamplingPoints
The min number of matched sampling points for use as a key tensor element.
float GetL(const int layer) const
Get longitudinal coordinate for a given sliding linear fit layer number.
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
bool m_majorityRulesMode
Whether to run in majority rules mode (always split overshoots, always merge undershoots) ...
float m_minLongitudinalImpactParameter
The min longitudinal impact parameter for connecting accompanying clusters.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
float m_minMatchedFraction
The min matched sampling point fraction for use as a key tensor element.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
int GetLayer(const float rL) const
Get layer number for given sliding linear fit longitudinal coordinate.
QTextStream & endl(QTextStream &s)