LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
TrackShowerIdFeatureTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 #include "Pandora/StatusCodes.h"
11 
16 
18 
21 
22 using namespace pandora;
23 
24 namespace lar_content
25 {
26 
27 TwoDShowerFitFeatureTool::TwoDShowerFitFeatureTool() :
28  m_slidingShowerFitWindow(3),
29  m_slidingLinearFitWindow(10000)
30 {
31 }
32 
33 //------------------------------------------------------------------------------------------------------------------------------------------
34 
35 void TwoDShowerFitFeatureTool::Run(LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
36 {
37  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
38  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
39 
40  float ratio(-1.f);
41  try
42  {
43  const TwoDSlidingFitResult slidingFitResultLarge(pCluster, m_slidingLinearFitWindow, LArGeometryHelper::GetWireZPitch(this->GetPandora()));
44  const float straightLineLength =
45  (slidingFitResultLarge.GetGlobalMaxLayerPosition() - slidingFitResultLarge.GetGlobalMinLayerPosition()).GetMagnitude();
46  if (straightLineLength > std::numeric_limits<float>::epsilon())
47  ratio = (CutClusterCharacterisationAlgorithm::GetShowerFitWidth(pAlgorithm, pCluster, m_slidingShowerFitWindow)) / straightLineLength;
48  }
49  catch (const StatusCodeException &)
50  {
51  ratio = -1.f;
52  }
53  featureVector.push_back(ratio);
54 }
55 
56 //------------------------------------------------------------------------------------------------------------------------------------------
57 
58 void TwoDShowerFitFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder, const std::string &featureToolName,
59  const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
60 {
61  LArMvaHelper::MvaFeatureVector toolFeatureVec;
62  this->Run(toolFeatureVec, pAlgorithm, pCluster);
63 
64  if (featureMap.find(featureToolName + "_WidthLenRatio") != featureMap.end())
65  {
66  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
67  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
68  }
69 
70  featureOrder.push_back(featureToolName + "_WidthLenRatio");
71  featureMap[featureToolName + "_WidthLenRatio"] = toolFeatureVec[0];
72 }
73 
74 //------------------------------------------------------------------------------------------------------------------------------------------
75 
76 StatusCode TwoDShowerFitFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
77 {
78  PANDORA_RETURN_RESULT_IF_AND_IF(
79  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingShowerFitWindow", m_slidingShowerFitWindow));
80 
81  PANDORA_RETURN_RESULT_IF_AND_IF(
82  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingLinearFitWindow", m_slidingLinearFitWindow));
83 
84  return STATUS_CODE_SUCCESS;
85 }
86 
87 //------------------------------------------------------------------------------------------------------------------------------------------
88 //------------------------------------------------------------------------------------------------------------------------------------------
89 
92  m_slidingLinearFitWindowLarge(10000)
93 {
94 }
95 
96 //------------------------------------------------------------------------------------------------------------------------------------------
97 
98 void TwoDLinearFitFeatureTool::Run(LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
99 {
100  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
101  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
102 
103  float dTdLWidth(-1.f), straightLineLengthLarge(-1.f), diffWithStraightLineMean(-1.f), diffWithStraightLineSigma(-1.f),
104  maxFitGapLength(-1.f), rmsSlidingLinearFit(-1.f);
105  this->CalculateVariablesSlidingLinearFit(pCluster, straightLineLengthLarge, diffWithStraightLineMean, diffWithStraightLineSigma,
106  dTdLWidth, maxFitGapLength, rmsSlidingLinearFit);
107 
108  if (straightLineLengthLarge > std::numeric_limits<float>::epsilon())
109  {
110  diffWithStraightLineMean /= straightLineLengthLarge;
111  diffWithStraightLineSigma /= straightLineLengthLarge;
112  dTdLWidth /= straightLineLengthLarge;
113  maxFitGapLength /= straightLineLengthLarge;
114  rmsSlidingLinearFit /= straightLineLengthLarge;
115  }
116 
117  featureVector.push_back(straightLineLengthLarge);
118  featureVector.push_back(diffWithStraightLineMean);
119  featureVector.push_back(diffWithStraightLineSigma);
120  featureVector.push_back(dTdLWidth);
121  featureVector.push_back(maxFitGapLength);
122  featureVector.push_back(rmsSlidingLinearFit);
123 }
124 
125 //------------------------------------------------------------------------------------------------------------------------------------------
126 
127 void TwoDLinearFitFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder, const std::string &featureToolName,
128  const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
129 {
130  LArMvaHelper::MvaFeatureVector toolFeatureVec;
131  this->Run(toolFeatureVec, pAlgorithm, pCluster);
132 
133  if (featureMap.find(featureToolName + "_StLineLenLarge") != featureMap.end() ||
134  featureMap.find(featureToolName + "_DiffStLineMean") != featureMap.end() ||
135  featureMap.find(featureToolName + "_DiffStLineSigma") != featureMap.end() ||
136  featureMap.find(featureToolName + "_dTdLWidth") != featureMap.end() ||
137  featureMap.find(featureToolName + "_MaxFitGapLen") != featureMap.end() ||
138  featureMap.find(featureToolName + "_rmsSlidingLinFit") != featureMap.end())
139  {
140  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
141  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
142  }
143 
144  featureOrder.push_back(featureToolName + "_StLineLenLarge");
145  featureOrder.push_back(featureToolName + "_DiffStLineMean");
146  featureOrder.push_back(featureToolName + "_DiffStLineSigma");
147  featureOrder.push_back(featureToolName + "_dTdLWidth");
148  featureOrder.push_back(featureToolName + "_MaxFitGapLen");
149  featureOrder.push_back(featureToolName + "_rmsSlidingLinFit");
150 
151  featureMap[featureToolName + "_StLineLenLarge"] = toolFeatureVec[0];
152  featureMap[featureToolName + "_DiffStLineMean"] = toolFeatureVec[1];
153  featureMap[featureToolName + "_DiffStLineSigma"] = toolFeatureVec[2];
154  featureMap[featureToolName + "_dTdLWidth"] = toolFeatureVec[3];
155  featureMap[featureToolName + "_MaxFitGapLen"] = toolFeatureVec[4];
156  featureMap[featureToolName + "_rmsSlidingLinFit"] = toolFeatureVec[5];
157 }
158 
159 //------------------------------------------------------------------------------------------------------------------------------------------
160 
161 void TwoDLinearFitFeatureTool::CalculateVariablesSlidingLinearFit(const pandora::Cluster *const pCluster, float &straightLineLengthLarge,
162  float &diffWithStraightLineMean, float &diffWithStraightLineSigma, float &dTdLWidth, float &maxFitGapLength, float &rmsSlidingLinearFit) const
163 {
164  try
165  {
166  const TwoDSlidingFitResult slidingFitResult(pCluster, m_slidingLinearFitWindow, LArGeometryHelper::GetWireZPitch(this->GetPandora()));
167  const TwoDSlidingFitResult slidingFitResultLarge(
168  pCluster, m_slidingLinearFitWindowLarge, LArGeometryHelper::GetWireZPitch(this->GetPandora()));
169 
170  if (slidingFitResult.GetLayerFitResultMap().empty())
171  throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
172 
173  straightLineLengthLarge =
174  (slidingFitResultLarge.GetGlobalMaxLayerPosition() - slidingFitResultLarge.GetGlobalMinLayerPosition()).GetMagnitude();
175  rmsSlidingLinearFit = 0.f;
176 
177  FloatVector diffWithStraightLineVector;
178  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
179  CartesianVector previousFitPosition(slidingFitResult.GetGlobalMinLayerPosition());
180  float dTdLMin(+std::numeric_limits<float>::max()), dTdLMax(-std::numeric_limits<float>::max());
181 
182  for (const auto &mapEntry : slidingFitResult.GetLayerFitResultMap())
183  {
184  const LayerFitResult &layerFitResult(mapEntry.second);
185  rmsSlidingLinearFit += layerFitResult.GetRms();
186 
187  CartesianVector thisFitPosition(0.f, 0.f, 0.f);
188  slidingFitResult.GetGlobalPosition(layerFitResult.GetL(), layerFitResult.GetFitT(), thisFitPosition);
189 
191  slidingFitResultLarge.GetLayerFitResultMap().find(slidingFitResultLarge.GetLayer(layerFitResult.GetL()));
192 
193  if (slidingFitResultLarge.GetLayerFitResultMap().end() == iterLarge)
194  throw StatusCodeException(STATUS_CODE_FAILURE);
195 
196  diffWithStraightLineVector.push_back(static_cast<float>(std::fabs(layerFitResult.GetFitT() - iterLarge->second.GetFitT())));
197 
198  const float thisGapLength((thisFitPosition - previousFitPosition).GetMagnitude());
199  const float minZ(std::min(thisFitPosition.GetZ(), previousFitPosition.GetZ()));
200  const float maxZ(std::max(thisFitPosition.GetZ(), previousFitPosition.GetZ()));
201 
202  if ((maxZ - minZ) > std::numeric_limits<float>::epsilon())
203  {
204  const float gapZ(LArGeometryHelper::CalculateGapDeltaZ(this->GetPandora(), minZ, maxZ, hitType));
205  const float correctedGapLength(thisGapLength * (1.f - gapZ / (maxZ - minZ)));
206 
207  if (correctedGapLength > maxFitGapLength)
208  maxFitGapLength = correctedGapLength;
209  }
210 
211  dTdLMin = std::min(dTdLMin, static_cast<float>(layerFitResult.GetGradient()));
212  dTdLMax = std::max(dTdLMax, static_cast<float>(layerFitResult.GetGradient()));
213  previousFitPosition = thisFitPosition;
214  }
215 
216  if (diffWithStraightLineVector.empty())
217  throw StatusCodeException(STATUS_CODE_FAILURE);
218 
219  diffWithStraightLineMean = 0.f;
220  diffWithStraightLineSigma = 0.f;
221 
222  for (const float diffWithStraightLine : diffWithStraightLineVector)
223  diffWithStraightLineMean += diffWithStraightLine;
224 
225  diffWithStraightLineMean /= static_cast<float>(diffWithStraightLineVector.size());
226 
227  for (const float diffWithStraightLine : diffWithStraightLineVector)
228  diffWithStraightLineSigma += (diffWithStraightLine - diffWithStraightLineMean) * (diffWithStraightLine - diffWithStraightLineMean);
229 
230  if (diffWithStraightLineSigma < 0.f)
231  throw StatusCodeException(STATUS_CODE_FAILURE);
232 
233  diffWithStraightLineSigma = std::sqrt(diffWithStraightLineSigma / static_cast<float>(diffWithStraightLineVector.size()));
234  dTdLWidth = dTdLMax - dTdLMin;
235  }
236  catch (const StatusCodeException &)
237  {
238  straightLineLengthLarge = -1.f;
239  diffWithStraightLineMean = -1.f;
240  diffWithStraightLineSigma = -1.f;
241  dTdLWidth = -1.f;
242  maxFitGapLength = -1.f;
243  rmsSlidingLinearFit = -1.f;
244  }
245 }
246 
247 //------------------------------------------------------------------------------------------------------------------------------------------
248 
249 StatusCode TwoDLinearFitFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
250 {
251  PANDORA_RETURN_RESULT_IF_AND_IF(
252  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingLinearFitWindow", m_slidingLinearFitWindow));
253 
254  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
255  XmlHelper::ReadValue(xmlHandle, "SlidingLinearFitWindowLarge", m_slidingLinearFitWindowLarge));
256 
257  return STATUS_CODE_SUCCESS;
258 }
259 
260 //------------------------------------------------------------------------------------------------------------------------------------------
261 //------------------------------------------------------------------------------------------------------------------------------------------
262 
265 {
266 }
267 
268 //------------------------------------------------------------------------------------------------------------------------------------------
269 
271  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
272 {
273  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
274  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
275 
276  float straightLineLength(-1.f), ratio(-1.f);
277  try
278  {
279  const TwoDSlidingFitResult slidingFitResultLarge(pCluster, m_slidingLinearFitWindow, LArGeometryHelper::GetWireZPitch(this->GetPandora()));
280  straightLineLength = (slidingFitResultLarge.GetGlobalMaxLayerPosition() - slidingFitResultLarge.GetGlobalMinLayerPosition()).GetMagnitude();
281  if (straightLineLength > std::numeric_limits<float>::epsilon())
282  ratio = (CutClusterCharacterisationAlgorithm::GetVertexDistance(pAlgorithm, pCluster)) / straightLineLength;
283  }
284  catch (const StatusCodeException &)
285  {
286  ratio = -1.f;
287  }
288  featureVector.push_back(ratio);
289 }
290 
291 //------------------------------------------------------------------------------------------------------------------------------------------
292 
293 void TwoDVertexDistanceFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder,
294  const std::string &featureToolName, const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
295 {
296  LArMvaHelper::MvaFeatureVector toolFeatureVec;
297  this->Run(toolFeatureVec, pAlgorithm, pCluster);
298 
299  if (featureMap.find(featureToolName + "_DistLenRatio") != featureMap.end())
300  {
301  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
302  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
303  }
304 
305  featureOrder.push_back(featureToolName + "_DistLenRatio");
306  featureMap[featureToolName + "_DistLenRatio"] = toolFeatureVec[0];
307 }
308 
309 //------------------------------------------------------------------------------------------------------------------------------------------
310 
311 StatusCode TwoDVertexDistanceFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
312 {
313  PANDORA_RETURN_RESULT_IF_AND_IF(
314  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingLinearFitWindow", m_slidingLinearFitWindow));
315 
316  return STATUS_CODE_SUCCESS;
317 }
318 
319 //------------------------------------------------------------------------------------------------------------------------------------------
320 //------------------------------------------------------------------------------------------------------------------------------------------
321 
323 {
324 }
325 
326 //------------------------------------------------------------------------------------------------------------------------------------------
327 
329  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
330 {
331  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
332  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
333 
334  CaloHitList parent3DHitList;
335  LArPfoHelper::GetCaloHits(pInputPfo, TPC_3D, parent3DHitList);
336  const unsigned int nParentHits3D(parent3DHitList.size());
337 
338  PfoList allDaughtersPfoList;
339  LArPfoHelper::GetAllDownstreamPfos(pInputPfo, allDaughtersPfoList);
340  const unsigned int nDaughterPfos(allDaughtersPfoList.empty() ? 0 : allDaughtersPfoList.size() - 1);
341 
342  unsigned int nDaughterHits3DTotal(0);
343 
344  if (nDaughterPfos > 0)
345  {
346  // ATTN This relies on knowing that the first pfo in allDaughtersPfoList is the input pfo
347  allDaughtersPfoList.pop_front();
348 
349  for (const ParticleFlowObject *const pDaughterPfo : allDaughtersPfoList)
350  {
351  CaloHitList daughter3DHitList;
352  LArPfoHelper::GetCaloHits(pDaughterPfo, TPC_3D, daughter3DHitList);
353  nDaughterHits3DTotal += daughter3DHitList.size();
354  }
355  }
356 
357  const LArMvaHelper::MvaFeature nDaughters(static_cast<double>(nDaughterPfos));
358  const LArMvaHelper::MvaFeature nDaughterHits3D(static_cast<double>(nDaughterHits3DTotal));
359  const LArMvaHelper::MvaFeature daughterParentNHitsRatio(
360  (nParentHits3D > 0) ? static_cast<double>(nDaughterHits3DTotal) / static_cast<double>(nParentHits3D) : 0.);
361 
362  featureVector.push_back(nDaughters);
363  featureVector.push_back(nDaughterHits3D);
364  featureVector.push_back(daughterParentNHitsRatio);
365 }
366 
367 //------------------------------------------------------------------------------------------------------------------------------------------
368 
369 void PfoHierarchyFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder, const std::string &featureToolName,
370  const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
371 {
372  LArMvaHelper::MvaFeatureVector toolFeatureVec;
373  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
374 
375  if (featureMap.find(featureToolName + "_NDaughters") != featureMap.end() ||
376  featureMap.find(featureToolName + "_NDaughterHits3D") != featureMap.end() ||
377  featureMap.find(featureToolName + "_DaughterParentHitRatio") != featureMap.end())
378  {
379  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
380  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
381  }
382 
383  featureOrder.push_back(featureToolName + "_NDaughters");
384  featureOrder.push_back(featureToolName + "_NDaughterHits3D");
385  featureOrder.push_back(featureToolName + "_DaughterParentHitRatio");
386 
387  featureMap[featureToolName + "_NDaughters"] = toolFeatureVec[0];
388  featureMap[featureToolName + "_NDaughterHits3D"] = toolFeatureVec[1];
389  featureMap[featureToolName + "_DaughterParentHitRatio"] = toolFeatureVec[2];
390 }
391 
392 //------------------------------------------------------------------------------------------------------------------------------------------
393 
394 StatusCode PfoHierarchyFeatureTool::ReadSettings(const TiXmlHandle /*xmlHandle*/)
395 {
396  return STATUS_CODE_SUCCESS;
397 }
398 
399 //------------------------------------------------------------------------------------------------------------------------------------------
400 //------------------------------------------------------------------------------------------------------------------------------------------
401 
403  m_conMinHits(3),
404  m_minCharge(0.1f),
405  m_conFracRange(0.2f),
406  m_MoliereRadius(10.1f),
407  m_MoliereRadiusFrac(0.2f)
408 {
409 }
410 
411 //------------------------------------------------------------------------------------------------------------------------------------------
412 
414  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
415 {
416  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
417  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
418 
419  ClusterList clusterListW;
420  LArPfoHelper::GetClusters(pInputPfo, TPC_VIEW_W, clusterListW);
421 
422  LArMvaHelper::MvaFeature haloTotalRatio, concentration, conicalness;
423 
424  if (!clusterListW.empty())
425  {
426  CaloHitList clusterCaloHitList;
427  clusterListW.front()->GetOrderedCaloHitList().FillCaloHitList(clusterCaloHitList);
428 
429  const CartesianVector &pfoStart(clusterCaloHitList.front()->GetPositionVector());
430  CartesianVector centroid(0.f, 0.f, 0.f);
431  LArPcaHelper::EigenVectors eigenVecs;
432  LArPcaHelper::EigenValues eigenValues(0.f, 0.f, 0.f);
433  LArPcaHelper::RunPca(clusterCaloHitList, centroid, eigenValues, eigenVecs);
434 
435  float chargeCore(0.f), chargeHalo(0.f), chargeCon(0.f);
436  this->CalculateChargeDistribution(clusterCaloHitList, pfoStart, eigenVecs[0], chargeCore, chargeHalo, chargeCon);
437  haloTotalRatio = (chargeCore + chargeHalo > std::numeric_limits<float>::epsilon()) ? chargeHalo / (chargeCore + chargeHalo) : -1.f;
438  concentration = (chargeCore + chargeHalo > std::numeric_limits<float>::epsilon()) ? chargeCon / (chargeCore + chargeHalo) : -1.f;
439  const float pfoLength(std::sqrt(LArPfoHelper::GetThreeDLengthSquared(pInputPfo)));
440  conicalness = (pfoLength > std::numeric_limits<float>::epsilon())
441  ? this->CalculateConicalness(clusterCaloHitList, pfoStart, eigenVecs[0], pfoLength)
442  : 1.f;
443  }
444 
445  featureVector.push_back(haloTotalRatio);
446  featureVector.push_back(concentration);
447  featureVector.push_back(conicalness);
448 }
449 
450 //------------------------------------------------------------------------------------------------------------------------------------------
451 
452 void ConeChargeFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder, const std::string &featureToolName,
453  const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
454 {
455  LArMvaHelper::MvaFeatureVector toolFeatureVec;
456  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
457 
458  if (featureMap.find(featureToolName + "_HaloTotalRatio") != featureMap.end() ||
459  featureMap.find(featureToolName + "_Concentration") != featureMap.end() ||
460  featureMap.find(featureToolName + "_Conicalness") != featureMap.end())
461  {
462  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
463  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
464  }
465 
466  featureOrder.push_back(featureToolName + "_HaloTotalRatio");
467  featureOrder.push_back(featureToolName + "_Concentration");
468  featureOrder.push_back(featureToolName + "_Conicalness");
469 
470  featureMap[featureToolName + "_HaloTotalRatio"] = toolFeatureVec[0];
471  featureMap[featureToolName + "_Concentration"] = toolFeatureVec[1];
472  featureMap[featureToolName + "_Conicalness"] = toolFeatureVec[2];
473 }
474 
475 //------------------------------------------------------------------------------------------------------------------------------------------
476 
477 void ConeChargeFeatureTool::CalculateChargeDistribution(const CaloHitList &caloHitList, const CartesianVector &pfoStart,
478  const CartesianVector &pfoDir, float &chargeCore, float &chargeHalo, float &chargeCon)
479 {
480  for (const CaloHit *const pCaloHit : caloHitList)
481  {
482  const float distFromTrackFit(((pCaloHit->GetPositionVector() - pfoStart).GetCrossProduct(pfoDir)).GetMagnitude());
483 
484  if (distFromTrackFit < m_MoliereRadiusFrac * m_MoliereRadius)
485  chargeCore += pCaloHit->GetInputEnergy();
486  else
487  chargeHalo += pCaloHit->GetInputEnergy();
488 
489  chargeCon += pCaloHit->GetInputEnergy() / std::max(1.E-2f, distFromTrackFit); /* Set 1.E-2f to prevent division by 0 and to set max histogram bin as 100 */
490  }
491 }
492 
493 //------------------------------------------------------------------------------------------------------------------------------------------
494 
496  const CaloHitList &caloHitList, const CartesianVector &pfoStart, const CartesianVector &pfoDir, const float pfoLength)
497 {
498  float totalChargeStart(0.f), totalChargeEnd(0.f);
499  float chargeConStart(0.f), chargeConEnd(0.f);
500  unsigned int nHitsConStart(0), nHitsConEnd(0);
501 
502  for (const CaloHit *const pCaloHit : caloHitList)
503  {
504  const float distFromTrackFit(((pCaloHit->GetPositionVector() - pfoStart).GetCrossProduct(pfoDir)).GetMagnitude());
505  const float hitLength(std::fabs((pCaloHit->GetPositionVector() - pfoStart).GetDotProduct(pfoDir)));
506 
507  if (hitLength / pfoLength < m_conFracRange)
508  {
509  chargeConStart += distFromTrackFit * distFromTrackFit * pCaloHit->GetInputEnergy();
510  ++nHitsConStart;
511  totalChargeStart += pCaloHit->GetInputEnergy();
512  }
513  else if (1.f - hitLength / pfoLength < m_conFracRange)
514  {
515  chargeConEnd += distFromTrackFit * distFromTrackFit * pCaloHit->GetInputEnergy();
516  ++nHitsConEnd;
517  totalChargeEnd += pCaloHit->GetInputEnergy();
518  }
519  }
520 
521  float conicalness(1.f);
522 
523  if (nHitsConStart >= m_conMinHits && nHitsConEnd >= m_conMinHits && totalChargeEnd > m_minCharge &&
524  std::sqrt(chargeConStart) > m_minCharge && totalChargeStart > m_minCharge)
525  conicalness = (std::sqrt(chargeConEnd / chargeConStart)) / (totalChargeEnd / totalChargeStart);
526 
527  return conicalness;
528 }
529 
530 //------------------------------------------------------------------------------------------------------------------------------------------
531 
532 StatusCode ConeChargeFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
533 {
534  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConMinHits", m_conMinHits));
535  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinCharge", m_minCharge));
536  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConFracRange", m_conFracRange));
537  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MoliereRadius", m_MoliereRadius));
538  PANDORA_RETURN_RESULT_IF_AND_IF(
539  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MoliereRadiusFrac", m_MoliereRadiusFrac));
540 
541  return STATUS_CODE_SUCCESS;
542 }
543 
544 //------------------------------------------------------------------------------------------------------------------------------------------
545 //------------------------------------------------------------------------------------------------------------------------------------------
546 
548  m_slidingLinearFitWindow(3),
549  m_slidingLinearFitWindowLarge(10000)
550 {
551 }
552 
553 //------------------------------------------------------------------------------------------------------------------------------------------
554 
556  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
557 {
558  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
559  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
560 
561  ClusterList clusterList;
562  LArPfoHelper::GetTwoDClusterList(pInputPfo, clusterList);
563  float diffWithStraightLineMean(0.f), maxFitGapLength(0.f), rmsSlidingLinearFit(0.f);
564  LArMvaHelper::MvaFeature length, diff, gap, rms;
565  unsigned int nClustersUsed(0);
566 
567  for (const Cluster *const pCluster : clusterList)
568  {
569  float straightLineLengthLargeCluster(-1.f), diffWithStraightLineMeanCluster(-1.f), maxFitGapLengthCluster(-1.f),
570  rmsSlidingLinearFitCluster(-1.f);
571 
573  pCluster, straightLineLengthLargeCluster, diffWithStraightLineMeanCluster, maxFitGapLengthCluster, rmsSlidingLinearFitCluster);
574 
575  if (straightLineLengthLargeCluster > std::numeric_limits<float>::epsilon())
576  {
577  diffWithStraightLineMeanCluster /= straightLineLengthLargeCluster;
578  maxFitGapLengthCluster /= straightLineLengthLargeCluster;
579  rmsSlidingLinearFitCluster /= straightLineLengthLargeCluster;
580 
581  diffWithStraightLineMean += diffWithStraightLineMeanCluster;
582  maxFitGapLength += maxFitGapLengthCluster;
583  rmsSlidingLinearFit += rmsSlidingLinearFitCluster;
584 
585  ++nClustersUsed;
586  }
587  }
588 
589  if (nClustersUsed > 0)
590  {
591  const float nClusters(static_cast<float>(nClustersUsed));
592  length = std::sqrt(LArPfoHelper::GetThreeDLengthSquared(pInputPfo));
593  diff = diffWithStraightLineMean / nClusters;
594  gap = maxFitGapLength / nClusters;
595  rms = rmsSlidingLinearFit / nClusters;
596  }
597 
598  featureVector.push_back(length);
599  featureVector.push_back(diff);
600  featureVector.push_back(gap);
601  featureVector.push_back(rms);
602 }
603 
604 //------------------------------------------------------------------------------------------------------------------------------------------
605 
606 void ThreeDLinearFitFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder,
607  const std::string &featureToolName, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
608 {
609  LArMvaHelper::MvaFeatureVector toolFeatureVec;
610  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
611 
612  if (featureMap.find(featureToolName + "_Length") != featureMap.end() ||
613  featureMap.find(featureToolName + "_DiffStraightLineMean") != featureMap.end() ||
614  featureMap.find(featureToolName + "_MaxFitGapLength") != featureMap.end() ||
615  featureMap.find(featureToolName + "_SlidingLinearFitRMS") != featureMap.end())
616  {
617  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
618  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
619  }
620 
621  featureOrder.push_back(featureToolName + "_Length");
622  featureOrder.push_back(featureToolName + "_DiffStraightLineMean");
623  featureOrder.push_back(featureToolName + "_MaxFitGapLength");
624  featureOrder.push_back(featureToolName + "_SlidingLinearFitRMS");
625 
626  featureMap[featureToolName + "_Length"] = toolFeatureVec[0];
627  featureMap[featureToolName + "_DiffStraightLineMean"] = toolFeatureVec[1];
628  featureMap[featureToolName + "_MaxFitGapLength"] = toolFeatureVec[2];
629  featureMap[featureToolName + "_SlidingLinearFitRMS"] = toolFeatureVec[3];
630 }
631 
632 //------------------------------------------------------------------------------------------------------------------------------------------
633 
634 void ThreeDLinearFitFeatureTool::CalculateVariablesSlidingLinearFit(const pandora::Cluster *const pCluster, float &straightLineLengthLarge,
635  float &diffWithStraightLineMean, float &maxFitGapLength, float &rmsSlidingLinearFit) const
636 {
637  try
638  {
639  const TwoDSlidingFitResult slidingFitResult(pCluster, m_slidingLinearFitWindow, LArGeometryHelper::GetWireZPitch(this->GetPandora()));
640  const TwoDSlidingFitResult slidingFitResultLarge(
641  pCluster, m_slidingLinearFitWindowLarge, LArGeometryHelper::GetWireZPitch(this->GetPandora()));
642 
643  if (slidingFitResult.GetLayerFitResultMap().empty())
644  throw StatusCodeException(STATUS_CODE_NOT_INITIALIZED);
645 
646  straightLineLengthLarge =
647  (slidingFitResultLarge.GetGlobalMaxLayerPosition() - slidingFitResultLarge.GetGlobalMinLayerPosition()).GetMagnitude();
648  rmsSlidingLinearFit = 0.f;
649 
650  FloatVector diffWithStraightLineVector;
651  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
652  CartesianVector previousFitPosition(slidingFitResult.GetGlobalMinLayerPosition());
653  float dTdLMin(+std::numeric_limits<float>::max()), dTdLMax(-std::numeric_limits<float>::max());
654 
655  for (const auto &mapEntry : slidingFitResult.GetLayerFitResultMap())
656  {
657  const LayerFitResult &layerFitResult(mapEntry.second);
658  rmsSlidingLinearFit += layerFitResult.GetRms();
659 
660  CartesianVector thisFitPosition(0.f, 0.f, 0.f);
661  slidingFitResult.GetGlobalPosition(layerFitResult.GetL(), layerFitResult.GetFitT(), thisFitPosition);
662 
664  slidingFitResultLarge.GetLayerFitResultMap().find(slidingFitResultLarge.GetLayer(layerFitResult.GetL()));
665 
666  if (slidingFitResultLarge.GetLayerFitResultMap().end() == iterLarge)
667  throw StatusCodeException(STATUS_CODE_FAILURE);
668 
669  diffWithStraightLineVector.push_back(static_cast<float>(std::fabs(layerFitResult.GetFitT() - iterLarge->second.GetFitT())));
670 
671  const float thisGapLength((thisFitPosition - previousFitPosition).GetMagnitude());
672  const float minZ(std::min(thisFitPosition.GetZ(), previousFitPosition.GetZ()));
673  const float maxZ(std::max(thisFitPosition.GetZ(), previousFitPosition.GetZ()));
674 
675  if ((maxZ - minZ) > std::numeric_limits<float>::epsilon())
676  {
677  const float gapZ(LArGeometryHelper::CalculateGapDeltaZ(this->GetPandora(), minZ, maxZ, hitType));
678  const float correctedGapLength(thisGapLength * (1.f - gapZ / (maxZ - minZ)));
679 
680  if (correctedGapLength > maxFitGapLength)
681  maxFitGapLength = correctedGapLength;
682  }
683  else
684  {
685  maxFitGapLength = 0.f;
686  }
687 
688  dTdLMin = std::min(dTdLMin, static_cast<float>(layerFitResult.GetGradient()));
689  dTdLMax = std::max(dTdLMax, static_cast<float>(layerFitResult.GetGradient()));
690  previousFitPosition = thisFitPosition;
691  }
692 
693  if (diffWithStraightLineVector.empty())
694  throw StatusCodeException(STATUS_CODE_FAILURE);
695 
696  diffWithStraightLineMean = 0.f;
697 
698  for (const float diffWithStraightLine : diffWithStraightLineVector)
699  diffWithStraightLineMean += diffWithStraightLine;
700 
701  diffWithStraightLineMean /= static_cast<float>(diffWithStraightLineVector.size());
702  }
703  catch (const StatusCodeException &)
704  {
705  straightLineLengthLarge = -1.f;
706  diffWithStraightLineMean = -1.f;
707  maxFitGapLength = -1.f;
708  rmsSlidingLinearFit = -1.f;
709  }
710 }
711 
712 //------------------------------------------------------------------------------------------------------------------------------------------
713 
714 StatusCode ThreeDLinearFitFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
715 {
716  PANDORA_RETURN_RESULT_IF_AND_IF(
717  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingLinearFitWindow", m_slidingLinearFitWindow));
718 
719  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
720  XmlHelper::ReadValue(xmlHandle, "SlidingLinearFitWindowLarge", m_slidingLinearFitWindowLarge));
721 
722  return STATUS_CODE_SUCCESS;
723 }
724 
725 //------------------------------------------------------------------------------------------------------------------------------------------
726 //------------------------------------------------------------------------------------------------------------------------------------------
727 
729 {
730 }
731 
732 //------------------------------------------------------------------------------------------------------------------------------------------
733 
735  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
736 {
737  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
738  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
739 
740  LArMvaHelper::MvaFeature vertexDistance;
741 
742  const VertexList *pVertexList(nullptr);
743  (void)PandoraContentApi::GetCurrentList(*pAlgorithm, pVertexList);
744 
745  if (!pVertexList || pVertexList->empty())
746  {
747  featureVector.push_back(vertexDistance);
748  return;
749  }
750 
751  unsigned int nInteractionVertices(0);
752  const Vertex *pInteractionVertex(nullptr);
753 
754  for (const Vertex *pVertex : *pVertexList)
755  {
756  if ((pVertex->GetVertexLabel() == VERTEX_INTERACTION) && (pVertex->GetVertexType() == VERTEX_3D))
757  {
758  ++nInteractionVertices;
759  pInteractionVertex = pVertex;
760  }
761  }
762 
763  if (pInteractionVertex && (1 == nInteractionVertices))
764  {
765  try
766  {
767  vertexDistance = (pInteractionVertex->GetPosition() - LArPfoHelper::GetVertex(pInputPfo)->GetPosition()).GetMagnitude();
768  }
769  catch (const StatusCodeException &)
770  {
771  CaloHitList threeDCaloHitList;
772  LArPfoHelper::GetCaloHits(pInputPfo, TPC_3D, threeDCaloHitList);
773 
774  if (!threeDCaloHitList.empty())
775  vertexDistance = (pInteractionVertex->GetPosition() - (threeDCaloHitList.front())->GetPositionVector()).GetMagnitude();
776  }
777  }
778 
779  featureVector.push_back(vertexDistance);
780 }
781 
782 //------------------------------------------------------------------------------------------------------------------------------------------
783 
784 void ThreeDVertexDistanceFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder,
785  const std::string &featureToolName, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
786 {
787  LArMvaHelper::MvaFeatureVector toolFeatureVec;
788  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
789 
790  if (featureMap.find(featureToolName + "_VertexDistance") != featureMap.end())
791  {
792  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
793  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
794  }
795 
796  featureOrder.push_back(featureToolName + "_VertexDistance");
797 
798  featureMap[featureToolName + "_VertexDistance"] = toolFeatureVec[0];
799 }
800 
801 //------------------------------------------------------------------------------------------------------------------------------------------
802 
803 StatusCode ThreeDVertexDistanceFeatureTool::ReadSettings(const TiXmlHandle /*xmlHandle*/)
804 {
805  return STATUS_CODE_SUCCESS;
806 }
807 
808 //------------------------------------------------------------------------------------------------------------------------------------------
809 //------------------------------------------------------------------------------------------------------------------------------------------
810 
812  m_hitFraction(0.5f),
813  m_defaultValue(0.1f)
814 {
815 }
816 
817 //------------------------------------------------------------------------------------------------------------------------------------------
818 
820  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
821 {
822  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
823  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
824 
825  // Need the 3D hits to calculate PCA components
826  CaloHitList threeDCaloHitList;
827  LArPfoHelper::GetCaloHits(pInputPfo, TPC_3D, threeDCaloHitList);
828 
829  LArMvaHelper::MvaFeature diffAngle;
830  if (!threeDCaloHitList.empty())
831  {
832  CartesianPointVector pointVectorStart, pointVectorEnd;
833  this->Divide3DCaloHitList(pAlgorithm, threeDCaloHitList, pointVectorStart, pointVectorEnd);
834 
835  // Able to calculate angles only if > 1 point provided
836  if ((pointVectorStart.size() > 1) && (pointVectorEnd.size() > 1))
837  {
838  try
839  {
840  // Run the PCA analysis twice
841  CartesianVector centroidStart(0.f, 0.f, 0.f), centroidEnd(0.f, 0.f, 0.f);
842  LArPcaHelper::EigenVectors eigenVecsStart, eigenVecsEnd;
843  LArPcaHelper::EigenValues eigenValuesStart(0.f, 0.f, 0.f), eigenValuesEnd(0.f, 0.f, 0.f);
844 
845  LArPcaHelper::RunPca(pointVectorStart, centroidStart, eigenValuesStart, eigenVecsStart);
846  LArPcaHelper::RunPca(pointVectorEnd, centroidEnd, eigenValuesEnd, eigenVecsEnd);
847 
848  const float openingAngle(this->OpeningAngle(eigenVecsStart.at(0), eigenVecsStart.at(1), eigenValuesStart));
849  const float closingAngle(this->OpeningAngle(eigenVecsEnd.at(0), eigenVecsEnd.at(1), eigenValuesEnd));
850  diffAngle = std::fabs(openingAngle - closingAngle);
851  }
852  catch (const StatusCodeException &)
853  {
854  }
855  }
856  else
857  {
858  diffAngle = m_defaultValue;
859  }
860  }
861 
862  featureVector.push_back(diffAngle);
863 }
864 
865 //------------------------------------------------------------------------------------------------------------------------------------------
866 
867 void ThreeDOpeningAngleFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder,
868  const std::string &featureToolName, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
869 {
870  LArMvaHelper::MvaFeatureVector toolFeatureVec;
871  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
872 
873  if (featureMap.find(featureToolName + "_AngleDiff") != featureMap.end())
874  {
875  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
876  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
877  }
878 
879  featureOrder.push_back(featureToolName + "_AngleDiff");
880 
881  featureMap[featureToolName + "_AngleDiff"] = toolFeatureVec[0];
882 }
883 
884 //------------------------------------------------------------------------------------------------------------------------------------------
885 
886 void ThreeDOpeningAngleFeatureTool::Divide3DCaloHitList(const Algorithm *const pAlgorithm, const CaloHitList &threeDCaloHitList,
887  CartesianPointVector &pointVectorStart, CartesianPointVector &pointVectorEnd)
888 {
889  const VertexList *pVertexList(nullptr);
890  (void)PandoraContentApi::GetCurrentList(*pAlgorithm, pVertexList);
891 
892  if (threeDCaloHitList.empty() || !pVertexList || pVertexList->empty())
893  return;
894 
895  unsigned int nInteractionVertices(0);
896  const Vertex *pInteractionVertex(nullptr);
897 
898  for (const Vertex *pVertex : *pVertexList)
899  {
900  if ((pVertex->GetVertexLabel() == VERTEX_INTERACTION) && (pVertex->GetVertexType() == VERTEX_3D))
901  {
902  ++nInteractionVertices;
903  pInteractionVertex = pVertex;
904  }
905  }
906 
907  if (pInteractionVertex && (1 == nInteractionVertices))
908  {
909  // Order by distance to vertex, so first ones are closer to nuvertex
910  CaloHitVector threeDCaloHitVector(threeDCaloHitList.begin(), threeDCaloHitList.end());
911  std::sort(threeDCaloHitVector.begin(), threeDCaloHitVector.end(),
912  ThreeDChargeFeatureTool::VertexComparator(pInteractionVertex->GetPosition()));
913 
914  unsigned int iHit(1);
915  const unsigned int nHits(threeDCaloHitVector.size());
916 
917  for (const CaloHit *const pCaloHit : threeDCaloHitVector)
918  {
919  if (static_cast<float>(iHit) / static_cast<float>(nHits) <= m_hitFraction)
920  pointVectorStart.push_back(pCaloHit->GetPositionVector());
921 
922  if (static_cast<float>(iHit) / static_cast<float>(nHits) >= 1.f - m_hitFraction)
923  pointVectorEnd.push_back(pCaloHit->GetPositionVector());
924 
925  ++iHit;
926  }
927  }
928 }
929 
930 //------------------------------------------------------------------------------------------------------------------------------------------
931 
932 float ThreeDOpeningAngleFeatureTool::OpeningAngle(const CartesianVector &principal, const CartesianVector &secondary, const CartesianVector &eigenValues) const
933 {
934  const float principalMagnitude(principal.GetMagnitude());
935  const float secondaryMagnitude(secondary.GetMagnitude());
936 
937  if (std::fabs(principalMagnitude) < std::numeric_limits<float>::epsilon())
938  {
939  std::cout << "ThreeDOpeningAngleFeatureTool::OpeningAngle - The principal eigenvector is 0." << std::endl;
940  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
941  }
942  else if (std::fabs(secondaryMagnitude) < std::numeric_limits<float>::epsilon())
943  {
944  return 0.f;
945  }
946 
947  const float cosTheta(principal.GetDotProduct(secondary) / (principalMagnitude * secondaryMagnitude));
948 
949  if (cosTheta > 1.f)
950  {
951  std::cout << "PcaShowerParticleBuildingAlgorithm::OpeningAngle - cos(theta) reportedly greater than 1." << std::endl;
952  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
953  }
954 
955  const float sinTheta(std::sqrt(1.f - cosTheta * cosTheta));
956 
957  if (eigenValues.GetX() < std::numeric_limits<float>::epsilon())
958  {
959  std::cout << "PcaShowerParticleBuildingAlgorithm::OpeningAngle - principal eigenvalue less than or equal to 0." << std::endl;
960  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
961  }
962  else if (eigenValues.GetY() < std::numeric_limits<float>::epsilon())
963  {
964  return 0.f;
965  }
966 
967  return std::atan(std::sqrt(eigenValues.GetY()) * sinTheta / std::sqrt(eigenValues.GetX()));
968 }
969 
970 //------------------------------------------------------------------------------------------------------------------------------------------
971 
972 StatusCode ThreeDOpeningAngleFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
973 {
974  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "HitFraction", m_hitFraction));
975 
976  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "DefaultValue", m_defaultValue));
977 
978  return STATUS_CODE_SUCCESS;
979 }
980 
981 //------------------------------------------------------------------------------------------------------------------------------------------
982 //------------------------------------------------------------------------------------------------------------------------------------------
983 
985 {
986 }
987 
988 //------------------------------------------------------------------------------------------------------------------------------------------
989 
991  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
992 {
993  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
994  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
995 
996  LArMvaHelper::MvaFeature pca1, pca2;
997 
998  // Need the 3D hits to calculate PCA components
999  CaloHitList threeDCaloHitList;
1000  LArPfoHelper::GetCaloHits(pInputPfo, TPC_3D, threeDCaloHitList);
1001 
1002  if (!threeDCaloHitList.empty())
1003  {
1004  try
1005  {
1006  CartesianVector centroid(0.f, 0.f, 0.f);
1007  LArPcaHelper::EigenVectors eigenVecs;
1008  LArPcaHelper::EigenValues eigenValues(0.f, 0.f, 0.f);
1009 
1010  LArPcaHelper::RunPca(threeDCaloHitList, centroid, eigenValues, eigenVecs);
1011  const float principalEigenvalue(eigenValues.GetX()), secondaryEigenvalue(eigenValues.GetY()), tertiaryEigenvalue(eigenValues.GetZ());
1012 
1013  if (principalEigenvalue > std::numeric_limits<float>::epsilon())
1014  {
1015  pca1 = secondaryEigenvalue / principalEigenvalue;
1016  pca2 = tertiaryEigenvalue / principalEigenvalue;
1017  }
1018  else
1019  {
1020  // ATTN if n3dHits == 1 then principal, secondary, and tertiary eigenvalues are zero hence default to zero
1021  pca1 = 0.;
1022  pca2 = 0.;
1023  }
1024  }
1025  catch (const StatusCodeException &)
1026  {
1027  }
1028  }
1029 
1030  featureVector.push_back(pca1);
1031  featureVector.push_back(pca2);
1032 }
1033 
1034 //------------------------------------------------------------------------------------------------------------------------------------------
1035 
1036 void ThreeDPCAFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder, const std::string &featureToolName,
1037  const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
1038 {
1039  LArMvaHelper::MvaFeatureVector toolFeatureVec;
1040  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
1041 
1042  if (featureMap.find(featureToolName + "_SecondaryPCARatio") != featureMap.end() ||
1043  featureMap.find(featureToolName + "_TertiaryPCARatio") != featureMap.end())
1044  {
1045  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
1046  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
1047  }
1048 
1049  featureOrder.push_back(featureToolName + "_SecondaryPCARatio");
1050  featureOrder.push_back(featureToolName + "_TertiaryPCARatio");
1051 
1052  featureMap[featureToolName + "_SecondaryPCARatio"] = toolFeatureVec[0];
1053  featureMap[featureToolName + "_TertiaryPCARatio"] = toolFeatureVec[1];
1054 }
1055 
1056 //------------------------------------------------------------------------------------------------------------------------------------------
1057 
1058 StatusCode ThreeDPCAFeatureTool::ReadSettings(const TiXmlHandle /*xmlHandle*/)
1059 {
1060  return STATUS_CODE_SUCCESS;
1061 }
1062 
1063 //------------------------------------------------------------------------------------------------------------------------------------------
1064 //------------------------------------------------------------------------------------------------------------------------------------------
1065 
1067  m_endChargeFraction(0.1f)
1068 {
1069 }
1070 
1071 //------------------------------------------------------------------------------------------------------------------------------------------
1072 
1074  LArMvaHelper::MvaFeatureVector &featureVector, const Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
1075 {
1076  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
1077  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
1078 
1079  float totalCharge(-1.f), chargeSigma(-1.f), chargeMean(-1.f), endCharge(-1.f);
1080  LArMvaHelper::MvaFeature charge1, charge2;
1081 
1082  ClusterList clusterListW;
1083  LArPfoHelper::GetClusters(pInputPfo, TPC_VIEW_W, clusterListW);
1084 
1085  if (!clusterListW.empty())
1086  this->CalculateChargeVariables(pAlgorithm, clusterListW.front(), totalCharge, chargeSigma, chargeMean, endCharge);
1087 
1088  if (chargeMean > std::numeric_limits<float>::epsilon())
1089  charge1 = chargeSigma / chargeMean;
1090 
1091  if (totalCharge > std::numeric_limits<float>::epsilon())
1092  charge2 = endCharge / totalCharge;
1093 
1094  featureVector.push_back(charge1);
1095  featureVector.push_back(charge2);
1096 }
1097 
1098 //------------------------------------------------------------------------------------------------------------------------------------------
1099 
1100 void ThreeDChargeFeatureTool::Run(LArMvaHelper::MvaFeatureMap &featureMap, StringVector &featureOrder, const std::string &featureToolName,
1101  const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
1102 {
1103  LArMvaHelper::MvaFeatureVector toolFeatureVec;
1104  this->Run(toolFeatureVec, pAlgorithm, pInputPfo);
1105 
1106  if (featureMap.find(featureToolName + "_FractionalSpread") != featureMap.end() ||
1107  featureMap.find(featureToolName + "_EndFraction") != featureMap.end())
1108  {
1109  std::cout << "Already wrote this feature into map! Not writing again." << std::endl;
1110  throw pandora::StatusCodeException(pandora::STATUS_CODE_INVALID_PARAMETER);
1111  }
1112 
1113  featureOrder.push_back(featureToolName + "_FractionalSpread");
1114  featureOrder.push_back(featureToolName + "_EndFraction");
1115 
1116  featureMap[featureToolName + "_FractionalSpread"] = toolFeatureVec[0];
1117  featureMap[featureToolName + "_EndFraction"] = toolFeatureVec[1];
1118 }
1119 
1120 //------------------------------------------------------------------------------------------------------------------------------------------
1121 
1122 void ThreeDChargeFeatureTool::CalculateChargeVariables(const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster,
1123  float &totalCharge, float &chargeSigma, float &chargeMean, float &endCharge)
1124 {
1125  totalCharge = 0.f;
1126  chargeSigma = 0.f;
1127  chargeMean = 0.f;
1128  endCharge = 0.f;
1129 
1130  CaloHitList orderedCaloHitList;
1131  this->OrderCaloHitsByDistanceToVertex(pAlgorithm, pCluster, orderedCaloHitList);
1132 
1133  FloatVector chargeVector;
1134  unsigned int hitCounter(0);
1135  const unsigned int nTotalHits(orderedCaloHitList.size());
1136 
1137  for (const CaloHit *const pCaloHit : orderedCaloHitList)
1138  {
1139  ++hitCounter;
1140  const float pCaloHitCharge(pCaloHit->GetInputEnergy());
1141 
1142  if (pCaloHitCharge >= 0.f)
1143  {
1144  totalCharge += pCaloHitCharge;
1145  chargeVector.push_back(pCaloHitCharge);
1146 
1147  if (hitCounter >= std::floor(static_cast<float>(nTotalHits) * (1.f - m_endChargeFraction)))
1148  endCharge += pCaloHitCharge;
1149  }
1150  }
1151 
1152  if (!chargeVector.empty())
1153  {
1154  chargeMean = totalCharge / static_cast<float>(chargeVector.size());
1155 
1156  for (const float charge : chargeVector)
1157  chargeSigma += (charge - chargeMean) * (charge - chargeMean);
1158 
1159  chargeSigma = std::sqrt(chargeSigma / static_cast<float>(chargeVector.size()));
1160  }
1161 }
1162 
1163 //------------------------------------------------------------------------------------------------------------------------------------------
1164 
1166  const Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster, CaloHitList &caloHitList)
1167 {
1168  const VertexList *pVertexList(nullptr);
1169  (void)PandoraContentApi::GetCurrentList(*pAlgorithm, pVertexList);
1170 
1171  if (!pVertexList || pVertexList->empty())
1172  return;
1173 
1174  unsigned int nInteractionVertices(0);
1175  const Vertex *pInteractionVertex(nullptr);
1176 
1177  for (const Vertex *pVertex : *pVertexList)
1178  {
1179  if ((pVertex->GetVertexLabel() == VERTEX_INTERACTION) && (pVertex->GetVertexType() == VERTEX_3D))
1180  {
1181  ++nInteractionVertices;
1182  pInteractionVertex = pVertex;
1183  }
1184  }
1185 
1186  if (pInteractionVertex && (1 == nInteractionVertices))
1187  {
1188  const HitType hitType(LArClusterHelper::GetClusterHitType(pCluster));
1189  const CartesianVector vertexPosition2D(LArGeometryHelper::ProjectPosition(pAlgorithm->GetPandora(), pInteractionVertex->GetPosition(), hitType));
1190 
1191  CaloHitList clusterCaloHitList;
1192  pCluster->GetOrderedCaloHitList().FillCaloHitList(clusterCaloHitList);
1193 
1194  clusterCaloHitList.sort(ThreeDChargeFeatureTool::VertexComparator(vertexPosition2D));
1195  caloHitList.insert(caloHitList.end(), clusterCaloHitList.begin(), clusterCaloHitList.end());
1196  }
1197 }
1198 
1199 //------------------------------------------------------------------------------------------------------------------------------------------
1200 
1201 StatusCode ThreeDChargeFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
1202 {
1203  PANDORA_RETURN_RESULT_IF_AND_IF(
1204  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "EndChargeFraction", m_endChargeFraction));
1205 
1206  return STATUS_CODE_SUCCESS;
1207 }
1208 
1209 //------------------------------------------------------------------------------------------------------------------------------------------
1210 //------------------------------------------------------------------------------------------------------------------------------------------
1211 
1212 ThreeDChargeFeatureTool::VertexComparator::VertexComparator(const CartesianVector vertexPosition2D) :
1213  m_neutrinoVertex(vertexPosition2D)
1214 {
1215 }
1216 
1217 //------------------------------------------------------------------------------------------------------------------------------------------
1218 
1219 bool ThreeDChargeFeatureTool::VertexComparator::operator()(const CaloHit *const left, const CaloHit *const right) const
1220 {
1221  const float distanceL((left->GetPositionVector() - m_neutrinoVertex).GetMagnitudeSquared());
1222  const float distanceR((right->GetPositionVector() - m_neutrinoVertex).GetMagnitudeSquared());
1223  return distanceL < distanceR;
1224 }
1225 
1226 } // namespace lar_content
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
void OrderCaloHitsByDistanceToVertex(const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster, pandora::CaloHitList &caloHitList)
Function to order the calo hit list by distance to neutrino vertex.
Header file for the pfo helper class.
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
Header file for the cut based cluster characterisation algorithm class.
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:75
float m_hitFraction
Fraction of hits in start and end of pfo.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
static void GetClusters(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::ClusterList &clusterList)
Get a list of clusters of a particular hit type from a list of pfos.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
static void GetTwoDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 2D clusters from an input pfo.
pandora::CartesianVector EigenValues
Definition: LArPcaHelper.h:24
static float GetThreeDLengthSquared(const pandora::ParticleFlowObject *const pPfo)
Calculate length of Pfo using 3D clusters.
static float CalculateGapDeltaZ(const pandora::Pandora &pandora, const float minZ, const float maxZ, const pandora::HitType hitType)
Calculate the total distance within a given 2D region that is composed of detector gaps...
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
static float GetVertexDistance(const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
Get the distance between the interaction vertex (if present in the current vertex list) and a provide...
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
unsigned int m_slidingShowerFitWindow
The sliding shower fit window.
Header file for the principal curve analysis helper class.
intermediate_table::const_iterator const_iterator
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
MvaTypes::MvaFeatureMap MvaFeatureMap
Definition: LArMvaHelper.h:78
unsigned int m_conMinHits
Configurable parameters to calculate cone charge variables.
void CalculateVariablesSlidingLinearFit(const pandora::Cluster *const pCluster, float &straightLineLengthLarge, float &diffWithStraigthLineMean, float &maxFitGapLength, float &rmsSlidingLinearFit) const
Calculation of several variables related to sliding linear fit.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
unsigned int m_slidingLinearFitWindow
The sliding linear fit window.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
Header file for the track shower id feature tools.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
unsigned int m_slidingLinearFitWindow
The sliding linear fit window.
bool operator()(const pandora::CaloHit *const left, const pandora::CaloHit *const right) const
operator <
double GetFitT() const
Get the fitted t coordinate.
InitializedDouble class used to define mva features.
unsigned int m_slidingLinearFitWindowLarge
The sliding linear fit window - should be large, providing a simple linear fit.
Float_t E
Definition: plot.C:20
Header file for the cluster helper class.
float OpeningAngle(const pandora::CartesianVector &principal, const pandora::CartesianVector &secondary, const pandora::CartesianVector &eigenValues) const
Use the results of principal component analysis to calculate an opening angle.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
Header file for the lar two dimensional sliding fit result class.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
unsigned int m_slidingLinearFitWindow
The sliding linear fit window.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
pandora::CartesianVector GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
double GetGradient() const
Get the fitted gradient dt/dz.
const LayerFitResultMap & GetLayerFitResultMap() const
Get the layer fit result map.
VertexComparator class for comparison of two points wrt neutrino vertex position. ...
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:94
double GetRms() const
Get the rms of the fit residuals.
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...
VertexComparator(const pandora::CartesianVector vertexPosition2D)
Constructor.
std::vector< pandora::CartesianVector > EigenVectors
Definition: LArPcaHelper.h:25
HitType
Definition: HitType.h:12
static void GetAllDownstreamPfos(const pandora::PfoList &inputPfoList, pandora::PfoList &outputPfoList)
Get a flat list of all pfos, recursively, of all daughters associated with those pfos in an input lis...
void GetGlobalPosition(const float rL, const float rT, pandora::CartesianVector &position) const
Get global coordinates for given sliding linear fit coordinates.
unsigned int m_slidingLinearFitWindowLarge
The sliding linear fit window - should be large, providing a simple linear fit.
float m_defaultValue
Default value to return, in case calculation not feasible.
void CalculateChargeVariables(const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster, float &totalCharge, float &chargeSigma, float &chargeMean, float &endCharge)
Calculation of the charge variables.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::ParticleFlowObject *const pInputPfo)
void Divide3DCaloHitList(const pandora::Algorithm *const pAlgorithm, const pandora::CaloHitList &threeDCaloHitList, pandora::CartesianPointVector &pointVectorStart, pandora::CartesianPointVector &pointVectorEnd)
Obtain positions at the vertex and non-vertex end of a list of three dimensional calo hits...
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
Definition: ModuleGraph.h:25
float m_endChargeFraction
Fraction of hits that will be considered to calculate end charge (default 10%)
double GetL() const
Get the l coordinate.
static float GetShowerFitWidth(const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster, const unsigned int showerFitWindow)
Get a measure of the width of a cluster, using a sliding shower fit result.
float CalculateConicalness(const pandora::CaloHitList &caloHitList, const pandora::CartesianVector &pfoStart, const pandora::CartesianVector &pfoDir, const float pfoLength)
Calculate conicalness as a ratio of charge distribution at the end and start of pfo.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
unsigned int m_slidingLinearFitWindow
The sliding linear fit window.
void CalculateVariablesSlidingLinearFit(const pandora::Cluster *const pCluster, float &straightLineLengthLarge, float &diffWithStraigthLineMean, float &diffWithStraightLineSigma, float &dTdLWidth, float &maxFitGapLength, float &rmsSlidingLinearFit) const
Calculation of several variables related to sliding linear fit.
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.
void CalculateChargeDistribution(const pandora::CaloHitList &caloHitList, const pandora::CartesianVector &pfoStart, const pandora::CartesianVector &pfoDir, float &chargeCore, float &chargeHalo, float &chargeCon)
Calculate charge distribution in relation to the Moeliere radius.
std::list< Vertex > VertexList
Definition: DCEL.h:169
pandora::CartesianVector GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
int GetLayer(const float rL) const
Get layer number for given sliding linear fit longitudinal coordinate.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const pandora::Algorithm *const pAlgorithm, const pandora::Cluster *const pCluster)
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)