8 #include "Pandora/AlgorithmHeaders.h"
22 VertexSelectionBaseAlgorithm::VertexSelectionBaseAlgorithm() :
23 m_replaceCurrentVertexList(
true),
25 m_nDecayLengthsInZSpan(2.f),
26 m_selectSingleVertex(
true),
27 m_maxTopScoreSelections(3),
28 m_maxOnHitDisplacement(1.f),
29 m_minCandidateDisplacement(2.f),
30 m_minCandidateScoreFraction(0.5f),
31 m_useDetectorGaps(
true),
33 m_isEmptyViewAcceptable(
true),
34 m_minVertexAcceptableViews(3)
43 for (
const Vertex *
const pVertex : *pInputVertexList)
45 unsigned int nAcceptableViews(0);
57 filteredVertices.push_back(pVertex);
70 if (vertexVector.empty())
71 throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
73 float minZCoordinate(std::numeric_limits<float>::max()), maxZCoordinate(-std::numeric_limits<float>::max());
75 for (
const Vertex *
const pVertex : vertexVector)
77 if (pVertex->GetPosition().GetZ() < minZCoordinate)
78 minZCoordinate = pVertex->GetPosition().GetZ();
80 if (pVertex->GetPosition().GetZ() > maxZCoordinate)
81 maxZCoordinate = pVertex->GetPosition().GetZ();
84 const float zSpan(maxZCoordinate - minZCoordinate);
85 const float decayConstant((zSpan < std::numeric_limits<float>::epsilon()) ? 0.f : (
m_nDecayLengthsInZSpan / zSpan));
86 beamConstants.
SetConstants(minZCoordinate, decayConstant);
92 const StringVector &inputClusterListNames, ClusterList &clusterListU, ClusterList &clusterListV, ClusterList &clusterListW)
const
94 for (
const std::string &clusterListName : inputClusterListNames)
96 const ClusterList *pClusterList(NULL);
97 PANDORA_THROW_RESULT_IF_AND_IF(
98 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, clusterListName, pClusterList));
100 if (!pClusterList || pClusterList->empty())
102 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
103 std::cout <<
"EnergyKickVertexSelectionAlgorithm: unable to find cluster list " << clusterListName << std::endl;
110 if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
111 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
113 ClusterList &clusterList((TPC_VIEW_U == hitType) ? clusterListU : (TPC_VIEW_V == hitType) ? clusterListV : clusterListW);
114 clusterList.insert(clusterList.end(), pClusterList->begin(), pClusterList->end());
125 ClusterVector sortedClusters(inputClusterList.begin(), inputClusterList.end());
128 for (
const Cluster *
const pCluster : sortedClusters)
130 if (pCluster->GetNCaloHits() < minClusterCaloHits)
134 const unsigned int newSlidingFitWindow(
135 std::min(static_cast<int>(pCluster->GetNCaloHits()), static_cast<int>(slidingFitPitch * slidingFitWindow)));
136 slidingFitDataList.emplace_back(pCluster, newSlidingFitWindow, slidingFitPitch);
145 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*
this, pInputVertexList));
147 if (!pInputVertexList || pInputVertexList->empty())
149 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
150 std::cout <<
"VertexSelectionBaseAlgorithm: unable to find current vertex list " << std::endl;
152 return STATUS_CODE_SUCCESS;
159 this->
FilterVertexList(pInputVertexList, kdTreeU, kdTreeV, kdTreeW, filteredVertices);
161 if (filteredVertices.empty())
162 return STATUS_CODE_SUCCESS;
168 this->
GetVertexScoreList(filteredVertices, beamConstants, kdTreeU, kdTreeV, kdTreeW, vertexScoreList);
173 if (!selectedVertexList.empty())
175 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList(*
this,
m_outputVertexListName, selectedVertexList));
178 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*
this,
m_outputVertexListName));
181 return STATUS_CODE_SUCCESS;
190 const CaloHitList *pCaloHitList = NULL;
191 PANDORA_THROW_RESULT_IF_AND_IF(
192 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, caloHitListName, pCaloHitList));
194 if (!pCaloHitList || pCaloHitList->empty())
196 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
197 std::cout <<
"VertexSelectionBaseAlgorithm: unable to find calo hit list " << caloHitListName << std::endl;
202 const HitType hitType((*(pCaloHitList->begin()))->GetHitType());
204 if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
205 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
207 HitKDTree2D &kdTree((TPC_VIEW_U == hitType) ? kdTreeU : (TPC_VIEW_V == hitType) ? kdTreeV : kdTreeW);
210 throw StatusCodeException(STATUS_CODE_FAILURE);
214 kdTree.
build(hitKDNode2DList, hitsBoundingRegion2D);
226 kdTree.
search(searchRegionHits, found);
228 return (!found.empty());
245 float totalEnergy(0.f);
248 totalEnergy += this->
VertexHitEnergy(pVertex, TPC_VIEW_U, kdTreeMap.at(TPC_VIEW_U));
251 totalEnergy += this->
VertexHitEnergy(pVertex, TPC_VIEW_V, kdTreeMap.at(TPC_VIEW_V));
254 totalEnergy += this->
VertexHitEnergy(pVertex, TPC_VIEW_W, kdTreeMap.at(TPC_VIEW_W));
267 kdTree.
search(searchRegionHits, foundHits);
269 float dr(std::numeric_limits<float>::max());
272 for (
auto hit : foundHits)
274 const float diff = (vertexPosition2D -
hit.data->GetPositionVector()).GetMagnitude();
278 energy =
hit.data->GetElectromagneticEnergy();
288 float bestScore(0.f);
289 std::sort(vertexScoreList.begin(), vertexScoreList.end());
291 for (
const VertexScore &vertexScore : vertexScoreList)
296 if (!selectedVertexList.empty() && !this->
AcceptVertexLocation(vertexScore.GetVertex(), selectedVertexList))
302 selectedVertexList.push_back(vertexScore.GetVertex());
307 if (vertexScore.GetScore() > bestScore)
308 bestScore = vertexScore.GetScore();
316 const CartesianVector &position(pVertex->GetPosition());
319 for (
const Vertex *
const pSelectedVertex : selectedVertexList)
321 if (pVertex == pSelectedVertex)
324 if ((position - pSelectedVertex->GetPosition()).GetMagnitudeSquared() < minCandidateDisplacementSquared)
335 const CartesianVector deltaPosition(pRhs->GetPosition() - pLhs->GetPosition());
337 if (std::fabs(deltaPosition.GetZ()) > std::numeric_limits<float>::epsilon())
338 return (deltaPosition.GetZ() > std::numeric_limits<float>::epsilon());
340 if (std::fabs(deltaPosition.GetX()) > std::numeric_limits<float>::epsilon())
341 return (deltaPosition.GetX() > std::numeric_limits<float>::epsilon());
344 return (deltaPosition.GetY() > std::numeric_limits<float>::epsilon());
350 m_minLayerDirection(0.f, 0.f, 0.f),
351 m_maxLayerDirection(0.f, 0.f, 0.f),
352 m_minLayerPosition(0.f, 0.f, 0.f),
353 m_maxLayerPosition(0.f, 0.f, 0.f),
366 m_clusterList(clusterList),
367 m_coordinateVector(
this->GetClusterListCoordinateVector(clusterList)),
368 m_twoDSlidingFitResult(&m_coordinateVector, slidingFitWindow, slidingFitPitch)
376 CartesianPointVector coordinateVector;
378 for (
const Cluster *
const pCluster : clusterList)
380 CartesianPointVector clusterCoordinateVector;
383 coordinateVector.insert(coordinateVector.end(), std::make_move_iterator(clusterCoordinateVector.begin()),
384 std::make_move_iterator(clusterCoordinateVector.end()));
387 return coordinateVector;
395 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"InputCaloHitListNames",
m_inputCaloHitListNames));
397 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"OutputVertexListName",
m_outputVertexListName));
399 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
402 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"BeamMode",
m_beamMode));
404 PANDORA_RETURN_RESULT_IF_AND_IF(
405 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NDecayLengthsInZSpan",
m_nDecayLengthsInZSpan));
407 PANDORA_RETURN_RESULT_IF_AND_IF(
408 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectSingleVertex",
m_selectSingleVertex));
410 PANDORA_RETURN_RESULT_IF_AND_IF(
411 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxTopScoreSelections",
m_maxTopScoreSelections));
413 PANDORA_RETURN_RESULT_IF_AND_IF(
414 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxOnHitDisplacement",
m_maxOnHitDisplacement));
416 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
419 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
422 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"UseDetectorGaps",
m_useDetectorGaps));
424 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"GapTolerance",
m_gapTolerance));
426 PANDORA_RETURN_RESULT_IF_AND_IF(
427 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"IsEmptyViewAcceptable",
m_isEmptyViewAcceptable));
429 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
432 return STATUS_CODE_SUCCESS;
float m_minCandidateScoreFraction
Ignore other top-scoring candidates with score less than a fraction of original.
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.
Header file for the kd tree linker algo template class.
void SetConstants(const float minZCoordinate, const float decayConstant)
Set the beam constants.
pandora::CartesianPointVector GetClusterListCoordinateVector(const pandora::ClusterList &clusterList) const
Get the coordinate vector for a cluster list.
virtual void FilterVertexList(const pandora::VertexList *const pInputVertexList, HitKDTree2D &kdTreeU, HitKDTree2D &kdTreeV, HitKDTree2D &kdTreeW, pandora::VertexVector &filteredVertices) const
Filter the input list of vertices to obtain a reduced number of vertex candidates.
pandora::StatusCode Run()
std::string m_outputVertexListName
The name under which to save the output vertex list.
virtual void GetVertexScoreList(const pandora::VertexVector &vertexVector, const BeamConstants &beamConstants, HitKDTree2D &kdTreeU, HitKDTree2D &kdTreeV, HitKDTree2D &kdTreeW, VertexScoreList &vertexScoreList) const =0
Get the vertex score list for a provided list of candidate vertices.
pandora::StringVector m_inputCaloHitListNames
The list of calo hit list names.
void GetClusterLists(const pandora::StringVector &inputClusterListNames, pandora::ClusterList &clusterListU, pandora::ClusterList &clusterListV, pandora::ClusterList &clusterListW) const
Get the cluster lists.
void CalculateClusterSlidingFits(const pandora::ClusterList &inputClusterList, const unsigned int minClusterCaloHits, const unsigned int slidingFitWindow, SlidingFitDataList &slidingFitDataList) const
Calculate the cluster sliding fits.
Box structure used to define 2D field. It's used in KDTree building step to divide the detector space...
pandora::CartesianVector m_minLayerPosition
The position of the fit at the max layer.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
pandora::CartesianVector GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
bool empty()
Whether the tree is empty.
bool IsVertexOnHit(const pandora::Vertex *const pVertex, const pandora::HitType hitType, HitKDTree2D &kdTree) const
Whether the vertex lies on a hit in the specified view.
std::vector< SlidingFitData > SlidingFitDataList
pandora::CartesianVector m_maxLayerDirection
The direction of the fit at the min layer.
bool AcceptVertexLocation(const pandora::Vertex *const pVertex, const pandora::VertexList &selectedVertexList) const
Whether to accept a candidate vertex, based on its spatial position in relation to other selected can...
Header file for the geometry helper class.
std::vector< HitKDNode2D > HitKDNode2DList
float VertexHitEnergy(const pandora::Vertex *const pVertex, const pandora::HitType hitType, HitKDTree2D &kdTree) const
Finds the energy of the nearest hit to the vertex candidate in this view.
virtual void GetBeamConstants(const pandora::VertexVector &vertexVector, BeamConstants &beamConstants) const
Get the beam score constants for a provided list of candidate vertices.
ShowerCluster(const pandora::ClusterList &clusterList, const int slidingFitWindow, const float slidingFitPitch)
Constructor.
unsigned int m_maxTopScoreSelections
Max number of top-scoring vertex candidate to select for output.
pandora::CartesianVector m_minLayerDirection
The direction of the fit at the min layer.
bool IsVertexInGap(const pandora::Vertex *const pVertex, const pandora::HitType hitType) const
Whether the vertex lies in a registered gap.
Header file for the cluster helper class.
SlidingFitData(const pandora::Cluster *const pCluster, const int slidingFitWindow, const float slidingFitPitch)
Constructor.
void build(std::vector< KDTreeNodeInfoT< DATA, DIM >> &eltList, const KDTreeBoxT< DIM > ®ion)
Build the KD tree from the "eltList" in the space define by "region".
Header file for the vertex selection base algorithm class.
pandora::CartesianVector m_maxLayerPosition
The position of the fit at the max layer.
bool m_useDetectorGaps
Whether to account for registered detector gaps in vertex selection.
static bool SortByVertexZPosition(const pandora::Vertex *const pLhs, const pandora::Vertex *const pRhs)
Sort vertices by increasing z position.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
void InitializeKDTrees(HitKDTree2D &kdTreeU, HitKDTree2D &kdTreeV, HitKDTree2D &kdTreeW) const
Initialize kd trees with details of hits in algorithm-configured cluster lists.
std::vector< VertexScore > VertexScoreList
bool m_beamMode
Whether to run in beam mode, assuming neutrinos travel in positive z-direction.
bool m_isEmptyViewAcceptable
Whether views entirely empty of hits are classed as 'acceptable' for candidate filtration.
required by fuzzyCluster table::sbnd_g4_services gaushitTruthMatch pandora
bool m_selectSingleVertex
Whether to make a final decision and select just one vertex candidate.
float GetVertexEnergy(const pandora::Vertex *const pVertex, const KDTreeMap &kdTreeMap) const
Calculate the energy of a vertex candidate by summing values from all three planes.
unsigned int m_minVertexAcceptableViews
The minimum number of views in which a candidate must sit on/near a hit or in a gap (or view can be e...
pandora::CartesianVector GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
KDTreeBox fill_and_bound_2d_kd_tree(const MANAGED_CONTAINER< const T * > &points, std::vector< KDTreeNodeInfoT< const T *, 2 >> &nodes)
fill_and_bound_2d_kd_tree
static void GetCoordinateVector(const pandora::Cluster *const pCluster, pandora::CartesianPointVector &coordinateVector)
Get vector of hit coordinates from an input cluster.
void SelectTopScoreVertices(VertexScoreList &vertexScoreList, pandora::VertexList &selectedVertexList) const
From the top-scoring candidate vertices, select a subset for further investigation.
std::map< pandora::HitType, const std::reference_wrapper< HitKDTree2D > > KDTreeMap
Map array of hit kd trees for passing to tools.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
float m_nDecayLengthsInZSpan
The number of score decay lengths to use over the course of the vertex z-span.
float m_minCandidateDisplacement
Ignore other top-scoring candidates located in close proximity to original.
bool m_replaceCurrentVertexList
Whether to replace the current vertex list with the output list.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
KDTreeBox build_2d_kd_search_region(const pandora::CaloHit *const point, const float x_span, const float z_span)
build_2d_kd_search_region
void search(const KDTreeBoxT< DIM > &searchBox, std::vector< KDTreeNodeInfoT< DATA, DIM >> &resRecHitList)
Search in the KDTree for all points that would be contained in the given searchbox The founded points...
std::array< float, 2 > VertexVector(const recob::Vertex &vert, const geo::PlaneID &plane, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
std::list< Vertex > VertexList
float m_gapTolerance
The tolerance to use when querying whether a sampling point is in a gap, units cm.
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
TwoDSlidingFitResult class.
BEGIN_PROLOG could also be cout
float m_maxOnHitDisplacement
Max hit-vertex displacement for declaring vertex to lie on a hit in each view.
static bool IsInGap3D(const pandora::Pandora &pandora, const pandora::CartesianVector &testPoint3D, const pandora::HitType hitType, const float gapTolerance=0.f)
Whether a 3D test point lies in a registered gap with the associated hit type.