9 #include "Pandora/AlgorithmHeaders.h" 21 BeamParticleIdTool::BeamParticleIdTool() :
22 m_selectAllBeamParticles(false),
23 m_selectOnlyFirstSliceBeamParticles(false),
24 m_tpcMinX(
std::numeric_limits<float>::max()),
25 m_tpcMaxX(-
std::numeric_limits<float>::max()),
26 m_tpcMinY(
std::numeric_limits<float>::max()),
27 m_tpcMaxY(-
std::numeric_limits<float>::max()),
28 m_tpcMinZ(
std::numeric_limits<float>::max()),
29 m_tpcMaxZ(-
std::numeric_limits<float>::max()),
30 m_beamTPCIntersection(0.
f, 0.
f, 0.
f),
31 m_beamDirection(0.
f, 0.
f, 0.
f),
32 m_projectionIntersectionCut(100.
f),
33 m_closestDistanceCut(100.
f),
34 m_angleToBeamCut(150.
f * M_PI / 180.
f),
35 m_selectedFraction(10.
f),
45 if (beamSliceHypotheses.size() != crSliceHypotheses.size())
46 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
51 for (
unsigned int sliceIndex = 0, nSlices = beamSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
54 ? beamSliceHypotheses.at(sliceIndex)
55 : crSliceHypotheses.at(sliceIndex));
59 for (
const ParticleFlowObject *
const pPfo : sliceOutput)
61 object_creation::ParticleFlowObject::Metadata metadata;
62 metadata.m_propertiesToAdd[
"TestBeamScore"] = score;
63 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
66 selectedPfos.insert(selectedPfos.end(), sliceOutput.begin(), sliceOutput.end());
73 for (
unsigned int sliceIndex = 0, nSlices = beamSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
75 bool usebeamHypothesis(
false);
79 PfoList allConnectedPfoList;
82 CaloHitList caloHitList3D;
85 CaloHitList selectedCaloHitList;
86 float closestDistance(std::numeric_limits<float>::max());
89 if (!selectedCaloHitList.empty())
91 CartesianVector centroidSel(0.
f, 0.
f, 0.
f);
96 const CartesianVector &majorAxisSel(eigenVecsSel.front());
97 const float supplementaryAngleToBeam(majorAxisSel.GetOpeningAngle(
m_beamDirection));
99 CartesianVector interceptOne(0.
f, 0.
f, 0.
f), interceptTwo(0.
f, 0.
f, 0.
f);
100 this->
GetTPCIntercepts(centroidSel, majorAxisSel, interceptOne, interceptTwo);
108 usebeamHypothesis =
true;
112 catch (
const StatusCodeException &)
114 usebeamHypothesis =
false;
117 const PfoList &sliceOutput(usebeamHypothesis ? beamSliceHypotheses.at(sliceIndex) : crSliceHypotheses.at(sliceIndex));
118 selectedPfos.insert(selectedPfos.end(), sliceOutput.begin(), sliceOutput.end());
120 const float score(usebeamHypothesis ? 1.
f : -1.
f);
122 for (
const ParticleFlowObject *
const pPfo : sliceOutput)
124 object_creation::ParticleFlowObject::Metadata metadata;
125 metadata.m_propertiesToAdd[
"TestBeamScore"] = score;
126 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
136 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
137 const LArTPC *
const pFirstLArTPC(larTPCMap.begin()->second);
138 float parentMinX(pFirstLArTPC->GetCenterX() - 0.5f * pFirstLArTPC->GetWidthX());
139 float parentMaxX(pFirstLArTPC->GetCenterX() + 0.5f * pFirstLArTPC->GetWidthX());
140 float parentMinY(pFirstLArTPC->GetCenterY() - 0.5f * pFirstLArTPC->GetWidthY());
141 float parentMaxY(pFirstLArTPC->GetCenterY() + 0.5f * pFirstLArTPC->GetWidthY());
142 float parentMinZ(pFirstLArTPC->GetCenterZ() - 0.5f * pFirstLArTPC->GetWidthZ());
143 float parentMaxZ(pFirstLArTPC->GetCenterZ() + 0.5f * pFirstLArTPC->GetWidthZ());
145 for (
const LArTPCMap::value_type &mapEntry : larTPCMap)
147 const LArTPC *
const pLArTPC(mapEntry.second);
148 parentMinX = std::min(parentMinX, pLArTPC->GetCenterX() - 0.5f * pLArTPC->GetWidthX());
149 parentMaxX = std::max(parentMaxX, pLArTPC->GetCenterX() + 0.5f * pLArTPC->GetWidthX());
150 parentMinY = std::min(parentMinY, pLArTPC->GetCenterY() - 0.5f * pLArTPC->GetWidthY());
151 parentMaxY = std::max(parentMaxY, pLArTPC->GetCenterY() + 0.5f * pLArTPC->GetWidthY());
152 parentMinZ = std::min(parentMinZ, pLArTPC->GetCenterZ() - 0.5f * pLArTPC->GetWidthZ());
153 parentMaxZ = std::max(parentMaxZ, pLArTPC->GetCenterZ() + 0.5f * pLArTPC->GetWidthZ());
162 const CartesianVector normalTop(0.
f, 0.
f, 1.
f), pointTop(0.
f, 0.
f,
m_tpcMaxZ);
163 const CartesianVector normalBottom(0.
f, 0.
f, -1.
f), pointBottom(0.
f, 0.
f,
m_tpcMinZ);
164 const CartesianVector normalRight(1.
f, 0.
f, 0.
f), pointRight(
m_tpcMaxX, 0.
f, 0.
f);
165 const CartesianVector normalLeft(-1.
f, 0.
f, 0.
f), pointLeft(m_tpcMinX, 0.
f, 0.
f);
166 const CartesianVector normalBack(0.
f, 1.
f, 0.
f), pointBack(0.
f,
m_tpcMaxY, 0.
f);
167 const CartesianVector normalFront(0.
f, -1.
f, 0.
f), pointFront(0.
f,
m_tpcMinY, 0.
f);
169 m_tpcPlanes.emplace_back(normalBottom, pointBottom);
175 return STATUS_CODE_SUCCESS;
182 if (inputCaloHitList.empty())
183 throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
185 typedef std::pair<const CaloHit *, float> HitDistancePair;
186 typedef std::vector<HitDistancePair> HitDistanceVector;
187 HitDistanceVector hitDistanceVector;
189 for (
const CaloHit *
const pCaloHit : inputCaloHitList)
190 hitDistanceVector.emplace_back(pCaloHit, (pCaloHit->GetPositionVector() -
m_beamTPCIntersection).GetMagnitudeSquared());
192 std::sort(hitDistanceVector.begin(), hitDistanceVector.end(),
193 [](
const HitDistancePair &lhs,
const HitDistancePair &rhs) ->
bool {
return (lhs.second < rhs.second); });
194 closestHitToFaceDistance = std::sqrt(hitDistanceVector.front().second);
196 const unsigned int nInputHits(inputCaloHitList.size());
199 : static_cast<unsigned int>(std::round(static_cast<float>(nInputHits) *
m_selectedFraction / 100.
f + 0.5
f)));
201 for (
const HitDistancePair &hitDistancePair : hitDistanceVector)
203 outputCaloHitList.push_back(hitDistancePair.first);
205 if (outputCaloHitList.size() >= nSelectedCaloHits)
213 const CartesianVector &
a0,
const CartesianVector &lineDirection, CartesianVector &interceptOne, CartesianVector &interceptTwo)
const 215 CartesianPointVector intercepts;
216 const CartesianVector lineUnitVector(lineDirection.GetUnitVector());
220 const CartesianVector intercept(plane.GetLineIntersection(a0, lineUnitVector));
223 intercepts.push_back(intercept);
226 if (intercepts.size() == 2)
228 interceptOne = intercepts.at(0);
229 interceptTwo = intercepts.at(1);
233 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
241 if ((
m_tpcMinX - spacePoint.GetX() > std::numeric_limits<float>::epsilon()) ||
242 (spacePoint.GetX() -
m_tpcMaxX > std::numeric_limits<float>::epsilon()) ||
243 (
m_tpcMinY - spacePoint.GetY() > std::numeric_limits<float>::epsilon()) ||
244 (spacePoint.GetY() -
m_tpcMaxY > std::numeric_limits<float>::epsilon()) ||
245 (
m_tpcMinZ - spacePoint.GetZ() > std::numeric_limits<float>::epsilon()) ||
246 (spacePoint.GetZ() -
m_tpcMaxZ > std::numeric_limits<float>::epsilon()))
258 m_unitNormal(normal.GetUnitVector()),
260 m_d(-1.
f * (normal.GetDotProduct(point)))
268 if (std::fabs(a.GetDotProduct(
m_unitNormal)) < std::numeric_limits<float>::min())
269 return CartesianVector(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
273 if (std::fabs(denominator) < std::numeric_limits<float>::epsilon())
274 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
277 return (a0 + (a * t));
285 PANDORA_RETURN_RESULT_IF_AND_IF(
286 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectAllBeamParticles",
m_selectAllBeamParticles));
288 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
293 std::cout <<
"BeamParticleIdTool::ReadSettings - cannot use both SelectAllBeamParticles and SelectOnlyFirstSliceBeamParticles simultaneously" 295 return STATUS_CODE_INVALID_PARAMETER;
298 FloatVector beamTPCIntersection;
299 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
300 XmlHelper::ReadVectorOfValues(xmlHandle,
"BeamTPCIntersection", beamTPCIntersection));
302 if (3 == beamTPCIntersection.size())
304 m_beamTPCIntersection.SetValues(beamTPCIntersection.at(0), beamTPCIntersection.at(1), beamTPCIntersection.at(2));
306 else if (!beamTPCIntersection.empty())
308 std::cout <<
"BeamParticleIdTool::ReadSettings - invalid BeamTPCIntersection specified " << std::endl;
309 return STATUS_CODE_INVALID_PARAMETER;
317 FloatVector beamDirection;
318 PANDORA_RETURN_RESULT_IF_AND_IF(
319 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
"BeamDirection", beamDirection));
321 if (3 == beamDirection.size())
323 m_beamDirection.SetValues(beamDirection.at(0), beamDirection.at(1), beamDirection.at(2));
325 else if (!beamDirection.empty())
327 std::cout <<
"BeamParticleIdTool::ReadSettings - invalid BeamDirection specified " << std::endl;
328 return STATUS_CODE_INVALID_PARAMETER;
333 const float thetaXZ0(-11.844
f * M_PI / 180.
f);
337 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
340 PANDORA_RETURN_RESULT_IF_AND_IF(
341 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ClosestDistanceCut",
m_closestDistanceCut));
343 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"AngleToBeamCut",
m_angleToBeamCut));
345 PANDORA_RETURN_RESULT_IF_AND_IF(
346 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectedFraction",
m_selectedFraction));
348 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"NSelectedHits",
m_nSelectedHits));
350 return STATUS_CODE_SUCCESS;
std::vector< pandora::PfoList > SliceHypotheses
pandora::CartesianVector m_beamTPCIntersection
Intersection of beam and global TPC volume.
Header file for the pfo helper class.
bool IsContained(const pandora::CartesianVector &spacePoint) const
Check if a given 3D spacepoint is inside the global TPC volume.
bool m_selectAllBeamParticles
First approach: select all beam particles, as opposed to selecting all cosmics.
pandora::CartesianVector EigenValues
void GetSelectedCaloHits(const pandora::CaloHitList &inputCaloHitList, pandora::CaloHitList &outputCaloHitList, float &closestHitToFaceDistance) const
Select a given fraction of a slice's calo hits that are closest to the beam spot. ...
float m_closestDistanceCut
Closest distance (of hit to beam spot), used in beam event selection.
pandora::CartesianVector GetLineIntersection(const pandora::CartesianVector &a0, const pandora::CartesianVector &a) const
Return the intersection between the plane and a line.
float m_tpcMaxX
Global TPC volume maximum x extent.
Header file for the principal curve analysis helper class.
float m_tpcMinZ
Global TPC volume minimum z extent.
pandora::StatusCode Initialize()
float m_tpcMaxZ
Global TPC volume maximum z extent.
float m_d
Parameter defining a plane.
Header file for the beam particle id tool class.
float m_angleToBeamCut
Angle between major axis and beam direction, used in beam event selection.
bool m_selectOnlyFirstSliceBeamParticles
First approach: select first slice beam particles, cosmics for all subsequent slices.
pandora::CartesianVector m_unitNormal
Unit normal to plane.
void GetTPCIntercepts(const pandora::CartesianVector &a0, const pandora::CartesianVector &majorAxis, pandora::CartesianVector &interceptOne, pandora::CartesianVector &interceptTwo) const
Find the intercepts of a line with the protoDUNE detector.
Plane(const pandora::CartesianVector &normal, const pandora::CartesianVector &point)
Constructor, using equation of plane: m_a*x + m_b*y + m_c*z + m_d = 0.
unsigned int m_nSelectedHits
Minimum number of hits to use in 3D cluster fits.
static void RunPca(const T &t, pandora::CartesianVector ¢roid, EigenValues &outputEigenValues, EigenVectors &outputEigenVectors)
Run principal component analysis using input calo hits (TPC_VIEW_U,V,W or TPC_3D; all treated as 3D p...
std::vector< pandora::CartesianVector > EigenVectors
float m_selectedFraction
Fraction of hits to use in 3D cluster fits.
float m_projectionIntersectionCut
Projection intersection distance cut, used in beam event selection.
float m_tpcMaxY
Global TPC volume maximum y extent.
pandora::CartesianVector m_beamDirection
Beam direction.
void SelectOutputPfos(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &beamSliceHypotheses, const SliceHypotheses &crSliceHypotheses, pandora::PfoList &selectedPfos)
Select which reconstruction hypotheses to use; neutrino outcomes or cosmic-ray muon outcomes for each...
static void GetAllConnectedPfos(const pandora::PfoList &inputPfoList, pandora::PfoList &outputPfoList)
Get a flat list of all pfos, recursively including all daughters and parents associated with those pf...
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.
float m_tpcMinY
Global TPC volume minimum y extent.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
PlaneVector m_tpcPlanes
Vector of all planes making up global TPC volume.
float m_tpcMinX
Global TPC volume minimum x extent.