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.