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