8 #include "Pandora/AlgorithmHeaders.h" 
   21 TrackRefinementBaseAlgorithm::TrackRefinementBaseAlgorithm() :
 
   22     m_minClusterLength(15.f),
 
   23     m_microSlidingFitWindow(20),
 
   24     m_macroSlidingFitWindow(1000),
 
   25     m_stableRegionClusterFraction(0.05f),
 
   26     m_mergePointMinCosAngleDeviation(0.999f),
 
   27     m_minHitFractionForHitRemoval(0.05f),
 
   28     m_maxDistanceFromMainTrack(0.75f),
 
   29     m_maxHitDistanceFromCluster(4.f),
 
   30     m_maxHitSeparationForConnectedCluster(4.f),
 
   32     m_lineSegmentLength(3.f),
 
   45     for (
const Cluster *
const pCluster : *pClusterList)
 
   55             slidingFitResultMapPair.first->insert(TwoDSlidingFitResultMap::value_type(pCluster, microSlidingFitResult));
 
   56             slidingFitResultMapPair.second->insert(TwoDSlidingFitResultMap::value_type(pCluster, macroSlidingFitResult));
 
   57             clusterVector.push_back(pCluster);
 
   59         catch (
const StatusCodeException &)
 
   64     std::sort(clusterVector.begin(), clusterVector.end(), sortFunction);
 
   71     CartesianVector &clusterMergePosition, CartesianVector &clusterMergeDirection)
 const 
   73     CartesianVector clusterAverageDirection(0.f, 0.f, 0.f), associatedAverageDirection(0.f, 0.f, 0.f);
 
   78     const int startLayer(isEndUpstream ? clusterMicroFitResult.
GetMinLayer() : clusterMicroFitResult.
GetMaxLayer());
 
   79     const int endLayer(isEndUpstream ? clusterMicroFitResult.
GetMaxLayer() : clusterMicroFitResult.
GetMinLayer());
 
   80     const int loopTerminationLayer(endLayer + (isEndUpstream ? 1 : -1));
 
   81     const int step(isEndUpstream ? 1 : -1);
 
   85     unsigned int goodLayerCount(0);
 
   87     clusterMicroLayerFitResultMap.at(endLayer);
 
   89     for (
int i = startLayer; i != loopTerminationLayer; i += step)
 
   91         const auto microIter(clusterMicroLayerFitResultMap.find(i));
 
   93         if (microIter == clusterMicroLayerFitResultMap.end())
 
   96         CartesianVector microDirection(0.f, 0.f, 0.f);
 
   97         clusterMicroFitResult.
GetGlobalDirection(microIter->second.GetGradient(), microDirection);
 
   99         const float cosDirectionOpeningAngle(microDirection.GetCosOpeningAngle(associatedAverageDirection));
 
  103             if (goodLayerCount == 0)
 
  105                 clusterMergeDirection = clusterAverageDirection;
 
  106                 PANDORA_THROW_RESULT_IF(
 
  107                     STATUS_CODE_SUCCESS, !=, clusterMicroFitResult.
GetGlobalFitPosition(microIter->second.GetL(), clusterMergePosition));
 
  117         if (goodLayerCount > gradientStabilityWindow)
 
  132     const ClusterList &unavailableProtectedClusters, 
const float distanceToLine)
 const 
  134     const float minX(std::min(firstCorner.GetX(), secondCorner.GetX())), maxX(std::max(firstCorner.GetX(), secondCorner.GetX()));
 
  135     const float minZ(std::min(firstCorner.GetZ(), secondCorner.GetZ())), maxZ(std::max(firstCorner.GetZ(), secondCorner.GetZ()));
 
  137     CartesianVector connectingLineDirection(firstCorner - secondCorner);
 
  138     connectingLineDirection = connectingLineDirection.GetUnitVector();
 
  140     for (
const Cluster *
const pCluster : *pClusterList)
 
  142         if (std::find(unavailableProtectedClusters.begin(), unavailableProtectedClusters.end(), pCluster) != unavailableProtectedClusters.end())
 
  145         const OrderedCaloHitList &orderedCaloHitList(pCluster->GetOrderedCaloHitList());
 
  146         for (
const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
 
  148             for (
const CaloHit *
const pCaloHit : *mapEntry.second)
 
  151                                                            : pCaloHit->GetPositionVector());
 
  156                 if (distanceToLine > 0.f)
 
  158                     if (!this->
IsCloseToLine(hitPosition, firstCorner, connectingLineDirection, distanceToLine))
 
  162                 clusterToCaloHitListMap[pCluster].push_back(pCaloHit);
 
  171     const float minX, 
const float maxX, 
const float minZ, 
const float maxZ, 
const CartesianVector &hitPosition)
 const 
  173     return !((hitPosition.GetX() < minX) || (hitPosition.GetX() > maxX) || (hitPosition.GetZ() < minZ) || (hitPosition.GetZ() > maxZ));
 
  179     const CartesianVector &lineDirection, 
const float distanceToLine)
 const 
  181     const float transverseDistanceFromLine(lineDirection.GetCrossProduct(hitPosition - lineStart).GetMagnitude());
 
  183     return (transverseDistanceFromLine < distanceToLine);
 
  190     CaloHitVector extrapolatedHitVector;
 
  191     for (
const auto &entry : clusterToCaloHitListMap)
 
  192         extrapolatedHitVector.insert(extrapolatedHitVector.begin(), entry.second.begin(), entry.second.end());
 
  195     std::sort(extrapolatedHitVector.begin(), extrapolatedHitVector.end(),
 
  201     if (clusterToCaloHitListMap.empty())
 
  216     return (distanceToBoundary < boundaryTolerance);
 
  223     CartesianPointVector trackSegmentBoundaries;
 
  226     if (trackSegmentBoundaries.size() < 2)
 
  228         std::cout << 
"TrackInEMShowerAlgorithm: Less than two track segment boundaries" << std::endl;
 
  229         throw STATUS_CODE_NOT_ALLOWED;
 
  232     unsigned int segmentsWithoutHits(0);
 
  233     CaloHitVector::const_iterator caloHitIter(extrapolatedCaloHitVector.begin());
 
  236                                                : (*caloHitIter)->GetPositionVector());
 
  238     for (
unsigned int i = 0; i < (trackSegmentBoundaries.size() - 1); ++i)
 
  240         if (caloHitIter == extrapolatedCaloHitVector.end())
 
  242             ++segmentsWithoutHits;
 
  250         unsigned int hitsInSegment(0);
 
  251         while (this->
IsInLineSegment(trackSegmentBoundaries.at(i), trackSegmentBoundaries.at(i + 1), hitPosition))
 
  256             if (caloHitIter == extrapolatedCaloHitVector.end())
 
  261                                          : (*caloHitIter)->GetPositionVector();
 
  264         segmentsWithoutHits = hitsInSegment ? 0 : segmentsWithoutHits + 1;
 
  279         std::cout << 
"TrackInEMShowerAlgorithm: Line segment length must be positive and nonzero" << std::endl;
 
  280         throw STATUS_CODE_INVALID_PARAMETER;
 
  287     DetectorGapList consideredGaps;
 
  290     consideredGaps.clear();
 
  294     if (fullSegments == 0)
 
  302     const bool splitFinalSegment(lengthOfTrackRemainder > m_lineSegmentLength * 0.5f);
 
  303     const int numberOfBoundaries(fullSegments + (splitFinalSegment ? 2 : 1));
 
  305     CartesianVector segmentUpstreamBoundary(clusterAssociation.
GetUpstreamMergePoint()), segmentDownstreamBoundary(segmentUpstreamBoundary);
 
  307     trackSegmentBoundaries.push_back(segmentUpstreamBoundary);
 
  309     for (
int i = 1; i < numberOfBoundaries; ++i)
 
  311         if (i < fullSegments)
 
  317             if (splitFinalSegment)
 
  319                 segmentDownstreamBoundary += trackDirection * (m_lineSegmentLength + lengthOfTrackRemainder) * 0.5f;
 
  323                 segmentDownstreamBoundary += trackDirection * (m_lineSegmentLength + lengthOfTrackRemainder);
 
  327         float distanceInGap(this->
DistanceInGap(segmentUpstreamBoundary, segmentDownstreamBoundary, trackDirection, consideredGaps));
 
  328         while (distanceInGap > std::numeric_limits<float>::epsilon())
 
  331             segmentDownstreamBoundary += trackDirection * distanceInGap;
 
  332             distanceInGap = this->
DistanceInGap(segmentUpstreamBoundary, segmentDownstreamBoundary, trackDirection, consideredGaps);
 
  335         trackSegmentBoundaries.push_back(segmentDownstreamBoundary);
 
  343     const DetectorGapList detectorGapList(this->GetPandora().GetGeometry()->GetDetectorGapList());
 
  344     for (
const DetectorGap *
const pDetectorGap : detectorGapList)
 
  346         const LineGap *
const pLineGap(dynamic_cast<const LineGap *>(pDetectorGap));
 
  350             const LineGapType lineGapType(pLineGap->GetLineGapType());
 
  352             if (lineGapType == TPC_DRIFT_GAP)
 
  354                 if ((pLineGap->GetLineStartX() < trackPoint.GetX()) && (pLineGap->GetLineEndX() > trackPoint.GetX()))
 
  356                     if (std::fabs(mergeDirection.GetX()) < std::numeric_limits<float>::epsilon())
 
  357                         throw StatusCodeException(STATUS_CODE_FAILURE);
 
  359                     const float gradient(mergeDirection.GetZ() / mergeDirection.GetX());
 
  361                     trackPoint = CartesianVector(
 
  362                         pLineGap->GetLineEndX(), 0.f, trackPoint.GetZ() + (gradient * (pLineGap->GetLineEndX() - trackPoint.GetX())));
 
  366             if ((lineGapType == TPC_WIRE_GAP_VIEW_U) || (lineGapType == TPC_WIRE_GAP_VIEW_V) || (lineGapType == TPC_WIRE_GAP_VIEW_W))
 
  368                 if ((pLineGap->GetLineStartZ() < trackPoint.GetZ()) && (pLineGap->GetLineEndZ() > trackPoint.GetZ()))
 
  370                     if (std::fabs(mergeDirection.GetZ()) < std::numeric_limits<float>::epsilon())
 
  371                         throw StatusCodeException(STATUS_CODE_FAILURE);
 
  373                     const float gradient(mergeDirection.GetX() / mergeDirection.GetZ());
 
  375                     trackPoint = CartesianVector(
 
  376                         trackPoint.GetX() + (gradient * (pLineGap->GetLineEndZ() - trackPoint.GetZ())), 0.f, pLineGap->GetLineEndZ());
 
  386     const CartesianVector &connectingLine, DetectorGapList &consideredGaps)
 const 
  388     const CartesianVector &lowerXPoint(upstreamPoint.GetX() < downstreamPoint.GetX() ? upstreamPoint : downstreamPoint);
 
  389     const CartesianVector &higherXPoint(upstreamPoint.GetX() < downstreamPoint.GetX() ? downstreamPoint : upstreamPoint);
 
  391     const float cosAngleToX(std::fabs(connectingLine.GetDotProduct(CartesianVector(1.f, 0.f, 0.f))));
 
  392     const float cosAngleToZ(std::fabs(connectingLine.GetDotProduct(CartesianVector(0.f, 0.f, 1.f))));
 
  394     float distanceInGaps(0.f);
 
  395     const DetectorGapList detectorGapList(this->GetPandora().GetGeometry()->GetDetectorGapList());
 
  396     for (
const DetectorGap *
const pDetectorGap : detectorGapList)
 
  398         if (std::find(consideredGaps.begin(), consideredGaps.end(), pDetectorGap) != consideredGaps.end())
 
  401         const LineGap *
const pLineGap(dynamic_cast<const LineGap *>(pDetectorGap));
 
  405             const LineGapType lineGapType(pLineGap->GetLineGapType());
 
  407             if (lineGapType == TPC_DRIFT_GAP)
 
  409                 float xDistanceInGap(0.f);
 
  411                 if ((pLineGap->GetLineStartX() > lowerXPoint.GetX()) && (pLineGap->GetLineEndX() < higherXPoint.GetX()))
 
  413                     xDistanceInGap = (pLineGap->GetLineEndX() - pLineGap->GetLineStartX());
 
  415                 else if ((pLineGap->GetLineStartX() < lowerXPoint.GetX()) && (pLineGap->GetLineEndX() > lowerXPoint.GetX()))
 
  417                     xDistanceInGap = (pLineGap->GetLineEndX() - lowerXPoint.GetX());
 
  419                 else if ((pLineGap->GetLineStartX() < higherXPoint.GetX()) && (pLineGap->GetLineEndX() > higherXPoint.GetX()))
 
  421                     xDistanceInGap = (higherXPoint.GetX() - pLineGap->GetLineStartX());
 
  428                 if (std::fabs(cosAngleToX) < std::numeric_limits<float>::epsilon())
 
  429                     throw StatusCodeException(STATUS_CODE_FAILURE);
 
  431                 distanceInGaps += (xDistanceInGap / cosAngleToX);
 
  433                 consideredGaps.push_back(pDetectorGap);
 
  436             if ((lineGapType == TPC_WIRE_GAP_VIEW_U) || (lineGapType == TPC_WIRE_GAP_VIEW_V) || (lineGapType == TPC_WIRE_GAP_VIEW_W))
 
  438                 float zDistanceInGap(0.f);
 
  440                 if ((pLineGap->GetLineStartZ() > upstreamPoint.GetZ()) && (pLineGap->GetLineEndZ() < downstreamPoint.GetZ()))
 
  442                     zDistanceInGap = pLineGap->GetLineEndZ() - pLineGap->GetLineStartZ();
 
  444                 else if ((pLineGap->GetLineStartZ() < upstreamPoint.GetZ()) && (pLineGap->GetLineEndZ() > upstreamPoint.GetZ()))
 
  446                     zDistanceInGap = pLineGap->GetLineEndZ() - upstreamPoint.GetZ();
 
  448                 else if ((pLineGap->GetLineStartZ() < downstreamPoint.GetZ()) && (pLineGap->GetLineEndZ() > downstreamPoint.GetZ()))
 
  450                     zDistanceInGap = downstreamPoint.GetZ() - pLineGap->GetLineStartZ();
 
  457                 if (std::fabs(cosAngleToZ) < std::numeric_limits<float>::epsilon())
 
  458                     throw StatusCodeException(STATUS_CODE_FAILURE);
 
  460                 distanceInGaps += (zDistanceInGap / cosAngleToZ);
 
  462                 consideredGaps.push_back(pDetectorGap);
 
  467     return distanceInGaps;
 
  473     const CartesianVector &lowerBoundary, 
const CartesianVector &upperBoundary, 
const CartesianVector &point)
 const 
  475     const float segmentBoundaryGradient = (-1.f) * (upperBoundary.GetX() - lowerBoundary.GetX()) / (upperBoundary.GetZ() - lowerBoundary.GetZ());
 
  476     const float xPointOnUpperLine((point.GetZ() - upperBoundary.GetZ()) / segmentBoundaryGradient + upperBoundary.GetX());
 
  477     const float xPointOnLowerLine((point.GetZ() - lowerBoundary.GetZ()) / segmentBoundaryGradient + lowerBoundary.GetX());
 
  479     if (std::fabs(xPointOnUpperLine - point.GetX()) < std::numeric_limits<float>::epsilon())
 
  482     if (std::fabs(xPointOnLowerLine - point.GetX()) < std::numeric_limits<float>::epsilon())
 
  485     if ((point.GetX() > xPointOnUpperLine) && (point.GetX() > xPointOnLowerLine))
 
  488     if ((point.GetX() < xPointOnUpperLine) && (point.GetX() < xPointOnLowerLine))
 
  497     const bool isEndUpstream, 
const ClusterToCaloHitListMap &clusterToCaloHitListMap, ClusterList &remnantClusterList,
 
  500     float rL(0.f), rT(0.f);
 
  505     CartesianVector averageDirection(0.f, 0.f, 0.f);
 
  506     macroFitResult.GetGlobalDirection(macroFitResult.GetLayerFitResultMap().begin()->second.GetGradient(), averageDirection);
 
  508     const bool isVertical(std::fabs(averageDirection.GetX()) < std::numeric_limits<float>::epsilon());
 
  509     const float clusterGradient(isVertical ? 0.f : averageDirection.GetZ() / averageDirection.GetX());
 
  510     const float clusterIntercept(isVertical ? splitPosition.GetX() : splitPosition.GetZ() - (clusterGradient * splitPosition.GetX()));
 
  513     std::string originalListName, fragmentListName;
 
  514     const ClusterList originalClusterList(1, pCluster);
 
  515     PANDORA_THROW_RESULT_IF(
 
  516         STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*
this, originalClusterList, originalListName, fragmentListName));
 
  518     const Cluster *pMainTrackCluster(
nullptr), *pAboveCluster(
nullptr), *pBelowCluster(
nullptr);
 
  520     const OrderedCaloHitList &orderedCaloHitList(pCluster->GetOrderedCaloHitList());
 
  521     for (
const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
 
  523         for (
const CaloHit *
const pCaloHit : *mapEntry.second)
 
  525             const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
 
  526             float thisL(0.f), thisT(0.f);
 
  528             microFitResult.GetLocalPosition(pCaloHit->GetPositionVector(), thisL, thisT);
 
  530             bool isAnExtrapolatedHit(
false);
 
  531             const auto extrapolatedCaloHitIter(clusterToCaloHitListMap.find(pCluster));
 
  533             if (extrapolatedCaloHitIter != clusterToCaloHitListMap.end())
 
  534                 isAnExtrapolatedHit = std::find(extrapolatedCaloHitIter->second.begin(), extrapolatedCaloHitIter->second.end(), pCaloHit) !=
 
  535                                       extrapolatedCaloHitIter->second.end();
 
  537             const bool isAbove(((clusterGradient * hitPosition.GetX()) + clusterIntercept) < (isVertical ? hitPosition.GetX() : hitPosition.GetZ()));
 
  538             const bool isToRemove(!isAnExtrapolatedHit && (((thisL < rL) && isEndUpstream) || ((thisL > rL) && !isEndUpstream)));
 
  540             const Cluster *&pClusterToModify(isToRemove ? (isAbove ? pAboveCluster : pBelowCluster) : pMainTrackCluster);
 
  542             if (pClusterToModify)
 
  544                 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*
this, pClusterToModify, pCaloHit));
 
  549                 parameters.m_caloHitList.push_back(pCaloHit);
 
  550                 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, parameters, pClusterToModify));
 
  552                 if (pClusterToModify != pMainTrackCluster)
 
  553                     remnantClusterList.push_back(pClusterToModify);
 
  559     if (pAboveCluster || pBelowCluster)
 
  561         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, fragmentListName, originalListName));
 
  562         return pMainTrackCluster;
 
  566         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, originalListName, fragmentListName));
 
  574     const CaloHitList &caloHitsToMerge, 
const ClusterAssociation &clusterAssociation, ClusterList &remnantClusterList)
 const 
  581     if (pShowerCluster->GetNCaloHits() == caloHitsToMerge.size())
 
  583         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*
this, pMainTrackCluster, pShowerCluster));
 
  588     std::string originalListName, fragmentListName;
 
  589     const ClusterList originalClusterList(1, pShowerCluster);
 
  590     PANDORA_THROW_RESULT_IF(
 
  591         STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*
this, originalClusterList, originalListName, fragmentListName));
 
  593     const Cluster *pAboveCluster(
nullptr), *pBelowCluster(
nullptr);
 
  595     const bool isVertical(std::fabs(clusterAssociation.
GetConnectingLineDirection().GetX()) < std::numeric_limits<float>::epsilon());
 
  596     const float connectingLineGradient(
 
  602     const OrderedCaloHitList orderedCaloHitList(pShowerCluster->GetOrderedCaloHitList());
 
  603     for (
const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
 
  605         for (
const CaloHit *
const pCaloHit : *mapEntry.second)
 
  607             const bool isAnExtrapolatedHit(std::find(caloHitsToMerge.begin(), caloHitsToMerge.end(), pCaloHit) != caloHitsToMerge.end());
 
  608             if (isAnExtrapolatedHit)
 
  610                 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::RemoveFromCluster(*
this, pShowerCluster, pCaloHit));
 
  611                 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*
this, pMainTrackCluster, pCaloHit));
 
  615                 const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
 
  616                 const bool isAbove(((connectingLineGradient * hitPosition.GetX()) + connectingLineIntercept) <
 
  617                                    (isVertical ? hitPosition.GetX() : hitPosition.GetZ()));
 
  618                 const Cluster *&pClusterToModify(isAbove ? pAboveCluster : pBelowCluster);
 
  620                 if (pClusterToModify)
 
  622                     PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*
this, pClusterToModify, pCaloHit));
 
  627                     parameters.m_caloHitList.push_back(pCaloHit);
 
  628                     PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, parameters, pClusterToModify));
 
  630                     remnantClusterList.push_back(pClusterToModify);
 
  636     PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, fragmentListName, originalListName));
 
  642     const ClusterList *
const pClusterList, ClusterList &createdClusters)
 const 
  644     ClusterList fragmentedClusters;
 
  645     for (
const Cluster *
const pRemnantCluster : remnantClusterList)
 
  653             fragmentedClusters.push_back(pRemnantCluster);
 
  657     for (
const Cluster *
const pFragmentedCluster : fragmentedClusters)
 
  659         if ((pFragmentedCluster->GetNCaloHits() == 1) && (this->
AddToNearestCluster(pFragmentedCluster, pMainTrackCluster, pClusterList)))
 
  662         createdClusters.push_back(pFragmentedCluster);
 
  669     const Cluster *
const pClusterToMerge, 
const Cluster *
const pMainTrackCluster, 
const ClusterList *
const pClusterList)
 const 
  671     const Cluster *pClosestCluster(
nullptr);
 
  674     for (
const Cluster *
const pCluster : *pClusterList)
 
  676         if (pCluster == pClusterToMerge)
 
  681         if (separationDistance < closestDistance)
 
  686             pClosestCluster = pCluster;
 
  687             closestDistance = separationDistance;
 
  693         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::MergeAndDeleteClusters(*
this, pClosestCluster, pClusterToMerge));
 
  704     if (pRemnantCluster->GetNCaloHits() == 1)
 
  707     const OrderedCaloHitList &orderedCaloHitList(pRemnantCluster->GetOrderedCaloHitList());
 
  708     const CaloHit *pPreviousCaloHit(orderedCaloHitList.begin()->second->front());
 
  710     for (
const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
 
  712         for (
const CaloHit *
const pCaloHit : *mapEntry.second)
 
  714             if (pCaloHit == pPreviousCaloHit)
 
  717             const float separationDistanceSquared(pCaloHit->GetPositionVector().GetDistanceSquared(pPreviousCaloHit->GetPositionVector()));
 
  722             pPreviousCaloHit = pCaloHit;
 
  734     std::string originalListName, fragmentListName;
 
  735     const ClusterList originalClusterList(1, pRemnantCluster);
 
  736     PANDORA_THROW_RESULT_IF(
 
  737         STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*
this, originalClusterList, originalListName, fragmentListName));
 
  739     ClusterList createdClusters;
 
  741     const OrderedCaloHitList &orderedCaloHitList(pRemnantCluster->GetOrderedCaloHitList());
 
  742     for (
const OrderedCaloHitList::value_type &mapEntry : orderedCaloHitList)
 
  744         for (
const CaloHit *
const pCaloHit : *mapEntry.second)
 
  746             const Cluster *pClosestCluster(
nullptr);
 
  748             if (!createdClusters.empty())
 
  752                 for (
const Cluster *
const pCreatedCluster : createdClusters)
 
  757                         closestDistance = separationDistance;
 
  758                         pClosestCluster = pCreatedCluster;
 
  765                 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToCluster(*
this, pClosestCluster, pCaloHit));
 
  770                 parameters.m_caloHitList.push_back(pCaloHit);
 
  771                 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, parameters, pClosestCluster));
 
  772                 createdClusters.push_back(pClosestCluster);
 
  778     if (createdClusters.empty())
 
  780         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, originalListName, fragmentListName));
 
  781         fragmentedClusterList.push_back(pRemnantCluster);
 
  785         PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, fragmentListName, originalListName));
 
  786         fragmentedClusterList.insert(fragmentedClusterList.begin(), createdClusters.begin(), createdClusters.end());
 
  792 template <
typename T>
 
  797     for (
const Cluster *
const pClusterToDelete : clustersToDelete)
 
  800     this->
InitialiseContainers(&clustersToAdd, sortFunction, clusterVector, slidingFitResultMapPair);
 
  808     const TwoDSlidingFitResultMap::const_iterator microFitToDelete(slidingFitResultMapPair.first->find(pClusterToRemove));
 
  809     if (microFitToDelete != slidingFitResultMapPair.first->end())
 
  810         slidingFitResultMapPair.first->erase(microFitToDelete);
 
  812     const TwoDSlidingFitResultMap::const_iterator macroFitToDelete(slidingFitResultMapPair.second->find(pClusterToRemove));
 
  813     if (macroFitToDelete != slidingFitResultMapPair.second->end())
 
  814         slidingFitResultMapPair.second->erase(macroFitToDelete);
 
  816     const ClusterVector::const_iterator clusterToDelete(std::find(clusterVector.begin(), clusterVector.end(), pClusterToRemove));
 
  817     if (clusterToDelete != clusterVector.end())
 
  818         clusterVector.erase(clusterToDelete);
 
  825     PANDORA_RETURN_RESULT_IF_AND_IF(
 
  826         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MinClusterLength", 
m_minClusterLength));
 
  828     PANDORA_RETURN_RESULT_IF_AND_IF(
 
  829         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MicroSlidingFitWindow", 
m_microSlidingFitWindow));
 
  831     PANDORA_RETURN_RESULT_IF_AND_IF(
 
  832         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MacroSlidingFitWindow", 
m_macroSlidingFitWindow));
 
  834     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
 
  837     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
 
  840     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
 
  843     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
 
  846     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
 
  849     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
 
  852     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"MaxTrackGaps", 
m_maxTrackGaps));
 
  854     PANDORA_RETURN_RESULT_IF_AND_IF(
 
  855         STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"LineSegmentLength", 
m_lineSegmentLength));
 
  859         std::cout << 
"TrackInEMShowerAlgorithm: Line segment length must be positive and nonzero" << std::endl;
 
  860         throw STATUS_CODE_INVALID_PARAMETER;
 
  863     PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, 
"HitWidthMode", 
m_hitWidthMode));
 
  865     return STATUS_CODE_SUCCESS;
 
  873     const CartesianVector lhsHitPosition(
 
  876     const CartesianVector rhsHitPosition(
 
  882     if (std::fabs(lhsLongitudinal - rhsLongitudinal) > std::numeric_limits<float>::epsilon())
 
  885         return (lhsLongitudinal < rhsLongitudinal);
 
  896 template void TrackRefinementBaseAlgorithm::UpdateContainers<SortFunction>(
 
  898 template void TrackRefinementBaseAlgorithm::InitialiseContainers<SortFunction>(
 
float DistanceInGap(const pandora::CartesianVector &upstreamPoint, const pandora::CartesianVector &downstreamPoint, const pandora::CartesianVector &connectingLine, pandora::DetectorGapList &consideredGaps) const 
Calculate the track length between two points that lies in gaps. 
unsigned int m_macroSlidingFitWindow
The sliding fit window used in the fits contained within the macroSlidingFitResultMap. 
bool m_hitWidthMode
Whether to consider the width of hits. 
SortByDistanceAlongLine class. 
ClusterAssociation class. 
static bool SortHitsByPulseHeight(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs)
Sort calo hits by their pulse height. 
Header file for the lar hit width helper class. 
bool IsCloseToLine(const pandora::CartesianVector &hitPosition, const pandora::CartesianVector &lineStart, const pandora::CartesianVector &lineDirection, const float distanceToLine) const 
Check whether a hit is close to a line. 
bool IsInLineSegment(const pandora::CartesianVector &lowerBoundary, const pandora::CartesianVector &upperBoundary, const pandora::CartesianVector &point) const 
Whether a position falls within a specified segment of the cluster connecting line. 
void AddHitsToMainTrack(const pandora::Cluster *const pMainTrackCluster, const pandora::Cluster *const pShowerTrackCluster, const pandora::CaloHitList &caloHitsToMerge, const ClusterAssociation &clusterAssociation, pandora::ClusterList &remnantClusterList) const 
Remove the hits from a shower cluster that belong to the main track and add them into the main track ...
float m_minClusterLength
The minimum length of a considered cluster. 
double closestDistance(const TVector3 &line0, const TVector3 &line1, const TVector3 &p)
std::pair< TwoDSlidingFitResultMap *, TwoDSlidingFitResultMap * > SlidingFitResultMapPair
unsigned int m_maxTrackGaps
The maximum number of graps allowed in the extrapolated hit vector. 
const pandora::CartesianVector GetUpstreamMergePoint() const 
Returns the upstream cluster merge point. 
std::unordered_map< const pandora::Cluster *, pandora::CaloHitList > ClusterToCaloHitListMap
bool m_hitWidthMode
Wether to consider hit widths or not. 
static pandora::CartesianVector GetClosestPointToLine2D(const pandora::CartesianVector &lineStart, const pandora::CartesianVector &lineDirection, const pandora::CaloHit *const pCaloHit)
Consider the hit width to find the closest position of a calo hit to a specified line. 
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)=0
float m_minHitFractionForHitRemoval
The threshold fraction of hits to be removed from the cluster for hit removal to proceed. 
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch. 
virtual bool AreExtrapolatedHitsNearBoundaries(const pandora::CaloHitVector &extrapolatedHitVector, ClusterAssociation &clusterAssociation) const =0
Check the separation of the extremal extrapolated hits with the expected endpoints or...
bool IsTrackContinuous(const ClusterAssociation &clusterAssociation, const pandora::CaloHitVector &extrapolatedCaloHitVector) const 
Check whether the extrapolatedCaloHitVector contains a continuous line of hits between the cluster me...
bool GetClusterMergingCoordinates(const TwoDSlidingFitResult &clusterMicroFitResult, const TwoDSlidingFitResult &clusterMacroFitResult, const TwoDSlidingFitResult &associatedMacroFitResult, const bool isEndUpstream, pandora::CartesianVector &clusterMergePosition, pandora::CartesianVector &clusterMergeDirection) const 
Get the merging coordinate and direction for an input cluster with respect to an associated cluster...
bool(* SortFunction)(const Cluster *, const Cluster *)
bool AddToNearestCluster(const pandora::Cluster *const pClusterToMerge, const pandora::Cluster *const pMainTrackCluster, const pandora::ClusterList *const pClusterList) const 
Add a cluster to the nearest cluster satisfying separation distance thresholds. 
Header file for the geometry helper class. 
float m_maxHitDistanceFromCluster
The threshold separation between a hit and cluster for the hit to be merged into the cluster...
bool AreExtrapolatedHitsGood(const ClusterToCaloHitListMap &clusterToCaloHitListMap, ClusterAssociation &clusterAssociation) const 
Perform topological checks on the collected hits to ensure no gaps are present. 
int GetMaxLayer() const 
Get the maximum occupied layer in the sliding fit. 
bool IsClusterRemnantDisconnected(const pandora::Cluster *const pRemnantCluster) const 
Whether a remnant cluster is considered to be disconnected and therefore should undergo further fragm...
int GetMinLayer() const 
Get the minimum occupied layer in the sliding fit. 
void UpdateContainers(const pandora::ClusterList &clustersToAdd, const pandora::ClusterList &clustersToDelete, const T sortFunction, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const 
Remove deleted clusters from the cluster vector and sliding fit maps and add in created clusters that...
pandora::CartesianVector m_lineDirection
The line end point. 
void FragmentRemnantCluster(const pandora::Cluster *const pRemnantCluster, pandora::ClusterList &fragmentedClusterList) const 
Fragment a cluster using simple hit separation logic. 
Header file for the cluster helper class. 
pandora::StatusCode GetGlobalFitPosition(const float rL, pandora::CartesianVector &position) const 
Get global fit position for a given longitudinal coordinate. 
float m_maxHitSeparationForConnectedCluster
The maximum separation between two adjacent (in z) hits in a connected cluster. 
void ProcessRemnantClusters(const pandora::ClusterList &remnantClusterList, const pandora::Cluster *const pMainTrackCluster, const pandora::ClusterList *const pClusterList, pandora::ClusterList &createdClusters) const 
Process the remnant clusters separating those that stradle the main track. 
float m_stableRegionClusterFraction
The threshold fraction of fit contributing layers which defines the stable region. 
std::map< int, LayerFitResult > LayerFitResultMap
void RepositionIfInGap(const pandora::CartesianVector &mergeDirection, pandora::CartesianVector &trackPoint) const 
Move an input position to the higher line gap edge if it lies within a gap. 
float m_lineSegmentLength
The length of a track gap. 
const pandora::CartesianVector GetDownstreamMergePoint() const 
Returns the downstream cluster merge point. 
void GetGlobalDirection(const float dTdL, pandora::CartesianVector &direction) const 
Get global direction coordinates for given sliding linear fit gradient. 
const LayerFitResultMap & GetLayerFitResultMap() const 
Get the layer fit result map. 
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
fhicl::Table< sbnd::crt::CRTDetSimParams > Parameters
static float GetClosestDistanceToPoint2D(const pandora::CaloHit *const pCaloHit, const pandora::CartesianVector &point2D)
Consider the hit width to find the smallest distance between a calo hit and a given point...
void InitialiseContainers(const pandora::ClusterList *pClusterList, const T sortFunction, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const 
Fill the cluster vector and sliding fit maps with clusters that are determined to be track-like...
void RemoveClusterFromContainers(const pandora::Cluster *const pClustertoRemove, pandora::ClusterVector &clusterVector, SlidingFitResultMapPair &slidingFitResultMapPair) const 
Remove a cluster from the cluster vector and sliding fit maps. 
Header file for the track refinement base class. 
required by fuzzyCluster table::sbnd_g4_services gaushitTruthMatch pandora
bool IsInBoundingBox(const float minX, const float maxX, const float minZ, const float maxZ, const pandora::CartesianVector &hitPosition) const 
check whether a hit is contained within a defined square region 
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster. 
float m_maxDistanceFromMainTrack
The threshold distance for a hit to be added to the main track. 
bool operator()(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs) const 
Sort hits by their projected distance along a line from a start point. 
void GetHitsInBoundingBox(const pandora::CartesianVector &firstCorner, const pandora::CartesianVector &secondCorner, const pandora::ClusterList *const pClusterList, ClusterToCaloHitListMap &clusterToCaloHitListMap, const pandora::ClusterList &unavailableProtectedClusters=pandora::ClusterList(), const float distanceToLine=-1.f) const 
Find the unprotected hits that are contained within a defined box with the option to apply a cut on t...
std::vector< art::Ptr< recob::Cluster > > ClusterVector
bool IsNearBoundary(const pandora::CaloHit *const pCaloHit, const pandora::CartesianVector &boundaryPosition2D, const float boundaryTolerance) const 
Check whether a hit is close to a boundary point. 
pandora::CartesianVector m_startPoint
The line start point. 
const pandora::Cluster * RemoveOffAxisHitsFromTrack(const pandora::Cluster *const pCluster, const pandora::CartesianVector &splitPosition, const bool isEndUpstream, const ClusterToCaloHitListMap &clusterToCaloHitListMap, pandora::ClusterList &remnantClusterList, TwoDSlidingFitResultMap µSlidingFitResultMap, TwoDSlidingFitResultMap ¯oSlidingFitResultMap) const 
Remove any hits in the upstream/downstream cluster that lie off of the main track axis (i...
void GetTrackSegmentBoundaries(const ClusterAssociation &clusterAssociation, pandora::CartesianPointVector &trackSegmentBoundaries) const 
Obtain the segment boundaries of the connecting line to test whether extrapolated hits are continuous...
const pandora::CartesianVector GetConnectingLineDirection() const 
Returns the unit vector of the line connecting the upstream and downstream merge points (upstream -> ...
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const 
Get local sliding fit coordinates for a given global position. 
unsigned int m_microSlidingFitWindow
The sliding fit window used in the fits contained within the microSlidingFitResultMap. 
TwoDSlidingFitResult class. 
BEGIN_PROLOG could also be cout
float m_mergePointMinCosAngleDeviation
The threshold cos opening angle between the cluster local gradient and the associated cluster global ...
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.