LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
NeutrinoIdTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
13 #include "Helpers/MCParticleHelper.h"
14 
20 
22 
23 using namespace pandora;
24 
25 namespace lar_content
26 {
27 
28 NeutrinoIdTool::NeutrinoIdTool() :
29  m_useTrainingMode(false),
30  m_selectNuanceCode(false),
31  m_nuance(-std::numeric_limits<int>::max()),
32  m_minPurity(0.9f),
33  m_minCompleteness(0.9f),
34  m_minProbability(0.0f),
35  m_maxNeutrinos(1),
36  m_filePathEnvironmentVariable("FW_SEARCH_PATH")
37 {
38 }
39 
40 //------------------------------------------------------------------------------------------------------------------------------------------
41 
42 void NeutrinoIdTool::SelectOutputPfos(const Algorithm *const pAlgorithm, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, PfoList &selectedPfos)
43 {
44  if (nuSliceHypotheses.size() != crSliceHypotheses.size())
45  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
46 
47  const unsigned int nSlices(nuSliceHypotheses.size());
48  if (nSlices == 0) return;
49 
50  SliceFeaturesVector sliceFeaturesVector;
51  this->GetSliceFeatures(this, nuSliceHypotheses, crSliceHypotheses, sliceFeaturesVector);
52 
54  {
55  // ATTN in training mode, just return everything as a cosmic-ray
56  this->SelectAllPfos(pAlgorithm, crSliceHypotheses, selectedPfos);
57 
58  unsigned int bestSliceIndex(std::numeric_limits<unsigned int>::max());
59  if (!this->GetBestMCSliceIndex(pAlgorithm, nuSliceHypotheses, crSliceHypotheses, bestSliceIndex)) return;
60 
61  for (unsigned int sliceIndex = 0; sliceIndex < nSlices; ++sliceIndex)
62  {
63  const SliceFeatures &features(sliceFeaturesVector.at(sliceIndex));
64  if (!features.IsFeatureVectorAvailable()) continue;
65 
66  LArMvaHelper::MvaFeatureVector featureVector;
67  features.GetFeatureVector(featureVector);
68  LArMvaHelper::ProduceTrainingExample(m_trainingOutputFile, sliceIndex == bestSliceIndex, featureVector);
69  }
70 
71  return;
72  }
73 
74  this->SelectPfosByProbability(pAlgorithm, nuSliceHypotheses, crSliceHypotheses, sliceFeaturesVector, selectedPfos);
75 }
76 
77 //------------------------------------------------------------------------------------------------------------------------------------------
78 
79 void NeutrinoIdTool::GetSliceFeatures(const NeutrinoIdTool *const pTool, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, SliceFeaturesVector &sliceFeaturesVector) const
80 {
81  for (unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
82  sliceFeaturesVector.push_back(SliceFeatures(nuSliceHypotheses.at(sliceIndex), crSliceHypotheses.at(sliceIndex), pTool));
83 }
84 
85 //------------------------------------------------------------------------------------------------------------------------------------------
86 
87 bool NeutrinoIdTool::GetBestMCSliceIndex(const Algorithm *const pAlgorithm, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, unsigned int &bestSliceIndex) const
88 {
89  unsigned int nHitsInBestSlice(0), nNuHitsInBestSlice(0);
90 
91  // Get all hits in all slices to find true number of mc hits
92  const CaloHitList *pAllReconstructedCaloHitList(nullptr);
93  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pAllReconstructedCaloHitList));
94 
95  const MCParticleList *pMCParticleList(nullptr);
96  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pMCParticleList));
97 
98  // Obtain map: [mc particle -> primary mc particle]
99  LArMCParticleHelper::MCRelationMap mcToPrimaryMCMap;
100  LArMCParticleHelper::GetMCPrimaryMap(pMCParticleList, mcToPrimaryMCMap);
101 
102  // Remove non-reconstructable hits, e.g. those downstream of a neutron
103  CaloHitList reconstructableCaloHitList;
105  LArMCParticleHelper::SelectCaloHits(pAllReconstructedCaloHitList, mcToPrimaryMCMap, reconstructableCaloHitList, parameters.m_selectInputHits, parameters.m_maxPhotonPropagation);
106 
107  const int nuNHitsTotal(this->CountNeutrinoInducedHits(reconstructableCaloHitList));
108  const CaloHitSet reconstructableCaloHitSet(reconstructableCaloHitList.begin(), reconstructableCaloHitList.end());
109 
110  for (unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
111  {
112  CaloHitList reconstructedCaloHitList;
113  this->Collect2DHits(crSliceHypotheses.at(sliceIndex), reconstructedCaloHitList, reconstructableCaloHitSet);
114 
115  for (const ParticleFlowObject *const pNeutrino : nuSliceHypotheses.at(sliceIndex))
116  {
117  const PfoList &nuFinalStates(pNeutrino->GetDaughterPfoList());
118  this->Collect2DHits(nuFinalStates, reconstructedCaloHitList, reconstructableCaloHitSet);
119  }
120 
121  const unsigned int nNuHits(this->CountNeutrinoInducedHits(reconstructedCaloHitList));
122 
123  if (nNuHits > nNuHitsInBestSlice)
124  {
125  nNuHitsInBestSlice = nNuHits;
126  nHitsInBestSlice = reconstructedCaloHitList.size();
127  bestSliceIndex = sliceIndex;
128  }
129  }
130 
131  // ATTN for events with no neutrino induced hits, default neutrino purity and completeness to zero
132  const float purity(nHitsInBestSlice > 0 ? static_cast<float>(nNuHitsInBestSlice) / static_cast<float>(nHitsInBestSlice) : 0.f);
133  const float completeness(nuNHitsTotal > 0 ? static_cast<float>(nNuHitsInBestSlice) / static_cast<float>(nuNHitsTotal) : 0.f);
134 
135  return this->PassesQualityCuts(pAlgorithm, purity, completeness);
136 }
137 
138 //------------------------------------------------------------------------------------------------------------------------------------------
139 
140 bool NeutrinoIdTool::PassesQualityCuts(const Algorithm *const pAlgorithm, const float purity, const float completeness) const
141 {
142  if (purity < m_minPurity || completeness < m_minCompleteness) return false;
143  if (m_selectNuanceCode && (this->GetNuanceCode(pAlgorithm) != m_nuance)) return false;
144 
145  return true;
146 }
147 
148 //------------------------------------------------------------------------------------------------------------------------------------------
149 
150 void NeutrinoIdTool::Collect2DHits(const PfoList &pfos, CaloHitList &reconstructedCaloHitList, const CaloHitSet &reconstructableCaloHitSet) const
151 {
152  CaloHitList collectedHits;
153  LArPfoHelper::GetCaloHits(pfos, TPC_VIEW_U, collectedHits);
154  LArPfoHelper::GetCaloHits(pfos, TPC_VIEW_V, collectedHits);
155  LArPfoHelper::GetCaloHits(pfos, TPC_VIEW_W, collectedHits);
156 
157  for (const CaloHit *const pCaloHit : collectedHits)
158  {
159  if (!reconstructableCaloHitSet.count(pCaloHit))
160  continue;
161 
162  // Ensure no hits have been double counted
163  if (std::find(reconstructedCaloHitList.begin(), reconstructedCaloHitList.end(), pCaloHit) == reconstructedCaloHitList.end())
164  reconstructedCaloHitList.push_back(pCaloHit);
165  }
166 }
167 
168 //------------------------------------------------------------------------------------------------------------------------------------------
169 
170 unsigned int NeutrinoIdTool::CountNeutrinoInducedHits(const CaloHitList &caloHitList) const
171 {
172  unsigned int nNuHits(0);
173  for (const CaloHit *const pCaloHit : caloHitList)
174  {
175  try
176  {
177  if (LArMCParticleHelper::IsNeutrino(LArMCParticleHelper::GetParentMCParticle(MCParticleHelper::GetMainMCParticle(pCaloHit))))
178  nNuHits++;
179  }
180  catch (const StatusCodeException &)
181  {
182  }
183  }
184 
185  return nNuHits;
186 }
187 
188 //------------------------------------------------------------------------------------------------------------------------------------------
189 
190 int NeutrinoIdTool::GetNuanceCode(const Algorithm *const pAlgorithm) const
191 {
192  const MCParticleList *pMCParticleList = nullptr;
193  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pMCParticleList));
194 
195  MCParticleVector trueNeutrinos;
196  LArMCParticleHelper::GetTrueNeutrinos(pMCParticleList, trueNeutrinos);
197 
198  if (trueNeutrinos.size() != 1)
199  {
200  std::cout << "NeutrinoIdTool::GetNuanceCode - Error: number of true neutrinos in event must be exactly one" << std::endl;
201  throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
202  }
203 
204  return LArMCParticleHelper::GetNuanceCode(trueNeutrinos.front());
205 }
206 
207 //------------------------------------------------------------------------------------------------------------------------------------------
208 
209 void NeutrinoIdTool::SelectAllPfos(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &hypotheses, PfoList &selectedPfos) const
210 {
211  for (const PfoList &pfos : hypotheses)
212  {
213  for (const ParticleFlowObject *const pPfo : pfos)
214  {
215  object_creation::ParticleFlowObject::Metadata metadata;
216  metadata.m_propertiesToAdd["NuScore"] = -1.f;
217  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
218  }
219 
220  this->SelectPfos(pfos, selectedPfos);
221  }
222 }
223 
224 //------------------------------------------------------------------------------------------------------------------------------------------
225 
226 void NeutrinoIdTool::SelectPfosByProbability(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, const SliceFeaturesVector &sliceFeaturesVector, PfoList &selectedPfos) const
227 {
228  // Calculate the probability of each slice that passes the minimum probability cut
229  std::vector<UintFloatPair> sliceIndexProbabilityPairs;
230  for (unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
231  {
232  const float nuProbability(sliceFeaturesVector.at(sliceIndex).GetNeutrinoProbability(m_supportVectorMachine));
233 
234  for (const ParticleFlowObject *const pPfo : crSliceHypotheses.at(sliceIndex))
235  {
236  object_creation::ParticleFlowObject::Metadata metadata;
237  metadata.m_propertiesToAdd["NuScore"] = nuProbability;
238  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
239  }
240 
241  for (const ParticleFlowObject *const pPfo : nuSliceHypotheses.at(sliceIndex))
242  {
243  object_creation::ParticleFlowObject::Metadata metadata;
244  metadata.m_propertiesToAdd["NuScore"] = nuProbability;
245  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
246  }
247 
248  if (nuProbability < m_minProbability)
249  {
250  this->SelectPfos(crSliceHypotheses.at(sliceIndex), selectedPfos);
251  continue;
252  }
253 
254  sliceIndexProbabilityPairs.push_back(UintFloatPair(sliceIndex, nuProbability));
255  }
256 
257  // Sort the slices by probability
258  std::sort(sliceIndexProbabilityPairs.begin(), sliceIndexProbabilityPairs.end(), [] (const UintFloatPair &a, const UintFloatPair &b)
259  {
260  return (a.second > b.second);
261  });
262 
263  // Select the first m_maxNeutrinos as neutrinos, and the rest as cosmic
264  unsigned int nNuSlices(0);
265  for (const UintFloatPair &slice : sliceIndexProbabilityPairs)
266  {
267  if (nNuSlices < m_maxNeutrinos)
268  {
269  this->SelectPfos(nuSliceHypotheses.at(slice.first), selectedPfos);
270  nNuSlices++;
271  continue;
272  }
273 
274  this->SelectPfos(crSliceHypotheses.at(slice.first), selectedPfos);
275  }
276 }
277 
278 //------------------------------------------------------------------------------------------------------------------------------------------
279 
280 void NeutrinoIdTool::SelectPfos(const PfoList &pfos, PfoList &selectedPfos) const
281 {
282  selectedPfos.insert(selectedPfos.end(), pfos.begin(), pfos.end());
283 }
284 
285 //------------------------------------------------------------------------------------------------------------------------------------------
286 //------------------------------------------------------------------------------------------------------------------------------------------
287 
288 // TODO think about how to make this function cleaner when features are more established
289 NeutrinoIdTool::SliceFeatures::SliceFeatures(const PfoList &nuPfos, const PfoList &crPfos, const NeutrinoIdTool *const pTool) :
290  m_isAvailable(false),
291  m_pTool(pTool)
292 {
293  try
294  {
295  const ParticleFlowObject *const pNeutrino(this->GetNeutrino(nuPfos));
296  const CartesianVector &nuVertex(LArPfoHelper::GetVertex(pNeutrino)->GetPosition());
297  const PfoList &nuFinalStates(pNeutrino->GetDaughterPfoList());
298 
299  // Neutrino features
300  CartesianVector nuWeightedDirTotal(0.f, 0.f, 0.f);
301  unsigned int nuNHitsUsedTotal(0);
302  unsigned int nuNHitsTotal(0);
303  CartesianPointVector nuAllSpacePoints;
304  for (const ParticleFlowObject *const pPfo : nuFinalStates)
305  {
306  CartesianPointVector spacePoints;
307  this->GetSpacePoints(pPfo, spacePoints);
308 
309  nuAllSpacePoints.insert(nuAllSpacePoints.end(), spacePoints.begin(), spacePoints.end());
310  nuNHitsTotal += spacePoints.size();
311 
312  if (spacePoints.size() < 5) continue;
313 
314  const CartesianVector dir(this->GetDirectionFromVertex(spacePoints, nuVertex));
315  nuWeightedDirTotal += dir * static_cast<float>(spacePoints.size());
316  nuNHitsUsedTotal += spacePoints.size();
317  }
318 
319  if (nuNHitsUsedTotal == 0) return;
320  const CartesianVector nuWeightedDir(nuWeightedDirTotal * (1.f / static_cast<float>(nuNHitsUsedTotal)));
321 
322  CartesianPointVector pointsInSphere;
323  this->GetPointsInSphere(nuAllSpacePoints, nuVertex, 10, pointsInSphere);
324 
327  LArPcaHelper::EigenVectors eigenVectors;
328  LArPcaHelper::RunPca(pointsInSphere, centroid, eigenValues, eigenVectors);
329 
330 
331  const float nuNFinalStatePfos(static_cast<float>(nuFinalStates.size()));
332  const float nuVertexY(nuVertex.GetY());
333  const float nuWeightedDirZ(nuWeightedDir.GetZ());
334  const float nuNSpacePointsInSphere(static_cast<float>(pointsInSphere.size()));
335 
336  if (eigenValues.GetX() <= std::numeric_limits<float>::epsilon()) return;
337  const float nuEigenRatioInSphere(eigenValues.GetY() / eigenValues.GetX());
338 
339  // Cosmic-ray features
340  unsigned int nCRHitsMax(0);
341  unsigned int nCRHitsTotal(0);
342  float crLongestTrackDirY(std::numeric_limits<float>::max());
343  float crLongestTrackDeflection(-std::numeric_limits<float>::max());
344 
345  for (const ParticleFlowObject *const pPfo : crPfos)
346  {
347  CartesianPointVector spacePoints;
348  this->GetSpacePoints(pPfo, spacePoints);
349 
350  nCRHitsTotal += spacePoints.size();
351 
352  if (spacePoints.size() < 5) continue;
353 
354  if (spacePoints.size() > nCRHitsMax)
355  {
356  nCRHitsMax = spacePoints.size();
357  const CartesianVector upperDir(this->GetUpperDirection(spacePoints));
358  const CartesianVector lowerDir(this->GetLowerDirection(spacePoints));
359 
360  crLongestTrackDirY = upperDir.GetY();
361  crLongestTrackDeflection = 1.f - upperDir.GetDotProduct(lowerDir * (-1.f));
362  }
363  }
364 
365  if (nCRHitsMax == 0) return;
366  if (nCRHitsTotal == 0) return;
367 
368  const float crFracHitsInLongestTrack = static_cast<float>(nCRHitsMax)/static_cast<float>(nCRHitsTotal);
369 
370  // Push the features to the feature vector
371  m_featureVector.push_back(nuNFinalStatePfos);
372  m_featureVector.push_back(nuNHitsTotal);
373  m_featureVector.push_back(nuVertexY);
374  m_featureVector.push_back(nuWeightedDirZ);
375  m_featureVector.push_back(nuNSpacePointsInSphere);
376  m_featureVector.push_back(nuEigenRatioInSphere);
377  m_featureVector.push_back(crLongestTrackDirY);
378  m_featureVector.push_back(crLongestTrackDeflection);
379  m_featureVector.push_back(crFracHitsInLongestTrack);
380  m_featureVector.push_back(nCRHitsMax);
381 
382  m_isAvailable = true;
383  }
384  catch (StatusCodeException &)
385  {
386  return;
387  }
388 }
389 
390 //------------------------------------------------------------------------------------------------------------------------------------------
391 
393 {
394  return m_isAvailable;
395 }
396 
397 //------------------------------------------------------------------------------------------------------------------------------------------
398 
400 {
401  if (!m_isAvailable)
402  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
403 
404  featureVector.insert(featureVector.end(), m_featureVector.begin(), m_featureVector.end());
405 }
406 
407 //------------------------------------------------------------------------------------------------------------------------------------------
408 
410 {
411  // ATTN if one or more of the features can not be calculated, then default to calling the slice a cosmic ray
412  if (!this->IsFeatureVectorAvailable()) return 0.f;
413 
414  LArMvaHelper::MvaFeatureVector featureVector;
415  this->GetFeatureVector(featureVector);
416  return LArMvaHelper::CalculateProbability(supportVectorMachine, featureVector);
417 }
418 
419 //------------------------------------------------------------------------------------------------------------------------------------------
420 
421 const ParticleFlowObject *NeutrinoIdTool::SliceFeatures::GetNeutrino(const PfoList &nuPfos) const
422 {
423  // ATTN we should only ever have one neutrino reconstructed per slice
424  if (nuPfos.size() != 1)
425  throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
426 
427  return nuPfos.front();
428 }
429 
430 //------------------------------------------------------------------------------------------------------------------------------------------
431 
432 void NeutrinoIdTool::SliceFeatures::GetSpacePoints(const ParticleFlowObject *const pPfo, CartesianPointVector &spacePoints) const
433 {
434  ClusterList clusters3D;
435  LArPfoHelper::GetThreeDClusterList(pPfo, clusters3D);
436 
437  if (clusters3D.size() > 1)
438  throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
439 
440  if (clusters3D.empty()) return;
441 
442  CaloHitList caloHits;
443  clusters3D.front()->GetOrderedCaloHitList().FillCaloHitList(caloHits);
444 
445  for (const CaloHit *const pCaloHit : caloHits)
446  spacePoints.push_back(pCaloHit->GetPositionVector());
447 }
448 
449 //------------------------------------------------------------------------------------------------------------------------------------------
450 
451 CartesianVector NeutrinoIdTool::SliceFeatures::GetDirectionFromVertex(const CartesianPointVector &spacePoints, const CartesianVector &vertex) const
452 {
453  return this->GetDirection(spacePoints, [&] (const CartesianVector &pointA, const CartesianVector &pointB)
454  {
455  return ((pointA - vertex).GetMagnitude() < (pointB - vertex).GetMagnitude());
456  });
457 }
458 
459 //------------------------------------------------------------------------------------------------------------------------------------------
460 
461 CartesianVector NeutrinoIdTool::SliceFeatures::GetUpperDirection(const CartesianPointVector &spacePoints) const
462 {
463  return this->GetDirection(spacePoints, [&] (const CartesianVector &pointA, const CartesianVector &pointB)
464  {
465  return (pointA.GetY() > pointB.GetY());
466  });
467 }
468 
469 //------------------------------------------------------------------------------------------------------------------------------------------
470 
471 CartesianVector NeutrinoIdTool::SliceFeatures::GetLowerDirection(const CartesianPointVector &spacePoints) const
472 {
473  return this->GetDirection(spacePoints, [&] (const CartesianVector &pointA, const CartesianVector &pointB)
474  {
475  return (pointA.GetY() < pointB.GetY());
476  });
477 }
478 
479 //------------------------------------------------------------------------------------------------------------------------------------------
480 
481 CartesianVector NeutrinoIdTool::SliceFeatures::GetDirection(const CartesianPointVector &spacePoints, std::function<bool(const CartesianVector &pointA, const CartesianVector &pointB)> fShouldChooseA) const
482 {
483  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
484  const LArTPC *const pFirstLArTPC(m_pTool->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
485  const float layerPitch(pFirstLArTPC->GetWirePitchW());
486 
487  const ThreeDSlidingFitResult fit(&spacePoints, 5, layerPitch);
488  const CartesianVector endMin(fit.GetGlobalMinLayerPosition());
489  const CartesianVector endMax(fit.GetGlobalMaxLayerPosition());
490  const CartesianVector dirMin(fit.GetGlobalMinLayerDirection());
491  const CartesianVector dirMax(fit.GetGlobalMaxLayerDirection());
492 
493  const bool isMinStart(fShouldChooseA(endMin, endMax));
494  const CartesianVector startPoint(isMinStart ? endMin : endMax);
495  const CartesianVector endPoint(isMinStart ? endMax : endMin);
496  const CartesianVector startDir(isMinStart ? dirMin : dirMax);
497 
498  const bool shouldFlip((endPoint - startPoint).GetUnitVector().GetDotProduct(startDir) < 0.f);
499  return (shouldFlip ? startDir*(-1.f) : startDir);
500 }
501 
502 //------------------------------------------------------------------------------------------------------------------------------------------
503 
504 void NeutrinoIdTool::SliceFeatures::GetPointsInSphere(const CartesianPointVector &spacePoints, const CartesianVector &vertex, const float radius, CartesianPointVector &spacePointsInSphere) const
505 {
506  for (const CartesianVector &point : spacePoints)
507  {
508  if ((point - vertex).GetMagnitudeSquared() <= radius*radius)
509  spacePointsInSphere.push_back(point);
510  }
511 }
512 
513 //------------------------------------------------------------------------------------------------------------------------------------------
514 
515 StatusCode NeutrinoIdTool::ReadSettings(const TiXmlHandle xmlHandle)
516 {
517  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
518  "UseTrainingMode", m_useTrainingMode));
519 
520  if (m_useTrainingMode)
521  {
522  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
523  "TrainingOutputFileName", m_trainingOutputFile));
524  }
525 
526  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
527  "MinimumPurity", m_minPurity));
528 
529  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
530  "MinimumCompleteness", m_minCompleteness));
531 
532  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
533  "SelectNuanceCode", m_selectNuanceCode));
534 
535  if (m_selectNuanceCode)
536  {
537  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
538  "NuanceCode", m_nuance));
539  }
540 
541  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
542  "MinimumNeutrinoProbability", m_minProbability));
543 
544  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
545  "MaximumNeutrinos", m_maxNeutrinos));
546 
547  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
548  "FilePathEnvironmentVariable", m_filePathEnvironmentVariable));
549 
550  if (!m_useTrainingMode)
551  {
552  std::string svmName;
553  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
554  "SvmName", svmName));
555 
556  std::string svmFileName;
557  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
558  "SvmFileName", svmFileName));
559 
560  const std::string fullSvmFileName(LArFileHelper::FindFileInPath(svmFileName, m_filePathEnvironmentVariable));
561  m_supportVectorMachine.Initialize(fullSvmFileName, svmName);
562  }
563 
564  return STATUS_CODE_SUCCESS;
565 }
566 
567 } // namespace lar_content
float GetNeutrinoProbability(const SupportVectorMachine &supportVectorMachine) const
Get the probability that this slice contains a neutrino interaction.
static double CalculateProbability(const MvaInterface &classifier, TLISTS &&...featureLists)
Use the trained mva to calculate a classification probability for an example.
Definition: LArMvaHelper.h:236
void GetPointsInSphere(const pandora::CartesianPointVector &spacePoints, const pandora::CartesianVector &vertex, const float radius, pandora::CartesianPointVector &spacePointsInSphere) const
Get a vector of spacepoints within a given radius of a vertex point.
bool m_isAvailable
Is the feature vector available.
std::string m_filePathEnvironmentVariable
The environment variable providing a list of paths to svm files.
bool m_selectNuanceCode
Should select training events by nuance code.
float m_minCompleteness
Minimum completeness of the best slice to use event for training.
Header file for the pfo helper class.
const NeutrinoIdTool *const m_pTool
The tool that owns this.
bool GetBestMCSliceIndex(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, unsigned int &bestSliceIndex) const
Get the slice with the most neutrino induced hits using Monte-Carlo information.
Header file for the neutrino id tool class.
bool m_selectInputHits
whether to select input hits
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:58
pandora::CartesianVector GetDirection(const pandora::CartesianPointVector &spacePoints, std::function< bool(const pandora::CartesianVector &pointA, const pandora::CartesianVector &pointB)> fShouldChooseA) const
Use a sliding fit to get the direction of a collection of spacepoints.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
int m_nuance
Nuance code to select for training.
pandora::CartesianVector EigenValues
Definition: LArPcaHelper.h:21
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
STL namespace.
unsigned int m_maxNeutrinos
The maximum number of neutrinos to select in any one event.
Header file for the principal curve analysis helper class.
LArMvaHelper::MvaFeatureVector m_featureVector
The SVM feature vector.
static void GetMCPrimaryMap(const pandora::MCParticleList *const pMCParticleList, MCRelationMap &mcPrimaryMap)
Get mapping from individual mc particles (in a provided list) and their primary parent mc particles...
pandora::CartesianVector GetDirectionFromVertex(const pandora::CartesianPointVector &spacePoints, const pandora::CartesianVector &vertex) const
Use a sliding fit to get the direction of a collection of spacepoint near a vertex position...
float m_minPurity
Minimum purity of the best slice to use event for training.
bool IsFeatureVectorAvailable() const
Check if all features were calculable.
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
static unsigned int GetNuanceCode(const pandora::MCParticle *const pMCParticle)
Get the nuance code of an MCParticle.
float m_maxPhotonPropagation
the maximum photon propagation length
static void SelectCaloHits(const pandora::CaloHitList *const pCaloHitList, const MCRelationMap &mcToPrimaryMCMap, pandora::CaloHitList &selectedCaloHitList, const bool selectInputHits, const float maxPhotonPropagation)
Select a subset of calo hits representing those that represent "reconstructable" regions of the event...
TFile f
Definition: plotHisto.C:6
void GetSpacePoints(const pandora::ParticleFlowObject *const pPfo, pandora::CartesianPointVector &spacePoints) const
Get the 3D space points in a given pfo.
std::pair< unsigned int, float > UintFloatPair
unsigned int CountNeutrinoInducedHits(const pandora::CaloHitList &caloHitList) const
Count the number of neutrino induced hits in a given list using MC information.
void SelectPfosByProbability(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, const SliceFeaturesVector &sliceFeaturesVector, pandora::PfoList &selectedPfos) const
Select pfos based on the probability that their slice contains a neutrino interaction.
Int_t max
Definition: plot.C:27
static pandora::StatusCode ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TLISTS &&...featureLists)
Produce a training example with the given features and result.
Definition: LArMvaHelper.h:197
void SelectAllPfos(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &hypotheses, pandora::PfoList &selectedPfos) const
Select all pfos under the same hypothesis.
Header file for the lar monte carlo particle helper helper class.
std::vector< SliceFeatures > SliceFeaturesVector
void SelectOutputPfos(const pandora::Algorithm *const pAlgorithm, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, pandora::PfoList &selectedPfos)
Select which reconstruction hypotheses to use; neutrino outcomes or cosmic-ray muon outcomes for each...
std::vector< pandora::PfoList > SliceHypotheses
void Collect2DHits(const pandora::PfoList &pfos, pandora::CaloHitList &reconstructedCaloHitList, const pandora::CaloHitSet &reconstructableCaloHitSet) const
Collect all 2D hits in a supplied list of Pfos and push them on to an existing hit list...
int GetNuanceCode(const pandora::Algorithm *const pAlgorithm) const
Use the current MCParticle list to get the nuance code of the neutrino in the event.
static const pandora::MCParticle * GetParentMCParticle(const pandora::MCParticle *const pMCParticle)
Get the parent mc particle.
Double_t radius
static std::string FindFileInPath(const std::string &unqualifiedFileName, const std::string &environmentVariable, const std::string &delimiter=":")
Find the fully-qualified file name by searching through a list of delimiter-separated paths in a name...
Header file for the file helper class.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
Header file for the lar three dimensional sliding fit result class.
NeutrinoIdTool class.
SliceFeatures(const pandora::PfoList &nuPfos, const pandora::PfoList &crPfos, const NeutrinoIdTool *const pTool)
Constructor.
void GetFeatureVector(LArMvaHelper::MvaFeatureVector &featureVector) const
Get the feature vector for the SVM.
pandora::StatusCode Initialize(const std::string &parameterLocation, const std::string &svmName)
Initialize the svm using a serialized model.
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...
void GetSliceFeatures(const NeutrinoIdTool *const pTool, const SliceHypotheses &nuSliceHypotheses, const SliceHypotheses &crSliceHypotheses, SliceFeaturesVector &sliceFeaturesVector) const
Get the features of each slice.
static void GetTrueNeutrinos(const pandora::MCParticleList *const pMCParticleList, pandora::MCParticleVector &trueNeutrinos)
Get neutrino MC particles from an input MC particle list.
TDirectory * dir
Definition: macro.C:5
std::string m_trainingOutputFile
Output file name for training examples.
float m_minProbability
Minimum probability required to classify a slice as the neutrino.
std::vector< pandora::CartesianVector > EigenVectors
Definition: LArPcaHelper.h:22
bool m_useTrainingMode
Should use training mode. If true, training examples will be written to the output file...
void SelectPfos(const pandora::PfoList &pfos, pandora::PfoList &selectedPfos) const
Add the given pfos to the selected Pfo list.
SupportVectorMachine m_supportVectorMachine
The support vector machine.
pandora::CartesianVector GetLowerDirection(const pandora::CartesianPointVector &spacePoints) const
Use a sliding fit to get the lower direction of a collection of spacepoints.
std::unordered_map< const pandora::MCParticle *, const pandora::MCParticle * > MCRelationMap
pandora::CartesianVector GetUpperDirection(const pandora::CartesianPointVector &spacePoints) const
Use a sliding fit to get the upper direction of a collection of spacepoints.
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
bool PassesQualityCuts(const pandora::Algorithm *const pAlgorithm, const float purity, const float completeness) const
Determine if the event passes the selection cuts for training and has the required NUANCE code...
const pandora::ParticleFlowObject * GetNeutrino(const pandora::PfoList &nuPfos) const
Get the recontructed neutrino the input list of neutrino Pfos.
static bool IsNeutrino(const pandora::MCParticle *const pMCParticle)
Whether a mc particle is a neutrino or antineutrino.
vertex reconstruction