LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
PeakDirectionFinderTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 #include "Pandora/AlgorithmTool.h"
11 
14 
16 
17 using namespace pandora;
18 
19 namespace lar_content
20 {
21 
22 PeakDirectionFinderTool::PeakDirectionFinderTool() :
23  m_pathwaySearchRegion(10.f),
24  m_theta0XZBinSize(0.005f),
25  m_smoothingWindow(1),
26  m_ambiguousParticleMode(false)
27 {
28 }
29 
30 //------------------------------------------------------------------------------------------------------------------------------------------
31 
32 StatusCode PeakDirectionFinderTool::Run(const ParticleFlowObject *const pShowerPfo, const CartesianVector &nuVertex3D,
33  const CaloHitList *const pViewHitList, const HitType hitType, CartesianPointVector &peakDirectionVector)
34 {
35  CaloHitList viewShowerHitList;
36  LArPfoHelper::GetCaloHits(pShowerPfo, hitType, viewShowerHitList);
37 
38  const CartesianVector nuVertex2D(LArGeometryHelper::ProjectPosition(this->GetPandora(), nuVertex3D, hitType));
39 
40  // Get event hits in region of interest
41  CaloHitList viewROIHits;
42  this->CollectHitsWithinROI(viewShowerHitList, pViewHitList, nuVertex2D, viewROIHits);
43 
44  if (viewROIHits.empty())
45  return STATUS_CODE_NOT_FOUND;
46 
47  // Fill angular decomposition map
48  AngularDecompositionMap angularDecompositionMap;
49  this->FillAngularDecompositionMap(viewROIHits, nuVertex2D, angularDecompositionMap);
50 
51  if (angularDecompositionMap.empty())
52  return STATUS_CODE_NOT_FOUND;
53 
54  // Smooth angular decomposition map
55  this->SmoothAngularDecompositionMap(angularDecompositionMap);
56 
57  // Get peak directions
58  this->RetrievePeakDirections(angularDecompositionMap, peakDirectionVector);
59 
60  if (peakDirectionVector.empty())
61  return STATUS_CODE_NOT_FOUND;
62 
63  return STATUS_CODE_SUCCESS;
64 }
65 
66 //------------------------------------------------------------------------------------------------------------------------------------------
67 
68 void PeakDirectionFinderTool::CollectHitsWithinROI(const CaloHitList &showerHitList, const CaloHitList *const pViewHitList,
69  const CartesianVector &nuVertex2D, CaloHitList &viewROIHits) const
70 {
72  {
73  for (const CaloHit *const pCaloHit : *pViewHitList)
74  {
75  if (std::find(showerHitList.begin(), showerHitList.end(), pCaloHit) != showerHitList.end())
76  continue;
77 
78  viewROIHits.push_back(pCaloHit);
79  }
80  }
81  else
82  {
83  float lowestTheta(std::numeric_limits<float>::max()), highestTheta((-1.f) * std::numeric_limits<float>::max());
84 
85  this->GetAngularExtrema(showerHitList, nuVertex2D, lowestTheta, highestTheta);
86  this->CollectHitsWithinExtrema(pViewHitList, nuVertex2D, lowestTheta, highestTheta, viewROIHits);
87  }
88 }
89 
90 //------------------------------------------------------------------------------------------------------------------------------------------
91 
93  const CaloHitList &showerHitList, const CartesianVector &nuVertex2D, float &lowestTheta, float &highestTheta) const
94 {
95  lowestTheta = std::numeric_limits<float>::max();
96  highestTheta = (-1.f) * std::numeric_limits<float>::max();
97 
98  const CartesianVector xAxis(1.f, 0.f, 0.f);
99 
100  for (const CaloHit *const pCaloHit : showerHitList)
101  {
102  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
103  const CartesianVector displacementVector(hitPosition - nuVertex2D);
104 
105  float theta0XZ(xAxis.GetOpeningAngle(displacementVector));
106 
107  if (displacementVector.GetZ() < 0.f)
108  theta0XZ = (2.0 * M_PI) - theta0XZ;
109 
110  if (theta0XZ < lowestTheta)
111  lowestTheta = theta0XZ;
112 
113  if (theta0XZ > highestTheta)
114  highestTheta = theta0XZ;
115  }
116 }
117 
118 //------------------------------------------------------------------------------------------------------------------------------------------
119 
120 void PeakDirectionFinderTool::CollectHitsWithinExtrema(const CaloHitList *const pViewHitList, const CartesianVector &nuVertex2D,
121  const float lowestTheta, const float highestTheta, CaloHitList &viewROIHits) const
122 {
123  const CartesianVector xAxis(1.f, 0.f, 0.f);
124 
125  for (const CaloHit *const pCaloHit : *pViewHitList)
126  {
127  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
128  const CartesianVector displacementVector(hitPosition - nuVertex2D);
129 
130  float theta0XZ(xAxis.GetOpeningAngle(displacementVector));
131 
132  if (displacementVector.GetZ() < 0.f)
133  theta0XZ = (2.0 * M_PI) - theta0XZ;
134 
135  if ((theta0XZ < lowestTheta) || (theta0XZ > highestTheta))
136  continue;
137 
138  viewROIHits.push_back(pCaloHit);
139  }
140 }
141 
142 //------------------------------------------------------------------------------------------------------------------------------------------
143 
145  const CaloHitList &viewShowerHitList, const CartesianVector &nuVertex2D, AngularDecompositionMap &angularDecompositionMap) const
146 {
147  const CartesianVector xAxis(1.f, 0.f, 0.f);
148 
149  for (const CaloHit *const pCaloHit : viewShowerHitList)
150  {
151  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
152  const CartesianVector displacementVector(hitPosition - nuVertex2D);
153 
154  if (displacementVector.GetMagnitudeSquared() > (m_pathwaySearchRegion * m_pathwaySearchRegion))
155  continue;
156 
157  float theta0XZ(xAxis.GetOpeningAngle(displacementVector));
158 
159  if (displacementVector.GetZ() < 0.f)
160  theta0XZ *= -1.f;
161 
162  const int theta0XZFactor(std::floor(theta0XZ / m_theta0XZBinSize));
163 
164  if (angularDecompositionMap.find(theta0XZFactor) == angularDecompositionMap.end())
165  angularDecompositionMap[theta0XZFactor] = 1;
166  else
167  angularDecompositionMap[theta0XZFactor] += 1;
168  }
169 }
170 
171 //------------------------------------------------------------------------------------------------------------------------------------------
172 
174 {
175  const int loopMin((-1) * m_smoothingWindow);
176  const int loopMax(m_smoothingWindow);
177 
178  const AngularDecompositionMap angularDecompositionMapTemp(angularDecompositionMap);
179 
180  angularDecompositionMap.clear();
181 
182  for (const auto &entry : angularDecompositionMapTemp)
183  {
184  float total(0.f);
185  const int currentBin(entry.first);
186 
187  for (int binOffset = loopMin; binOffset <= loopMax; ++binOffset)
188  {
189  const int contributingBin = currentBin + binOffset;
190  total += (angularDecompositionMapTemp.find(contributingBin) == angularDecompositionMapTemp.end())
191  ? 0.f
192  : angularDecompositionMapTemp.at(contributingBin);
193  }
194 
195  angularDecompositionMap[currentBin] = total / static_cast<float>((2.0 * m_smoothingWindow) + 1);
196  }
197 }
198 
199 //------------------------------------------------------------------------------------------------------------------------------------------
200 
201 void PeakDirectionFinderTool::RetrievePeakDirections(const AngularDecompositionMap &angularDecompositionMap, CartesianPointVector &peakDirectionVector) const
202 {
203  IntVector orderedBinIndexVector;
204 
205  for (const auto &entry : angularDecompositionMap)
206  orderedBinIndexVector.push_back(entry.first);
207 
208  // Order peak bin vector from highest to lowest bin height
209  // Tie-break: highest index wins
210  std::sort(orderedBinIndexVector.begin(), orderedBinIndexVector.end(),
211  [&angularDecompositionMap](const int a, const int b) -> bool
212  {
213  const float aWeight(angularDecompositionMap.at(a));
214  const float bWeight(angularDecompositionMap.at(b));
215 
216  if (std::fabs(aWeight - bWeight) < std::numeric_limits<float>::epsilon())
217  return a > b;
218  else
219  return aWeight > bWeight;
220  });
221 
222  for (int binIndex : orderedBinIndexVector)
223  {
224  const float binWeight(angularDecompositionMap.at(binIndex));
225 
226  int precedingBin(binIndex - 1);
227  bool foundPreceeding(false);
228 
229  while (!foundPreceeding)
230  {
231  if ((angularDecompositionMap.find(precedingBin) == angularDecompositionMap.end()) ||
232  (std::fabs(angularDecompositionMap.at(precedingBin) - angularDecompositionMap.at(binIndex)) > std::numeric_limits<float>::epsilon()))
233  {
234  foundPreceeding = true;
235  break;
236  }
237 
238  --precedingBin;
239  }
240 
241  int followingBin(binIndex + 1);
242  bool foundFollowing(false);
243 
244  while (!foundFollowing)
245  {
246  if ((angularDecompositionMap.find(followingBin) == angularDecompositionMap.end()) ||
247  (std::fabs(angularDecompositionMap.at(followingBin) - angularDecompositionMap.at(binIndex)) > std::numeric_limits<float>::epsilon()))
248  {
249  foundFollowing = true;
250  break;
251  }
252 
253  ++followingBin;
254  }
255 
256  const float precedingBinWeight(
257  angularDecompositionMap.find(precedingBin) == angularDecompositionMap.end() ? 0.f : angularDecompositionMap.at(precedingBin));
258  const float followingBinWeight(
259  angularDecompositionMap.find(followingBin) == angularDecompositionMap.end() ? 0.f : angularDecompositionMap.at(followingBin));
260 
261  if ((binWeight < precedingBinWeight) || (binWeight < followingBinWeight))
262  continue;
263 
264  // Convert to a direction
265  const float theta0XZ(binIndex * m_theta0XZBinSize);
266  const CartesianVector peakDirection(std::cos(theta0XZ), 0.f, std::sin(theta0XZ));
267 
268  peakDirectionVector.push_back(peakDirection);
269  }
270 }
271 
272 //------------------------------------------------------------------------------------------------------------------------------------------
273 
274 StatusCode PeakDirectionFinderTool::ReadSettings(const TiXmlHandle xmlHandle)
275 {
276  PANDORA_RETURN_RESULT_IF_AND_IF(
277  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "PathwaySearchRegion", m_pathwaySearchRegion));
278 
279  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "Theta0XZBinSize", m_theta0XZBinSize));
280 
281  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SmoothingWindow", m_smoothingWindow));
282 
283  PANDORA_RETURN_RESULT_IF_AND_IF(
284  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "AmbiguousParticleMode", m_ambiguousParticleMode));
285 
286  return STATUS_CODE_SUCCESS;
287 }
288 
289 } // namespace lar_content
Header file for the pfo helper class.
float m_theta0XZBinSize
The angular distribution bin size.
void FillAngularDecompositionMap(const pandora::CaloHitList &viewShowerHitList, const pandora::CartesianVector &nuVertex2D, AngularDecompositionMap &angularDecompositionMap) const
Determine the angular distribution of the ROI hits.
void CollectHitsWithinROI(const pandora::CaloHitList &showerHitList, const pandora::CaloHitList *const pViewHitList, const pandora::CartesianVector &nuVertex2D, pandora::CaloHitList &viewROIHits) const
Collect the 2D hits within a region of interest (m_ambiguousParticleMode ? hits not in the shower : h...
pandora::StatusCode Run(const pandora::ParticleFlowObject *const pShowerPfo, const pandora::CartesianVector &nuVertex3D, const pandora::CaloHitList *const pViewHitList, const pandora::HitType hitType, pandora::CartesianPointVector &peakDirectionVector)
void CollectHitsWithinExtrema(const pandora::CaloHitList *const pViewHitList, const pandora::CartesianVector &nuVertex2D, const float lowestTheta, const float highestTheta, pandora::CaloHitList &viewROIHits) const
Collect the hits that lie within the initial shower cone (originating from the nu vertex) ...
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
int m_smoothingWindow
On each side, the number of neighbouring bins with which each bin is averaged.
std::vector< int > IntVector
float m_pathwaySearchRegion
The initial shower cone distance.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
void SmoothAngularDecompositionMap(AngularDecompositionMap &angularDecompositionMap) const
Smooth the ROI angular angular distribution.
void RetrievePeakDirections(const AngularDecompositionMap &angularDecompositionMap, pandora::CartesianPointVector &peakDirectionVector) const
Obtain a vector of directions from the angular distribution peaks.
Header file for the peak direction finder tool class.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
HitType
Definition: HitType.h:12
void GetAngularExtrema(const pandora::CaloHitList &showerHitList, const pandora::CartesianVector &nuVertex2D, float &lowestTheta, float &highestTheta) const
Determine the angle (from the +ve drift-axis) of the shower cone boundaries (originating from the nu ...
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.
bool m_ambiguousParticleMode
Whether to find the initial pathway direction of the shower or of the other event particles...