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