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)
53 PandoraContentApi::GetCurrentList(*
this, pVertexList);
54 if (pVertexList !=
nullptr && !pVertexList->empty())
56 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
57 std::cout <<
"CandidateVertexCreationAlgorithm: Vertex already defined, skipping" << std::endl;
59 return STATUS_CODE_SUCCESS;
63 this->
SelectClusters(clusterVectorU, clusterVectorV, clusterVectorW);
65 std::string temporaryListName;
66 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pVertexList, temporaryListName));
81 if (!pVertexList->empty())
83 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*
this,
m_outputVertexListName));
86 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*
this,
m_outputVertexListName));
89 catch (StatusCodeException &statusCodeException)
92 throw statusCodeException;
97 return STATUS_CODE_SUCCESS;
106 const ClusterList *pClusterList(NULL);
107 PANDORA_THROW_RESULT_IF_AND_IF(
108 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, clusterListName, pClusterList));
110 if (!pClusterList || pClusterList->empty())
112 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
113 std::cout <<
"CandidateVertexCreationAlgorithm: unable to find cluster list " << clusterListName << std::endl;
120 if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
121 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
123 ClusterVector &selectedClusterVector((TPC_VIEW_U == hitType) ? clusterVectorU
124 : (TPC_VIEW_V == hitType) ? clusterVectorV
127 if (!selectedClusterVector.empty())
128 throw StatusCodeException(STATUS_CODE_FAILURE);
130 ClusterVector sortedClusters(pClusterList->begin(), pClusterList->end());
133 unsigned int nClustersPassingMaxCuts(0);
136 for (
const Cluster *
const pCluster : sortedClusters)
138 float selectionCutFactor(1.
f);
140 if (pCluster->GetParticleId() == E_MINUS)
149 nClustersPassingMaxCuts++;
153 for (
const Cluster *
const pCluster : sortedClusters)
155 float selectionCutFactor(1.
f);
172 selectedClusterVector.push_back(pCluster);
174 catch (StatusCodeException &statusCodeException)
176 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
177 throw statusCodeException;
187 for (
const Cluster *
const pCluster1 : clusterVector1)
195 for (
const Cluster *
const pCluster2 : clusterVector2)
219 if ((((position1.GetX() < minLayerPosition2.GetX()) && (position1.GetX() < maxLayerPosition2.GetX())) ||
220 ((position1.GetX() > minLayerPosition2.GetX()) && (position1.GetX() > maxLayerPosition2.GetX()))) &&
227 CartesianVector position2(0.
f, 0.
f, 0.
f);
233 float chiSquared(0.
f);
234 CartesianVector position3D(0.
f, 0.
f, 0.
f);
240 PandoraContentApi::Vertex::Parameters parameters;
241 parameters.m_position = position3D;
242 parameters.m_vertexLabel = VERTEX_INTERACTION;
243 parameters.m_vertexType = VERTEX_3D;
245 const Vertex *pVertex(NULL);
246 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
254 CartesianPointVector crossingsU, crossingsV, crossingsW;
259 unsigned int nCrossingCandidates(0);
271 for (
const Cluster *
const pCluster : clusterVector)
277 for (
const Cluster *
const pCluster1 : clusterVector)
279 for (
const Cluster *
const pCluster2 : clusterVector)
281 if (pCluster1 == pCluster2)
284 this->
FindCrossingPoints(clusterToSpacepointsMap.at(pCluster1), clusterToSpacepointsMap.at(pCluster2), crossingPoints);
303 CartesianVector positionPositive(0.
f, 0.
f, 0.
f), positionNegative(0.
f, 0.
f, 0.
f);
307 spacepoints.push_back(positionPositive);
308 spacepoints.push_back(positionNegative);
317 const CartesianPointVector &spacepoints1,
const CartesianPointVector &spacepoints2, CartesianPointVector &crossingPoints)
const 319 bool bestCrossingFound(
false);
321 CartesianVector bestPosition1(0.
f, 0.
f, 0.
f), bestPosition2(0.
f, 0.
f, 0.
f);
323 for (
const CartesianVector &position1 : spacepoints1)
325 for (
const CartesianVector &position2 : spacepoints2)
327 const float separationSquared((position1 - position2).GetMagnitudeSquared());
329 if (separationSquared < bestSeparationSquared)
331 bestCrossingFound =
true;
332 bestSeparationSquared = separationSquared;
333 bestPosition1 = position1;
334 bestPosition2 = position2;
339 if (bestCrossingFound)
341 bool alreadyPopulated(
false);
343 for (
const CartesianVector &existingPosition : crossingPoints)
348 alreadyPopulated =
true;
353 if (!alreadyPopulated)
355 crossingPoints.push_back(bestPosition1);
356 crossingPoints.push_back(bestPosition2);
364 const CartesianPointVector &crossingPoints2,
const HitType hitType1,
const HitType hitType2,
unsigned int &nCrossingCandidates)
const 367 for (
const CartesianVector &position1 : crossingPoints1)
369 for (
const CartesianVector &position2 : crossingPoints2)
377 float chiSquared(0.
f);
378 CartesianVector position3D(0.
f, 0.
f, 0.
f);
384 PandoraContentApi::Vertex::Parameters parameters;
385 parameters.m_position = position3D;
386 parameters.m_vertexLabel = VERTEX_INTERACTION;
387 parameters.m_vertexType = VERTEX_3D;
389 const Vertex *pVertex(NULL);
390 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
391 ++nCrossingCandidates;
404 if (!pInputVertexList)
407 for (
const Vertex *pInputVertex : *pInputVertexList)
409 PandoraContentApi::Vertex::Parameters parameters;
410 parameters.m_position = pInputVertex->GetPosition();
411 parameters.m_vertexLabel = VERTEX_INTERACTION;
412 parameters.m_vertexType = VERTEX_3D;
414 const Vertex *pVertex(
nullptr);
415 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
418 catch (
const StatusCodeException &)
431 if (!
m_slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(pCluster, slidingFitResult)).second)
432 throw StatusCodeException(STATUS_CODE_FAILURE);
442 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
458 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"InputClusterListNames",
m_inputClusterListNames));
460 PANDORA_RETURN_RESULT_IF_AND_IF(
461 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InputVertexListName",
m_inputVertexListName));
463 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"OutputVertexListName",
m_outputVertexListName));
465 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
468 PANDORA_RETURN_RESULT_IF_AND_IF(
469 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SlidingFitWindow",
m_slidingFitWindow));
471 PANDORA_RETURN_RESULT_IF_AND_IF(
472 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterCaloHits",
m_minClusterCaloHits));
475 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLength", minClusterLength));
478 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ChiSquaredCut",
m_chiSquaredCut));
480 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
483 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
486 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
489 PANDORA_RETURN_RESULT_IF_AND_IF(
490 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NMaxCrossingCandidates",
m_nMaxCrossingCandidates));
492 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
495 PANDORA_RETURN_RESULT_IF_AND_IF(
496 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationNSteps",
m_extrapolationNSteps));
498 PANDORA_RETURN_RESULT_IF_AND_IF(
499 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationStepSize",
m_extrapolationStepSize));
501 PANDORA_RETURN_RESULT_IF_AND_IF(
502 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ReducedCandidates",
m_reducedCandidates));
504 PANDORA_RETURN_RESULT_IF_AND_IF(
505 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectionCutFactorMax",
m_selectionCutFactorMax));
507 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
511 PANDORA_RETURN_RESULT_IF_AND_IF(
512 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxCrossingSeparation", maxCrossingSeparation));
516 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
517 XmlHelper::ReadValue(xmlHandle,
"MinNearbyCrossingDistance", minNearbyCrossingDistance));
520 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.