Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
BeamParticleIdTool.cc
Go to the documentation of this file.
1
10
12
15
16using namespace pandora;
17
18namespace lar_content
19{
20
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),
36 m_nSelectedHits(100)
37{
38}
39
40//------------------------------------------------------------------------------------------------------------------------------------------
41
42void BeamParticleIdTool::SelectOutputPfos(const Algorithm *const pAlgorithm, const SliceHypotheses &beamSliceHypotheses,
43 const SliceHypotheses &crSliceHypotheses, PfoList &selectedPfos)
44{
45 if (beamSliceHypotheses.size() != crSliceHypotheses.size())
46 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
47
48 // First, simple approach
50 {
51 for (unsigned int sliceIndex = 0, nSlices = beamSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
52 {
53 const PfoList &sliceOutput((m_selectAllBeamParticles || (m_selectOnlyFirstSliceBeamParticles && (0 == sliceIndex)))
54 ? beamSliceHypotheses.at(sliceIndex)
55 : crSliceHypotheses.at(sliceIndex));
56
57 const float score(m_selectAllBeamParticles || (m_selectOnlyFirstSliceBeamParticles && (0 == sliceIndex)) ? 1.f : -1.f);
58
59 for (const ParticleFlowObject *const pPfo : sliceOutput)
60 {
62 metadata.m_propertiesToAdd["TestBeamScore"] = score;
63 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
64 }
65
66 selectedPfos.insert(selectedPfos.end(), sliceOutput.begin(), sliceOutput.end());
67 }
68
69 return;
70 }
71
72 // Now start to examine topology of beam slice hypotheses
73 for (unsigned int sliceIndex = 0, nSlices = beamSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
74 {
75 bool usebeamHypothesis(false);
76
77 try
78 {
79 PfoList allConnectedPfoList;
80 LArPfoHelper::GetAllConnectedPfos(beamSliceHypotheses.at(sliceIndex), allConnectedPfoList);
81
82 CaloHitList caloHitList3D;
83 LArPfoHelper::GetCaloHits(allConnectedPfoList, TPC_3D, caloHitList3D);
84
85 CaloHitList selectedCaloHitList;
86 float closestDistance(std::numeric_limits<float>::max());
87 this->GetSelectedCaloHits(caloHitList3D, selectedCaloHitList, closestDistance);
88
89 if (!selectedCaloHitList.empty())
90 {
91 CartesianVector centroidSel(0.f, 0.f, 0.f);
92 LArPcaHelper::EigenVectors eigenVecsSel;
93 LArPcaHelper::EigenValues eigenValuesSel(0.f, 0.f, 0.f);
94 LArPcaHelper::RunPca(selectedCaloHitList, centroidSel, eigenValuesSel, eigenVecsSel);
95
96 const CartesianVector &majorAxisSel(eigenVecsSel.front());
97 const float supplementaryAngleToBeam(majorAxisSel.GetOpeningAngle(m_beamDirection));
98
99 CartesianVector interceptOne(0.f, 0.f, 0.f), interceptTwo(0.f, 0.f, 0.f);
100 this->GetTPCIntercepts(centroidSel, majorAxisSel, interceptOne, interceptTwo);
101
102 const float separationOne((interceptOne - m_beamTPCIntersection).GetMagnitude());
103 const float separationTwo((interceptTwo - m_beamTPCIntersection).GetMagnitude());
104
105 if ((std::min(separationOne, separationTwo) < m_projectionIntersectionCut) && (closestDistance < m_closestDistanceCut) &&
106 (supplementaryAngleToBeam > m_angleToBeamCut))
107 {
108 usebeamHypothesis = true;
109 }
110 }
111 }
112 catch (const StatusCodeException &)
113 {
114 usebeamHypothesis = false;
115 }
116
117 const PfoList &sliceOutput(usebeamHypothesis ? beamSliceHypotheses.at(sliceIndex) : crSliceHypotheses.at(sliceIndex));
118 selectedPfos.insert(selectedPfos.end(), sliceOutput.begin(), sliceOutput.end());
119
120 const float score(usebeamHypothesis ? 1.f : -1.f);
121
122 for (const ParticleFlowObject *const pPfo : sliceOutput)
123 {
125 metadata.m_propertiesToAdd["TestBeamScore"] = score;
126 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
127 }
128 }
129}
130
131//------------------------------------------------------------------------------------------------------------------------------------------
132
134{
135 // Get global TPC geometry information
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());
144
145 for (const LArTPCMap::value_type &mapEntry : larTPCMap)
146 {
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());
154 }
155 m_tpcMinX = parentMinX;
156 m_tpcMaxX = parentMaxX;
157 m_tpcMinY = parentMinY;
158 m_tpcMaxY = parentMaxY;
159 m_tpcMinZ = parentMinZ;
160 m_tpcMaxZ = parentMaxZ;
161
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);
168 m_tpcPlanes.emplace_back(normalTop, pointTop);
169 m_tpcPlanes.emplace_back(normalBottom, pointBottom);
170 m_tpcPlanes.emplace_back(normalRight, pointRight);
171 m_tpcPlanes.emplace_back(normalLeft, pointLeft);
172 m_tpcPlanes.emplace_back(normalBack, pointBack);
173 m_tpcPlanes.emplace_back(normalFront, pointFront);
174
175 return STATUS_CODE_SUCCESS;
176}
177
178//------------------------------------------------------------------------------------------------------------------------------------------
179
180void BeamParticleIdTool::GetSelectedCaloHits(const CaloHitList &inputCaloHitList, CaloHitList &outputCaloHitList, float &closestHitToFaceDistance) const
181{
182 if (inputCaloHitList.empty())
183 throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
184
185 typedef std::pair<const CaloHit *, float> HitDistancePair;
186 typedef std::vector<HitDistancePair> HitDistanceVector;
187 HitDistanceVector hitDistanceVector;
188
189 for (const CaloHit *const pCaloHit : inputCaloHitList)
190 hitDistanceVector.emplace_back(pCaloHit, (pCaloHit->GetPositionVector() - m_beamTPCIntersection).GetMagnitudeSquared());
191
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);
195
196 const unsigned int nInputHits(inputCaloHitList.size());
197 const unsigned int nSelectedCaloHits(
198 nInputHits < m_nSelectedHits ? nInputHits
199 : static_cast<unsigned int>(std::round(static_cast<float>(nInputHits) * m_selectedFraction / 100.f + 0.5f)));
200
201 for (const HitDistancePair &hitDistancePair : hitDistanceVector)
202 {
203 outputCaloHitList.push_back(hitDistancePair.first);
204
205 if (outputCaloHitList.size() >= nSelectedCaloHits)
206 break;
207 }
208}
209
210//------------------------------------------------------------------------------------------------------------------------------------------
211
213 const CartesianVector &a0, const CartesianVector &lineDirection, CartesianVector &interceptOne, CartesianVector &interceptTwo) const
214{
215 CartesianPointVector intercepts;
216 const CartesianVector lineUnitVector(lineDirection.GetUnitVector());
217
218 for (const Plane &plane : m_tpcPlanes)
219 {
220 const CartesianVector intercept(plane.GetLineIntersection(a0, lineUnitVector));
221
222 if (this->IsContained(intercept))
223 intercepts.push_back(intercept);
224 }
225
226 if (intercepts.size() == 2)
227 {
228 interceptOne = intercepts.at(0);
229 interceptTwo = intercepts.at(1);
230 }
231 else
232 {
233 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
234 }
235}
236
237//------------------------------------------------------------------------------------------------------------------------------------------
238
240{
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()))
247 {
248 return false;
249 }
250
251 return true;
252}
253
254//------------------------------------------------------------------------------------------------------------------------------------------
255//------------------------------------------------------------------------------------------------------------------------------------------
256
258 m_unitNormal(normal.GetUnitVector()),
259 m_point(point),
260 m_d(-1.f * (normal.GetDotProduct(point)))
261{
262}
263
264//------------------------------------------------------------------------------------------------------------------------------------------
265
267{
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());
270
271 const float denominator(a.GetDotProduct(m_unitNormal));
272
273 if (std::fabs(denominator) < std::numeric_limits<float>::epsilon())
274 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
275
276 const float t(-1.f * (a0.GetDotProduct(m_unitNormal) + m_d) / denominator);
277 return (a0 + (a * t));
278}
279
280//------------------------------------------------------------------------------------------------------------------------------------------
281//------------------------------------------------------------------------------------------------------------------------------------------
282
284{
286 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SelectAllBeamParticles", m_selectAllBeamParticles));
287
288 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
289 XmlHelper::ReadValue(xmlHandle, "SelectOnlyFirstSliceBeamParticles", m_selectOnlyFirstSliceBeamParticles));
290
292 {
293 std::cout << "BeamParticleIdTool::ReadSettings - cannot use both SelectAllBeamParticles and SelectOnlyFirstSliceBeamParticles simultaneously"
294 << std::endl;
295 return STATUS_CODE_INVALID_PARAMETER;
296 }
297
298 FloatVector beamTPCIntersection;
299 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
300 XmlHelper::ReadVectorOfValues(xmlHandle, "BeamTPCIntersection", beamTPCIntersection));
301
302 if (3 == beamTPCIntersection.size())
303 {
304 m_beamTPCIntersection.SetValues(beamTPCIntersection.at(0), beamTPCIntersection.at(1), beamTPCIntersection.at(2));
305 }
306 else if (!beamTPCIntersection.empty())
307 {
308 std::cout << "BeamParticleIdTool::ReadSettings - invalid BeamTPCIntersection specified " << std::endl;
309 return STATUS_CODE_INVALID_PARAMETER;
310 }
311 else
312 {
313 // Default for protoDUNE.
314 m_beamTPCIntersection.SetValues(-33.051, 461.06, 0);
315 }
316
317 FloatVector beamDirection;
319 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "BeamDirection", beamDirection));
320
321 if (3 == beamDirection.size())
322 {
323 m_beamDirection.SetValues(beamDirection.at(0), beamDirection.at(1), beamDirection.at(2));
324 }
325 else if (!beamDirection.empty())
326 {
327 std::cout << "BeamParticleIdTool::ReadSettings - invalid BeamDirection specified " << std::endl;
328 return STATUS_CODE_INVALID_PARAMETER;
329 }
330 else
331 {
332 // Default for protoDUNE.
333 const float thetaXZ0(-11.844f * M_PI / 180.f);
334 m_beamDirection.SetValues(std::sin(thetaXZ0), 0, std::cos(thetaXZ0));
335 }
336
337 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
338 XmlHelper::ReadValue(xmlHandle, "ProjectionIntersectionCut", m_projectionIntersectionCut));
339
341 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ClosestDistanceCut", m_closestDistanceCut));
342
343 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "AngleToBeamCut", m_angleToBeamCut));
344
346 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SelectedFraction", m_selectedFraction));
347
348 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NSelectedHits", m_nSelectedHits));
349
350 return STATUS_CODE_SUCCESS;
351}
352
353} // namespace lar_content
Grouping of header files for many classes of use in particle flow algorithms.
Header file for the beam particle id tool class.
Header file for the principal curve analysis helper class.
Header file for the pfo helper class.
#define PANDORA_THROW_RESULT_IF(StatusCode1, Operator, Command)
Definition StatusCodes.h:43
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:31
pandora::CartesianVector GetLineIntersection(const pandora::CartesianVector &a0, const pandora::CartesianVector &a) const
Return the intersection between the plane and a line.
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.
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.
float m_tpcMaxX
Global TPC volume maximum x extent.
pandora::CartesianVector m_beamDirection
Beam direction.
float m_tpcMinZ
Global TPC volume minimum z extent.
bool m_selectAllBeamParticles
First approach: select all beam particles, as opposed to selecting all cosmics.
BeamParticleIdTool()
Default constructor.
pandora::StatusCode Initialize()
Perform any operations that must occur after reading settings, but before running the process.
bool IsContained(const pandora::CartesianVector &spacePoint) const
Check if a given 3D spacepoint is inside the global TPC volume.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
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...
float m_tpcMinY
Global TPC volume minimum y extent.
float m_tpcMaxZ
Global TPC volume maximum z extent.
bool m_selectOnlyFirstSliceBeamParticles
First approach: select first slice beam particles, cosmics for all subsequent slices.
PlaneVector m_tpcPlanes
Vector of all planes making up global TPC volume.
float m_selectedFraction
Fraction of hits to use in 3D cluster fits.
float m_tpcMinX
Global TPC volume minimum x extent.
pandora::CartesianVector m_beamTPCIntersection
Intersection of beam and global TPC volume.
float m_projectionIntersectionCut
Projection intersection distance cut, used in beam event selection.
float m_closestDistanceCut
Closest distance (of hit to beam spot), used in beam event selection.
float m_tpcMaxY
Global TPC volume maximum y extent.
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_angleToBeamCut
Angle between major axis and beam direction, used in beam event selection.
unsigned int m_nSelectedHits
Minimum number of hits to use in 3D cluster fits.
std::vector< pandora::CartesianVector > EigenVectors
static void RunPca(const T &t, pandora::CartesianVector &centroid, 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...
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.
Algorithm class. Algorithm addresses are held only by the algorithm manager. They have a fully define...
Definition Algorithm.h:21
CaloHit class.
Definition CaloHit.h:26
CartesianVector class.
void SetValues(float x, float y, float z)
Set the values of cartesian vector components.
float GetX() const
Get the cartesian x coordinate.
CartesianVector GetUnitVector() const
Get a unit vector in the direction of the cartesian vector.
float GetZ() const
Get the cartesian z coordinate.
float GetDotProduct(const CartesianVector &rhs) const
Get the dot product of the cartesian vector with a second cartesian vector.
float GetOpeningAngle(const CartesianVector &rhs) const
Get the opening angle of the cartesian vector with respect to a second cartesian vector.
float GetY() const
Get the cartesian y coordinate.
LArTPC class.
Definition LArTPC.h:26
float GetCenterY() const
Get center in y, units mm.
Definition LArTPC.h:182
float GetWidthZ() const
Get the width in z, units mm.
Definition LArTPC.h:210
float GetCenterZ() const
Get center in z, units mm.
Definition LArTPC.h:189
float GetCenterX() const
Get center in x, units mm.
Definition LArTPC.h:175
float GetWidthX() const
Get the width in x, units mm.
Definition LArTPC.h:196
float GetWidthY() const
Get the width in y, units mm.
Definition LArTPC.h:203
ParticleFlowObject class.
StatusCode AlterMetadata(const object_creation::ParticleFlowObject::Metadata &metadata)
Alter particle flow object metadata parameters.
const Pandora & GetPandora() const
Get the associated pandora instance.
Definition Process.h:116
StatusCodeException class.
static StatusCode ReadVectorOfValues(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, std::vector< T > &vector)
Read a vector of values from a (space separated) list in an xml element.
Definition XmlHelper.h:229
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
Definition XmlHelper.h:136
std::vector< pandora::PfoList > SliceHypotheses
std::vector< CartesianVector > CartesianPointVector
std::map< unsigned int, const LArTPC * > LArTPCMap
MANAGED_CONTAINER< const CaloHit * > CaloHitList
std::vector< float > FloatVector
StatusCode
The StatusCode enum.
MANAGED_CONTAINER< const ParticleFlowObject * > PfoList