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