9 #include "Pandora/AlgorithmHeaders.h"    26 ParticleRecoveryAlgorithm::ParticleRecoveryAlgorithm() :
    28     m_minClusterCaloHits(20),
    29     m_minClusterLengthSquared(5.
f * 5.
f),
    30     m_minClusterXSpan(0.25
f),
    31     m_vertexClusterMode(false),
    32     m_minVertexLongitudinalDistance(-2.5
f),
    33     m_maxVertexTransverseDistance(1.5
f),
    34     m_minXOverlapFraction(0.75
f),
    35     m_minXOverlapFractionGaps(0.75
f),
    36     m_sampleStepSize(0.5
f),
    37     m_slidingFitHalfWindow(10),
    46     ClusterList inputClusterListU, inputClusterListV, inputClusterListW;
    47     this->
GetInputClusters(inputClusterListU, inputClusterListV, inputClusterListW);
    49     ClusterList selectedClusterListU, selectedClusterListV, selectedClusterListW;
    55     this->
FindOverlaps(selectedClusterListU, selectedClusterListV, overlapTensor);
    56     this->
FindOverlaps(selectedClusterListV, selectedClusterListW, overlapTensor);
    57     this->
FindOverlaps(selectedClusterListW, selectedClusterListU, overlapTensor);
    60     return STATUS_CODE_SUCCESS;
    69         const ClusterList *pClusterList(NULL);
    70         PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*
this, *iter, pClusterList));
    72         if (!pClusterList || pClusterList->empty())
    74             if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
    75                 std::cout << 
"ParticleRecoveryAlgorithm: unable to find cluster list " << *iter << 
std::endl;
    82             const Cluster *
const pCluster(*cIter);
    85             if ((TPC_VIEW_U != hitType) && (TPC_VIEW_V != hitType) && (TPC_VIEW_W != hitType))
    86                 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
    88             ClusterList &clusterList((TPC_VIEW_U == hitType) ? inputClusterListU : (TPC_VIEW_V == hitType) ? inputClusterListV : inputClusterListW);
    89             clusterList.push_back(pCluster);
   100         ClusterList vertexClusterList;
   116         const Cluster *
const pCluster = *iter;
   118         if (!pCluster->IsAvailable())
   127         float xMin(0.
f), xMax(0.
f);
   128         pCluster->GetClusterSpanX(xMin, xMax);
   133         selectedClusterList.push_back(pCluster);
   141     CartesianPointVector vertexList;
   147             if (!(*iter)->IsAvailable())
   154         catch (StatusCodeException &)
   163             const Cluster *
const pCluster = *iter;
   165             if (!pCluster->IsAvailable())
   175                     selectedClusterList.push_back(pCluster);
   180         catch (StatusCodeException &)
   205         throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
   207     if ((0 == pCluster1->GetNCaloHits()) || (0 == pCluster2->GetNCaloHits()))
   208         throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
   210     float xMin1(0.
f), xMax1(0.
f), xMin2(0.
f), xMax2(0.
f);
   211     pCluster1->GetClusterSpanX(xMin1, xMax1);
   212     pCluster2->GetClusterSpanX(xMin2, xMax2);
   214     const float xSpan1(xMax1 - xMin1), xSpan2(xMax2 - xMin2);
   216     if ((xSpan1 < std::numeric_limits<float>::epsilon()) || (xSpan2 < std::numeric_limits<float>::epsilon()))
   217         throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
   221     float xOverlapFraction1(xOverlap / xSpan1), xOverlapFraction2(xOverlap / xSpan2);
   235     const Cluster *
const pCluster2, 
const float xMin2, 
const float xMax2, 
float &xOverlapFraction1, 
float &xOverlapFraction2)
 const   240     const float xMin(
std::min(xMin1, xMin2));
   241     const float xMax(
std::max(xMax1, xMax2));
   242     float xMinEff1(xMin1), xMaxEff1(xMax1), xMinEff2(xMin2), xMaxEff2(xMax2);
   247     const float effectiveXSpan1(xMaxEff1 - xMinEff1), effectiveXSpan2(xMaxEff2 - xMinEff2);
   248     const float effectiveXOverlapSpan(
std::min(xMaxEff1, xMaxEff2) - 
std::max(xMinEff1, xMinEff2));
   250     if ((effectiveXSpan1 > std::numeric_limits<float>::epsilon()) && (effectiveXSpan2 > std::numeric_limits<float>::epsilon()))
   252         xOverlapFraction1 = 
std::min(1.
f, (effectiveXOverlapSpan / effectiveXSpan1));
   253         xOverlapFraction2 = 
std::min(1.
f, (effectiveXOverlapSpan / effectiveXSpan2));
   260     const pandora::Cluster *
const pCluster, 
const float xMin, 
const float xMax, 
float &xMinEff, 
float &xMaxEff)
 const   269         const int nSamplingPointsLeft(1 + static_cast<int>((xMinEff - xMin) / 
m_sampleStepSize));
   270         const int nSamplingPointsRight(1 + static_cast<int>((xMax - xMaxEff) / 
m_sampleStepSize));
   271         float dxMin(0.
f), dxMax(0.
f);
   273         for (
int iSample = 1; iSample <= nSamplingPointsLeft; ++iSample)
   280             dxMin = xMinEff - xSample;
   283         for (
int iSample = 1; iSample <= nSamplingPointsRight; ++iSample)
   290             dxMax = xSample - xMaxEff;
   293         xMinEff = xMinEff - dxMin;
   294         xMaxEff = xMaxEff + dxMax;
   296     catch (StatusCodeException &)
   308     for (
const Cluster *
const pKeyCluster : sortedKeyClusters)
   310         ClusterList clusterListU, clusterListV, clusterListW;
   312         overlapTensor.
GetConnectedElements(pKeyCluster, 
true, clusterListU, clusterListV, clusterListW);
   313         const unsigned int nU(clusterListU.size()), nV(clusterListV.size()), nW(clusterListW.size());
   315         if ((0 == nU * nV) && (0 == nV * nW) && (0 == nW * nU))
   318         ClusterList clusterListAll;
   319         clusterListAll.insert(clusterListAll.end(), clusterListU.begin(), clusterListU.end());
   320         clusterListAll.insert(clusterListAll.end(), clusterListV.begin(), clusterListV.end());
   321         clusterListAll.insert(clusterListAll.end(), clusterListW.begin(), clusterListW.end());
   323         if ((1 == nU * nV * nW) && this->
CheckConsistency(*(clusterListU.begin()), *(clusterListV.begin()), *(clusterListW.begin())))
   327         else if ((0 == nU * nV * nW) && ((1 == nU && 1 == nV) || (1 == nV && 1 == nW) || (1 == nW && 1 == nU)))
   344     float xMinU(0.
f), xMinV(0.
f), xMinW(0.
f), xMaxU(0.
f), xMaxV(0.
f), xMaxW(0.
f);
   345     pClusterU->GetClusterSpanX(xMinU, xMaxU);
   346     pClusterV->GetClusterSpanX(xMinV, xMaxV);
   347     pClusterW->GetClusterSpanX(xMinW, xMaxW);
   351     const float xOverlap(xMax - xMin);
   353     if (xOverlap < std::numeric_limits<float>::epsilon())
   370     const float pseudoChi2(((u - vw2u) * (u - vw2u) + (v - wu2v) * (v - wu2v) + (w - uv2w) * (w - uv2w)) / 3.
f);
   382     if (clusterList.size() < 2)
   383         throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
   385     const PfoList *pPfoList = NULL;
   387     PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*
this, pPfoList, pfoListName));
   390     PandoraContentApi::ParticleFlowObject::Parameters pfoParameters;
   391     pfoParameters.m_particleId = MU_MINUS;
   392     pfoParameters.m_charge = PdgTable::GetParticleCharge(pfoParameters.m_particleId.Get());
   393     pfoParameters.m_mass = PdgTable::GetParticleMass(pfoParameters.m_particleId.Get());
   394     pfoParameters.m_energy = 0.f;
   395     pfoParameters.m_momentum = CartesianVector(0.
f, 0.
f, 0.
f);
   396     pfoParameters.m_clusterList = clusterList;
   398     const ParticleFlowObject *pPfo(NULL);
   399     PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::Create(*
this, pfoParameters, pPfo));
   401     if (!pPfoList->empty())
   403         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Pfo>(*
this, 
m_outputPfoListName));
   404         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Pfo>(*
this, 
m_outputPfoListName));
   416     const Cluster *
const pClusterU((TPC_VIEW_U == hitType1) ? pCluster1 : (TPC_VIEW_U == hitType2) ? pCluster2 : NULL);
   417     const Cluster *
const pClusterV((TPC_VIEW_V == hitType1) ? pCluster1 : (TPC_VIEW_V == hitType2) ? pCluster2 : NULL);
   418     const Cluster *
const pClusterW((TPC_VIEW_W == hitType1) ? pCluster1 : (TPC_VIEW_W == hitType2) ? pCluster2 : NULL);
   420     if (pClusterU && pClusterV && !pClusterW)
   422         m_clusterNavigationMapUV[pClusterU].push_back(pClusterV);
   424         if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterU))
   425             m_keyClusters.push_back(pClusterU);
   427     else if (!pClusterU && pClusterV && pClusterW)
   429         m_clusterNavigationMapVW[pClusterV].push_back(pClusterW);
   431         if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterV))
   432             m_keyClusters.push_back(pClusterV);
   434     else if (pClusterU && !pClusterV && pClusterW)
   436         m_clusterNavigationMapWU[pClusterW].push_back(pClusterU);
   438         if (m_keyClusters.end() == std::find(m_keyClusters.begin(), m_keyClusters.end(), pClusterW))
   439             m_keyClusters.push_back(pClusterW);
   443         throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
   450     ClusterList &clusterListU, ClusterList &clusterListV, ClusterList &clusterListW)
 const   452     if (ignoreUnavailable && !pCluster->IsAvailable())
   457     if (!((TPC_VIEW_U == hitType) || (TPC_VIEW_V == hitType) || (TPC_VIEW_W == hitType)))
   458         throw StatusCodeException(STATUS_CODE_FAILURE);
   460     ClusterList &clusterList((TPC_VIEW_U == hitType) ? clusterListU : (TPC_VIEW_V == hitType) ? clusterListV : clusterListW);
   462         (TPC_VIEW_U == hitType) ? m_clusterNavigationMapUV : (TPC_VIEW_V == hitType) ? m_clusterNavigationMapVW : m_clusterNavigationMapWU);
   464     if (clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pCluster))
   467     clusterList.push_back(pCluster);
   471     if (navigationMap.end() == iter)
   475         this->GetConnectedElements(*cIter, ignoreUnavailable, clusterListU, clusterListV, clusterListW);
   483     PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle, 
"InputClusterListNames", 
m_inputClusterListNames));
   484     PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, 
"OutputPfoListName", 
m_outputPfoListName));
   486     PANDORA_RETURN_RESULT_IF_AND_IF(
   487         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MinClusterCaloHits", 
m_minClusterCaloHits));
   489     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"CheckGaps", 
m_checkGaps));
   492     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MinClusterLength", minClusterLength));
   495     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MinClusterXSpan", 
m_minClusterXSpan));
   497     PANDORA_RETURN_RESULT_IF_AND_IF(
   498         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"VertexClusterMode", 
m_vertexClusterMode));
   500     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
   503     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
   506     PANDORA_RETURN_RESULT_IF_AND_IF(
   507         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MinXOverlapFraction", 
m_minXOverlapFraction));
   509     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
   512     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"SampleStepSize", 
m_sampleStepSize));
   517         throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
   520     PANDORA_RETURN_RESULT_IF_AND_IF(
   521         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"SlidingFitHalfWindow", 
m_slidingFitHalfWindow));
   523     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"PseudoChi2Cut", 
m_pseudoChi2Cut));
   525     return STATUS_CODE_SUCCESS;
 pandora::StringVector m_inputClusterListNames
The list of cluster list names. 
 
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. 
 
unsigned int m_minClusterCaloHits
The min number of hits in base cluster selection method. 
 
void GetInputClusters(pandora::ClusterList &inputClusterListU, pandora::ClusterList &inputClusterListV, pandora::ClusterList &inputClusterListW) const 
Get the input cluster lists for processing in this algorithm. 
 
const pandora::ClusterList & GetKeyClusters() const 
Get the list of key clusters. 
 
Header file for the lar pointing cluster class. 
 
float m_minClusterLengthSquared
The min length (squared) in base cluster selection method. 
 
void ExamineTensor(const SimpleOverlapTensor &overlapTensor) const 
Identify unambiguous cluster overlaps and resolve ambiguous overlaps, creating new track particles...
 
float m_maxVertexTransverseDistance
Vertex association check: max transverse distance cut. 
 
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterNavigationMap
 
bool CheckConsistency(const pandora::Cluster *const pClusterU, const pandora::Cluster *const pClusterV, const pandora::Cluster *const pClusterW) const 
Whether a trio of clusters are consistent with representing projections of the same 3d trajectory...
 
LArPointingCluster class. 
 
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster. 
 
static pandora::StatusCode GetAverageZ(const pandora::Cluster *const pCluster, const float xmin, const float xmax, float &averageZ)
Get average Z positions of the calo hits in a cluster in range xmin to xmax. 
 
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch. 
 
float m_minXOverlapFractionGaps
The min x overlap fraction when there are gaps involved. 
 
void SelectInputClusters(const pandora::ClusterList &inputClusterList, pandora::ClusterList &selectedClusterList) const 
Select a subset of input clusters for processing in this algorithm. 
 
Header file for the geometry helper class. 
 
void CalculateEffectiveSpan(const pandora::Cluster *const pCluster, const float xMin, const float xMax, float &xMinEff, float &xMaxEff) const 
Calculate effective span for a given clsuter taking gaps into account. 
 
void CreateTrackParticle(const pandora::ClusterList &clusterList) const 
Create and save a track particle containing the provided clusters. 
 
bool IsOverlap(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2) const 
Whether two clusters overlap convincingly in x. 
 
void AddAssociation(const pandora::Cluster *const pCluster1, const pandora::Cluster *const pCluster2)
Add an association between two clusters to the simple overlap tensor. 
 
Header file for the cluster helper class. 
 
void FindOverlaps(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2, SimpleOverlapTensor &overlapTensor) const 
Find cluster overlaps and record these in the overlap tensor. 
 
const Vertex & GetOuterVertex() const 
Get the outer vertex. 
 
pandora::StatusCode Run()
 
const Vertex & GetInnerVertex() const 
Get the inner vertex. 
 
float m_minVertexLongitudinalDistance
Vertex association check: min longitudinal distance cut. 
 
static float MergeTwoPositions(const pandora::Pandora &pandora, const pandora::HitType view1, const pandora::HitType view2, const float position1, const float position2)
Merge two views (U,V) to give a third view (Z). 
 
float m_minClusterXSpan
The min x span required in order to consider a cluster. 
 
static int max(int a, int b)
 
float m_pseudoChi2Cut
The selection cut on the matched chi2. 
 
void CalculateEffectiveOverlapFractions(const pandora::Cluster *const pCluster1, const float xMin1, const float xMax1, const pandora::Cluster *const pCluster2, const float xMin2, const float xMax2, float &xOverlapFraction1, float &xOverlapFraction2) const 
Calculate effective overlap fractions taking into account gaps. 
 
static bool IsXSamplingPointInGap(const pandora::Pandora &pandora, const float xSample, const TwoDSlidingFitResult &slidingFitResult, const float gapTolerance=0.f)
Whether there is a gap in a cluster (described via its sliding fit result) at a specified x sampling ...
 
unsigned int m_slidingFitHalfWindow
The half window for the fit sliding result constructor. 
 
float m_minXOverlapFraction
The min x overlap fraction required in order to id overlapping clusters. 
 
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
 
SimpleOverlapTensor class. 
 
bool m_checkGaps
Whether to check for gaps in the calculation of the overlap. 
 
bool m_vertexClusterMode
Whether to demand clusters are associated with vertices of existing particles. 
 
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
 
Header file for the track recovery algorithm class. 
 
std::string m_outputPfoListName
The output pfo list name. 
 
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster. 
 
std::vector< art::Ptr< recob::Cluster > > ClusterVector
 
void StandardClusterSelection(const pandora::ClusterList &inputClusterList, pandora::ClusterList &selectedClusterList) const 
Select a subset of input clusters for processing in this algorithm. 
 
float m_sampleStepSize
The sampling step size used in association checks, units cm. 
 
void VertexClusterSelection(const pandora::ClusterList &inputClusterList, pandora::ClusterList &selectedClusterList) const 
Select a subset of input clusters nodally associated with the vertices of existing particles...
 
const pandora::CartesianVector & GetPosition() const 
Get the vertex position. 
 
TwoDSlidingFitResult class. 
 
QTextStream & endl(QTextStream &s)
 
static bool IsNode(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxTransverseDistance)
Whether pointing vertex is adjacent to a given position. 
 
void GetConnectedElements(const pandora::Cluster *const pCluster, const bool ignoreUnavailable, pandora::ClusterList &clusterListU, pandora::ClusterList &clusterListV, pandora::ClusterList &clusterListW) const 
Get elements connected to a specified cluster. 
 
GeomAnalyzerI * GetGeometry(void)