9 #include "Pandora/AlgorithmHeaders.h" 23 CosmicRayTaggingTool::CosmicRayTaggingTool() :
25 m_angularUncertainty(5.
f),
26 m_positionalUncertainty(3.
f),
27 m_maxAssociationDist(3.
f * 18.
f),
33 m_maxNeutrinoCosTheta(0.2
f),
34 m_minCosmicCosTheta(0.6
f),
35 m_maxCosmicCurvature(0.04
f),
65 std::cout <<
"CosmicRayTaggingTool - invalid cut mode " <<
m_cutMode << std::endl;
66 return STATUS_CODE_INVALID_PARAMETER;
69 return STATUS_CODE_SUCCESS;
76 if (this->GetPandora().GetSettings()->ShouldDisplayAlgorithmInfo())
77 std::cout <<
"----> Running Algorithm Tool: " << this->GetInstanceName() <<
", " << this->GetType() << std::endl;
80 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
81 const LArTPC *
const pFirstLArTPC(larTPCMap.begin()->second);
83 float parentMinX(pFirstLArTPC->GetCenterX() - 0.5f * pFirstLArTPC->GetWidthX());
84 float parentMaxX(pFirstLArTPC->GetCenterX() + 0.5f * pFirstLArTPC->GetWidthX());
85 float parentMinY(pFirstLArTPC->GetCenterY() - 0.5f * pFirstLArTPC->GetWidthY());
86 float parentMaxY(pFirstLArTPC->GetCenterY() + 0.5f * pFirstLArTPC->GetWidthY());
87 float parentMinZ(pFirstLArTPC->GetCenterZ() - 0.5f * pFirstLArTPC->GetWidthZ());
88 float parentMaxZ(pFirstLArTPC->GetCenterZ() + 0.5f * pFirstLArTPC->GetWidthZ());
90 for (
const LArTPCMap::value_type &mapEntry : larTPCMap)
92 const LArTPC *
const pLArTPC(mapEntry.second);
93 parentMinX = std::min(parentMinX, pLArTPC->GetCenterX() - 0.5f * pLArTPC->GetWidthX());
94 parentMaxX = std::max(parentMaxX, pLArTPC->GetCenterX() + 0.5f * pLArTPC->GetWidthX());
95 parentMinY = std::min(parentMinY, pLArTPC->GetCenterY() - 0.5f * pLArTPC->GetWidthY());
96 parentMaxY = std::max(parentMaxY, pLArTPC->GetCenterY() + 0.5f * pLArTPC->GetWidthY());
97 parentMinZ = std::min(parentMinZ, pLArTPC->GetCenterZ() - 0.5f * pLArTPC->GetWidthZ());
98 parentMaxZ = std::max(parentMaxZ, pLArTPC->GetCenterZ() + 0.5f * pLArTPC->GetWidthZ());
112 this->
SliceEvent(parentCosmicRayPfos, pfoAssociationMap, pfoToSliceIdMap);
115 this->
GetCRCandidates(parentCosmicRayPfos, pfoToSliceIdMap, candidates);
127 this->
GetNeutrinoSlices(candidates, pfoToInTimeMap, pfoToIsContainedMap, neutrinoSliceSet);
130 this->
TagCRMuons(candidates, pfoToInTimeMap, pfoToIsTopToBottomMap, neutrinoSliceSet, pfoToIsLikelyCRMuonMap);
132 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
134 if (!pfoToIsLikelyCRMuonMap.at(pPfo))
135 ambiguousPfos.push_back(pPfo);
143 pCluster3D =
nullptr;
144 ClusterList clusters3D;
148 if (clusters3D.empty() || (clusters3D.front()->GetNCaloHits() <
m_minimumHits))
151 pCluster3D = clusters3D.front();
160 const LArTPC *
const pFirstLArTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().
begin()->
second);
161 const float layerPitch(pFirstLArTPC->GetWirePitchW());
165 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
167 const pandora::Cluster *pCluster(
nullptr);
171 (void)pfoToSlidingFitsMap.insert(PfoToSlidingFitsMap::value_type(pPfo,
175 for (
const ParticleFlowObject *
const pPfo1 : parentCosmicRayPfos)
178 if (pfoToSlidingFitsMap.end() == iter1)
183 for (
const ParticleFlowObject *
const pPfo2 : parentCosmicRayPfos)
189 if (pfoToSlidingFitsMap.end() == iter2)
207 PfoList &pfoList1(pfoAssociationMap[pPfo1]), &pfoList2(pfoAssociationMap[pPfo2]);
209 if (pfoList1.end() == std::find(pfoList1.begin(), pfoList1.end(), pPfo2))
210 pfoList1.push_back(pPfo2);
212 if (pfoList2.end() == std::find(pfoList2.begin(), pfoList2.end(), pPfo1))
213 pfoList2.push_back(pPfo1);
221 const CartesianVector &endPoint1,
const CartesianVector &endDir1,
const CartesianVector &endPoint2,
const CartesianVector &endDir2)
const 224 const CartesianVector
n(endDir1.GetUnitVector());
225 const CartesianVector m(endDir2.GetUnitVector());
226 const CartesianVector a(endPoint2 - endPoint1);
227 const float b(
n.GetDotProduct(m));
230 if (std::fabs(b - 1.
f) < std::numeric_limits<float>::epsilon())
234 const float lambda((
n - m * b).GetDotProduct(a) / (1.
f - b * b));
237 const float mu((
n * b - m).GetDotProduct(a) / (1.
f - b * b));
244 if ((lambda < -maxVertexUncertainty) || (mu < -maxVertexUncertainty) || (lambda >
m_maxAssociationDist + maxVertexUncertainty) ||
251 const CartesianVector impactPosition((endPoint1 +
n * lambda + endPoint2 + m * mu) * 0.5
f);
253 if ((impactPosition.GetX() <
m_face_Xa - maxVertexUncertainty) || (impactPosition.GetX() >
m_face_Xc + maxVertexUncertainty) ||
254 (impactPosition.GetY() <
m_face_Yb - maxVertexUncertainty) || (impactPosition.GetY() >
m_face_Yt + maxVertexUncertainty) ||
255 (impactPosition.GetZ() <
m_face_Zu - maxVertexUncertainty) || (impactPosition.GetZ() >
m_face_Zd + maxVertexUncertainty))
261 const float maxImpactDist(std::sin(deltaTheta) * (std::fabs(mu) + std::fabs(lambda)) +
m_positionalUncertainty);
262 const CartesianVector
d(a -
n * lambda + m * mu);
264 return (d.GetMagnitude() < maxImpactDist);
273 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
275 bool isAlreadyInSlice(
false);
277 for (
const PfoList &slice : sliceList)
279 if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
281 isAlreadyInSlice =
true;
286 if (!isAlreadyInSlice)
288 sliceList.push_back(PfoList());
289 this->
FillSlice(pPfo, pfoAssociationMap, sliceList.back());
293 unsigned int sliceId(0);
294 for (
const PfoList &slice : sliceList)
296 for (
const ParticleFlowObject *
const pPfo : slice)
298 if (!pfoToSliceIdMap.insert(PfoToSliceIdMap::value_type(pPfo, sliceId)).second)
299 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
310 if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
313 slice.push_back(pPfo);
317 if (pfoAssociationMap.end() != iter)
319 for (
const ParticleFlowObject *
const pAssociatedPfo : iter->second)
320 this->
FillSlice(pAssociatedPfo, pfoAssociationMap, slice);
328 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
331 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
333 candidates.push_back(
CRCandidate(this->GetPandora(), pPfo, pfoToSliceIdMap.at(pPfo)));
341 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
346 float minX(std::numeric_limits<float>::max()), maxX(-std::numeric_limits<float>::max());
348 if (candidate.m_canFit)
350 minX = ((candidate.m_endPoint1.GetX() < candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
351 maxX = ((candidate.m_endPoint1.GetX() > candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
356 for (
const Cluster *
const pCluster : candidate.m_pPfo->GetClusterList())
358 float clusterMinX(std::numeric_limits<float>::max()), clusterMaxX(-std::numeric_limits<float>::max());
359 pCluster->GetClusterSpanX(clusterMinX, clusterMaxX);
360 minX = std::min(clusterMinX, minX);
361 maxX = std::max(clusterMaxX, maxX);
375 catch (
const StatusCodeException &)
383 CaloHitList caloHitList;
388 bool isFirstHit(
true);
389 bool isInSingleVolume(
true);
390 unsigned int volumeId(std::numeric_limits<unsigned int>::max());
392 for (
const CaloHit *
const pCaloHit : caloHitList)
394 const LArCaloHit *
const pLArCaloHit(dynamic_cast<const LArCaloHit *>(pCaloHit));
406 isInSingleVolume =
false;
413 if (isInSingleVolume && (larTPCMap.end() != tpcIter))
415 const float thisFaceXLow(tpcIter->second->GetCenterX() - 0.5f * tpcIter->second->GetWidthX());
416 const float thisFaceXHigh(tpcIter->second->GetCenterX() + 0.5f * tpcIter->second->GetWidthX());
423 if (!pfoToInTimeMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, isInTime)).second)
424 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
435 (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
437 (candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
439 const float zAtUpperY(
440 (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetZ() : candidate.m_endPoint2.GetZ());
441 const float zAtLowerY(
442 (candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetZ() : candidate.m_endPoint2.GetZ());
448 if (!pfoToIsContainedMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, isContained)).second)
449 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
460 (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
462 (candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
466 if (!pfoToIsTopToBottomMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, isTopToBottom)).second)
467 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
480 if (sliceIdToIsInTimeMap.find(candidate.m_sliceId) == sliceIdToIsInTimeMap.end())
481 sliceIdToIsInTimeMap.insert(std::make_pair(candidate.m_sliceId,
true));
483 if (!pfoToInTimeMap.at(candidate.m_pPfo))
484 sliceIdToIsInTimeMap.at(candidate.m_sliceId) =
false;
489 if (neutrinoSliceSet.count(candidate.m_sliceId))
492 const bool likelyNeutrino(candidate.m_canFit && sliceIdToIsInTimeMap.at(candidate.m_sliceId) &&
496 (void)neutrinoSliceSet.insert(candidate.m_sliceId);
507 const bool likelyCRMuon(!neutrinoSliceSet.count(candidate.m_sliceId) &&
508 (!pfoToInTimeMap.at(candidate.m_pPfo) ||
509 (candidate.m_canFit &&
510 (pfoToIsTopToBottomMap.at(candidate.m_pPfo) ||
513 if (!pfoToIsLikelyCRMuonMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, likelyCRMuon)).second)
514 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
525 m_endPoint1(
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max()),
526 m_endPoint2(
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max()),
527 m_length(
std::numeric_limits<float>::max()),
528 m_curvature(
std::numeric_limits<float>::max()),
529 m_theta(
std::numeric_limits<float>::max())
531 ClusterList clusters3D;
534 if (!clusters3D.empty() && (clusters3D.front()->GetNCaloHits() > 15))
537 const LArTPC *
const pFirstLArTPC(pandora.GetGeometry()->GetLArTPCMap().begin()->second);
551 if (std::fabs(
m_length) > std::numeric_limits<float>::epsilon())
556 CartesianPointVector directionList;
559 CartesianVector direction(0.
f, 0.
f, 0.
f);
560 if (STATUS_CODE_SUCCESS == slidingFitResult.
GetGlobalFitDirection(static_cast<float>(i) * layerPitch, direction))
561 directionList.push_back(direction);
564 CartesianVector meanDirection(0.
f, 0.
f, 0.
f);
565 for (
const CartesianVector &direction : directionList)
566 meanDirection += direction;
568 if (!directionList.empty() > 0)
569 meanDirection *= 1.
f / static_cast<float>(directionList.size());
572 for (
const CartesianVector &direction : directionList)
573 m_curvature += (direction - meanDirection).GetMagnitude();
575 if (!directionList.empty() > 0)
576 m_curvature *= 1.
f / static_cast<float>(directionList.size());
583 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"CutMode",
m_cutMode));
586 PANDORA_RETURN_RESULT_IF_AND_IF(
587 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"AngularUncertainty",
m_angularUncertainty));
589 PANDORA_RETURN_RESULT_IF_AND_IF(
590 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"PositionalUncertainty",
m_positionalUncertainty));
592 PANDORA_RETURN_RESULT_IF_AND_IF(
593 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxAssociationDist",
m_maxAssociationDist));
595 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"HitThreshold",
m_minimumHits));
597 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InTimeMargin",
m_inTimeMargin));
599 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InTimeMaxX0",
m_inTimeMaxX0));
601 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MarginY",
m_marginY));
603 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MarginZ",
m_marginZ));
605 PANDORA_RETURN_RESULT_IF_AND_IF(
606 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxNeutrinoCosTheta",
m_maxNeutrinoCosTheta));
608 PANDORA_RETURN_RESULT_IF_AND_IF(
609 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinCosmicCosTheta",
m_minCosmicCosTheta));
611 PANDORA_RETURN_RESULT_IF_AND_IF(
612 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxCosmicCurvature",
m_maxCosmicCurvature));
614 return STATUS_CODE_SUCCESS;
std::unordered_map< const pandora::ParticleFlowObject *, pandora::PfoList > PfoToPfoListMap
std::unordered_map< const pandora::ParticleFlowObject *, bool > PfoToBoolMap
void FindAmbiguousPfos(const pandora::PfoList &parentCosmicRayPfos, pandora::PfoList &ambiguousPfos, const MasterAlgorithm *const pAlgorithm)
Find the list of ambiguous pfos (could represent cosmic-ray muons or neutrinos)
float m_face_Yb
Bottom Y face.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void TagCRMuons(const CRCandidateList &candidates, const PfoToBoolMap &pfoToInTimeMap, const PfoToBoolMap &pfoToIsTopToBottomMap, const UIntSet &neutrinoSliceSet, PfoToBoolMap &pfoToIsLikelyCRMuonMap) const
Tag Pfos which are likely to be a CR muon.
Header file for the pfo helper class.
std::unordered_map< const pandora::ParticleFlowObject *, unsigned int > PfoToSliceIdMap
float m_maxNeutrinoCosTheta
The maximum cos(theta) that a Pfo can have to be classified as a likely neutrino. ...
float m_face_Zu
Upstream Z face.
const pandora::CartesianVector & GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
Header file for the lar calo hit class.
void SliceEvent(const pandora::PfoList &parentCosmicRayPfos, const PfoToPfoListMap &pfoAssociationMap, PfoToSliceIdMap &pfoToSliceIdMap) const
Break the event up into slices of associated Pfos.
bool CheckAssociation(const pandora::CartesianVector &endPoint1, const pandora::CartesianVector &endDir1, const pandora::CartesianVector &endPoint2, const pandora::CartesianVector &endDir2) const
Check whethe two Pfo endpoints are associated by distance of closest approach.
float m_positionalUncertainty
The uncertainty in cm for the position of Pfo endpoint in 3D.
void CheckIfTopToBottom(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsTopToBottomMap) const
Check if each candidate is "top to bottom".
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
double m_theta
Direction made with vertical.
bool m_canFit
If there are a sufficient number of 3D hits to perform a fitting.
Class to encapsulate the logic required determine if a Pfo should or shouldn't be tagged as a cosmic ...
void CheckIfContained(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsContainedMap) const
Check if each candidate is "contained" (contained = no associations to Y or Z detector faces...
unsigned int GetLArTPCVolumeId() const
Get the lar tpc volume id.
float m_angularUncertainty
The uncertainty in degrees for the angle of a Pfo.
CRCandidate(const pandora::Pandora &pandora, const pandora::ParticleFlowObject *const pPfo, const unsigned int sliceId)
Constructor.
void FillSlice(const pandora::ParticleFlowObject *const pPfo, const PfoToPfoListMap &pfoAssociationMap, pandora::PfoList &slice) const
Fill a slice iteratively using Pfo associations.
std::string m_cutMode
Choose a set of cuts using a keyword - "cautious" = remove as few neutrinos as possible "nominal" = o...
std::list< CRCandidate > CRCandidateList
double m_length
Straight line length of the linear fit.
float m_inTimeMaxX0
The maximum pfo x0 (determined from shifted vertex) to allow pfo to still be considered in time...
float m_face_Yt
Top Y face.
Header file for the cluster helper class.
void CheckIfInTime(const CRCandidateList &candidates, PfoToBoolMap &pfoToInTimeMap) const
Check if each candidate is "in time".
pandora::CartesianVector m_endPoint2
Second fitted end point in 3D.
const pandora::CartesianVector & GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
float m_inTimeMargin
The maximum distance outside of the physical detector volume that a Pfo may be to still be considered...
float m_face_Xa
Anode X face.
double m_curvature
Measure of the curvature of the track.
pandora::StatusCode GetGlobalFitDirection(const float rL, pandora::CartesianVector &direction) const
Get global fit direction for a given longitudinal coordinate.
std::set< unsigned int > UIntSet
void CalculateFitVariables(const ThreeDSlidingFitResult &slidingFitResult)
Calculate all variables which require a fit.
float GetLayerPitch() const
Get the layer pitch, units cm.
void GetPfoAssociations(const pandora::PfoList &parentCosmicRayPfos, PfoToPfoListMap &pfoAssociationMap) const
Get mapping between Pfos that are associated with it other by pointing.
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
pandora::StatusCode Initialize()
const pandora::CartesianVector & GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
float m_minCosmicCosTheta
The minimum cos(theta) that a Pfo can have to be classified as a likely CR muon.
bool GetValid3DCluster(const pandora::ParticleFlowObject *const pPfo, const pandora::Cluster *&pCluster3D) const
Get the 3D calo hit cluster associated with a given Pfo, and check if it has sufficient hits...
std::vector< pandora::PfoList > SliceList
std::unordered_map< int, bool > IntBoolMap
float m_marginZ
The minimum distance from a detector Z-face for a Pfo to be associated.
float m_marginY
The minimum distance from a detector Y-face for a Pfo to be associated.
float m_maxCosmicCurvature
The maximum curvature that a Pfo can have to be classified as a likely CR muon.
static bool IsFinalState(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a primary parent particle.
ThreeDSlidingFitResult class.
const TwoDSlidingFitResult & GetFirstFitResult() const
Get the first sliding fit result for this cluster.
float m_face_Xc
Cathode X face.
float m_maxAssociationDist
The maximum distance from endpoint to point of closest approach, typically a multiple of LAr radiatio...
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
unsigned int m_minimumHits
The minimum number of hits for a Pfo to be considered.
float m_face_Zd
Downstream Z face.
std::unordered_map< const pandora::ParticleFlowObject *, SlidingFitPair > PfoToSlidingFitsMap
second_as<> second
Type of time stored in seconds, in double precision.
void GetCRCandidates(const pandora::PfoList &parentCosmicRayPfos, const PfoToSliceIdMap &pfoToSliceIdMap, CRCandidateList &candidates) const
Make a list of CRCandidates.
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
void GetNeutrinoSlices(const CRCandidateList &candidates, const PfoToBoolMap &pfoToInTimeMap, const PfoToBoolMap &pfoToIsContainedMap, UIntSet &neutrinoSliceSet) const
Get the slice indices which contain a likely neutrino Pfo.
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
pandora::CartesianVector m_endPoint1
First fitted end point in 3D.