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),
44 if (beamSliceHypotheses.size() != crSliceHypotheses.size())
45 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
50 for (
unsigned int sliceIndex = 0, nSlices = beamSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
53 beamSliceHypotheses.at(sliceIndex) : crSliceHypotheses.at(sliceIndex));
57 for (
const ParticleFlowObject *
const pPfo : sliceOutput)
59 object_creation::ParticleFlowObject::Metadata metadata;
60 metadata.m_propertiesToAdd[
"TestBeamScore"] = score;
61 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
64 selectedPfos.insert(selectedPfos.end(), sliceOutput.begin(), sliceOutput.end());
71 for (
unsigned int sliceIndex = 0, nSlices = beamSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
73 bool usebeamHypothesis(
false);
77 PfoList allConnectedPfoList;
80 CaloHitList caloHitList3D;
83 CaloHitList selectedCaloHitList;
87 if (!selectedCaloHitList.empty())
89 CartesianVector centroidSel(0.
f, 0.
f, 0.
f);
94 const CartesianVector &majorAxisSel(eigenVecsSel.front());
95 const float supplementaryAngleToBeam(majorAxisSel.GetOpeningAngle(
m_beamDirection));
97 CartesianVector interceptOne(0.
f, 0.
f, 0.
f), interceptTwo(0.
f, 0.
f, 0.
f);
98 this->
GetTPCIntercepts(centroidSel, majorAxisSel, interceptOne, interceptTwo);
106 usebeamHypothesis =
true;
110 catch (
const StatusCodeException &)
112 usebeamHypothesis =
false;
115 const PfoList &sliceOutput(usebeamHypothesis ? beamSliceHypotheses.at(sliceIndex) : crSliceHypotheses.at(sliceIndex));
116 selectedPfos.insert(selectedPfos.end(), sliceOutput.begin(), sliceOutput.end());
118 const float score(usebeamHypothesis ? 1.
f : -1.
f);
120 for (
const ParticleFlowObject *
const pPfo : sliceOutput)
122 object_creation::ParticleFlowObject::Metadata metadata;
123 metadata.m_propertiesToAdd[
"TestBeamScore"] = score;
124 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
134 const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
135 const LArTPC *
const pFirstLArTPC(larTPCMap.begin()->second);
136 float parentMinX(pFirstLArTPC->GetCenterX() - 0.5f * pFirstLArTPC->GetWidthX());
137 float parentMaxX(pFirstLArTPC->GetCenterX() + 0.5f * pFirstLArTPC->GetWidthX());
138 float parentMinY(pFirstLArTPC->GetCenterY() - 0.5f * pFirstLArTPC->GetWidthY());
139 float parentMaxY(pFirstLArTPC->GetCenterY() + 0.5f * pFirstLArTPC->GetWidthY());
140 float parentMinZ(pFirstLArTPC->GetCenterZ() - 0.5f * pFirstLArTPC->GetWidthZ());
141 float parentMaxZ(pFirstLArTPC->GetCenterZ() + 0.5f * pFirstLArTPC->GetWidthZ());
143 for (
const LArTPCMap::value_type &mapEntry : larTPCMap)
145 const LArTPC *
const pLArTPC(mapEntry.second);
146 parentMinX =
std::min(parentMinX, pLArTPC->GetCenterX() - 0.5f * pLArTPC->GetWidthX());
147 parentMaxX =
std::max(parentMaxX, pLArTPC->GetCenterX() + 0.5f * pLArTPC->GetWidthX());
148 parentMinY =
std::min(parentMinY, pLArTPC->GetCenterY() - 0.5f * pLArTPC->GetWidthY());
149 parentMaxY =
std::max(parentMaxY, pLArTPC->GetCenterY() + 0.5f * pLArTPC->GetWidthY());
150 parentMinZ =
std::min(parentMinZ, pLArTPC->GetCenterZ() - 0.5f * pLArTPC->GetWidthZ());
151 parentMaxZ =
std::max(parentMaxZ, pLArTPC->GetCenterZ() + 0.5f * pLArTPC->GetWidthZ());
160 const CartesianVector normalTop(0.
f, 0.
f, 1.
f), pointTop(0.
f, 0.
f,
m_tpcMaxZ);
161 const CartesianVector normalBottom(0.
f, 0.
f, -1.
f), pointBottom(0.
f, 0.
f,
m_tpcMinZ);
162 const CartesianVector normalRight(1.
f, 0.
f, 0.
f), pointRight(
m_tpcMaxX, 0.
f, 0.
f);
163 const CartesianVector normalLeft(-1.
f, 0.
f, 0.
f), pointLeft(m_tpcMinX, 0.
f, 0.
f);
164 const CartesianVector normalBack(0.
f, 1.
f, 0.
f), pointBack(0.
f,
m_tpcMaxY, 0.
f);
165 const CartesianVector normalFront(0.
f, -1.
f, 0.
f), pointFront(0.
f,
m_tpcMinY, 0.
f);
167 m_tpcPlanes.emplace_back(normalBottom, pointBottom);
173 return STATUS_CODE_SUCCESS;
179 float &closestHitToFaceDistance)
const 181 if (inputCaloHitList.empty())
182 throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
184 typedef std::pair<const CaloHit*, float> HitDistancePair;
185 typedef std::vector<HitDistancePair> HitDistanceVector;
186 HitDistanceVector hitDistanceVector;
188 for (
const CaloHit *
const pCaloHit : inputCaloHitList)
189 hitDistanceVector.emplace_back(pCaloHit, (pCaloHit->GetPositionVector() -
m_beamTPCIntersection).GetMagnitudeSquared());
191 std::sort(hitDistanceVector.begin(), hitDistanceVector.end(), [](
const HitDistancePair &lhs,
const HitDistancePair &rhs) ->
bool {
return (lhs.second < rhs.second);});
192 closestHitToFaceDistance = std::sqrt(hitDistanceVector.front().second);
194 const unsigned int nInputHits(inputCaloHitList.size());
195 const unsigned int nSelectedCaloHits(nInputHits <
m_nSelectedHits ? nInputHits :
196 static_cast<unsigned int>(std::round(static_cast<float>(nInputHits) *
m_selectedFraction / 100.
f + 0.5
f)));
198 for (
const HitDistancePair &hitDistancePair : hitDistanceVector)
200 outputCaloHitList.push_back(hitDistancePair.first);
202 if (outputCaloHitList.size() >= nSelectedCaloHits)
210 CartesianVector &interceptOne, CartesianVector &interceptTwo)
const 212 CartesianPointVector intercepts;
213 const CartesianVector lineUnitVector(lineDirection.GetUnitVector());
217 const CartesianVector intercept(plane.GetLineIntersection(a0, lineUnitVector));
220 intercepts.push_back(intercept);
223 if (intercepts.size() == 2)
225 interceptOne = intercepts.at(0);
226 interceptTwo = intercepts.at(1);
230 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
238 if ((
m_tpcMinX - spacePoint.GetX() > std::numeric_limits<float>::epsilon()) || (spacePoint.GetX() -
m_tpcMaxX > std::numeric_limits<float>::epsilon()) ||
239 (
m_tpcMinY - spacePoint.GetY() > std::numeric_limits<float>::epsilon()) || (spacePoint.GetY() -
m_tpcMaxY > std::numeric_limits<float>::epsilon()) ||
240 (
m_tpcMinZ - spacePoint.GetZ() > std::numeric_limits<float>::epsilon()) || (spacePoint.GetZ() -
m_tpcMaxZ > std::numeric_limits<float>::epsilon()))
252 m_unitNormal(normal.GetUnitVector()),
254 m_d(-1.
f * (normal.GetDotProduct(point)))
267 if (std::fabs(denominator) < std::numeric_limits<float>::epsilon())
268 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
271 return (a0 + (a * t));
279 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
282 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
287 std::cout <<
"BeamParticleIdTool::ReadSettings - cannot use both SelectAllBeamParticles and SelectOnlyFirstSliceBeamParticles simultaneously" << std::endl;
288 return STATUS_CODE_INVALID_PARAMETER;
291 FloatVector beamTPCIntersection;
292 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
293 "BeamTPCIntersection", beamTPCIntersection));
295 if (3 == beamTPCIntersection.size())
297 m_beamTPCIntersection.SetValues(beamTPCIntersection.at(0), beamTPCIntersection.at(1), beamTPCIntersection.at(2));
299 else if (!beamTPCIntersection.empty())
301 std::cout <<
"BeamParticleIdTool::ReadSettings - invalid BeamTPCIntersection specified " << std::endl;
302 return STATUS_CODE_INVALID_PARAMETER;
310 FloatVector beamDirection;
311 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
312 "BeamDirection", beamDirection));
314 if (3 == beamDirection.size())
316 m_beamDirection.SetValues(beamDirection.at(0), beamDirection.at(1), beamDirection.at(2));
318 else if (!beamDirection.empty())
320 std::cout <<
"BeamParticleIdTool::ReadSettings - invalid BeamDirection specified " << std::endl;
321 return STATUS_CODE_INVALID_PARAMETER;
326 const float thetaXZ0(-11.844
f * M_PI / 180.
f);
330 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
333 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
336 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
339 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
342 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
345 return STATUS_CODE_SUCCESS;
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.
std::vector< pandora::PfoList > SliceHypotheses
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.