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);
55 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pVertexList, temporaryListName));
67 if (!pVertexList->empty())
69 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*
this,
m_outputVertexListName));
72 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*
this,
m_outputVertexListName));
75 catch (StatusCodeException &statusCodeException)
78 throw statusCodeException;
83 return STATUS_CODE_SUCCESS;
92 const ClusterList *pClusterList(NULL);
93 PANDORA_THROW_RESULT_IF_AND_IF(
94 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, clusterListName, pClusterList));
96 if (!pClusterList || pClusterList->empty())
98 if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
99 std::cout <<
"CandidateVertexCreationAlgorithm: unable to find cluster list " << clusterListName <<
std::endl;
106 if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
107 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
109 ClusterVector &selectedClusterVector((TPC_VIEW_U == hitType) ? clusterVectorU : (TPC_VIEW_V == hitType) ? clusterVectorV : clusterVectorW);
111 if (!selectedClusterVector.empty())
112 throw StatusCodeException(STATUS_CODE_FAILURE);
114 ClusterVector sortedClusters(pClusterList->begin(), pClusterList->end());
117 unsigned int nClustersPassingMaxCuts(0);
120 for (
const Cluster *
const pCluster : sortedClusters)
122 float selectionCutFactor(1.
f);
124 if (pCluster->GetParticleId() == E_MINUS)
133 nClustersPassingMaxCuts++;
137 for (
const Cluster *
const pCluster : sortedClusters)
139 float selectionCutFactor(1.
f);
157 selectedClusterVector.push_back(pCluster);
159 catch (StatusCodeException &statusCodeException)
161 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
162 throw statusCodeException;
172 for (
const Cluster *
const pCluster1 : clusterVector1)
180 for (
const Cluster *
const pCluster2 : clusterVector2)
204 if ((((position1.GetX() < minLayerPosition2.GetX()) && (position1.GetX() < maxLayerPosition2.GetX())) ||
205 ((position1.GetX() > minLayerPosition2.GetX()) && (position1.GetX() > maxLayerPosition2.GetX()))) &&
212 CartesianVector position2(0.
f, 0.
f, 0.
f);
218 float chiSquared(0.
f);
219 CartesianVector position3D(0.
f, 0.
f, 0.
f);
225 PandoraContentApi::Vertex::Parameters parameters;
226 parameters.m_position = position3D;
227 parameters.m_vertexLabel = VERTEX_INTERACTION;
228 parameters.m_vertexType = VERTEX_3D;
230 const Vertex *pVertex(NULL);
231 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
239 CartesianPointVector crossingsU, crossingsV, crossingsW;
244 unsigned int nCrossingCandidates(0);
256 for (
const Cluster *
const pCluster : clusterVector)
262 for (
const Cluster *
const pCluster1 : clusterVector)
264 for (
const Cluster *
const pCluster2 : clusterVector)
266 if (pCluster1 == pCluster2)
269 this->
FindCrossingPoints(clusterToSpacepointsMap.at(pCluster1), clusterToSpacepointsMap.at(pCluster2), crossingPoints);
288 CartesianVector positionPositive(0.
f, 0.
f, 0.
f), positionNegative(0.
f, 0.
f, 0.
f);
292 spacepoints.push_back(positionPositive);
293 spacepoints.push_back(positionNegative);
302 const CartesianPointVector &spacepoints1,
const CartesianPointVector &spacepoints2, CartesianPointVector &crossingPoints)
const 304 bool bestCrossingFound(
false);
306 CartesianVector bestPosition1(0.
f, 0.
f, 0.
f), bestPosition2(0.
f, 0.
f, 0.
f);
308 for (
const CartesianVector &position1 : spacepoints1)
310 for (
const CartesianVector &position2 : spacepoints2)
312 const float separationSquared((position1 - position2).GetMagnitudeSquared());
314 if (separationSquared < bestSeparationSquared)
316 bestCrossingFound =
true;
317 bestSeparationSquared = separationSquared;
318 bestPosition1 = position1;
319 bestPosition2 = position2;
324 if (bestCrossingFound)
326 bool alreadyPopulated(
false);
328 for (
const CartesianVector &existingPosition : crossingPoints)
333 alreadyPopulated =
true;
338 if (!alreadyPopulated)
340 crossingPoints.push_back(bestPosition1);
341 crossingPoints.push_back(bestPosition2);
349 const CartesianPointVector &crossingPoints2,
const HitType hitType1,
const HitType hitType2,
unsigned int &nCrossingCandidates)
const 352 for (
const CartesianVector &position1 : crossingPoints1)
354 for (
const CartesianVector &position2 : crossingPoints2)
362 float chiSquared(0.
f);
363 CartesianVector position3D(0.
f, 0.
f, 0.
f);
369 PandoraContentApi::Vertex::Parameters parameters;
370 parameters.m_position = position3D;
371 parameters.m_vertexLabel = VERTEX_INTERACTION;
372 parameters.m_vertexType = VERTEX_3D;
374 const Vertex *pVertex(NULL);
375 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*
this, parameters, pVertex));
376 ++nCrossingCandidates;
388 if (!
m_slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(pCluster, slidingFitResult)).second)
389 throw StatusCodeException(STATUS_CODE_FAILURE);
399 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
415 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"InputClusterListNames",
m_inputClusterListNames));
417 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"OutputVertexListName",
m_outputVertexListName));
419 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
422 PANDORA_RETURN_RESULT_IF_AND_IF(
423 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SlidingFitWindow",
m_slidingFitWindow));
425 PANDORA_RETURN_RESULT_IF_AND_IF(
426 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterCaloHits",
m_minClusterCaloHits));
429 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLength", minClusterLength));
432 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ChiSquaredCut",
m_chiSquaredCut));
434 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
437 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
440 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
443 PANDORA_RETURN_RESULT_IF_AND_IF(
444 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NMaxCrossingCandidates",
m_nMaxCrossingCandidates));
446 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
449 PANDORA_RETURN_RESULT_IF_AND_IF(
450 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationNSteps",
m_extrapolationNSteps));
452 PANDORA_RETURN_RESULT_IF_AND_IF(
453 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ExtrapolationStepSize",
m_extrapolationStepSize));
455 PANDORA_RETURN_RESULT_IF_AND_IF(
456 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ReducedCandidates",
m_reducedCandidates));
458 PANDORA_RETURN_RESULT_IF_AND_IF(
459 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectionCutFactorMax",
m_selectionCutFactorMax));
461 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
465 PANDORA_RETURN_RESULT_IF_AND_IF(
466 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxCrossingSeparation", maxCrossingSeparation));
470 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
471 XmlHelper::ReadValue(xmlHandle,
"MinNearbyCrossingDistance", minNearbyCrossingDistance));
474 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.
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 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.
QTextStream & endl(QTextStream &s)