UndershootTracksTool.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArThreeDReco/LArTransverseTrackMatching/UndershootTracksTool.cc
3  *
4  * @brief Implementation of the undershoot tracks tool class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
14 
16 
18 
19 using namespace pandora;
20 
21 namespace lar_content
22 {
23 
24 UndershootTracksTool::UndershootTracksTool() :
26  m_splitMode(false),
27  m_maxTransverseImpactParameter(5.f),
28  m_minImpactParameterCosTheta(0.5f),
29  m_cosThetaCutForKinkSearch(0.75f)
30 {
31 }
32 
33 //------------------------------------------------------------------------------------------------------------------------------------------
34 
36  ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const IteratorList &iteratorList, ModificationList &modificationList) const
37 {
38  for (IteratorList::const_iterator iIter1 = iteratorList.begin(), iIter1End = iteratorList.end(); iIter1 != iIter1End; ++iIter1)
39  {
40  for (IteratorList::const_iterator iIter2 = iIter1; iIter2 != iIter1End; ++iIter2)
41  {
42  if (iIter1 == iIter2)
43  continue;
44 
45  try
46  {
47  const unsigned int nMatchedSamplingPoints1((*iIter1)->GetOverlapResult().GetNMatchedSamplingPoints());
48  const unsigned int nMatchedSamplingPoints2((*iIter2)->GetOverlapResult().GetNMatchedSamplingPoints());
49  IteratorList::const_iterator iIterA((nMatchedSamplingPoints1 >= nMatchedSamplingPoints2) ? iIter1 : iIter2);
50  IteratorList::const_iterator iIterB((nMatchedSamplingPoints1 >= nMatchedSamplingPoints2) ? iIter2 : iIter1);
51 
52  Particle particle(*(*iIterA), *(*iIterB));
53  const LArPointingCluster pointingClusterA(pAlgorithm->GetCachedSlidingFitResult(particle.m_pClusterA));
54  const LArPointingCluster pointingClusterB(pAlgorithm->GetCachedSlidingFitResult(particle.m_pClusterB));
55 
56  LArPointingCluster::Vertex vertexA, vertexB;
57  LArPointingClusterHelper::GetClosestVertices(pointingClusterA, pointingClusterB, vertexA, vertexB);
58 
59  float transverseAB(std::numeric_limits<float>::max()), transverseBA(std::numeric_limits<float>::max());
60  float longitudinalAB(-std::numeric_limits<float>::max()), longitudinalBA(-std::numeric_limits<float>::max());
61 
62  LArPointingClusterHelper::GetImpactParameters(vertexA, vertexB, longitudinalAB, transverseAB);
63  LArPointingClusterHelper::GetImpactParameters(vertexB, vertexA, longitudinalBA, transverseBA);
64 
65  if (std::min(longitudinalAB, longitudinalBA) < m_minLongitudinalImpactParameter)
66  continue;
67 
68  if (std::min(transverseAB, transverseBA) > m_maxTransverseImpactParameter)
69  continue;
70 
71  const float cosTheta(-vertexA.GetDirection().GetCosOpeningAngle(vertexB.GetDirection()));
72 
73  if (cosTheta < m_minImpactParameterCosTheta)
74  continue;
75 
76  const bool isALowestInX(this->IsALowestInX(pointingClusterA, pointingClusterB));
77  const CartesianVector splitPosition((vertexA.GetPosition() + vertexB.GetPosition()) * 0.5f);
78  const bool isThreeDKink(m_majorityRulesMode ? false : this->IsThreeDKink(pAlgorithm, particle, splitPosition, isALowestInX));
79 
80  if (isThreeDKink != m_splitMode)
81  continue;
82 
83  // Construct the modification object
84  Modification modification;
85 
86  if (m_splitMode)
87  {
88  const TwoDSlidingFitResult &fitResult1(pAlgorithm->GetCachedSlidingFitResult(particle.m_pCommonCluster1));
89  const TwoDSlidingFitResult &fitResult2(pAlgorithm->GetCachedSlidingFitResult(particle.m_pCommonCluster2));
90 
91  CartesianVector splitPosition1(0.f, 0.f, 0.f), splitPosition2(0.f, 0.f, 0.f);
92  if ((STATUS_CODE_SUCCESS != fitResult1.GetGlobalFitPositionAtX(splitPosition.GetX(), splitPosition1)) ||
93  (STATUS_CODE_SUCCESS != fitResult2.GetGlobalFitPositionAtX(splitPosition.GetX(), splitPosition2)))
94  {
95  continue;
96  }
97 
98  modification.m_splitPositionMap[particle.m_pCommonCluster1].push_back(splitPosition1);
99  modification.m_splitPositionMap[particle.m_pCommonCluster2].push_back(splitPosition2);
100  }
101  else
102  {
103  const bool vertexAIsLowX(vertexA.GetPosition().GetX() < vertexB.GetPosition().GetX());
104  const Cluster *const pLowXCluster(vertexAIsLowX ? particle.m_pClusterA : particle.m_pClusterB);
105  const Cluster *const pHighXCluster(vertexAIsLowX ? particle.m_pClusterB : particle.m_pClusterA);
106  modification.m_clusterMergeMap[pLowXCluster].push_back(pHighXCluster);
107  }
108 
109  modification.m_affectedClusters.push_back(particle.m_pClusterA);
110  modification.m_affectedClusters.push_back(particle.m_pClusterB);
111  modification.m_affectedClusters.push_back(particle.m_pCommonCluster1);
112  modification.m_affectedClusters.push_back(particle.m_pCommonCluster2);
113 
114  modificationList.push_back(modification);
115  }
116  catch (StatusCodeException &statusCodeException)
117  {
118  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
119  throw statusCodeException;
120 
121  continue;
122  }
123  }
124  }
125 }
126 
127 //------------------------------------------------------------------------------------------------------------------------------------------
128 
130  const CartesianVector &splitPosition, const bool isALowestInX) const
131 {
132  try
133  {
134  const TwoDSlidingFitResult &fitResultCommon1(pAlgorithm->GetCachedSlidingFitResult(particle.m_pCommonCluster1));
135  const TwoDSlidingFitResult &fitResultCommon2(pAlgorithm->GetCachedSlidingFitResult(particle.m_pCommonCluster2));
136  const TwoDSlidingFitResult &lowXFitResult(isALowestInX ? pAlgorithm->GetCachedSlidingFitResult(particle.m_pClusterA)
137  : pAlgorithm->GetCachedSlidingFitResult(particle.m_pClusterB));
138  const TwoDSlidingFitResult &highXFitResult(isALowestInX ? pAlgorithm->GetCachedSlidingFitResult(particle.m_pClusterB)
139  : pAlgorithm->GetCachedSlidingFitResult(particle.m_pClusterA));
140 
141  const float minusX(this->GetXSamplingPoint(splitPosition, false, lowXFitResult, fitResultCommon1, fitResultCommon2));
142  const float plusX(this->GetXSamplingPoint(splitPosition, true, highXFitResult, fitResultCommon1, fitResultCommon2));
143  const float splitX(splitPosition.GetX());
144 
145  CartesianVector minus1(0.f, 0.f, 0.f), split1(0.f, 0.f, 0.f), plus1(0.f, 0.f, 0.f);
146  CartesianVector minus2(0.f, 0.f, 0.f), split2(0.f, 0.f, 0.f), plus2(0.f, 0.f, 0.f);
147  CartesianVector minus3(0.f, 0.f, 0.f), split3(splitPosition), plus3(0.f, 0.f, 0.f);
148 
149  if ((STATUS_CODE_SUCCESS != fitResultCommon1.GetGlobalFitPositionAtX(minusX, minus1)) ||
150  (STATUS_CODE_SUCCESS != fitResultCommon1.GetGlobalFitPositionAtX(splitX, split1)) ||
151  (STATUS_CODE_SUCCESS != fitResultCommon1.GetGlobalFitPositionAtX(plusX, plus1)) ||
152  (STATUS_CODE_SUCCESS != fitResultCommon2.GetGlobalFitPositionAtX(minusX, minus2)) ||
153  (STATUS_CODE_SUCCESS != fitResultCommon2.GetGlobalFitPositionAtX(splitX, split2)) ||
154  (STATUS_CODE_SUCCESS != fitResultCommon2.GetGlobalFitPositionAtX(plusX, plus2)) ||
155  (STATUS_CODE_SUCCESS != lowXFitResult.GetGlobalFitPositionAtX(minusX, minus3)) ||
156  (STATUS_CODE_SUCCESS != highXFitResult.GetGlobalFitPositionAtX(plusX, plus3)))
157  {
158  return false; // majority rules, by default
159  }
160 
161  // Extract results
164  const HitType hitType3(LArClusterHelper::GetClusterHitType(particle.m_pClusterA));
165 
166  CartesianVector minus(0.f, 0.f, 0.f), split(0.f, 0.f, 0.f), plus(0.f, 0.f, 0.f);
167  float chi2Minus(std::numeric_limits<float>::max()), chi2Split(std::numeric_limits<float>::max()),
169  LArGeometryHelper::MergeThreePositions3D(this->GetPandora(), hitType1, hitType2, hitType3, minus1, minus2, minus3, minus, chi2Minus);
170  LArGeometryHelper::MergeThreePositions3D(this->GetPandora(), hitType1, hitType2, hitType3, split1, split2, split3, split, chi2Split);
171  LArGeometryHelper::MergeThreePositions3D(this->GetPandora(), hitType1, hitType2, hitType3, plus1, plus2, plus3, plus, chi2Plus);
172 
173  // Apply final cuts
174  const CartesianVector minusToSplit((split - minus).GetUnitVector());
175  const CartesianVector splitToPlus((plus - split).GetUnitVector());
176  const float dotProduct(minusToSplit.GetDotProduct(splitToPlus));
177 
178  if (dotProduct < m_cosThetaCutForKinkSearch)
179  return true;
180  }
181  catch (StatusCodeException &s)
182  {
183  }
184 
185  return false;
186 }
187 
188 //------------------------------------------------------------------------------------------------------------------------------------------
189 //------------------------------------------------------------------------------------------------------------------------------------------
190 
191 UndershootTracksTool::Particle::Particle(const TensorType::Element &elementA, const TensorType::Element &elementB)
192 {
193  m_pClusterA = (elementA.GetClusterU() != elementB.GetClusterU())
194  ? elementA.GetClusterU()
195  : (elementA.GetClusterV() != elementB.GetClusterV()) ? elementA.GetClusterV() : elementA.GetClusterW();
196  m_pClusterB = (elementA.GetClusterU() != elementB.GetClusterU())
197  ? elementB.GetClusterU()
198  : (elementA.GetClusterV() != elementB.GetClusterV()) ? elementB.GetClusterV() : elementB.GetClusterW();
199  m_pCommonCluster1 = (elementA.GetClusterU() == elementB.GetClusterU())
200  ? elementA.GetClusterU()
201  : (elementA.GetClusterV() == elementB.GetClusterV()) ? elementA.GetClusterV() : elementA.GetClusterW();
202  m_pCommonCluster2 = ((m_pClusterA != elementA.GetClusterU()) && (m_pCommonCluster1 != elementA.GetClusterU()))
203  ? elementA.GetClusterU()
204  : ((m_pClusterA != elementA.GetClusterV()) && (m_pCommonCluster1 != elementA.GetClusterV()))
205  ? elementA.GetClusterV()
206  : elementA.GetClusterW();
207 
208  if ((m_pClusterA == m_pClusterB) || (m_pCommonCluster1 == m_pCommonCluster2))
209  throw StatusCodeException(STATUS_CODE_FAILURE);
210 }
211 
212 //------------------------------------------------------------------------------------------------------------------------------------------
213 //------------------------------------------------------------------------------------------------------------------------------------------
214 
215 StatusCode UndershootTracksTool::ReadSettings(const TiXmlHandle xmlHandle)
216 {
217  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SplitMode", m_splitMode));
218 
219  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
220  XmlHelper::ReadValue(xmlHandle, "MaxTransverseImpactParameter", m_maxTransverseImpactParameter));
221 
222  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
223  XmlHelper::ReadValue(xmlHandle, "MinImpactParameterCosTheta", m_minImpactParameterCosTheta));
224 
225  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
226  XmlHelper::ReadValue(xmlHandle, "CosThetaCutForKinkSearch", m_cosThetaCutForKinkSearch));
227 
228  return ThreeDKinkBaseTool::ReadSettings(xmlHandle);
229 }
230 
231 } // namespace lar_content
pandora::ClusterList m_affectedClusters
The list of affected clusters.
std::vector< Modification > ModificationList
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.
const pandora::Cluster * m_pClusterA
Address of non-shared cluster in element A.
Header file for the lar pointing cluster class.
std::vector< TensorType::ElementList::const_iterator > IteratorList
enum cvn::HType HitType
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
intermediate_table::const_iterator const_iterator
LArPointingCluster class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
ClusterMergeMap m_clusterMergeMap
The cluster merge map.
static void GetClosestVertices(const bool useX, const bool useY, const bool useZ, const LArPointingCluster &pointingClusterI, const LArPointingCluster &pointingClusterJ, LArPointingCluster::Vertex &closestVertexI, LArPointingCluster::Vertex &closestVertexJ)
Given a pair of pointing clusters, receive the closest or farthest pair of vertices.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the geometry helper class.
float m_cosThetaCutForKinkSearch
The cos theta cut used for the kink search in three dimensions.
float m_minImpactParameterCosTheta
The minimum cos theta (angle between vertex directions) for connecting broken clusters.
Header file for the cluster helper class.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
const pandora::Cluster * m_pCommonCluster1
Address of the common cluster in view 1.
const pandora::Cluster * m_pClusterB
Address of non-shared cluster in element B.
static void MergeThreePositions3D(const pandora::Pandora &pandora, const pandora::HitType view1, const pandora::HitType view2, const pandora::HitType view3, const pandora::CartesianVector &position1, const pandora::CartesianVector &position2, const pandora::CartesianVector &position3, pandora::CartesianVector &position3D, float &chiSquared)
Merge 2D positions from three views to give unified 3D position.
static int max(int a, int b)
bool m_splitMode
Whether to run in cluster splitting mode, as opposed to cluster merging mode.
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) ...
bool IsThreeDKink(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const Particle &particle, const pandora::CartesianVector &splitPosition, const bool isALowestInX) const
Whether the provided particle is consistent with being a kink, when examined in three dimensions at t...
void GetIteratorListModifications(ThreeViewTransverseTracksAlgorithm *const pAlgorithm, const IteratorList &iteratorList, ModificationList &modificationList) const
Get modification objects for a specific elements of the tensor, identifying required splits and merge...
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
ThreeDKinkBaseTool class.
const pandora::Cluster * m_pCommonCluster2
Address of the common cluster in view 2.
bool m_majorityRulesMode
Whether to run in majority rules mode (always split overshoots, always merge undershoots) ...
void split(std::string const &s, char c, OutIter dest)
Definition: split.h:35
float m_minLongitudinalImpactParameter
The min longitudinal impact parameter for connecting accompanying clusters.
float m_maxTransverseImpactParameter
The maximum transverse impact parameter for connecting broken clusters.
Header file for the undershoot tracks tool class.
Particle(const TensorType::Element &elementA, const TensorType::Element &elementB)
Constructor.
static QCString * s
Definition: config.cpp:1042
SplitPositionMap m_splitPositionMap
The split position map.