9 #include "Pandora/AlgorithmHeaders.h" 13 #include "Helpers/MCParticleHelper.h" 28 NeutrinoIdTool::NeutrinoIdTool() :
29 m_useTrainingMode(false),
30 m_selectNuanceCode(false),
31 m_nuance(-
std::numeric_limits<int>::
max()),
33 m_minCompleteness(0.9
f),
34 m_minProbability(0.0
f),
36 m_filePathEnvironmentVariable(
"FW_SEARCH_PATH")
44 if (nuSliceHypotheses.size() != crSliceHypotheses.size())
45 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
47 const unsigned int nSlices(nuSliceHypotheses.size());
48 if (nSlices == 0)
return;
51 this->
GetSliceFeatures(
this, nuSliceHypotheses, crSliceHypotheses, sliceFeaturesVector);
56 this->
SelectAllPfos(pAlgorithm, crSliceHypotheses, selectedPfos);
59 if (!this->
GetBestMCSliceIndex(pAlgorithm, nuSliceHypotheses, crSliceHypotheses, bestSliceIndex))
return;
61 for (
unsigned int sliceIndex = 0; sliceIndex < nSlices; ++sliceIndex)
63 const SliceFeatures &features(sliceFeaturesVector.at(sliceIndex));
64 if (!features.IsFeatureVectorAvailable())
continue;
74 this->
SelectPfosByProbability(pAlgorithm, nuSliceHypotheses, crSliceHypotheses, sliceFeaturesVector, selectedPfos);
81 for (
unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
82 sliceFeaturesVector.push_back(
SliceFeatures(nuSliceHypotheses.at(sliceIndex), crSliceHypotheses.at(sliceIndex), pTool));
89 unsigned int nHitsInBestSlice(0), nNuHitsInBestSlice(0);
92 const CaloHitList *pAllReconstructedCaloHitList(
nullptr);
93 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pAllReconstructedCaloHitList));
95 const MCParticleList *pMCParticleList(
nullptr);
96 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pMCParticleList));
103 CaloHitList reconstructableCaloHitList;
108 const CaloHitSet reconstructableCaloHitSet(reconstructableCaloHitList.begin(), reconstructableCaloHitList.end());
110 for (
unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
112 CaloHitList reconstructedCaloHitList;
113 this->
Collect2DHits(crSliceHypotheses.at(sliceIndex), reconstructedCaloHitList, reconstructableCaloHitSet);
115 for (
const ParticleFlowObject *
const pNeutrino : nuSliceHypotheses.at(sliceIndex))
117 const PfoList &nuFinalStates(pNeutrino->GetDaughterPfoList());
118 this->
Collect2DHits(nuFinalStates, reconstructedCaloHitList, reconstructableCaloHitSet);
123 if (nNuHits > nNuHitsInBestSlice)
125 nNuHitsInBestSlice = nNuHits;
126 nHitsInBestSlice = reconstructedCaloHitList.size();
127 bestSliceIndex = sliceIndex;
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);
152 CaloHitList collectedHits;
157 for (
const CaloHit *
const pCaloHit : collectedHits)
159 if (!reconstructableCaloHitSet.count(pCaloHit))
163 if (std::find(reconstructedCaloHitList.begin(), reconstructedCaloHitList.end(), pCaloHit) == reconstructedCaloHitList.end())
164 reconstructedCaloHitList.push_back(pCaloHit);
172 unsigned int nNuHits(0);
173 for (
const CaloHit *
const pCaloHit : caloHitList)
180 catch (
const StatusCodeException &)
192 const MCParticleList *pMCParticleList =
nullptr;
193 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pMCParticleList));
198 if (trueNeutrinos.size() != 1)
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);
211 for (
const PfoList &pfos : hypotheses)
213 for (
const ParticleFlowObject *
const pPfo : pfos)
215 object_creation::ParticleFlowObject::Metadata metadata;
216 metadata.m_propertiesToAdd[
"TestBeamScore"] = -1.f;
217 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*pAlgorithm, pPfo, metadata));
229 std::vector<UintFloatPair> sliceIndexProbabilityPairs;
230 for (
unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
232 const float nuProbability(sliceFeaturesVector.at(sliceIndex).GetNeutrinoProbability(
m_supportVectorMachine));
234 for (
const ParticleFlowObject *
const pPfo : crSliceHypotheses.at(sliceIndex))
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));
241 for (
const ParticleFlowObject *
const pPfo : nuSliceHypotheses.at(sliceIndex))
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));
250 this->
SelectPfos(crSliceHypotheses.at(sliceIndex), selectedPfos);
254 sliceIndexProbabilityPairs.push_back(
UintFloatPair(sliceIndex, nuProbability));
258 std::sort(sliceIndexProbabilityPairs.begin(), sliceIndexProbabilityPairs.end(), [] (
const UintFloatPair &a,
const UintFloatPair &b)
260 return (a.second > b.second);
264 unsigned int nNuSlices(0);
265 for (
const UintFloatPair &slice : sliceIndexProbabilityPairs)
269 this->
SelectPfos(nuSliceHypotheses.at(slice.first), selectedPfos);
274 this->
SelectPfos(crSliceHypotheses.at(slice.first), selectedPfos);
282 selectedPfos.insert(selectedPfos.end(), pfos.begin(), pfos.end());
290 m_isAvailable(false),
295 const ParticleFlowObject *
const pNeutrino(this->
GetNeutrino(nuPfos));
297 const PfoList &nuFinalStates(pNeutrino->GetDaughterPfoList());
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)
306 CartesianPointVector spacePoints;
309 nuAllSpacePoints.insert(nuAllSpacePoints.end(), spacePoints.begin(), spacePoints.end());
310 nuNHitsTotal += spacePoints.size();
312 if (spacePoints.size() < 5)
continue;
315 nuWeightedDirTotal += dir *
static_cast<float>(spacePoints.size());
316 nuNHitsUsedTotal += spacePoints.size();
319 if (nuNHitsUsedTotal == 0)
return;
320 const CartesianVector nuWeightedDir(nuWeightedDirTotal * (1.
f / static_cast<float>(nuNHitsUsedTotal)));
322 CartesianPointVector pointsInSphere;
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()));
336 if (eigenValues.GetX() <= std::numeric_limits<float>::epsilon())
return;
337 const float nuEigenRatioInSphere(eigenValues.GetY() / eigenValues.GetX());
340 unsigned int nCRHitsMax(0);
341 unsigned int nCRHitsTotal(0);
345 for (
const ParticleFlowObject *
const pPfo : crPfos)
347 CartesianPointVector spacePoints;
350 nCRHitsTotal += spacePoints.size();
352 if (spacePoints.size() < 5)
continue;
354 if (spacePoints.size() > nCRHitsMax)
356 nCRHitsMax = spacePoints.size();
360 crLongestTrackDirY = upperDir.GetY();
361 crLongestTrackDeflection = 1.f - upperDir.GetDotProduct(lowerDir * (-1.
f));
365 if (nCRHitsMax == 0)
return;
366 if (nCRHitsTotal == 0)
return;
368 const float crFracHitsInLongestTrack =
static_cast<float>(nCRHitsMax)/static_cast<float>(nCRHitsTotal);
384 catch (StatusCodeException &)
402 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
424 if (nuPfos.size() != 1)
425 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
427 return nuPfos.front();
434 ClusterList clusters3D;
437 if (clusters3D.size() > 1)
438 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
440 if (clusters3D.empty())
return;
442 CaloHitList caloHits;
443 clusters3D.front()->GetOrderedCaloHitList().FillCaloHitList(caloHits);
445 for (
const CaloHit *
const pCaloHit : caloHits)
446 spacePoints.push_back(pCaloHit->GetPositionVector());
453 return this->
GetDirection(spacePoints, [&] (
const CartesianVector &pointA,
const CartesianVector &pointB)
455 return ((pointA - vertex).GetMagnitude() < (pointB - vertex).GetMagnitude());
463 return this->
GetDirection(spacePoints, [&] (
const CartesianVector &pointA,
const CartesianVector &pointB)
465 return (pointA.GetY() > pointB.GetY());
473 return this->
GetDirection(spacePoints, [&] (
const CartesianVector &pointA,
const CartesianVector &pointB)
475 return (pointA.GetY() < pointB.GetY());
484 const LArTPC *
const pFirstLArTPC(
m_pTool->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
485 const float layerPitch(pFirstLArTPC->GetWirePitchW());
488 const CartesianVector endMin(fit.GetGlobalMinLayerPosition());
489 const CartesianVector endMax(fit.GetGlobalMaxLayerPosition());
490 const CartesianVector dirMin(fit.GetGlobalMinLayerDirection());
491 const CartesianVector dirMax(fit.GetGlobalMaxLayerDirection());
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);
498 const bool shouldFlip((endPoint - startPoint).GetUnitVector().GetDotProduct(startDir) < 0.
f);
499 return (shouldFlip ? startDir*(-1.
f) : startDir);
506 for (
const CartesianVector &point : spacePoints)
508 if ((point - vertex).GetMagnitudeSquared() <= radius*radius)
509 spacePointsInSphere.push_back(point);
517 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
522 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
526 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
529 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
532 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
537 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
541 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
544 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
547 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
553 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
554 "SvmName", svmName));
556 std::string svmFileName;
557 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
558 "SvmFileName", svmFileName));
564 return STATUS_CODE_SUCCESS;
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.
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.
SupportVectorMachine class.
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.
bool m_selectInputHits
whether to select input hits
MvaTypes::MvaFeatureVector MvaFeatureVector
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
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
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...
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.
static pandora::StatusCode ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TLISTS &&...featureLists)
Produce a training example with the given features and result.
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.
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.
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 ¶meterLocation, const std::string &svmName)
Initialize the svm using a serialized model.
static void RunPca(const T &t, pandora::CartesianVector ¢roid, 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.
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
bool m_useTrainingMode
Should use training mode. If true, training examples will be written to the output file...
ThreeDSlidingFitResult class.
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.