22 m_nMaxTensorToolRepeats(1000),
24 m_minXOverlapFraction(0.8f),
25 m_maxPointDisplacementSquared(1.5f * 1.5f),
26 m_minMatchedSamplingPointFraction(0.5f),
41 if (STATUS_CODE_FAILURE == statusCodeException.
GetStatusCode())
42 throw statusCodeException;
55 : (
TPC_VIEW_V == hitType) ? matchingControl.m_clusterListV : matchingControl.m_clusterListW);
57 if (clusterList.end() != std::find(clusterList.begin(), clusterList.end(), pNewCluster))
60 clusterList.push_back(pNewCluster);
67 for (
const Cluster *
const pCluster1 : clusterList1)
83 for (
const Cluster *
const pCluster2 : clusterList2)
105 std::string oldClusterListName, newClusterListName;
111 newClusters.insert(newClusters.end(), pNewClusterList->begin(), pNewClusterList->end());
126 for (
const Cluster *
const pClusterU : clusterListU)
128 for (
const Cluster *
const pClusterV : clusterListV)
132 for (
const Cluster *
const pClusterU : clusterListU)
134 for (
const Cluster *
const pClusterW : clusterListW)
138 for (
const Cluster *
const pClusterV : clusterListV)
140 for (
const Cluster *
const pClusterW : clusterListW)
149 const HitType missingHitType(((
nullptr != pClusterU) && (
nullptr != pClusterV) && (
nullptr == pClusterW))
151 : ((
nullptr != pClusterU) && (
nullptr == pClusterV) && (
nullptr != pClusterW))
153 : ((
nullptr == pClusterU) && (
nullptr != pClusterV) && (
nullptr != pClusterW)) ?
TPC_VIEW_U :
HIT_CUSTOM);
160 const Cluster *pMatchedClusterU(
nullptr), *pMatchedClusterV(
nullptr), *pMatchedClusterW(
nullptr);
172 const Cluster *pBestMatchedCluster(
nullptr);
175 if ((STATUS_CODE_SUCCESS != statusCode) && (STATUS_CODE_NOT_FOUND != statusCode))
181 MatchingType::TensorType &overlapTensor(this->
GetMatchingControl().GetOverlapTensor());
183 if (STATUS_CODE_SUCCESS == statusCode)
185 pMatchedClusterU = ((
nullptr != pClusterU) ? pClusterU : pBestMatchedCluster);
186 pMatchedClusterV = ((
nullptr != pClusterV) ? pClusterV : pBestMatchedCluster);
187 pMatchedClusterW = ((
nullptr != pClusterW) ? pClusterW : pBestMatchedCluster);
189 if (
nullptr == pMatchedClusterU ||
nullptr == pMatchedClusterV ||
nullptr == pMatchedClusterW)
194 oldOverlapResult = overlapTensor.GetOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW);
203 overlapTensor.SetOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW, newOverlapResult);
207 overlapTensor.ReplaceOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW, newOverlapResult);
211 float newEnergySum(0.f), oldEnergySum(0.f);
213 newEnergySum += pCaloHit->GetHadronicEnergy();
215 oldEnergySum += pCaloHit->GetHadronicEnergy();
217 if (newEnergySum > oldEnergySum)
218 overlapTensor.ReplaceOverlapResult(pMatchedClusterU, pMatchedClusterV, pMatchedClusterW, newOverlapResult);
230 float xMin1(0.f), xMax1(0.f), xMin2(0.f), xMax2(0.f);
234 const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
236 if (xOverlap < std::numeric_limits<float>::epsilon())
237 return STATUS_CODE_NOT_FOUND;
242 if (STATUS_CODE_SUCCESS != statusCode1)
248 const StatusCode statusCode2(this->
GetMatchedHits(inputClusterList, projectedPositions, hitToClusterMap, matchedHits));
250 if (STATUS_CODE_SUCCESS != statusCode2)
255 if (STATUS_CODE_SUCCESS != statusCode3)
259 return STATUS_CODE_NOT_FOUND;
265 return STATUS_CODE_NOT_FOUND;
267 fragmentOverlapResult = overlapResult;
268 return STATUS_CODE_SUCCESS;
289 return STATUS_CODE_INVALID_PARAMETER;
292 float xMin1(0.f), xMax1(0.f), xMin2(0.f), xMax2(0.f);
296 const float xOverlap(std::min(xMax1, xMax2) - std::max(xMin1, xMin2));
297 const float xSpan(std::max(xMax1, xMax2) - std::min(xMin1, xMin2));
300 return STATUS_CODE_NOT_FOUND;
308 const float dx_A(std::fabs(minPosition2.
GetX() - minPosition1.
GetX()));
309 const float dx_B(std::fabs(maxPosition2.
GetX() - maxPosition1.
GetX()));
310 const float dx_C(std::fabs(maxPosition2.
GetX() - minPosition1.
GetX()));
311 const float dx_D(std::fabs(minPosition2.
GetX() - maxPosition1.
GetX()));
313 if (std::min(dx_C, dx_D) > std::max(dx_A, dx_B) && std::min(dx_A, dx_B) > std::max(dx_C, dx_D))
314 return STATUS_CODE_NOT_FOUND;
318 const CartesianVector &vtxPosition2((dx_A < dx_C) ? minPosition2 : maxPosition2);
319 const CartesianVector &endPosition2((dx_A < dx_C) ? maxPosition2 : minPosition2);
334 const float nSamplingPoints((endProjection3 - vtxProjection3).GetMagnitude() / samplingPitch);
336 if (nSamplingPoints < 1.f)
337 return STATUS_CODE_NOT_FOUND;
340 bool foundLastPosition(
false);
343 for (
float iSample = 0.5f; iSample < nSamplingPoints; iSample += 1.f)
345 const CartesianVector linearPosition3D(vtxPosition3D + (endPosition3D - vtxPosition3D) * (iSample / nSamplingPoints));
350 CartesianVector fitPosition1(0.f, 0.f, 0.f), fitPosition2(0.f, 0.f, 0.f);
358 float rL1(0.f), rL2(0.f), rT1(0.f), rT2(0.f);
362 const float x(0.5 * (fitPosition1.GetX() + fitPosition2.
GetX()));
363 CartesianVector position1(0.f, 0.f, 0.f), position2(0.f, 0.f, 0.f), position3(0.f, 0.f, 0.f);
378 if (STATUS_CODE_FAILURE == statusCodeException.
GetStatusCode())
379 throw statusCodeException;
387 if (foundLastPosition)
389 const float thisDisplacement((lastPosition - position3).GetMagnitude());
390 if (thisDisplacement > 2.f * samplingPitch)
392 const float nExtraPoints(thisDisplacement / samplingPitch);
393 for (
float iExtra = 0.5f; iExtra < nExtraPoints; iExtra += 1.f)
395 const CartesianVector extraPosition(position3 + (lastPosition - position3) * (iExtra / nExtraPoints));
396 projectedPositions.push_back(extraPosition);
401 projectedPositions.push_back(position3);
403 lastPosition = position3;
404 foundLastPosition =
true;
408 if (projectedPositions.empty())
409 return STATUS_CODE_NOT_FOUND;
411 return STATUS_CODE_SUCCESS;
421 for (ClusterList::const_iterator iter = inputClusterList.begin(), iterEnd = inputClusterList.end(); iter != iterEnd; ++iter)
423 const Cluster *
const pCluster = *iter;
430 availableCaloHits.insert(availableCaloHits.end(), caloHitList.begin(), caloHitList.end());
432 for (CaloHitList::const_iterator hIter = caloHitList.begin(), hIterEnd = caloHitList.end(); hIter != hIterEnd; ++hIter)
433 hitToClusterMap.insert(HitToClusterMap::value_type(*hIter, pCluster));
440 const CaloHit *pClosestCaloHit(
nullptr);
441 float closestDistanceSquared(std::numeric_limits<float>::max()), tieBreakerBestEnergy(0.f);
443 for (
const CaloHit *
const pCaloHit : availableCaloHits)
445 const float distanceSquared((pCaloHit->GetPositionVector() - projectedPosition).GetMagnitudeSquared());
447 if ((distanceSquared < closestDistanceSquared) ||
448 ((std::fabs(distanceSquared - closestDistanceSquared) < std::numeric_limits<float>::epsilon()) &&
449 (pCaloHit->GetHadronicEnergy() > tieBreakerBestEnergy)))
451 pClosestCaloHit = pCaloHit;
452 closestDistanceSquared = distanceSquared;
458 (matchedHits.end() == std::find(matchedHits.begin(), matchedHits.end(), pClosestCaloHit)))
459 matchedHits.push_back(pClosestCaloHit);
462 if (matchedHits.empty())
463 return STATUS_CODE_NOT_FOUND;
465 return STATUS_CODE_SUCCESS;
475 for (CaloHitList::const_iterator iter = matchedHits.begin(), iterEnd = matchedHits.end(); iter != iterEnd; ++iter)
477 const CaloHit *
const pCaloHit = *iter;
478 HitToClusterMap::const_iterator cIter = hitToClusterMap.find(pCaloHit);
480 if (hitToClusterMap.end() == cIter)
483 ++clusterToMatchedHitsMap[cIter->second];
485 if (matchedClusters.end() == std::find(matchedClusters.begin(), matchedClusters.end(), cIter->second))
486 matchedClusters.push_back(cIter->second);
489 if (matchedClusters.empty())
490 return STATUS_CODE_NOT_FOUND;
492 pBestMatchedCluster =
nullptr;
493 unsigned int bestClusterMatchedHits(0);
494 float tieBreakerBestEnergy(0.f);
497 for (
const auto &mapEntry : clusterToMatchedHitsMap)
498 sortedClusters.push_back(mapEntry.first);
501 for (
const Cluster *
const pCluster : sortedClusters)
503 const unsigned int nMatchedHits(clusterToMatchedHitsMap.at(pCluster));
505 if ((nMatchedHits > bestClusterMatchedHits) || ((nMatchedHits == bestClusterMatchedHits) && (pCluster->GetHadronicEnergy() > tieBreakerBestEnergy)))
507 pBestMatchedCluster = pCluster;
508 bestClusterMatchedHits = nMatchedHits;
513 if (
nullptr == pBestMatchedCluster)
514 return STATUS_CODE_NOT_FOUND;
516 return STATUS_CODE_SUCCESS;
525 unsigned int nMatchedSamplingPoints(0);
527 CaloHitVector sortedMatchedHits(matchedHits.begin(), matchedHits.end());
532 float closestDistanceSquared(std::numeric_limits<float>::max());
534 for (
const CaloHit *
const pCaloHit : matchedHits)
536 const float distanceSquared((pCaloHit->GetPositionVector() - projectedPosition).GetMagnitudeSquared());
538 if (distanceSquared < closestDistanceSquared)
539 closestDistanceSquared = distanceSquared;
544 ++nMatchedSamplingPoints;
545 chi2Sum += closestDistanceSquared;
549 fragmentOverlapResult =
FragmentOverlapResult(nMatchedSamplingPoints, projectedPositions.size(), chi2Sum, matchedHits, matchedClusters);
556 if (projectedPositions.empty() || matchedClusters.empty())
560 float minXproj(+std::numeric_limits<float>::max());
561 float maxXproj(-std::numeric_limits<float>::max());
562 float minZproj(+std::numeric_limits<float>::max());
563 float maxZproj(-std::numeric_limits<float>::max());
567 minXproj = std::min(minXproj, projectedPosition.GetX());
568 maxXproj = std::max(maxXproj, projectedPosition.GetX());
569 minZproj = std::min(minZproj, projectedPosition.GetZ());
570 maxZproj = std::max(maxZproj, projectedPosition.GetZ());
573 const float dXproj(maxXproj - minXproj);
574 const float dZproj(maxZproj - minZproj);
575 const float projectedLengthSquared(dXproj * dXproj + dZproj * dZproj);
578 float minXcluster(+std::numeric_limits<float>::max());
579 float maxXcluster(-std::numeric_limits<float>::max());
580 float minZcluster(+std::numeric_limits<float>::max());
581 float maxZcluster(-std::numeric_limits<float>::max());
583 for (
const Cluster *
const pCluster : matchedClusters)
590 minXcluster = std::min(minXcluster, minPosition.
GetX());
591 maxXcluster = std::max(maxXcluster, maxPosition.
GetX());
592 minZcluster = std::min(minZcluster, minPosition.
GetZ());
593 maxZcluster = std::max(maxZcluster, maxPosition.
GetZ());
596 const float dXcluster(maxXcluster - minXcluster);
597 const float dZcluster(maxZcluster - minZcluster);
598 const float clusterLengthSquared(dXcluster * dXcluster + dZcluster * dZcluster);
601 if (clusterLengthSquared > 4.f * projectedLengthSquared)
625 unsigned int repeatCounter(0);
629 if ((*iter)->Run(
this, this->GetMatchingControl().GetOverlapTensor()))
652 for (AlgorithmToolVector::const_iterator iter = algorithmToolVector.begin(), iterEnd = algorithmToolVector.end(); iter != iterEnd; ++iter)
656 if (!pFragmentTensorTool)
657 return STATUS_CODE_INVALID_PARAMETER;
672 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
XmlHelper::ReadValue(xmlHandle,
"MaxPointDisplacement", maxPointDisplacement));
Header file for the cluster helper class.
Header file for the geometry helper class.
#define PANDORA_THROW_RESULT_IF(StatusCode1, Operator, Command)
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
#define PANDORA_RETURN_RESULT_IF(StatusCode1, Operator, Command)
Header file for the three view fragments algorithm base class.
static pandora::StatusCode RunClusteringAlgorithm(const pandora::Algorithm &algorithm, const std::string &clusteringAlgorithmName, const pandora::ClusterList *&pNewClusterList, std::string &newClusterListName)
Run a clustering algorithm (an algorithm that will create new cluster objects)
static pandora::StatusCode EndReclustering(const pandora::Algorithm &algorithm, const std::string &selectedClusterListName)
End reclustering operations on clusters in the algorithm input list.
static pandora::StatusCode InitializeReclustering(const pandora::Algorithm &algorithm, const pandora::TrackList &inputTrackList, const pandora::ClusterList &inputClusterList, std::string &originalClustersListName)
Initialize reclustering operations on clusters in the algorithm input list. This allows hits in a lis...
FragmentOverlapResult class.
const pandora::CaloHitList & GetFragmentCaloHitList() const
Get the list of fragment-associated hits.
FragmentTensorTool class.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static bool SortHitsByPosition(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs)
Sort calo hits by their position (use Z, followed by X, followed by Y)
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,...
static void GetClusterBoundingBox(const pandora::Cluster *const pCluster, pandora::CartesianVector &minimumCoordinate, pandora::CartesianVector &maximumCoordinate)
Get minimum and maximum X, Y and Z positions of the calo hits in a cluster.
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).
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
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.
const pandora::ClusterList & GetInputClusterList(const pandora::HitType hitType) const
Get the input cluster list corresponding to a specified hit type.
MatchingType & GetMatchingControl()
Get the matching control.
const pandora::ClusterList & GetSelectedClusterList(const pandora::HitType hitType) const
Get the selected cluster list corresponding to a specified hit type.
void AddToSlidingFitCache(const pandora::Cluster *const pCluster)
Add a new sliding fit result, for the specified cluster, to the algorithm cache.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
const TwoDSlidingFitResult & GetCachedSlidingFitResult(const pandora::Cluster *const pCluster) const
Get a sliding fit result from the algorithm cache.
void PerformMainLoop()
Main loop over cluster combinations in order to populate the overlap container. Responsible for calli...
TensorToolVector m_algorithmToolVector
The algorithm tool list.
std::unordered_map< const pandora::CaloHit *, const pandora::Cluster * > HitToClusterMap
void GetFragmentOverlapResult(const pandora::CartesianPointVector &projectedPositions, const pandora::CaloHitList &matchedHits, const pandora::ClusterList &matchedClusters, FragmentOverlapResult &fragmentOverlapResult) const
Get the populated fragment overlap result.
void UpdateForNewCluster(const pandora::Cluster *const pNewCluster)
Update to reflect addition of a new cluster to the problem space.
void ExamineOverlapContainer()
Examine contents of overlap container, collect together best-matching 2D particles and modify cluster...
void RebuildClusters(const pandora::ClusterList &rebuildList, pandora::ClusterList &newClusters) const
Rebuild clusters after fragmentation.
float m_maxPointDisplacementSquared
maximum allowed distance (squared) between projected points and associated hits
unsigned int m_nMaxTensorToolRepeats
The maximum number of repeat loops over tensor tools.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
pandora::StatusCode GetMatchedClusters(const pandora::CaloHitList &matchedHits, const HitToClusterMap &hitToClusterMap, pandora::ClusterList &matchedClusters, const pandora::Cluster *&pBestMatchedCluster) const
Get the list of the relevant clusters and the address of the single best matched cluster.
void CalculateOverlapResult(const pandora::Cluster *const pClusterU, const pandora::Cluster *const pClusterV, const pandora::Cluster *const pClusterW)
Calculate cluster overlap result and store in container.
bool CheckMatchedClusters(const pandora::CartesianPointVector &projectedPositions, const pandora::ClusterList &matchedClusters) const
Whether the matched clusters are consistent with the projected positions.
float m_minMatchedSamplingPointFraction
minimum fraction of matched sampling points
float m_minXOverlap
requirement on minimum X overlap for associated clusters
bool CheckOverlapResult(const FragmentOverlapResult &overlapResult) const
Whether the matched clusters and hits pass the algorithm quality cuts.
std::string m_reclusteringAlgorithmName
Name of daughter algorithm to use for cluster re-building.
unsigned int m_minMatchedHits
minimum number of matched calo hits
float m_minXOverlapFraction
requirement on minimum X overlap fraction for associated clusters
std::unordered_map< const pandora::Cluster *, unsigned int > ClusterToMatchedHitsMap
pandora::StatusCode GetMatchedHits(const pandora::ClusterList &inputClusterList, const pandora::CartesianPointVector &projectedPositions, HitToClusterMap &hitToClusterMap, pandora::CaloHitList &matchedCaloHits) const
Get the list of hits associated with the projected positions and a useful hit to cluster map.
pandora::StatusCode GetProjectedPositions(const TwoDSlidingFitResult &fitResult1, const TwoDSlidingFitResult &fitResult2, pandora::CartesianPointVector &projectedPositions) const
Get the list of projected positions, in the third view, corresponding to a pair of sliding fit result...
ThreeViewTrackFragmentsAlgorithm()
Default constructor.
bool IsInitialized() const
Whether the track overlap result has been initialized.
float GetMatchedFraction() const
Get the fraction of sampling points resulting in a match.
TwoDSlidingFitResult class.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
const pandora::Cluster * GetCluster() const
Get the address of the cluster, if originally provided.
pandora::StatusCode GetTransverseProjection(const float x, const FitSegment &fitSegment, pandora::CartesianVector &position) const
Get projected position for a given input x coordinate and fit segment.
const FitSegment & GetFitSegment(const float rL) const
Get fit segment for a given longitudinal coordinate.
pandora::StatusCode GetGlobalFitProjection(const pandora::CartesianVector &inputPosition, pandora::CartesianVector &projectedPosition) const
Get projected position on global fit for a given position vector.
float GetHadronicEnergy() const
Get the calibrated hadronic energy measure.
float GetX() const
Get the cartesian x coordinate.
float GetZ() const
Get the cartesian z coordinate.
bool IsAvailable() const
Whether the cluster is available to be added to a particle flow object.
float GetHadronicEnergy() const
Get the sum of hadronic energy measures of all constituent calo hits, units GeV.
const OrderedCaloHitList & GetOrderedCaloHitList() const
Get the ordered calo hit list.
void GetClusterSpanX(float &xmin, float &xmax) const
Get minimum and maximum X positions of the calo hits in this cluster.
void FillCaloHitList(CaloHitList &caloHitList) const
Fill a provided calo hit list with all the calo hits in the ordered calo hit list.
const Pandora & GetPandora() const
Get the associated pandora instance.
StatusCodeException class.
StatusCode GetStatusCode() const
Get status code.
static StatusCode ProcessAlgorithm(const Algorithm &algorithm, const TiXmlHandle &xmlHandle, const std::string &description, std::string &algorithmName)
Process an algorithm described in an xml element with a matching "description = .....
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
static StatusCode ProcessAlgorithmToolList(const Algorithm &algorithm, const TiXmlHandle &xmlHandle, const std::string &listName, AlgorithmToolVector &algorithmToolVector)
Process a list of algorithms tools in an xml file.
HitType
Calorimeter hit type enum.
std::vector< const CaloHit * > CaloHitVector
std::vector< const Cluster * > ClusterVector
MANAGED_CONTAINER< const Cluster * > ClusterList
std::vector< CartesianVector > CartesianPointVector
std::vector< AlgorithmTool * > AlgorithmToolVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList
MANAGED_CONTAINER< const Track * > TrackList
StatusCode
The StatusCode enum.