9 #include "Pandora/AlgorithmHeaders.h"
23 CandidateVertexCreationAlgorithm::CandidateVertexCreationAlgorithm() :
24 m_replaceCurrentVertexList(
true),
25 m_slidingFitWindow(20),
26 m_minClusterCaloHits(5),
27 m_minClusterLengthSquared(3.f * 3.f),
29 m_enableEndpointCandidates(
true),
30 m_maxEndpointXDiscrepancy(4.f),
31 m_enableCrossingCandidates(
false),
32 m_nMaxCrossingCandidates(500),
33 m_maxCrossingXDiscrepancy(0.5f),
34 m_extrapolationNSteps(200),
35 m_extrapolationStepSize(0.1f),
36 m_maxCrossingSeparationSquared(2.f * 2.f),
37 m_minNearbyCrossingDistanceSquared(0.5f * 0.5f),
38 m_reducedCandidates(
false),
39 m_selectionCutFactorMax(2.f),
40 m_nClustersPassingMaxCutsPar(26.f)
51 this->
SelectClusters(clusterVectorU, clusterVectorV, clusterVectorW);
54 std::string temporaryListName;
55 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pVertexList, temporaryListName));
70 if (!pVertexList->empty())
72 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*
this,
m_outputVertexListName));
75 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*
this,
m_outputVertexListName));
78 catch (StatusCodeException &statusCodeException)
81 throw statusCodeException;
86 return STATUS_CODE_SUCCESS;
95 const ClusterList *pClusterList(NULL);
96 PANDORA_THROW_RESULT_IF_AND_IF(
97 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, clusterListName, pClusterList));
99 if (!pClusterList || pClusterList->empty())
101 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
102 std::cout <<
"CandidateVertexCreationAlgorithm: unable to find cluster list " << clusterListName << std::endl;
109 if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
110 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
112 ClusterVector &selectedClusterVector((TPC_VIEW_U == hitType) ? clusterVectorU : (TPC_VIEW_V == hitType) ? clusterVectorV : clusterVectorW);
114 if (!selectedClusterVector.empty())
115 throw StatusCodeException(STATUS_CODE_FAILURE);
117 ClusterVector sortedClusters(pClusterList->begin(), pClusterList->end());
120 unsigned int nClustersPassingMaxCuts(0);
123 for (
const Cluster *
const pCluster : sortedClusters)
125 float selectionCutFactor(1.f);
127 if (pCluster->GetParticleId() == E_MINUS)
136 nClustersPassingMaxCuts++;
140 for (
const Cluster *
const pCluster : sortedClusters)
142 float selectionCutFactor(1.f);
160 selectedClusterVector.push_back(pCluster);
162 catch (StatusCodeException &statusCodeException)
164 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
165 throw statusCodeException;
175 for (
const Cluster *
const pCluster1 : clusterVector1)
183 for (
const Cluster *
const pCluster2 : clusterVector2)
202 const CartesianVector &position1,
const HitType hitType1,
const TwoDSlidingFitResult &fitResult2)
const
207 if ((((position1.GetX() < minLayerPosition2.GetX()) && (position1.GetX() < maxLayerPosition2.GetX())) ||
208 ((position1.GetX() > minLayerPosition2.GetX()) && (position1.GetX() > maxLayerPosition2.GetX()))) &&
215 CartesianVector position2(0.f, 0.f, 0.f);
221 float chiSquared(0.f);
222 CartesianVector position3D(0.f, 0.f, 0.f);
229 parameters.m_position = position3D;
230 parameters.m_vertexLabel = VERTEX_INTERACTION;
231 parameters.m_vertexType = VERTEX_3D;
233 const Vertex *pVertex(NULL);
234 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
242 CartesianPointVector crossingsU, crossingsV, crossingsW;
247 unsigned int nCrossingCandidates(0);
259 for (
const Cluster *
const pCluster : clusterVector)
261 ClusterToSpacepointsMap::iterator mapIter(clusterToSpacepointsMap.emplace(pCluster, CartesianPointVector()).first);
265 for (
const Cluster *
const pCluster1 : clusterVector)
267 for (
const Cluster *
const pCluster2 : clusterVector)
269 if (pCluster1 == pCluster2)
272 this->
FindCrossingPoints(clusterToSpacepointsMap.at(pCluster1), clusterToSpacepointsMap.at(pCluster2), crossingPoints);
291 CartesianVector positionPositive(0.f, 0.f, 0.f), positionNegative(0.f, 0.f, 0.f);
295 spacepoints.push_back(positionPositive);
296 spacepoints.push_back(positionNegative);
305 const CartesianPointVector &spacepoints1,
const CartesianPointVector &spacepoints2, CartesianPointVector &crossingPoints)
const
307 bool bestCrossingFound(
false);
309 CartesianVector bestPosition1(0.f, 0.f, 0.f), bestPosition2(0.f, 0.f, 0.f);
311 for (
const CartesianVector &position1 : spacepoints1)
313 for (
const CartesianVector &position2 : spacepoints2)
315 const float separationSquared((position1 - position2).GetMagnitudeSquared());
317 if (separationSquared < bestSeparationSquared)
319 bestCrossingFound =
true;
320 bestSeparationSquared = separationSquared;
321 bestPosition1 = position1;
322 bestPosition2 = position2;
327 if (bestCrossingFound)
329 bool alreadyPopulated(
false);
331 for (
const CartesianVector &existingPosition : crossingPoints)
336 alreadyPopulated =
true;
341 if (!alreadyPopulated)
343 crossingPoints.push_back(bestPosition1);
344 crossingPoints.push_back(bestPosition2);
352 const CartesianPointVector &crossingPoints2,
const HitType hitType1,
const HitType hitType2,
unsigned int &nCrossingCandidates)
const
355 for (
const CartesianVector &position1 : crossingPoints1)
357 for (
const CartesianVector &position2 : crossingPoints2)
365 float chiSquared(0.f);
366 CartesianVector position3D(0.f, 0.f, 0.f);
373 parameters.m_position = position3D;
374 parameters.m_vertexLabel = VERTEX_INTERACTION;
375 parameters.m_vertexType = VERTEX_3D;
377 const Vertex *pVertex(NULL);
378 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
379 ++nCrossingCandidates;
392 if (!pInputVertexList)
395 for (
const Vertex *pInputVertex : *pInputVertexList)
398 parameters.m_position = pInputVertex->GetPosition();
399 parameters.m_vertexLabel = VERTEX_INTERACTION;
400 parameters.m_vertexType = VERTEX_3D;
402 const Vertex *pVertex(
nullptr);
403 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
406 catch (
const StatusCodeException &)
419 if (!
m_slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(pCluster, slidingFitResult)).second)
420 throw StatusCodeException(STATUS_CODE_FAILURE);
430 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
446 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"InputClusterListNames",
m_inputClusterListNames));
448 PANDORA_RETURN_RESULT_IF_AND_IF(
449 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InputVertexListName",
m_inputVertexListName));
451 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"OutputVertexListName",
m_outputVertexListName));
453 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
456 PANDORA_RETURN_RESULT_IF_AND_IF(
457 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SlidingFitWindow",
m_slidingFitWindow));
459 PANDORA_RETURN_RESULT_IF_AND_IF(
460 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterCaloHits",
m_minClusterCaloHits));
463 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLength", minClusterLength));
466 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ChiSquaredCut",
m_chiSquaredCut));
468 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
471 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
474 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
477 PANDORA_RETURN_RESULT_IF_AND_IF(
478 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NMaxCrossingCandidates",
m_nMaxCrossingCandidates));
480 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
483 PANDORA_RETURN_RESULT_IF_AND_IF(
484 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationNSteps",
m_extrapolationNSteps));
486 PANDORA_RETURN_RESULT_IF_AND_IF(
487 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationStepSize",
m_extrapolationStepSize));
489 PANDORA_RETURN_RESULT_IF_AND_IF(
490 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ReducedCandidates",
m_reducedCandidates));
492 PANDORA_RETURN_RESULT_IF_AND_IF(
493 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectionCutFactorMax",
m_selectionCutFactorMax));
495 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
499 PANDORA_RETURN_RESULT_IF_AND_IF(
500 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxCrossingSeparation", maxCrossingSeparation));
504 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
505 XmlHelper::ReadValue(xmlHandle,
"MinNearbyCrossingDistance", minNearbyCrossingDistance));
508 return STATUS_CODE_SUCCESS;
bool m_reducedCandidates
Whether to reduce the number of candidates.
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.
float m_minClusterLengthSquared
The min length (squared) in base cluster selection method.
void CreateEndpointVertex(const pandora::CartesianVector &position1, const pandora::HitType hitType1, const TwoDSlidingFitResult &fitResult2) const
Create a candidate vertex position, using an end-point position from one cluster and sliding fit to a...
void CreateCrossingCandidates(const pandora::ClusterVector &clusterVectorU, const pandora::ClusterVector &clusterVectorV, const pandora::ClusterVector &clusterVectorW) const
Extrapolate 2D clusters, find where they cross, and match crossing points between views to create ver...
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.
void GetSpacepoints(const pandora::Cluster *const pCluster, pandora::CartesianPointVector &spacePoints) const
Get a list of spacepoints representing cluster 2D hit positions and extrapolated positions.
float m_extrapolationStepSize
The extrapolation step size in cm.
float m_maxCrossingSeparationSquared
The separation (squared) between spacepoints below which a crossing can be identified.
pandora::StatusCode GetExtrapolatedPositionAtX(const float x, pandora::CartesianVector &position) const
Get extrapolated position (beyond span) for a given input x coordinate.
bool m_enableEndpointCandidates
Whether to create endpoint-based candidates.
pandora::StatusCode Run()
void AddToSlidingFitCache(const pandora::Cluster *const pCluster)
Creates a 2D sliding fit of a cluster and stores it for later use.
bool m_replaceCurrentVertexList
Whether to replace the current vertex list with the output list.
float m_maxEndpointXDiscrepancy
The max cluster endpoint discrepancy.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
void FindCrossingPoints(const pandora::ClusterVector &clusterVector, pandora::CartesianPointVector &crossingPoints) const
Identify where (extrapolated) clusters plausibly cross in 2D.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static bool SortCoordinatesByPosition(const pandora::CartesianVector &lhs, const pandora::CartesianVector &rhs)
Sort cartesian vectors by their position (use Z, followed by X, followed by Y)
Header file for the geometry helper class.
Header file for the candidate vertex creation algorithm class.
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
std::string m_inputVertexListName
The list name for existing candidate vertices.
Header file for the cluster helper class.
bool m_enableCrossingCandidates
Whether to create crossing vertex candidates.
float m_maxCrossingXDiscrepancy
The max cluster endpoint discrepancy.
TwoDSlidingFitResultMap m_slidingFitResultMap
The sliding fit result map.
void CreateEndpointCandidates(const pandora::ClusterVector &clusterVector1, const pandora::ClusterVector &clusterVector2) const
Create candidate vertex positions by comparing pairs of cluster end positions.
float m_nClustersPassingMaxCutsPar
Parameter for number of clusters passing the max base cluster selection cuts.
pandora::StatusCode GetExtrapolatedPosition(const float rL, pandora::CartesianVector &position) const
Get extrapolated position (beyond span) for a given input coordinate.
float m_minNearbyCrossingDistanceSquared
The minimum allowed distance between identified crossing positions.
unsigned int m_minClusterCaloHits
The min number of hits in base cluster selection method.
void TidyUp()
Clear relevant algorithm member variables between events.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
unsigned int m_extrapolationNSteps
Number of extrapolation steps, at each end of cluster, of specified size.
std::string m_outputVertexListName
The name under which to save the output vertex list.
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
pandora::StringVector m_inputClusterListNames
The list of cluster list names.
unsigned int m_nMaxCrossingCandidates
The max number of crossing candidates to create.
fhicl::Table< sbnd::crt::CRTDetSimParams > Parameters
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
std::unordered_map< const pandora::Cluster *, pandora::CartesianPointVector > ClusterToSpacepointsMap
required by fuzzyCluster table::sbnd_g4_services gaushitTruthMatch pandora
float m_selectionCutFactorMax
Maximum factor to multiply the base cluster selection cuts.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void SelectClusters(pandora::ClusterVector &clusterVectorU, pandora::ClusterVector &clusterVectorV, pandora::ClusterVector &clusterVectorW)
Select a subset of input clusters (contained in the input list names) for processing in this algorith...
float m_chiSquaredCut
The chi squared cut (accept only 3D vertex positions with values below cut)
float GetL(const int layer) const
Get longitudinal coordinate for a given sliding linear fit layer number.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
static void GetCoordinateVector(const pandora::Cluster *const pCluster, pandora::CartesianPointVector &coordinateVector)
Get vector of hit coordinates from an input cluster.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
void AddInputVertices() const
Add candidate vertices from any input vertices.
void CreateCrossingVertices(const pandora::CartesianPointVector &crossingPoints1, const pandora::CartesianPointVector &crossingPoints2, const pandora::HitType hitType1, const pandora::HitType hitType2, unsigned int &nCrossingCandidates) const
Attempt to create candidate vertex positions, using 2D crossing points in 2 views.
std::list< Vertex > VertexList
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
unsigned int m_slidingFitWindow
The layer window for the sliding linear fits.