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)
48 this->
SelectClusters(clusterVectorU, clusterVectorV, clusterVectorW);
50 const VertexList *pVertexList(NULL); std::string temporaryListName;
51 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pVertexList, temporaryListName));
63 if (!pVertexList->empty())
65 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*
this,
m_outputVertexListName));
68 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*
this,
m_outputVertexListName));
71 catch (StatusCodeException &statusCodeException)
74 throw statusCodeException;
79 return STATUS_CODE_SUCCESS;
88 const ClusterList *pClusterList(NULL);
89 PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, clusterListName, pClusterList));
91 if (!pClusterList || pClusterList->empty())
93 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
94 std::cout <<
"CandidateVertexCreationAlgorithm: unable to find cluster list " << clusterListName << std::endl;
101 if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
102 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
104 ClusterVector &selectedClusterVector((TPC_VIEW_U == hitType) ? clusterVectorU : (TPC_VIEW_V == hitType) ? clusterVectorV : clusterVectorW);
106 if (!selectedClusterVector.empty())
107 throw StatusCodeException(STATUS_CODE_FAILURE);
109 ClusterVector sortedClusters(pClusterList->begin(), pClusterList->end());
112 for (
const Cluster *
const pCluster : sortedClusters)
123 selectedClusterVector.push_back(pCluster);
125 catch (StatusCodeException &statusCodeException)
127 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
128 throw statusCodeException;
138 for (
const Cluster *
const pCluster1 : clusterVector1)
146 for (
const Cluster *
const pCluster2 : clusterVector2)
169 if ((((position1.GetX() < minLayerPosition2.GetX()) && (position1.GetX() < maxLayerPosition2.GetX())) ||
170 ((position1.GetX() > minLayerPosition2.GetX()) && (position1.GetX() > maxLayerPosition2.GetX()))) &&
177 CartesianVector position2(0.
f, 0.
f, 0.
f);
183 float chiSquared(0.
f);
184 CartesianVector position3D(0.
f, 0.
f, 0.
f);
190 PandoraContentApi::Vertex::Parameters parameters;
191 parameters.m_position = position3D;
192 parameters.m_vertexLabel = VERTEX_INTERACTION;
193 parameters.m_vertexType = VERTEX_3D;
195 const Vertex *pVertex(NULL);
196 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
204 CartesianPointVector crossingsU, crossingsV, crossingsW;
209 unsigned int nCrossingCandidates(0);
221 for (
const Cluster *
const pCluster : clusterVector)
227 for (
const Cluster *
const pCluster1 : clusterVector)
229 for (
const Cluster *
const pCluster2 : clusterVector)
231 if (pCluster1 == pCluster2)
234 this->
FindCrossingPoints(clusterToSpacepointsMap.at(pCluster1), clusterToSpacepointsMap.at(pCluster2), crossingPoints);
253 CartesianVector positionPositive(0.
f, 0.
f, 0.
f), positionNegative(0.
f, 0.
f, 0.
f);
257 spacepoints.push_back(positionPositive);
258 spacepoints.push_back(positionNegative);
267 CartesianPointVector &crossingPoints)
const 269 bool bestCrossingFound(
false);
271 CartesianVector bestPosition1(0.
f, 0.
f, 0.
f), bestPosition2(0.
f, 0.
f, 0.
f);
273 for (
const CartesianVector &position1: spacepoints1)
275 for (
const CartesianVector &position2: spacepoints2)
277 const float separationSquared((position1 - position2).GetMagnitudeSquared());
279 if (separationSquared < bestSeparationSquared)
281 bestCrossingFound =
true;
282 bestSeparationSquared = separationSquared;
283 bestPosition1 = position1;
284 bestPosition2 = position2;
289 if (bestCrossingFound)
291 bool alreadyPopulated(
false);
293 for (
const CartesianVector &existingPosition: crossingPoints)
298 alreadyPopulated =
true;
303 if (!alreadyPopulated)
305 crossingPoints.push_back(bestPosition1);
306 crossingPoints.push_back(bestPosition2);
314 const HitType hitType1,
const HitType hitType2,
unsigned int &nCrossingCandidates)
const 317 for (
const CartesianVector &position1: crossingPoints1)
319 for (
const CartesianVector &position2: crossingPoints2)
327 float chiSquared(0.
f);
328 CartesianVector position3D(0.
f, 0.
f, 0.
f);
334 PandoraContentApi::Vertex::Parameters parameters;
335 parameters.m_position = position3D;
336 parameters.m_vertexLabel = VERTEX_INTERACTION;
337 parameters.m_vertexType = VERTEX_3D;
339 const Vertex *pVertex(NULL);
340 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
341 ++nCrossingCandidates;
353 if (!
m_slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(pCluster, slidingFitResult)).second)
354 throw StatusCodeException(STATUS_CODE_FAILURE);
364 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
380 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
383 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
386 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
389 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
392 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
396 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
397 "MinClusterLength", minClusterLength));
400 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
403 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
406 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
409 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
412 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
415 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
418 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
421 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
425 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
426 "MaxCrossingSeparation", maxCrossingSeparation));
430 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
431 "MinNearbyCrossingDistance", minNearbyCrossingDistance));
434 return STATUS_CODE_SUCCESS;
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.
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.
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.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
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.
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.
std::unordered_map< const pandora::Cluster *, pandora::CartesianPointVector > ClusterToSpacepointsMap
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.
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.