LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
ShowerSpineFinderTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 #include "Pandora/AlgorithmTool.h"
11 
15 
17 
19 
20 using namespace pandora;
21 
22 namespace lar_content
23 {
24 
25 ShowerSpineFinderTool::ShowerSpineFinderTool() :
26  m_hitThresholdForSpine(7),
27  m_growingFitInitialLength(10.f),
28  m_initialFitDistanceToLine(0.5f),
29  m_minInitialHitsFound(7),
30  m_maxFittingHits(15),
31  m_localSlidingFitWindow(10),
32  m_growingFitSegmentLength(5.f),
33  m_highResolutionSlidingFitWindow(5),
34  m_distanceToLine(0.75f),
35  m_hitConnectionDistance(0.75f)
36 {
37 }
38 
39 //------------------------------------------------------------------------------------------------------------------------------------------
40 
41 StatusCode ShowerSpineFinderTool::Run(const CartesianVector &nuVertex3D, const CaloHitList *const pViewHitList, const HitType hitType,
42  const CartesianVector &peakDirection, CaloHitList &unavailableHitList, CaloHitList &showerSpineHitList)
43 {
44  const CartesianVector nuVertex2D(LArGeometryHelper::ProjectPosition(this->GetPandora(), nuVertex3D, hitType));
45 
46  this->FindShowerSpine(pViewHitList, nuVertex2D, peakDirection, unavailableHitList, showerSpineHitList);
47 
48  // Demand that spine is significant, be lenient here as some have small stubs and a gap
49  if (showerSpineHitList.size() < m_hitThresholdForSpine)
50  return STATUS_CODE_NOT_FOUND;
51 
52  return STATUS_CODE_SUCCESS;
53 }
54 
55 //------------------------------------------------------------------------------------------------------------------------------------------
56 
57 void ShowerSpineFinderTool::FindShowerSpine(const CaloHitList *const pViewHitList, const CartesianVector &nuVertex2D,
58  const CartesianVector &initialDirection, CaloHitList &unavailableHitList, CaloHitList &showerSpineHitList) const
59 {
60  // Use initial direction to find seed hits for a starting fit
61  float highestL(0.f);
62  CartesianPointVector runningFitPositionVector;
63 
64  for (const CaloHit *const pCaloHit : *pViewHitList)
65  {
66  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
67  const CartesianVector &displacementVector(hitPosition - nuVertex2D);
68  const float l(initialDirection.GetDotProduct(displacementVector));
69  const float t(initialDirection.GetCrossProduct(displacementVector).GetMagnitude());
70 
71  if ((l < m_growingFitInitialLength) && (l > 0.f) && (t < m_initialFitDistanceToLine))
72  {
73  if (l > highestL)
74  highestL = l;
75 
76  if (std::find(unavailableHitList.begin(), unavailableHitList.end(), pCaloHit) == unavailableHitList.end())
77  {
78  showerSpineHitList.push_back(pCaloHit);
79  }
80 
81  runningFitPositionVector.push_back(hitPosition);
82  }
83  }
84 
85  // Require significant number of initial hits
86  if (runningFitPositionVector.size() < m_minInitialHitsFound)
87  {
88  showerSpineHitList.clear();
89  return;
90  }
91 
92  // Perform a running fit to collect a pathway of hits
93  unsigned int count(0);
94  bool hitsCollected(true);
95  const bool isEndDownstream(initialDirection.GetZ() > 0.f);
96  const float slidingFitPitch(LArGeometryHelper::GetWirePitch(this->GetPandora(), showerSpineHitList.front()->GetHitType()));
97  CartesianVector extrapolatedStartPosition(nuVertex2D), extrapolatedDirection(initialDirection);
98  CartesianVector extrapolatedEndPosition(extrapolatedStartPosition + (extrapolatedDirection * highestL));
99 
100  while (hitsCollected)
101  {
102  ++count;
103 
104  try
105  {
106  const int excessHitsInFit(runningFitPositionVector.size() - m_maxFittingHits);
107 
108  if (excessHitsInFit > 0)
109  {
110  // Remove furthest away hits
111  std::sort(runningFitPositionVector.begin(), runningFitPositionVector.end(),
112  LArConnectionPathwayHelper::SortByDistanceToPoint(extrapolatedEndPosition));
113 
114  for (int i = 0; i < excessHitsInFit; ++i)
115  runningFitPositionVector.erase(std::prev(runningFitPositionVector.end()));
116  }
117 
118  const TwoDSlidingFitResult extrapolatedFit(&runningFitPositionVector, m_localSlidingFitWindow, slidingFitPitch);
119 
120  extrapolatedStartPosition = count == 1 ? extrapolatedEndPosition
121  : isEndDownstream ? extrapolatedFit.GetGlobalMaxLayerPosition()
122  : extrapolatedFit.GetGlobalMinLayerPosition();
123  extrapolatedDirection =
124  isEndDownstream ? extrapolatedFit.GetGlobalMaxLayerDirection() : extrapolatedFit.GetGlobalMinLayerDirection() * (-1.f);
125  extrapolatedEndPosition = extrapolatedStartPosition + (extrapolatedDirection * m_growingFitSegmentLength);
126 
127  hitsCollected = this->CollectSubsectionHits(extrapolatedFit, extrapolatedStartPosition, extrapolatedEndPosition,
128  extrapolatedDirection, isEndDownstream, pViewHitList, runningFitPositionVector, unavailableHitList, showerSpineHitList);
129 
130  // If no hits found, as a final effort, reduce the sliding fit window
131  if (!hitsCollected)
132  {
133  const TwoDSlidingFitResult microExtrapolatedFit(&runningFitPositionVector, m_highResolutionSlidingFitWindow, slidingFitPitch);
134 
135  extrapolatedStartPosition = count == 1 ? extrapolatedStartPosition
136  : isEndDownstream ? microExtrapolatedFit.GetGlobalMaxLayerPosition()
137  : microExtrapolatedFit.GetGlobalMinLayerPosition();
138  extrapolatedDirection = isEndDownstream ? microExtrapolatedFit.GetGlobalMaxLayerDirection()
139  : microExtrapolatedFit.GetGlobalMinLayerDirection() * (-1.f);
140  extrapolatedEndPosition = extrapolatedStartPosition + (extrapolatedDirection * m_growingFitSegmentLength);
141 
142  hitsCollected = this->CollectSubsectionHits(microExtrapolatedFit, extrapolatedStartPosition, extrapolatedEndPosition,
143  extrapolatedDirection, isEndDownstream, pViewHitList, runningFitPositionVector, unavailableHitList, showerSpineHitList);
144  }
145  }
146  catch (const StatusCodeException &)
147  {
148  return;
149  }
150  }
151 }
152 
153 //------------------------------------------------------------------------------------------------------------------------------------------
154 
156  const CartesianVector &extrapolatedStartPosition, const CartesianVector &extrapolatedEndPosition,
157  const CartesianVector &extrapolatedDirection, const bool isEndDownstream, const CaloHitList *const pViewHitList,
158  CartesianPointVector &runningFitPositionVector, CaloHitList &unavailableHitList, CaloHitList &showerSpineHitList) const
159 {
160  float extrapolatedStartL(0.f), extrapolatedStartT(0.f);
161  extrapolatedFit.GetLocalPosition(extrapolatedStartPosition, extrapolatedStartL, extrapolatedStartT);
162 
163  float extrapolatedEndL(0.f), extrapolatedEndT(0.f);
164  extrapolatedFit.GetLocalPosition(extrapolatedEndPosition, extrapolatedEndL, extrapolatedEndT);
165 
166  CaloHitList collectedHits;
167 
168  for (const CaloHit *const pCaloHit : *pViewHitList)
169  {
170  if (std::find(showerSpineHitList.begin(), showerSpineHitList.end(), pCaloHit) != showerSpineHitList.end())
171  continue;
172 
173  if (std::find(unavailableHitList.begin(), unavailableHitList.end(), pCaloHit) != unavailableHitList.end())
174  continue;
175 
176  const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
177 
178  float hitL(0.f), hitT(0.f);
179  extrapolatedFit.GetLocalPosition(hitPosition, hitL, hitT);
180 
181  // Assess whether hit is within section boundaries
182  if (isEndDownstream && ((hitL < extrapolatedStartL) || (hitL > extrapolatedEndL)))
183  continue;
184 
185  if (!isEndDownstream && ((hitL > extrapolatedStartL) || (hitL < extrapolatedEndL)))
186  continue;
187 
188  // Assess whether hit is close to connecting line - taking account hit width if necessary
189  if (this->IsCloseToLine(hitPosition, extrapolatedStartPosition, extrapolatedDirection, m_distanceToLine))
190  {
191  collectedHits.push_back(pCaloHit);
192  }
193  else
194  {
195  const CartesianVector closestPointInHit(
196  LArHitWidthHelper::GetClosestPointToLine2D(extrapolatedStartPosition, extrapolatedDirection, pCaloHit));
197 
198  if (this->IsCloseToLine(closestPointInHit, extrapolatedStartPosition, extrapolatedDirection, m_distanceToLine))
199  collectedHits.push_back(pCaloHit);
200  }
201  }
202 
203  const int nInitialHits(showerSpineHitList.size());
204 
205  // Now find a continuous path of collected hits
206  this->CollectConnectedHits(collectedHits, extrapolatedStartPosition, extrapolatedDirection, runningFitPositionVector, showerSpineHitList);
207 
208  const int nFinalHits(showerSpineHitList.size());
209 
210  return (nFinalHits != nInitialHits);
211 }
212 
213 //------------------------------------------------------------------------------------------------------------------------------------------
214 
215 bool ShowerSpineFinderTool::IsCloseToLine(const CartesianVector &hitPosition, const CartesianVector &lineStart,
216  const CartesianVector &lineDirection, const float distanceToLine) const
217 {
218  const float transverseDistanceFromLine(lineDirection.GetCrossProduct(hitPosition - lineStart).GetMagnitude());
219 
220  if (transverseDistanceFromLine > distanceToLine)
221  return false;
222 
223  return true;
224 }
225 
226 //------------------------------------------------------------------------------------------------------------------------------------------
227 
228 void ShowerSpineFinderTool::CollectConnectedHits(const CaloHitList &collectedHits, const CartesianVector &extrapolatedStartPosition,
229  const CartesianVector &extrapolatedDirection, CartesianPointVector &runningFitPositionVector, CaloHitList &showerSpineHitList) const
230 {
231  bool found(true);
232 
233  while (found)
234  {
235  found = false;
236 
237  for (const CaloHit *const pCaloHit : collectedHits)
238  {
239  if (std::find(showerSpineHitList.begin(), showerSpineHitList.end(), pCaloHit) != showerSpineHitList.end())
240  continue;
241 
242  CartesianVector hitPosition(pCaloHit->GetPositionVector());
243 
244  if (this->GetClosestDistance(hitPosition, runningFitPositionVector) > m_hitConnectionDistance)
245  {
246  if (LArHitWidthHelper::GetClosestDistance(pCaloHit, showerSpineHitList) > m_hitConnectionDistance)
247  continue;
248 
249  hitPosition = LArHitWidthHelper::GetClosestPointToLine2D(extrapolatedStartPosition, extrapolatedDirection, pCaloHit);
250  }
251 
252  found = true;
253 
254  runningFitPositionVector.push_back(hitPosition);
255  showerSpineHitList.push_back(pCaloHit);
256  }
257  }
258 }
259 
260 //------------------------------------------------------------------------------------------------------------------------------------------
261 
262 float ShowerSpineFinderTool::GetClosestDistance(const CartesianVector &position, const CartesianPointVector &testPositions) const
263 {
264  float closestDistanceSqaured(std::numeric_limits<float>::max());
265 
266  for (const CartesianVector &testPosition : testPositions)
267  {
268  const float separationSquared((testPosition - position).GetMagnitudeSquared());
269 
270  if (separationSquared < closestDistanceSqaured)
271  closestDistanceSqaured = separationSquared;
272  }
273 
274  return std::sqrt(closestDistanceSqaured);
275 }
276 
277 //------------------------------------------------------------------------------------------------------------------------------------------
278 
279 StatusCode ShowerSpineFinderTool::ReadSettings(const TiXmlHandle xmlHandle)
280 {
281  PANDORA_RETURN_RESULT_IF_AND_IF(
282  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HitThresholdForSpine", m_hitThresholdForSpine));
283 
284  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
285  XmlHelper::ReadValue(xmlHandle, "GrowingFitInitialLength", m_growingFitInitialLength));
286 
287  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
288  XmlHelper::ReadValue(xmlHandle, "InitialFitDistanceToLine", m_initialFitDistanceToLine));
289 
290  PANDORA_RETURN_RESULT_IF_AND_IF(
291  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinInitialHitsFound", m_minInitialHitsFound));
292 
293  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxFittingHits", m_maxFittingHits));
294 
295  PANDORA_RETURN_RESULT_IF_AND_IF(
296  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "LocalSlidingFitWindow", m_localSlidingFitWindow));
297 
298  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
299  XmlHelper::ReadValue(xmlHandle, "GrowingFitSegmentLength", m_growingFitSegmentLength));
300 
301  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
302  XmlHelper::ReadValue(xmlHandle, "HighResolutionSlidingFitWindow", m_highResolutionSlidingFitWindow));
303 
304  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "DistanceToLine", m_distanceToLine));
305 
306  PANDORA_RETURN_RESULT_IF_AND_IF(
307  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HitConnectionDistance", m_hitConnectionDistance));
308 
309  return STATUS_CODE_SUCCESS;
310 }
311 
312 } // namespace lar_content
pandora::StatusCode Run(const pandora::CartesianVector &nuVertex3D, const pandora::CaloHitList *const pViewHitList, const pandora::HitType hitType, const pandora::CartesianVector &peakDirection, pandora::CaloHitList &unavailableHitList, pandora::CaloHitList &showerSpineHitList)
Header file for the connection pathway helper class.
Header file for the lar hit width helper class.
unsigned int m_minInitialHitsFound
The min. number of hits collected in the first step for continuation.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
float m_initialFitDistanceToLine
The max. proximity to the spine projection for collection in the first step.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
float m_hitConnectionDistance
The max. separation between connected hits.
void FindShowerSpine(const pandora::CaloHitList *const pViewHitList, const pandora::CartesianVector &nuVertex2D, const pandora::CartesianVector &initialDirection, pandora::CaloHitList &unavailableHitList, pandora::CaloHitList &showerSpineHitList) const
Perform a running fit to collect the hits of the shower spine.
static pandora::CartesianVector GetClosestPointToLine2D(const pandora::CartesianVector &lineStart, const pandora::CartesianVector &lineDirection, const pandora::CaloHit *const pCaloHit)
Consider the hit width to find the closest position of a calo hit to a specified line.
float GetClosestDistance(const pandora::CartesianVector &position, const pandora::CartesianPointVector &testPositions) const
Find the smallest distance between a position and a list of other positions.
pandora::CartesianVector GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
bool CollectSubsectionHits(const TwoDSlidingFitResult &extrapolatedFit, const pandora::CartesianVector &extrapolatedStartPosition, const pandora::CartesianVector &extrapolatedEndPosition, const pandora::CartesianVector &extrapolatedDirection, const bool isEndDownstream, const pandora::CaloHitList *const pViewHitList, pandora::CartesianPointVector &runningFitPositionVector, pandora::CaloHitList &unavailableHitList, pandora::CaloHitList &showerSpineHitList) const
Perform a running fit step: collect hits which lie close to the shower spine projection.
float m_distanceToLine
The max. proximity to the spine projection for collection.
TFile f
Definition: plotHisto.C:6
unsigned int m_highResolutionSlidingFitWindow
The high resolution sliding fit window for spine fits.
Header file for the geometry helper class.
bool IsCloseToLine(const pandora::CartesianVector &hitPosition, const pandora::CartesianVector &lineStart, const pandora::CartesianVector &lineDirection, const float distanceToLine) const
Determine whether a hit lies close to the shower spine projection.
unsigned int m_maxFittingHits
The number of hits to consider in the running fit.
Header file for the lar two dimensional sliding fit result class.
float m_growingFitInitialLength
The first step distance.
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
unsigned int m_hitThresholdForSpine
The hit threshold for a significant spine.
void CollectConnectedHits(const pandora::CaloHitList &collectedHits, const pandora::CartesianVector &extrapolatedStartPosition, const pandora::CartesianVector &extrapolatedDirection, pandora::CartesianPointVector &runningFitPositionVector, pandora::CaloHitList &showerSpineHitList) const
Add to the shower spine the connecting hits.
HitType
Definition: HitType.h:12
pandora::CartesianVector GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
float m_growingFitSegmentLength
The standard step distance.
static float GetClosestDistance(const pandora::CaloHit *const pThisCaloHit, const pandora::CaloHitList &caloHitList)
Find the smallest separation between a hit and a list of hits, with the consideration of their hit wi...
Header file for the peak direction finder tool class.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
unsigned int m_localSlidingFitWindow
The standard sliding fit window for spine fits.