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.5
f),
34 m_extrapolationNSteps(200),
35 m_extrapolationStepSize(0.1
f),
36 m_maxCrossingSeparationSquared(2.
f * 2.
f),
37 m_minNearbyCrossingDistanceSquared(0.5
f * 0.5
f),
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
113 : (TPC_VIEW_V == hitType) ? clusterVectorV
116 if (!selectedClusterVector.empty())
117 throw StatusCodeException(STATUS_CODE_FAILURE);
119 ClusterVector sortedClusters(pClusterList->begin(), pClusterList->end());
122 unsigned int nClustersPassingMaxCuts(0);
125 for (
const Cluster *
const pCluster : sortedClusters)
127 float selectionCutFactor(1.
f);
129 if (pCluster->GetParticleId() == E_MINUS)
138 nClustersPassingMaxCuts++;
142 for (
const Cluster *
const pCluster : sortedClusters)
144 float selectionCutFactor(1.
f);
161 selectedClusterVector.push_back(pCluster);
163 catch (StatusCodeException &statusCodeException)
165 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
166 throw statusCodeException;
176 for (
const Cluster *
const pCluster1 : clusterVector1)
184 for (
const Cluster *
const pCluster2 : clusterVector2)
208 if ((((position1.GetX() < minLayerPosition2.GetX()) && (position1.GetX() < maxLayerPosition2.GetX())) ||
209 ((position1.GetX() > minLayerPosition2.GetX()) && (position1.GetX() > maxLayerPosition2.GetX()))) &&
216 CartesianVector position2(0.
f, 0.
f, 0.
f);
222 float chiSquared(0.
f);
223 CartesianVector position3D(0.
f, 0.
f, 0.
f);
229 PandoraContentApi::Vertex::Parameters parameters;
230 parameters.m_position = position3D;
231 parameters.m_vertexLabel = VERTEX_INTERACTION;
232 parameters.m_vertexType = VERTEX_3D;
234 const Vertex *pVertex(NULL);
235 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
243 CartesianPointVector crossingsU, crossingsV, crossingsW;
248 unsigned int nCrossingCandidates(0);
260 for (
const Cluster *
const pCluster : clusterVector)
266 for (
const Cluster *
const pCluster1 : clusterVector)
268 for (
const Cluster *
const pCluster2 : clusterVector)
270 if (pCluster1 == pCluster2)
273 this->
FindCrossingPoints(clusterToSpacepointsMap.at(pCluster1), clusterToSpacepointsMap.at(pCluster2), crossingPoints);
292 CartesianVector positionPositive(0.
f, 0.
f, 0.
f), positionNegative(0.
f, 0.
f, 0.
f);
296 spacepoints.push_back(positionPositive);
297 spacepoints.push_back(positionNegative);
306 const CartesianPointVector &spacepoints1,
const CartesianPointVector &spacepoints2, CartesianPointVector &crossingPoints)
const 308 bool bestCrossingFound(
false);
310 CartesianVector bestPosition1(0.
f, 0.
f, 0.
f), bestPosition2(0.
f, 0.
f, 0.
f);
312 for (
const CartesianVector &position1 : spacepoints1)
314 for (
const CartesianVector &position2 : spacepoints2)
316 const float separationSquared((position1 - position2).GetMagnitudeSquared());
318 if (separationSquared < bestSeparationSquared)
320 bestCrossingFound =
true;
321 bestSeparationSquared = separationSquared;
322 bestPosition1 = position1;
323 bestPosition2 = position2;
328 if (bestCrossingFound)
330 bool alreadyPopulated(
false);
332 for (
const CartesianVector &existingPosition : crossingPoints)
337 alreadyPopulated =
true;
342 if (!alreadyPopulated)
344 crossingPoints.push_back(bestPosition1);
345 crossingPoints.push_back(bestPosition2);
353 const CartesianPointVector &crossingPoints2,
const HitType hitType1,
const HitType hitType2,
unsigned int &nCrossingCandidates)
const 356 for (
const CartesianVector &position1 : crossingPoints1)
358 for (
const CartesianVector &position2 : crossingPoints2)
366 float chiSquared(0.
f);
367 CartesianVector position3D(0.
f, 0.
f, 0.
f);
373 PandoraContentApi::Vertex::Parameters parameters;
374 parameters.m_position = position3D;
375 parameters.m_vertexLabel = VERTEX_INTERACTION;
376 parameters.m_vertexType = VERTEX_3D;
378 const Vertex *pVertex(NULL);
379 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
380 ++nCrossingCandidates;
393 if (!pInputVertexList)
396 for (
const Vertex *pInputVertex : *pInputVertexList)
398 PandoraContentApi::Vertex::Parameters parameters;
399 parameters.m_position = pInputVertex->GetPosition();
400 parameters.m_vertexLabel = VERTEX_INTERACTION;
401 parameters.m_vertexType = VERTEX_3D;
403 const Vertex *pVertex(
nullptr);
404 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
407 catch (
const StatusCodeException &)
420 if (!
m_slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(pCluster, slidingFitResult)).second)
421 throw StatusCodeException(STATUS_CODE_FAILURE);
431 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
447 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"InputClusterListNames",
m_inputClusterListNames));
449 PANDORA_RETURN_RESULT_IF_AND_IF(
450 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InputVertexListName",
m_inputVertexListName));
452 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"OutputVertexListName",
m_outputVertexListName));
454 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
457 PANDORA_RETURN_RESULT_IF_AND_IF(
458 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SlidingFitWindow",
m_slidingFitWindow));
460 PANDORA_RETURN_RESULT_IF_AND_IF(
461 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterCaloHits",
m_minClusterCaloHits));
464 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLength", minClusterLength));
467 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ChiSquaredCut",
m_chiSquaredCut));
469 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
472 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
475 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
478 PANDORA_RETURN_RESULT_IF_AND_IF(
479 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NMaxCrossingCandidates",
m_nMaxCrossingCandidates));
481 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
484 PANDORA_RETURN_RESULT_IF_AND_IF(
485 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationNSteps",
m_extrapolationNSteps));
487 PANDORA_RETURN_RESULT_IF_AND_IF(
488 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationStepSize",
m_extrapolationStepSize));
490 PANDORA_RETURN_RESULT_IF_AND_IF(
491 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ReducedCandidates",
m_reducedCandidates));
493 PANDORA_RETURN_RESULT_IF_AND_IF(
494 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectionCutFactorMax",
m_selectionCutFactorMax));
496 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
500 PANDORA_RETURN_RESULT_IF_AND_IF(
501 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxCrossingSeparation", maxCrossingSeparation));
505 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
506 XmlHelper::ReadValue(xmlHandle,
"MinNearbyCrossingDistance", minNearbyCrossingDistance));
509 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.
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
std::unordered_map< const pandora::Cluster *, pandora::CartesianPointVector > ClusterToSpacepointsMap
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.
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
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.
TwoDSlidingFitResult class.
unsigned int m_slidingFitWindow
The layer window for the sliding linear fits.