VertexRefinementAlgorithm.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArVertex/VertexRefinementAlgorithm.cc
3  *
4  * @brief Implementation of the vertex refinement algorithm class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
14 
16 
17 #include <Eigen/Dense>
18 
19 using namespace pandora;
20 
21 namespace lar_content
22 {
23 
24 VertexRefinementAlgorithm::VertexRefinementAlgorithm() :
25  m_chiSquaredCut(2.f),
26  m_distanceCut(5.f),
27  m_minimumHitsCut(5),
28  m_twoDDistanceCut(10.f)
29 {
30 }
31 
32 //------------------------------------------------------------------------------------------------------------------------------------------
33 
35 {
36  const VertexList *pInputVertexList(nullptr);
37  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pInputVertexList));
38 
39  if (!pInputVertexList || pInputVertexList->empty())
40  {
41  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
42  std::cout << "VertexRefinementAlgorithm: unable to find current vertex list " << std::endl;
43 
44  return STATUS_CODE_SUCCESS;
45  }
46 
47  const VertexList *pOutputVertexList(NULL);
48  std::string temporaryListName;
49  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pOutputVertexList, temporaryListName));
50 
51  ClusterList clusterListU, clusterListV, clusterListW;
52  this->GetClusterLists(m_inputClusterListNames, clusterListU, clusterListV, clusterListW);
53 
54  this->RefineVertices(pInputVertexList, clusterListU, clusterListV, clusterListW);
55 
56  if (!pOutputVertexList->empty())
57  {
58  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*this, m_outputVertexListName));
59  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*this, m_outputVertexListName));
60  }
61 
62  return STATUS_CODE_SUCCESS;
63 }
64 
65 //------------------------------------------------------------------------------------------------------------------------------------------
66 
68  const StringVector &inputClusterListNames, ClusterList &clusterListU, ClusterList &clusterListV, ClusterList &clusterListW) const
69 {
70  for (const std::string &clusterListName : inputClusterListNames)
71  {
72  const ClusterList *pClusterList(nullptr);
73  PANDORA_THROW_RESULT_IF_AND_IF(
74  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, clusterListName, pClusterList));
75 
76  if (!pClusterList || pClusterList->empty())
77  {
78  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
79  std::cout << "VertexRefinementAlgorithm: unable to find cluster list " << clusterListName << std::endl;
80 
81  continue;
82  }
83 
84  const HitType hitType(LArClusterHelper::GetClusterHitType(pClusterList->front()));
85 
86  if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
87  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
88 
89  ClusterList &outputClusterList((TPC_VIEW_U == hitType) ? clusterListU : (TPC_VIEW_V == hitType) ? clusterListV : clusterListW);
90  outputClusterList.insert(outputClusterList.end(), pClusterList->begin(), pClusterList->end());
91  }
92 }
93 
94 //------------------------------------------------------------------------------------------------------------------------------------------
95 
96 void VertexRefinementAlgorithm::RefineVertices(const VertexList *const pVertexList, const ClusterList &clusterListU,
97  const ClusterList &clusterListV, const ClusterList &clusterListW) const
98 {
99  for (const Vertex *const pVertex : *pVertexList)
100  {
101  const CartesianVector originalPosition(pVertex->GetPosition());
102 
103  const CartesianVector vtxU(
104  this->RefineVertexTwoD(clusterListU, LArGeometryHelper::ProjectPosition(this->GetPandora(), originalPosition, TPC_VIEW_U)));
105  const CartesianVector vtxV(
106  this->RefineVertexTwoD(clusterListV, LArGeometryHelper::ProjectPosition(this->GetPandora(), originalPosition, TPC_VIEW_V)));
107  const CartesianVector vtxW(
108  this->RefineVertexTwoD(clusterListW, LArGeometryHelper::ProjectPosition(this->GetPandora(), originalPosition, TPC_VIEW_W)));
109 
110  CartesianVector vtxUV(0.f, 0.f, 0.f), vtxUW(0.f, 0.f, 0.f), vtxVW(0.f, 0.f, 0.f), vtx3D(0.f, 0.f, 0.f), position3D(0.f, 0.f, 0.f);
111  float chi2UV(0.f), chi2UW(0.f), chi2VW(0.f), chi23D(0.f), chi2(0.f);
112 
113  LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), TPC_VIEW_U, TPC_VIEW_V, vtxU, vtxV, vtxUV, chi2UV);
114  LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), TPC_VIEW_U, TPC_VIEW_W, vtxU, vtxW, vtxUW, chi2UW);
115  LArGeometryHelper::MergeTwoPositions3D(this->GetPandora(), TPC_VIEW_V, TPC_VIEW_W, vtxV, vtxW, vtxVW, chi2VW);
116  LArGeometryHelper::MergeThreePositions3D(this->GetPandora(), TPC_VIEW_U, TPC_VIEW_V, TPC_VIEW_W, vtxU, vtxV, vtxW, vtx3D, chi23D);
117 
118  if (chi2UV < chi2UW && chi2UV < chi2VW && chi2UV < chi23D)
119  {
120  position3D = vtxUV;
121  chi2 = chi2UV;
122  }
123  else if (chi2UW < chi2VW && chi2UW < chi23D)
124  {
125  position3D = vtxUW;
126  chi2 = chi2UW;
127  }
128  else if (chi2VW < chi23D)
129  {
130  position3D = vtxVW;
131  chi2 = chi2VW;
132  }
133  else
134  {
135  position3D = vtx3D;
136  chi2 = chi23D;
137  }
138 
139  if (chi2 > m_chiSquaredCut)
140  position3D = originalPosition;
141 
142  if ((position3D - originalPosition).GetMagnitude() > m_distanceCut)
143  position3D = originalPosition;
144 
145  PandoraContentApi::Vertex::Parameters parameters;
146  parameters.m_position = position3D;
147  parameters.m_vertexLabel = VERTEX_INTERACTION;
148  parameters.m_vertexType = VERTEX_3D;
149 
150  const Vertex *pNewVertex(NULL);
151  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*this, parameters, pNewVertex));
152  }
153 }
154 
155 //------------------------------------------------------------------------------------------------------------------------------------------
156 
157 CartesianVector VertexRefinementAlgorithm::RefineVertexTwoD(const ClusterList &clusterList, const CartesianVector &originalVtxPos) const
158 {
159  CartesianPointVector intercepts, directions;
160  FloatVector weights;
161 
162  for (const Cluster *const pCluster : clusterList)
163  {
164  if (LArClusterHelper::GetClosestDistance(originalVtxPos, pCluster) > 10)
165  continue;
166 
167  if (pCluster->GetNCaloHits() < m_minimumHitsCut)
168  continue;
169 
170  CartesianVector centroid(0.f, 0.f, 0.f);
171  LArPcaHelper::EigenValues eigenValues(0.f, 0.f, 0.f);
172  LArPcaHelper::EigenVectors eigenVectors;
173  CartesianPointVector pointVector;
174 
175  LArClusterHelper::GetCoordinateVector(pCluster, pointVector);
176  LArPcaHelper::RunPca(pointVector, centroid, eigenValues, eigenVectors);
177 
178  intercepts.push_back(LArClusterHelper::GetClosestPosition(originalVtxPos, pCluster));
179  directions.push_back(eigenVectors.at(0).GetUnitVector());
180  weights.push_back(1.f / ((LArClusterHelper::GetClosestPosition(originalVtxPos, pCluster) - originalVtxPos).GetMagnitudeSquared() + 1));
181  }
182 
183  CartesianVector newVtxPos(originalVtxPos);
184  if (intercepts.size() > 1)
185  GetBestFitPoint(intercepts, directions, weights, newVtxPos);
186 
187  if ((newVtxPos - originalVtxPos).GetMagnitude() > m_twoDDistanceCut)
188  return originalVtxPos;
189 
190  return newVtxPos;
191 }
192 
193 //------------------------------------------------------------------------------------------------------------------------------------------
194 
195 void VertexRefinementAlgorithm::GetBestFitPoint(const CartesianPointVector &intercepts, const CartesianPointVector &directions,
196  const FloatVector &weights, CartesianVector &bestFitPoint) const
197 {
198  const int n(intercepts.size());
199 
200  Eigen::VectorXd d = Eigen::VectorXd::Zero(3 * n);
201  Eigen::MatrixXd G = Eigen::MatrixXd::Zero(3 * n, n + 3);
202 
203  for (int i = 0; i < n; ++i)
204  {
205  d(3 * i) = intercepts[i].GetX() * weights[i];
206  d(3 * i + 1) = intercepts[i].GetY() * weights[i];
207  d(3 * i + 2) = intercepts[i].GetZ() * weights[i];
208 
209  G(3 * i, 0) = weights[i];
210  G(3 * i + 1, 1) = weights[i];
211  G(3 * i + 2, 2) = weights[i];
212 
213  G(3 * i, i + 3) = -directions[i].GetX();
214  G(3 * i + 1, i + 3) = -directions[i].GetY();
215  G(3 * i + 2, i + 3) = -directions[i].GetZ();
216  }
217 
218  if ((G.transpose() * G).determinant() < std::numeric_limits<float>::epsilon())
219  {
221  return;
222  }
223 
224  Eigen::VectorXd m = (G.transpose() * G).inverse() * G.transpose() * d;
225 
226  bestFitPoint = CartesianVector(m[0], m[1], m[2]);
227 }
228 
229 //------------------------------------------------------------------------------------------------------------------------------------------
230 
231 StatusCode VertexRefinementAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
232 {
233  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputClusterListNames", m_inputClusterListNames));
234 
235  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputVertexListName", m_inputVertexListName));
236 
237  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "OutputVertexListName", m_outputVertexListName));
238 
239  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ChiSquaredCut", m_chiSquaredCut));
240 
241  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "DistanceCut", m_distanceCut));
242 
243  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinimumHitsCut", m_minimumHitsCut));
244 
245  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "TwoDDistanceCut", m_twoDDistanceCut));
246 
247  return STATUS_CODE_SUCCESS;
248 }
249 
250 } // namespace lar_content
float m_chiSquaredCut
The maximum chi2 value a refined vertex can have to be kept.
static void MergeTwoPositions3D(const pandora::Pandora &pandora, const pandora::HitType view1, const pandora::HitType view2, const pandora::CartesianVector &position1, const pandora::CartesianVector &position2, pandora::CartesianVector &position3D, float &chiSquared)
Merge 2D positions from two views to give unified 3D position.
enum cvn::HType HitType
std::string string
Definition: nybbler.cc:12
pandora::CartesianVector EigenValues
Definition: LArPcaHelper.h:24
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
unsigned int m_minimumHitsCut
The minimum size of a cluster to be used in refinement.
Header file for the principal curve analysis helper class.
pandora::CartesianVector RefineVertexTwoD(const pandora::ClusterList &clusterList, const pandora::CartesianVector &originalVtxPos) const
Refine the position of a two dimensional projection of a vertex using the clusters in that view...
std::string m_outputVertexListName
The refined vertex list to be outputted.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
float m_twoDDistanceCut
The maximum distance a cluster can be from the original position to be used in refinement.
void GetClusterLists(const pandora::StringVector &inputClusterListNames, pandora::ClusterList &clusterListU, pandora::ClusterList &clusterListV, pandora::ClusterList &clusterListW) const
Get the input cluster lists.
void GetBestFitPoint(const pandora::CartesianPointVector &intercepts, const pandora::CartesianPointVector &directions, const pandora::FloatVector &weights, pandora::CartesianVector &bestFitPoint) const
Calculate the best fit point of a set of lines using a matrix equation.
Header file for the geometry helper class.
Header file for the cluster helper class.
std::void_t< T > n
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)
float m_distanceCut
The maximum distance a refined vertex can be from the original position to be kept.
void RefineVertices(const pandora::VertexList *const pVertexList, const pandora::ClusterList &clusterListU, const pandora::ClusterList &clusterListV, const pandora::ClusterList &clusterListW) const
Perform the refinement proceduce on a list of vertices.
std::string m_inputVertexListName
The initial vertex list.
pandora::StringVector m_inputClusterListNames
The list of input cluster list names.
static void RunPca(const T &t, pandora::CartesianVector &centroid, EigenValues &outputEigenValues, EigenVectors &outputEigenVectors)
Run principal component analysis using input calo hits (TPC_VIEW_U,V,W or TPC_3D; all treated as 3D p...
std::vector< pandora::CartesianVector > EigenVectors
Definition: LArPcaHelper.h:25
std::vector< string > StringVector
Definition: fcldump.cxx:29
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
static void GetCoordinateVector(const pandora::Cluster *const pCluster, pandora::CartesianPointVector &coordinateVector)
Get vector of hit coordinates from an input cluster.
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
Definition: ModuleGraph.h:25
Dft::FloatVector FloatVector
static pandora::CartesianVector GetClosestPosition(const pandora::CartesianVector &position, const pandora::ClusterList &clusterList)
Get closest position in a list of clusters to a specified input position vector.
Header file for the vertex refinement algorithm class.
std::list< Vertex > VertexList
Definition: DCEL.h:182
QTextStream & endl(QTextStream &s)
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.