LArSoft  v09_93_00
Liquid Argon Software toolkit - https://larsoft.org/
TestBeamCosmicRayTaggingTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
15 
17 
18 using namespace pandora;
19 
20 namespace lar_content
21 {
22 
23 TestBeamCosmicRayTaggingTool::TestBeamCosmicRayTaggingTool() :
24  m_angularUncertainty(5.f),
25  m_positionalUncertainty(3.f),
26  m_maxAssociationDist(3.f * 18.f),
27  m_minimumHits(15),
28  m_inTimeMargin(5.f),
29  m_inTimeMaxX0(1.f),
30  m_marginY(20.f),
31  m_tagTopEntering(true),
32  m_tagTopToBottom(true),
33  m_tagOutOfTime(true),
34  m_tagInVetoedTPCs(false),
35  m_face_Xa(0.f),
36  m_face_Xc(0.f),
37  m_face_Yb(0.f),
38  m_face_Yt(0.f),
39  m_face_Zu(0.f),
40  m_face_Zd(0.f)
41 {
42 }
43 
44 //------------------------------------------------------------------------------------------------------------------------------------------
45 
47 {
48  return STATUS_CODE_SUCCESS;
49 }
50 
51 //------------------------------------------------------------------------------------------------------------------------------------------
52 
53 void TestBeamCosmicRayTaggingTool::FindAmbiguousPfos(const PfoList &parentCosmicRayPfos, PfoList &ambiguousPfos, const MasterAlgorithm *const /*pAlgorithm*/)
54 {
55  if (this->GetPandora().GetSettings()->ShouldDisplayAlgorithmInfo())
56  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
57 
58  // TODO First time only, TODO Refactor with master algorithm
59  const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
60  const LArTPC *const pFirstLArTPC(larTPCMap.begin()->second);
61 
62  float parentMinX(pFirstLArTPC->GetCenterX() - 0.5f * pFirstLArTPC->GetWidthX());
63  float parentMaxX(pFirstLArTPC->GetCenterX() + 0.5f * pFirstLArTPC->GetWidthX());
64  float parentMinY(pFirstLArTPC->GetCenterY() - 0.5f * pFirstLArTPC->GetWidthY());
65  float parentMaxY(pFirstLArTPC->GetCenterY() + 0.5f * pFirstLArTPC->GetWidthY());
66  float parentMinZ(pFirstLArTPC->GetCenterZ() - 0.5f * pFirstLArTPC->GetWidthZ());
67  float parentMaxZ(pFirstLArTPC->GetCenterZ() + 0.5f * pFirstLArTPC->GetWidthZ());
68 
69  for (const LArTPCMap::value_type &mapEntry : larTPCMap)
70  {
71  const LArTPC *const pLArTPC(mapEntry.second);
72  parentMinX = std::min(parentMinX, pLArTPC->GetCenterX() - 0.5f * pLArTPC->GetWidthX());
73  parentMaxX = std::max(parentMaxX, pLArTPC->GetCenterX() + 0.5f * pLArTPC->GetWidthX());
74  parentMinY = std::min(parentMinY, pLArTPC->GetCenterY() - 0.5f * pLArTPC->GetWidthY());
75  parentMaxY = std::max(parentMaxY, pLArTPC->GetCenterY() + 0.5f * pLArTPC->GetWidthY());
76  parentMinZ = std::min(parentMinZ, pLArTPC->GetCenterZ() - 0.5f * pLArTPC->GetWidthZ());
77  parentMaxZ = std::max(parentMaxZ, pLArTPC->GetCenterZ() + 0.5f * pLArTPC->GetWidthZ());
78  }
79 
80  m_face_Xa = parentMinX;
81  m_face_Xc = parentMaxX;
82  m_face_Yb = parentMinY;
83  m_face_Yt = parentMaxY;
84  m_face_Zu = parentMinZ;
85  m_face_Zd = parentMaxZ;
86 
87  PfoToPfoListMap pfoAssociationMap;
88  this->GetPfoAssociations(parentCosmicRayPfos, pfoAssociationMap);
89 
90  PfoToSliceIdMap pfoToSliceIdMap;
91  this->SliceEvent(parentCosmicRayPfos, pfoAssociationMap, pfoToSliceIdMap);
92 
93  CRCandidateList candidates;
94  this->GetCRCandidates(parentCosmicRayPfos, pfoToSliceIdMap, candidates);
95 
96  // Create a map that will be used to find all cosmic ray pfos
97  PfoToBoolMap pfoToIsCosmicRayMap;
98  for (const CRCandidate &candidate : candidates)
99  {
100  pfoToIsCosmicRayMap[candidate.m_pPfo] = false;
101  }
102 
103  // Tag all particles appearing to enter from the top
104  if (m_tagTopEntering)
105  this->CheckIfTopEntering(candidates, pfoToIsCosmicRayMap);
106 
107  // Tag particles going from top to bottom
108  if (m_tagTopToBottom)
109  this->CheckIfTopToBottom(candidates, pfoToIsCosmicRayMap);
110 
111  // Tag particles with t0 != 0 or appears outside the detector with t0 = 0
112  if (m_tagOutOfTime)
113  this->CheckIfOutOfTime(candidates, pfoToIsCosmicRayMap);
114 
115  // Tag particles with their highest point in a given list of TPCs
116  if (m_tagInVetoedTPCs)
117  this->CheckIfInVetoedTPC(candidates, pfoToIsCosmicRayMap);
118 
119  for (const ParticleFlowObject *const pPfo : parentCosmicRayPfos)
120  {
121  if (!pfoToIsCosmicRayMap.at(pPfo))
122  ambiguousPfos.push_back(pPfo);
123  }
124 }
125 
126 //------------------------------------------------------------------------------------------------------------------------------------------
127 
128 bool TestBeamCosmicRayTaggingTool::GetValid3DCluster(const ParticleFlowObject *const pPfo, const Cluster *&pCluster3D) const
129 {
130  pCluster3D = nullptr;
131  ClusterList clusters3D;
132  LArPfoHelper::GetThreeDClusterList(pPfo, clusters3D);
133 
134  // ATTN Only uses first cluster with hits of type TPC_3D
135  if (clusters3D.empty() || (clusters3D.front()->GetNCaloHits() < m_minimumHits))
136  return false;
137 
138  pCluster3D = clusters3D.front();
139  return true;
140 }
141 
142 //------------------------------------------------------------------------------------------------------------------------------------------
143 
144 void TestBeamCosmicRayTaggingTool::GetPfoAssociations(const PfoList &parentCosmicRayPfos, PfoToPfoListMap &pfoAssociationMap) const
145 {
146  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
147  const LArTPC *const pFirstLArTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
148  const float layerPitch(pFirstLArTPC->GetWirePitchW());
149 
150  PfoToSlidingFitsMap pfoToSlidingFitsMap;
151 
152  for (const ParticleFlowObject *const pPfo : parentCosmicRayPfos)
153  {
154  const pandora::Cluster *pCluster(nullptr);
155  if (!this->GetValid3DCluster(pPfo, pCluster) || !pCluster)
156  continue;
157 
158  pfoToSlidingFitsMap.insert(PfoToSlidingFitsMap::value_type(pPfo,
159  std::make_pair(ThreeDSlidingFitResult(pCluster, 5, layerPitch), ThreeDSlidingFitResult(pCluster, 100, layerPitch)))); // TODO Configurable
160  }
161 
162  for (const ParticleFlowObject *const pPfo1 : parentCosmicRayPfos)
163  {
164  PfoToSlidingFitsMap::const_iterator iter1(pfoToSlidingFitsMap.find(pPfo1));
165  if (pfoToSlidingFitsMap.end() == iter1)
166  continue;
167 
168  const ThreeDSlidingFitResult &fitPos1(iter1->second.first), &fitDir1(iter1->second.second);
169 
170  for (const ParticleFlowObject *const pPfo2 : parentCosmicRayPfos)
171  {
172  if (pPfo1 == pPfo2)
173  continue;
174 
175  PfoToSlidingFitsMap::const_iterator iter2(pfoToSlidingFitsMap.find(pPfo2));
176  if (pfoToSlidingFitsMap.end() == iter2)
177  continue;
178 
179  const ThreeDSlidingFitResult &fitPos2(iter2->second.first), &fitDir2(iter2->second.second);
180 
181  // TODO Use existing LArPointingClusters and IsEmission/IsNode logic, for consistency
182  if (!(this->CheckAssociation(fitPos1.GetGlobalMinLayerPosition(), fitDir1.GetGlobalMinLayerDirection() * -1.f,
183  fitPos2.GetGlobalMinLayerPosition(), fitDir2.GetGlobalMinLayerDirection() * -1.f) ||
184  this->CheckAssociation(fitPos1.GetGlobalMinLayerPosition(), fitDir1.GetGlobalMinLayerDirection() * -1.f,
185  fitPos2.GetGlobalMaxLayerPosition(), fitDir2.GetGlobalMaxLayerDirection()) ||
186  this->CheckAssociation(fitPos1.GetGlobalMaxLayerPosition(), fitDir1.GetGlobalMaxLayerDirection(),
187  fitPos2.GetGlobalMinLayerPosition(), fitDir2.GetGlobalMinLayerDirection() * -1.f) ||
188  this->CheckAssociation(fitPos1.GetGlobalMaxLayerPosition(), fitDir1.GetGlobalMaxLayerDirection(),
189  fitPos2.GetGlobalMaxLayerPosition(), fitDir2.GetGlobalMaxLayerDirection())))
190  {
191  continue;
192  }
193 
194  PfoList &pfoList1(pfoAssociationMap[pPfo1]), &pfoList2(pfoAssociationMap[pPfo2]);
195 
196  if (pfoList1.end() == std::find(pfoList1.begin(), pfoList1.end(), pPfo2))
197  pfoList1.push_back(pPfo2);
198 
199  if (pfoList2.end() == std::find(pfoList2.begin(), pfoList2.end(), pPfo1))
200  pfoList2.push_back(pPfo1);
201  }
202  }
203 }
204 
205 //------------------------------------------------------------------------------------------------------------------------------------------
206 
208  const CartesianVector &endPoint1, const CartesianVector &endDir1, const CartesianVector &endPoint2, const CartesianVector &endDir2) const
209 {
210  // TODO This function needs significant tidying and checks (variable names must be self describing, check deltaTheta, etc.)
211  const CartesianVector n(endDir1.GetUnitVector());
212  const CartesianVector m(endDir2.GetUnitVector());
213  const CartesianVector a(endPoint2 - endPoint1);
214  const float b(n.GetDotProduct(m));
215 
216  // Parallel lines never meet
217  if (std::fabs(b - 1.f) < std::numeric_limits<float>::epsilon())
218  return false;
219 
220  // Distance from endPoint1 along endDir1 to the point of closest approach
221  const float lambda((n - m * b).GetDotProduct(a) / (1.f - b * b));
222 
223  // Distance from endPoint2 along endDir2 to the point of closest approach
224  const float mu((n * b - m).GetDotProduct(a) / (1.f - b * b));
225 
226  // Calculate the maximum "vertex uncertainty"
227  const float deltaTheta(m_angularUncertainty * M_PI / 180.f);
228  const float maxVertexUncertainty(m_maxAssociationDist * std::sin(deltaTheta) + m_positionalUncertainty);
229 
230  // Ensure that the distances to the point of closest approch are within the limits
231  if ((lambda < -maxVertexUncertainty) || (mu < -maxVertexUncertainty) || (lambda > m_maxAssociationDist + maxVertexUncertainty) ||
232  (mu > m_maxAssociationDist + maxVertexUncertainty))
233  {
234  return false;
235  }
236 
237  // Ensure point of closest approach is within detector
238  const CartesianVector impactPosition((endPoint1 + n * lambda + endPoint2 + m * mu) * 0.5f);
239 
240  if ((impactPosition.GetX() < m_face_Xa - maxVertexUncertainty) || (impactPosition.GetX() > m_face_Xc + maxVertexUncertainty) ||
241  (impactPosition.GetY() < m_face_Yb - maxVertexUncertainty) || (impactPosition.GetY() > m_face_Yt + maxVertexUncertainty) ||
242  (impactPosition.GetZ() < m_face_Zu - maxVertexUncertainty) || (impactPosition.GetZ() > m_face_Zd + maxVertexUncertainty))
243  {
244  return false;
245  }
246 
247  // Compare distance of closest approach and max uncertainty in impact parameter
248  const float maxImpactDist(std::sin(deltaTheta) * (std::fabs(mu) + std::fabs(lambda)) + m_positionalUncertainty);
249  const CartesianVector d(a - n * lambda + m * mu);
250 
251  return (d.GetMagnitude() < maxImpactDist);
252 }
253 
254 //------------------------------------------------------------------------------------------------------------------------------------------
255 
257  const PfoList &parentCosmicRayPfos, const PfoToPfoListMap &pfoAssociationMap, PfoToSliceIdMap &pfoToSliceIdMap) const
258 {
259  SliceList sliceList;
260 
261  for (const ParticleFlowObject *const pPfo : parentCosmicRayPfos)
262  {
263  bool isAlreadyInSlice(false);
264 
265  for (const PfoList &slice : sliceList)
266  {
267  if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
268  {
269  isAlreadyInSlice = true;
270  break;
271  }
272  }
273 
274  if (!isAlreadyInSlice)
275  {
276  sliceList.push_back(PfoList());
277  this->FillSlice(pPfo, pfoAssociationMap, sliceList.back());
278  }
279  }
280 
281  unsigned int sliceId(0);
282  for (const PfoList &slice : sliceList)
283  {
284  for (const ParticleFlowObject *const pPfo : slice)
285  {
286  if (!pfoToSliceIdMap.insert(PfoToSliceIdMap::value_type(pPfo, sliceId)).second)
287  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
288  }
289 
290  ++sliceId;
291  }
292 }
293 
294 //------------------------------------------------------------------------------------------------------------------------------------------
295 
296 void TestBeamCosmicRayTaggingTool::FillSlice(const ParticleFlowObject *const pPfo, const PfoToPfoListMap &pfoAssociationMap, PfoList &slice) const
297 {
298  if (std::find(slice.begin(), slice.end(), pPfo) != slice.end())
299  return;
300 
301  slice.emplace_back(pPfo);
302 
303  PfoToPfoListMap::const_iterator iter(pfoAssociationMap.find(pPfo));
304 
305  if (pfoAssociationMap.end() != iter)
306  {
307  for (const ParticleFlowObject *const pAssociatedPfo : iter->second)
308  this->FillSlice(pAssociatedPfo, pfoAssociationMap, slice);
309  }
310 }
311 
312 //------------------------------------------------------------------------------------------------------------------------------------------
313 
315  const PfoList &parentCosmicRayPfos, const PfoToSliceIdMap &pfoToSliceIdMap, CRCandidateList &candidates) const
316 {
317  for (const ParticleFlowObject *const pPfo : parentCosmicRayPfos)
318  {
319  if (!LArPfoHelper::IsFinalState(pPfo))
320  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
321 
322  candidates.emplace_back(CRCandidate(this->GetPandora(), pPfo, pfoToSliceIdMap.at(pPfo)));
323  }
324 }
325 
326 //------------------------------------------------------------------------------------------------------------------------------------------
327 
328 void TestBeamCosmicRayTaggingTool::CheckIfOutOfTime(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
329 {
330  const LArTPCMap &larTPCMap(this->GetPandora().GetGeometry()->GetLArTPCMap());
331 
332  for (const CRCandidate &candidate : candidates)
333  {
334  // Move on if this candidate has already been tagged
335  if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
336  continue;
337  // Cosmic-ray muons extending outside of (single) physical volume if given t0 is that of the beam particle
338  float minX(std::numeric_limits<float>::max()), maxX(-std::numeric_limits<float>::max());
339 
340  if (candidate.m_canFit)
341  {
342  minX = ((candidate.m_endPoint1.GetX() < candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
343  maxX = ((candidate.m_endPoint1.GetX() > candidate.m_endPoint2.GetX()) ? candidate.m_endPoint1.GetX() : candidate.m_endPoint2.GetX());
344  }
345  else
346  {
347  // Handle any particles with small numbers of 3D hits, for which no 3D sliding fit information is available
348  for (const Cluster *const pCluster : candidate.m_pPfo->GetClusterList())
349  {
350  float clusterMinX(std::numeric_limits<float>::max()), clusterMaxX(-std::numeric_limits<float>::max());
351  pCluster->GetClusterSpanX(clusterMinX, clusterMaxX);
352  minX = std::min(clusterMinX, minX);
353  maxX = std::max(clusterMaxX, maxX);
354  }
355  }
356 
357  bool isInTime((minX > m_face_Xa - m_inTimeMargin) && (maxX < m_face_Xc + m_inTimeMargin));
358 
359  // Cosmic-ray muons that have been shifted and stitched across mid plane between volumes
360  if (isInTime)
361  {
362  try
363  {
364  if (std::fabs(LArPfoHelper::GetVertex(candidate.m_pPfo)->GetX0()) > m_inTimeMaxX0)
365  isInTime = false;
366  }
367  catch (const StatusCodeException &)
368  {
369  }
370  }
371 
372  // Cosmic-ray muons extending outside of (any individual) physical volume if given t0 is that of the beam particle
373  if (isInTime)
374  {
375  CaloHitList caloHitList;
376  LArPfoHelper::GetCaloHits(candidate.m_pPfo, TPC_VIEW_U, caloHitList);
377  LArPfoHelper::GetCaloHits(candidate.m_pPfo, TPC_VIEW_V, caloHitList);
378  LArPfoHelper::GetCaloHits(candidate.m_pPfo, TPC_VIEW_W, caloHitList);
379 
380  bool isFirstHit(true);
381  bool isInSingleVolume(true);
382  unsigned int volumeId(std::numeric_limits<unsigned int>::max());
383 
384  for (const CaloHit *const pCaloHit : caloHitList)
385  {
386  const LArCaloHit *const pLArCaloHit(dynamic_cast<const LArCaloHit *>(pCaloHit));
387 
388  if (!pLArCaloHit)
389  continue;
390 
391  if (isFirstHit)
392  {
393  isFirstHit = false;
394  volumeId = pLArCaloHit->GetLArTPCVolumeId();
395  }
396  else if (volumeId != pLArCaloHit->GetLArTPCVolumeId())
397  {
398  isInSingleVolume = false;
399  break;
400  }
401  }
402 
403  LArTPCMap::const_iterator tpcIter(larTPCMap.find(volumeId));
404 
405  if (isInSingleVolume && (larTPCMap.end() != tpcIter))
406  {
407  const float thisFaceXLow(tpcIter->second->GetCenterX() - 0.5f * tpcIter->second->GetWidthX());
408  const float thisFaceXHigh(tpcIter->second->GetCenterX() + 0.5f * tpcIter->second->GetWidthX());
409 
410  if (!((minX > thisFaceXLow - m_inTimeMargin) && (maxX < thisFaceXHigh + m_inTimeMargin)))
411  isInTime = false;
412  }
413  }
414 
415  pfoToIsCosmicRayMap[candidate.m_pPfo] = !isInTime;
416  }
417 }
418 
419 //------------------------------------------------------------------------------------------------------------------------------------------
420 
421 void TestBeamCosmicRayTaggingTool::CheckIfTopToBottom(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
422 {
423  for (const CRCandidate &candidate : candidates)
424  {
425  // Move on if this candidate has already been tagged
426  if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
427  continue;
428  const float upperY(
429  (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
430  const float lowerY(
431  (candidate.m_endPoint1.GetY() < candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
432 
433  pfoToIsCosmicRayMap[candidate.m_pPfo] = ((upperY > m_face_Yt - m_marginY) && (lowerY < m_face_Yb + m_marginY));
434  }
435 }
436 
437 //------------------------------------------------------------------------------------------------------------------------------------------
438 
439 void TestBeamCosmicRayTaggingTool::CheckIfTopEntering(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
440 {
441  for (const CRCandidate &candidate : candidates)
442  {
443  // Move on if this candidate has already been tagged
444  if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
445  continue;
446  const float upperY(
447  (candidate.m_endPoint1.GetY() > candidate.m_endPoint2.GetY()) ? candidate.m_endPoint1.GetY() : candidate.m_endPoint2.GetY());
448  pfoToIsCosmicRayMap[candidate.m_pPfo] = (upperY > m_face_Yt - m_marginY);
449  }
450 }
451 
452 //------------------------------------------------------------------------------------------------------------------------------------------
453 
454 void TestBeamCosmicRayTaggingTool::CheckIfInVetoedTPC(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
455 {
456  if (m_vetoedTPCs.empty())
457  return;
458 
459  for (const CRCandidate &candidate : candidates)
460  {
461  // Move on if this candidate has already been tagged
462  if (pfoToIsCosmicRayMap.at(candidate.m_pPfo))
463  continue;
464 
465  // We have to go via the hit volume id to get the TPC
466  CaloHitList caloHitList3D;
467  LArPfoHelper::GetCaloHits(candidate.m_pPfo, TPC_3D, caloHitList3D);
468 
469  float maxYPosition{-1.f * std::numeric_limits<float>::max()};
470  unsigned int maxYTPCId{std::numeric_limits<unsigned int>::max()};
471  for (const CaloHit *const pCaloHit : caloHitList3D)
472  {
473  const float hitYPos(pCaloHit->GetPositionVector().GetY());
474  if (maxYPosition < hitYPos)
475  {
476  maxYPosition = hitYPos;
477  const LArCaloHit *const pLArCaloHit{reinterpret_cast<LArCaloHit *>(const_cast<void *>(pCaloHit->GetParentAddress()))};
478  const unsigned int maxYDriftVol = pLArCaloHit->GetLArTPCVolumeId();
479  const unsigned int maxYAPA = pLArCaloHit->GetDaughterVolumeId();
480  maxYTPCId = maxYDriftVol + maxYAPA * 4;
481  }
482  }
483  if (std::find(m_vetoedTPCs.begin(), m_vetoedTPCs.end(), maxYTPCId) != m_vetoedTPCs.end())
484  pfoToIsCosmicRayMap[candidate.m_pPfo] = true;
485  }
486 }
487 
488 //------------------------------------------------------------------------------------------------------------------------------------------
489 //------------------------------------------------------------------------------------------------------------------------------------------
490 
491 TestBeamCosmicRayTaggingTool::CRCandidate::CRCandidate(const Pandora &pandora, const ParticleFlowObject *const pPfo, const unsigned int sliceId) :
492  m_pPfo(pPfo),
493  m_sliceId(sliceId),
494  m_canFit(false),
495  m_endPoint1(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
496  m_endPoint2(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
497  m_length(std::numeric_limits<float>::max()),
498  m_curvature(std::numeric_limits<float>::max()),
499  m_theta(std::numeric_limits<float>::max())
500 {
501  ClusterList clusters3D;
502  LArPfoHelper::GetThreeDClusterList(pPfo, clusters3D);
503 
504  if (!clusters3D.empty() && (clusters3D.front()->GetNCaloHits() > 15)) // TODO Configurable
505  {
506  m_canFit = true;
507  const LArTPC *const pFirstLArTPC(pandora.GetGeometry()->GetLArTPCMap().begin()->second);
508  const ThreeDSlidingFitResult slidingFitResult(clusters3D.front(), 5, pFirstLArTPC->GetWirePitchW()); // TODO Configurable
509  this->CalculateFitVariables(slidingFitResult);
510  }
511 }
512 
513 //------------------------------------------------------------------------------------------------------------------------------------------
514 
516 {
517  m_endPoint1 = slidingFitResult.GetGlobalMinLayerPosition();
518  m_endPoint2 = slidingFitResult.GetGlobalMaxLayerPosition();
519  m_length = (m_endPoint2 - m_endPoint1).GetMagnitude();
520 
521  if (std::fabs(m_length) > std::numeric_limits<float>::epsilon())
522  m_theta = std::fabs(m_endPoint2.GetY() - m_endPoint1.GetY()) / m_length;
523 
524  const float layerPitch(slidingFitResult.GetFirstFitResult().GetLayerPitch());
525 
526  CartesianPointVector directionList;
527  for (int i = slidingFitResult.GetMinLayer(); i < slidingFitResult.GetMaxLayer(); ++i)
528  {
529  CartesianVector direction(0.f, 0.f, 0.f);
530  if (STATUS_CODE_SUCCESS == slidingFitResult.GetGlobalFitDirection(static_cast<float>(i) * layerPitch, direction))
531  directionList.push_back(direction);
532  }
533 
534  CartesianVector meanDirection(0.f, 0.f, 0.f);
535  for (const CartesianVector &direction : directionList)
536  meanDirection += direction;
537 
538  if (!directionList.empty() > 0)
539  meanDirection *= 1.f / static_cast<float>(directionList.size());
540 
541  m_curvature = 0.f;
542  for (const CartesianVector &direction : directionList)
543  m_curvature += (direction - meanDirection).GetMagnitude();
544 
545  if (!directionList.empty() > 0)
546  m_curvature *= 1.f / static_cast<float>(directionList.size());
547 }
548 
549 //------------------------------------------------------------------------------------------------------------------------------------------
550 
551 StatusCode TestBeamCosmicRayTaggingTool::ReadSettings(const TiXmlHandle xmlHandle)
552 {
553  PANDORA_RETURN_RESULT_IF_AND_IF(
554  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "AngularUncertainty", m_angularUncertainty));
555 
556  PANDORA_RETURN_RESULT_IF_AND_IF(
557  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "PositionalUncertainty", m_positionalUncertainty));
558 
559  PANDORA_RETURN_RESULT_IF_AND_IF(
560  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxAssociationDist", m_maxAssociationDist));
561 
562  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HitThreshold", m_minimumHits));
563 
564  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "InTimeMargin", m_inTimeMargin));
565 
566  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "InTimeMaxX0", m_inTimeMaxX0));
567 
568  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MarginY", m_marginY));
569 
570  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "TagTopEntering", m_tagTopEntering));
571  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "TagTopToBottom", m_tagTopToBottom));
572  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "TagOutOfTime", m_tagOutOfTime));
573 
574  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "TagInVetoedTPCs", m_tagInVetoedTPCs));
575  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "VetoedTPCs", m_vetoedTPCs));
576 
577  return STATUS_CODE_SUCCESS;
578 }
579 
580 } // namespace lar_content
bool m_canFit
If there are a sufficient number of 3D hits to perform a fitting.
void GetCRCandidates(const pandora::PfoList &parentCosmicRayPfos, const PfoToSliceIdMap &pfoToSliceIdMap, CRCandidateList &candidates) const
Make a list of CRCandidates.
Header file for the pfo helper class.
std::unordered_map< const pandora::ParticleFlowObject *, bool > PfoToBoolMap
const pandora::CartesianVector & GetGlobalMinLayerDirection() const
Get global direction corresponding to the fit result in minimum fit layer.
pandora::CartesianVector m_endPoint2
Second fitted end point in 3D.
Header file for the lar calo hit class.
float m_marginY
The minimum distance from a detector Y-face for a Pfo to be associated.
void FindAmbiguousPfos(const pandora::PfoList &parentCosmicRayPfos, pandora::PfoList &ambiguousPfos, const MasterAlgorithm *const pAlgorithm)
Find the list of ambiguous pfos (could represent cosmic-ray muons or neutrinos)
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
float m_angularUncertainty
The uncertainty in degrees for the angle of a Pfo.
STL namespace.
intermediate_table::const_iterator const_iterator
double m_length
Straight line length of the linear fit.
unsigned int GetLArTPCVolumeId() const
Get the lar tpc volume id.
Definition: LArCaloHit.h:167
void CheckIfInVetoedTPC(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate has its highest value in one of the vetoed TPC volumes.
double m_curvature
Measure of the curvature of the track.
void SliceEvent(const pandora::PfoList &parentCosmicRayPfos, const PfoToPfoListMap &pfoAssociationMap, PfoToSliceIdMap &pfoToSliceIdMap) const
Break the event up into slices of associated Pfos.
LAr calo hit class.
Definition: LArCaloHit.h:39
CRCandidate(const pandora::Pandora &pandora, const pandora::ParticleFlowObject *const pPfo, const unsigned int sliceId)
Constructor.
TFile f
Definition: plotHisto.C:6
bool GetValid3DCluster(const pandora::ParticleFlowObject *const pPfo, const pandora::Cluster *&pCluster3D) const
Get the 3D calo hit cluster associated with a given Pfo, and check if it has sufficient hits...
void GetPfoAssociations(const pandora::PfoList &parentCosmicRayPfos, PfoToPfoListMap &pfoAssociationMap) const
Get mapping between Pfos that are associated with each other by pointing.
Header file for the cluster helper class.
const pandora::CartesianVector & GetGlobalMaxLayerDirection() const
Get global direction corresponding to the fit result in maximum fit layer.
unsigned int m_minimumHits
The minimum number of hits for a Pfo to be considered.
pandora::StatusCode GetGlobalFitDirection(const float rL, pandora::CartesianVector &direction) const
Get global fit direction for a given longitudinal coordinate.
bool CheckAssociation(const pandora::CartesianVector &endPoint1, const pandora::CartesianVector &endDir1, const pandora::CartesianVector &endPoint2, const pandora::CartesianVector &endDir2) const
Check whethe two Pfo endpoints are associated by distance of closest approach.
Float_t d
Definition: plot.C:235
float GetLayerPitch() const
Get the layer pitch, units cm.
float m_inTimeMargin
The maximum distance outside of the physical detector volume that a Pfo may be to still be considered...
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
const pandora::CartesianVector & GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
bool m_tagOutOfTime
Whether to tag all out-of-time particles as cosmic rays.
float m_inTimeMaxX0
The maximum pfo x0 (determined from shifted vertex) to allow pfo to still be considered in time...
void FillSlice(const pandora::ParticleFlowObject *const pPfo, const PfoToPfoListMap &pfoAssociationMap, pandora::PfoList &slice) const
Fill a slice iteratively using Pfo associations.
bool m_tagTopEntering
Whether to tag all top entering particles as cosmic rays.
MasterAlgorithm class.
std::unordered_map< const pandora::ParticleFlowObject *, pandora::PfoList > PfoToPfoListMap
static bool IsFinalState(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a primary parent particle.
const TwoDSlidingFitResult & GetFirstFitResult() const
Get the first sliding fit result for this cluster.
float m_maxAssociationDist
The maximum distance from endpoint to point of closest approach, typically a multiple of LAr radiatio...
pandora::CartesianVector m_endPoint1
First fitted end point in 3D.
bool m_tagInVetoedTPCs
Whether to tag all particles with their highest position in vetoed TPCs as cosmic rays...
std::unordered_map< const pandora::ParticleFlowObject *, unsigned int > PfoToSliceIdMap
Char_t n[5]
void CalculateFitVariables(const ThreeDSlidingFitResult &slidingFitResult)
Calculate all variables which require a fit.
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
Class to encapsulate the logic required determine if a Pfo should or shouldn&#39;t be tagged as a cosmic ...
void CheckIfTopEntering(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate enters from the top of the detector.
Header file for the cosmic-ray tagging tool class.
void CheckIfOutOfTime(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate is "in time".
bool m_tagTopToBottom
Whether to tag all top-to-bottom particles as cosmic rays.
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:82
std::vector< unsigned int > m_vetoedTPCs
List of vetoed TPCs for tagging cosmic rays.
void CheckIfTopToBottom(const CRCandidateList &candidates, PfoToBoolMap &pfoToIsCosmicRayMap) const
Check if each candidate is "top to bottom".
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.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::ParticleFlowObject *, SlidingFitPair > PfoToSlidingFitsMap
float m_positionalUncertainty
The uncertainty in cm for the position of Pfo endpoint in 3D.
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.