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, std::make_pair(
175 for (
const ParticleFlowObject *
const pPfo1 : parentCosmicRayPfos)
178 if (pfoToSlidingFitsMap.end() == iter1)
183 for (
const ParticleFlowObject *
const pPfo2 : parentCosmicRayPfos)
189 if (pfoToSlidingFitsMap.end() == iter2)
203 PfoList &pfoList1(pfoAssociationMap[pPfo1]), &pfoList2(pfoAssociationMap[pPfo2]);
205 if (pfoList1.end() == std::find(pfoList1.begin(), pfoList1.end(), pPfo2))
206 pfoList1.push_back(pPfo2);
208 if (pfoList2.end() == std::find(pfoList2.begin(), pfoList2.end(), pPfo1))
209 pfoList2.push_back(pPfo1);
217 const CartesianVector &endDir2)
const 220 const CartesianVector
n(endDir1.GetUnitVector());
221 const CartesianVector m(endDir2.GetUnitVector());
222 const CartesianVector a(endPoint2 - endPoint1);
223 const float b(
n.GetDotProduct(m));
226 if (std::fabs(b - 1.
f) < std::numeric_limits<float>::epsilon())
230 const float lambda((
n - m * b).GetDotProduct(a) / (1.
f - b * b));
233 const float mu((
n * b - m).GetDotProduct(a) / (1.
f - b * b));
240 if ((lambda < -maxVertexUncertainty) || (mu < -maxVertexUncertainty) ||
247 const CartesianVector impactPosition((endPoint1 +
n * lambda + endPoint2 + m * mu) * 0.5
f);
249 if ((impactPosition.GetX() <
m_face_Xa - maxVertexUncertainty) || (impactPosition.GetX() >
m_face_Xc + maxVertexUncertainty) ||
250 (impactPosition.GetY() <
m_face_Yb - maxVertexUncertainty) || (impactPosition.GetY() >
m_face_Yt + maxVertexUncertainty) ||
251 (impactPosition.GetZ() <
m_face_Zu - maxVertexUncertainty) || (impactPosition.GetZ() >
m_face_Zd + maxVertexUncertainty))
257 const float maxImpactDist(std::sin(deltaTheta) * (std::fabs(mu) + std::fabs(lambda)) +
m_positionalUncertainty);
258 const CartesianVector
d(a -
n * lambda + m * mu);
260 return (d.GetMagnitude() < maxImpactDist);
269 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
271 bool isAlreadyInSlice(
false);
273 for (
const PfoList &slice : sliceList)
275 if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
277 isAlreadyInSlice =
true;
282 if (!isAlreadyInSlice)
284 sliceList.push_back(PfoList());
285 this->
FillSlice(pPfo, pfoAssociationMap, sliceList.back());
289 unsigned int sliceId(0);
290 for (
const PfoList &slice : sliceList)
292 for (
const ParticleFlowObject *
const pPfo : slice)
294 if (!pfoToSliceIdMap.insert(PfoToSliceIdMap::value_type(pPfo, sliceId)).second)
295 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
306 if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
309 slice.push_back(pPfo);
313 if (pfoAssociationMap.end() != iter)
315 for (
const ParticleFlowObject *
const pAssociatedPfo : iter->second)
316 this->
FillSlice(pAssociatedPfo, pfoAssociationMap, slice);
324 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
327 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
329 candidates.push_back(
CRCandidate(this->GetPandora(), pPfo, pfoToSliceIdMap.at(pPfo)));
337 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
344 if (candidate.m_canFit)
346 minX = ((candidate.m_endPoint1.GetX() < candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
347 maxX = ((candidate.m_endPoint1.GetX() > candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
352 for (
const Cluster *
const pCluster : candidate.m_pPfo->GetClusterList())
371 catch (
const StatusCodeException &) {}
377 CaloHitList caloHitList;
382 bool isFirstHit(
true);
383 bool isInSingleVolume(
true);
386 for (
const CaloHit *
const pCaloHit : caloHitList)
388 const LArCaloHit *
const pLArCaloHit(dynamic_cast<const LArCaloHit*>(pCaloHit));
400 isInSingleVolume =
false;
407 if (isInSingleVolume && (larTPCMap.end() != tpcIter))
409 const float thisFaceXLow(tpcIter->second->GetCenterX() - 0.5f * tpcIter->second->GetWidthX());
410 const float thisFaceXHigh(tpcIter->second->GetCenterX() + 0.5f * tpcIter->second->GetWidthX());
417 if (!pfoToInTimeMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, isInTime)).second)
418 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
428 const float upperY((candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
429 const float lowerY((candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
431 const float zAtUpperY((candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetZ() : candidate.m_endPoint2.GetZ());
432 const float zAtLowerY((candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetZ() : candidate.m_endPoint2.GetZ());
439 if (!pfoToIsContainedMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, isContained)).second)
440 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
450 const float upperY((candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
451 const float lowerY((candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
455 if (!pfoToIsTopToBottomMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, isTopToBottom)).second)
456 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
463 UIntSet &neutrinoSliceSet)
const 467 if (neutrinoSliceSet.count(candidate.m_sliceId))
470 const bool likelyNeutrino(candidate.m_canFit && pfoToInTimeMap.at(candidate.m_pPfo) &&
474 (void) neutrinoSliceSet.insert(candidate.m_sliceId);
485 const bool likelyCRMuon(!neutrinoSliceSet.count(candidate.m_sliceId) && (!pfoToInTimeMap.at(candidate.m_pPfo) || (candidate.m_canFit &&
488 if (!pfoToIsLikelyCRMuonMap.insert(PfoToBoolMap::value_type(candidate.m_pPfo, likelyCRMuon)).second)
489 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
500 m_endPoint1(
std::numeric_limits<float>::
max(),
std::numeric_limits<float>::
max(),
std::numeric_limits<float>::
max()),
501 m_endPoint2(
std::numeric_limits<float>::
max(),
std::numeric_limits<float>::
max(),
std::numeric_limits<float>::
max()),
502 m_length(
std::numeric_limits<float>::
max()),
503 m_curvature(
std::numeric_limits<float>::
max()),
504 m_theta(
std::numeric_limits<float>::
max())
506 ClusterList clusters3D;
509 if (!clusters3D.empty() && (clusters3D.front()->GetNCaloHits() > 15))
512 const LArTPC *
const pFirstLArTPC(pandora.GetGeometry()->GetLArTPCMap().begin()->second);
526 if (std::fabs(
m_length) > std::numeric_limits<float>::epsilon())
531 CartesianPointVector directionList;
534 CartesianVector direction(0.
f, 0.
f, 0.
f);
535 if (STATUS_CODE_SUCCESS == slidingFitResult.
GetGlobalFitDirection(static_cast<float>(i) * layerPitch, direction))
536 directionList.push_back(direction);
539 CartesianVector meanDirection(0.
f, 0.
f, 0.
f);
540 for (
const CartesianVector &direction : directionList)
541 meanDirection += direction;
543 if (!directionList.empty() > 0)
544 meanDirection *= 1.
f / static_cast<float>(directionList.size());
547 for (
const CartesianVector &direction : directionList)
548 m_curvature += (direction - meanDirection).GetMagnitude();
550 if (!directionList.empty() > 0)
551 m_curvature *= 1.
f / static_cast<float>(directionList.size());
558 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
562 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
565 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
568 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
571 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
574 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
577 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
580 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
583 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
586 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
589 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
592 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
595 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.
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
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
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.
static void GetClusterSpanX(const pandora::Cluster *const pCluster, float &xmin, float &xmax)
Get minimum and maximum X positions of the calo hits in a 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...
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
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.