9 #include "Pandora/AlgorithmHeaders.h" 23 TestBeamCosmicRayTaggingTool::TestBeamCosmicRayTaggingTool() :
24 m_angularUncertainty(5.
f),
25 m_positionalUncertainty(3.
f),
26 m_maxAssociationDist(3.
f * 18.
f),
31 m_tagTopEntering(true),
32 m_tagTopToBottom(true),
34 m_tagInVetoedTPCs(false),
48 return STATUS_CODE_SUCCESS;
55 if (this->GetPandora().GetSettings()->ShouldDisplayAlgorithmInfo())
56 std::cout <<
"----> Running Algorithm Tool: " << this->GetInstanceName() <<
", " << this->GetType() << std::endl;
59 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
60 const LArTPC *
const pFirstLArTPC(larTPCMap.begin()->second);
62 float parentMinX(pFirstLArTPC->GetCenterX() - 0.5f * pFirstLArTPC->GetWidthX());
63 float parentMaxX(pFirstLArTPC->GetCenterX() + 0.5f * pFirstLArTPC->GetWidthX());
64 float parentMinY(pFirstLArTPC->GetCenterY() - 0.5f * pFirstLArTPC->GetWidthY());
65 float parentMaxY(pFirstLArTPC->GetCenterY() + 0.5f * pFirstLArTPC->GetWidthY());
66 float parentMinZ(pFirstLArTPC->GetCenterZ() - 0.5f * pFirstLArTPC->GetWidthZ());
67 float parentMaxZ(pFirstLArTPC->GetCenterZ() + 0.5f * pFirstLArTPC->GetWidthZ());
69 for (
const LArTPCMap::value_type &mapEntry : larTPCMap)
71 const LArTPC *
const pLArTPC(mapEntry.second);
72 parentMinX = std::min(parentMinX, pLArTPC->GetCenterX() - 0.5f * pLArTPC->GetWidthX());
73 parentMaxX = std::max(parentMaxX, pLArTPC->GetCenterX() + 0.5f * pLArTPC->GetWidthX());
74 parentMinY = std::min(parentMinY, pLArTPC->GetCenterY() - 0.5f * pLArTPC->GetWidthY());
75 parentMaxY = std::max(parentMaxY, pLArTPC->GetCenterY() + 0.5f * pLArTPC->GetWidthY());
76 parentMinZ = std::min(parentMinZ, pLArTPC->GetCenterZ() - 0.5f * pLArTPC->GetWidthZ());
77 parentMaxZ = std::max(parentMaxZ, pLArTPC->GetCenterZ() + 0.5f * pLArTPC->GetWidthZ());
91 this->
SliceEvent(parentCosmicRayPfos, pfoAssociationMap, pfoToSliceIdMap);
94 this->
GetCRCandidates(parentCosmicRayPfos, pfoToSliceIdMap, candidates);
100 pfoToIsCosmicRayMap[candidate.m_pPfo] =
false;
119 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
121 if (!pfoToIsCosmicRayMap.at(pPfo))
122 ambiguousPfos.push_back(pPfo);
130 pCluster3D =
nullptr;
131 ClusterList clusters3D;
135 if (clusters3D.empty() || (clusters3D.front()->GetNCaloHits() <
m_minimumHits))
138 pCluster3D = clusters3D.front();
147 const LArTPC *
const pFirstLArTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().
begin()->
second);
148 const float layerPitch(pFirstLArTPC->GetWirePitchW());
152 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
154 const pandora::Cluster *pCluster(
nullptr);
158 pfoToSlidingFitsMap.insert(PfoToSlidingFitsMap::value_type(pPfo,
162 for (
const ParticleFlowObject *
const pPfo1 : parentCosmicRayPfos)
165 if (pfoToSlidingFitsMap.end() == iter1)
170 for (
const ParticleFlowObject *
const pPfo2 : parentCosmicRayPfos)
176 if (pfoToSlidingFitsMap.end() == iter2)
194 PfoList &pfoList1(pfoAssociationMap[pPfo1]), &pfoList2(pfoAssociationMap[pPfo2]);
196 if (pfoList1.end() == std::find(pfoList1.begin(), pfoList1.end(), pPfo2))
197 pfoList1.push_back(pPfo2);
199 if (pfoList2.end() == std::find(pfoList2.begin(), pfoList2.end(), pPfo1))
200 pfoList2.push_back(pPfo1);
208 const CartesianVector &endPoint1,
const CartesianVector &endDir1,
const CartesianVector &endPoint2,
const CartesianVector &endDir2)
const 211 const CartesianVector
n(endDir1.GetUnitVector());
212 const CartesianVector m(endDir2.GetUnitVector());
213 const CartesianVector a(endPoint2 - endPoint1);
214 const float b(
n.GetDotProduct(m));
217 if (std::fabs(b - 1.
f) < std::numeric_limits<float>::epsilon())
221 const float lambda((
n - m * b).GetDotProduct(a) / (1.
f - b * b));
224 const float mu((
n * b - m).GetDotProduct(a) / (1.
f - b * b));
231 if ((lambda < -maxVertexUncertainty) || (mu < -maxVertexUncertainty) || (lambda >
m_maxAssociationDist + maxVertexUncertainty) ||
238 const CartesianVector impactPosition((endPoint1 +
n * lambda + endPoint2 + m * mu) * 0.5
f);
240 if ((impactPosition.GetX() <
m_face_Xa - maxVertexUncertainty) || (impactPosition.GetX() >
m_face_Xc + maxVertexUncertainty) ||
241 (impactPosition.GetY() <
m_face_Yb - maxVertexUncertainty) || (impactPosition.GetY() >
m_face_Yt + maxVertexUncertainty) ||
242 (impactPosition.GetZ() <
m_face_Zu - maxVertexUncertainty) || (impactPosition.GetZ() >
m_face_Zd + maxVertexUncertainty))
248 const float maxImpactDist(std::sin(deltaTheta) * (std::fabs(mu) + std::fabs(lambda)) +
m_positionalUncertainty);
249 const CartesianVector
d(a -
n * lambda + m * mu);
251 return (d.GetMagnitude() < maxImpactDist);
261 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
263 bool isAlreadyInSlice(
false);
265 for (
const PfoList &slice : sliceList)
267 if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
269 isAlreadyInSlice =
true;
274 if (!isAlreadyInSlice)
276 sliceList.push_back(PfoList());
277 this->
FillSlice(pPfo, pfoAssociationMap, sliceList.back());
281 unsigned int sliceId(0);
282 for (
const PfoList &slice : sliceList)
284 for (
const ParticleFlowObject *
const pPfo : slice)
286 if (!pfoToSliceIdMap.insert(PfoToSliceIdMap::value_type(pPfo, sliceId)).second)
287 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
298 if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
301 slice.emplace_back(pPfo);
305 if (pfoAssociationMap.end() != iter)
307 for (
const ParticleFlowObject *
const pAssociatedPfo : iter->second)
308 this->
FillSlice(pAssociatedPfo, pfoAssociationMap, slice);
317 for (
const ParticleFlowObject *
const pPfo : parentCosmicRayPfos)
320 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
322 candidates.emplace_back(
CRCandidate(this->GetPandora(), pPfo, pfoToSliceIdMap.at(pPfo)));
330 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
335 if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
338 float minX(std::numeric_limits<float>::max()), maxX(-std::numeric_limits<float>::max());
340 if (candidate.m_canFit)
342 minX = ((candidate.m_endPoint1.GetX() < candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
343 maxX = ((candidate.m_endPoint1.GetX() > candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
348 for (
const Cluster *
const pCluster : candidate.m_pPfo->GetClusterList())
350 float clusterMinX(std::numeric_limits<float>::max()), clusterMaxX(-std::numeric_limits<float>::max());
351 pCluster->GetClusterSpanX(clusterMinX, clusterMaxX);
352 minX = std::min(clusterMinX, minX);
353 maxX = std::max(clusterMaxX, maxX);
367 catch (
const StatusCodeException &)
375 CaloHitList caloHitList;
380 bool isFirstHit(
true);
381 bool isInSingleVolume(
true);
382 unsigned int volumeId(std::numeric_limits<unsigned int>::max());
384 for (
const CaloHit *
const pCaloHit : caloHitList)
386 const LArCaloHit *
const pLArCaloHit(dynamic_cast<const LArCaloHit *>(pCaloHit));
398 isInSingleVolume =
false;
405 if (isInSingleVolume && (larTPCMap.end() != tpcIter))
407 const float thisFaceXLow(tpcIter->second->GetCenterX() - 0.5f * tpcIter->second->GetWidthX());
408 const float thisFaceXHigh(tpcIter->second->GetCenterX() + 0.5f * tpcIter->second->GetWidthX());
415 pfoToIsCosmicRayMap[candidate.m_pPfo] = !isInTime;
426 if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
429 (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
431 (candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
444 if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
447 (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
462 if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
466 CaloHitList caloHitList3D;
469 float maxYPosition{-1.f * std::numeric_limits<float>::max()};
470 unsigned int maxYTPCId{std::numeric_limits<unsigned int>::max()};
471 for (
const CaloHit *
const pCaloHit : caloHitList3D)
473 const float hitYPos(pCaloHit->GetPositionVector().GetY());
474 if (maxYPosition < hitYPos)
476 maxYPosition = hitYPos;
477 const LArCaloHit *
const pLArCaloHit{
reinterpret_cast<LArCaloHit *
>(
const_cast<void *
>(pCaloHit->GetParentAddress()))};
479 const unsigned int maxYAPA = pLArCaloHit->GetDaughterVolumeId();
480 maxYTPCId = maxYDriftVol + maxYAPA * 4;
484 pfoToIsCosmicRayMap[candidate.m_pPfo] =
true;
495 m_endPoint1(
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max()),
496 m_endPoint2(
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max()),
497 m_length(
std::numeric_limits<float>::max()),
498 m_curvature(
std::numeric_limits<float>::max()),
499 m_theta(
std::numeric_limits<float>::max())
501 ClusterList clusters3D;
504 if (!clusters3D.empty() && (clusters3D.front()->GetNCaloHits() > 15))
507 const LArTPC *
const pFirstLArTPC(pandora.GetGeometry()->GetLArTPCMap().begin()->second);
521 if (std::fabs(
m_length) > std::numeric_limits<float>::epsilon())
526 CartesianPointVector directionList;
529 CartesianVector direction(0.
f, 0.
f, 0.
f);
530 if (STATUS_CODE_SUCCESS == slidingFitResult.
GetGlobalFitDirection(static_cast<float>(i) * layerPitch, direction))
531 directionList.push_back(direction);
534 CartesianVector meanDirection(0.
f, 0.
f, 0.
f);
535 for (
const CartesianVector &direction : directionList)
536 meanDirection += direction;
538 if (!directionList.empty() > 0)
539 meanDirection *= 1.
f / static_cast<float>(directionList.size());
542 for (
const CartesianVector &direction : directionList)
543 m_curvature += (direction - meanDirection).GetMagnitude();
545 if (!directionList.empty() > 0)
546 m_curvature *= 1.
f / static_cast<float>(directionList.size());
553 PANDORA_RETURN_RESULT_IF_AND_IF(
554 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"AngularUncertainty",
m_angularUncertainty));
556 PANDORA_RETURN_RESULT_IF_AND_IF(
557 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"PositionalUncertainty",
m_positionalUncertainty));
559 PANDORA_RETURN_RESULT_IF_AND_IF(
560 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaxAssociationDist",
m_maxAssociationDist));
562 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"HitThreshold",
m_minimumHits));
564 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InTimeMargin",
m_inTimeMargin));
566 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"InTimeMaxX0",
m_inTimeMaxX0));
568 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MarginY",
m_marginY));
570 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"TagTopEntering",
m_tagTopEntering));
571 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"TagTopToBottom",
m_tagTopToBottom));
572 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"TagOutOfTime",
m_tagOutOfTime));
574 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"TagInVetoedTPCs",
m_tagInVetoedTPCs));
575 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"VetoedTPCs",
m_vetoedTPCs));
577 return STATUS_CODE_SUCCESS;
bool m_canFit
If there are a sufficient number of 3D hits to perform a fitting.
float m_face_Xc
Cathode X face.
void GetCRCandidates(const pandora::PfoList &parentCosmicRayPfos, const PfoToSliceIdMap &pfoToSliceIdMap, CRCandidateList &candidates) const
Make a list of CRCandidates.
Header file for the pfo helper class.
float m_face_Zu
Upstream Z face.
std::unordered_map< const pandora::ParticleFlowObject *, bool > PfoToBoolMap
const pandora::CartesianVector & GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
pandora::CartesianVector m_endPoint2
Second fitted end point in 3D.
Header file for the lar calo hit class.
float m_marginY
The minimum distance from a detector Y-face for a Pfo to be associated.
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)
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.
float m_angularUncertainty
The uncertainty in degrees for the angle of a Pfo.
double m_length
Straight line length of the linear fit.
unsigned int GetLArTPCVolumeId() const
Get the lar tpc volume id.
void CheckIfInVetoedTPC(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate has its highest value in one of the vetoed TPC volumes.
double m_curvature
Measure of the curvature of the track.
void SliceEvent(const pandora::PfoList &parentCosmicRayPfos, const PfoToPfoListMap &pfoAssociationMap, PfoToSliceIdMap &pfoToSliceIdMap) const
Break the event up into slices of associated Pfos.
CRCandidate(const pandora::Pandora &pandora, const pandora::ParticleFlowObject *const pPfo, const unsigned int sliceId)
Constructor.
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...
void GetPfoAssociations(const pandora::PfoList &parentCosmicRayPfos, PfoToPfoListMap &pfoAssociationMap) const
Get mapping between Pfos that are associated with each other by pointing.
std::list< CRCandidate > CRCandidateList
Header file for the cluster helper class.
const pandora::CartesianVector & GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
unsigned int m_minimumHits
The minimum number of hits for a Pfo to be considered.
pandora::StatusCode GetGlobalFitDirection(const float rL, pandora::CartesianVector &direction) const
Get global fit direction for a given longitudinal coordinate.
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 GetLayerPitch() const
Get the layer pitch, units cm.
float m_inTimeMargin
The maximum distance outside of the physical detector volume that a Pfo may be to still be considered...
pandora::StatusCode Initialize()
float m_face_Xa
Anode X face.
float m_face_Yb
Bottom Y face.
std::vector< pandora::PfoList > SliceList
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.
const pandora::CartesianVector & GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
bool m_tagOutOfTime
Whether to tag all out-of-time particles as cosmic rays.
float m_inTimeMaxX0
The maximum pfo x0 (determined from shifted vertex) to allow pfo to still be considered in time...
void FillSlice(const pandora::ParticleFlowObject *const pPfo, const PfoToPfoListMap &pfoAssociationMap, pandora::PfoList &slice) const
Fill a slice iteratively using Pfo associations.
bool m_tagTopEntering
Whether to tag all top entering particles as cosmic rays.
float m_face_Zd
Downstream Z face.
double m_theta
Direction made with vertical.
std::unordered_map< const pandora::ParticleFlowObject *, pandora::PfoList > PfoToPfoListMap
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_maxAssociationDist
The maximum distance from endpoint to point of closest approach, typically a multiple of LAr radiatio...
pandora::CartesianVector m_endPoint1
First fitted end point in 3D.
bool m_tagInVetoedTPCs
Whether to tag all particles with their highest position in vetoed TPCs as cosmic rays...
std::unordered_map< const pandora::ParticleFlowObject *, unsigned int > PfoToSliceIdMap
void CalculateFitVariables(const ThreeDSlidingFitResult &slidingFitResult)
Calculate all variables which require a fit.
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Class to encapsulate the logic required determine if a Pfo should or shouldn't be tagged as a cosmic ...
void CheckIfTopEntering(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate enters from the top of the detector.
void CheckIfOutOfTime(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate is "in time".
bool m_tagTopToBottom
Whether to tag all top-to-bottom particles as cosmic rays.
second_as<> second
Type of time stored in seconds, in double precision.
std::vector< unsigned int > m_vetoedTPCs
List of vetoed TPCs for tagging cosmic rays.
void CheckIfTopToBottom(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate is "top to bottom".
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.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::ParticleFlowObject *, SlidingFitPair > PfoToSlidingFitsMap
float m_face_Yt
Top Y face.
float m_positionalUncertainty
The uncertainty in cm for the position of Pfo endpoint in 3D.
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.