9 #include "Pandora/AlgorithmHeaders.h" 13 #include "Helpers/MCParticleHelper.h" 30 m_useTrainingMode(false),
31 m_selectNuanceCode(false),
32 m_nuance(-
std::numeric_limits<
int>::
max()),
34 m_minCompleteness(0.9
f),
35 m_minProbability(0.0
f),
37 m_filePathEnvironmentVariable(
"FW_SEARCH_PATH")
47 if (nuSliceHypotheses.size() != crSliceHypotheses.size())
48 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
50 const unsigned int nSlices(nuSliceHypotheses.size());
55 this->
GetSliceFeatures(
this, nuSliceHypotheses, crSliceHypotheses, sliceFeaturesVector);
60 this->
SelectAllPfos(pAlgorithm, crSliceHypotheses, selectedPfos);
63 if (!this->
GetBestMCSliceIndex(pAlgorithm, nuSliceHypotheses, crSliceHypotheses, bestSliceIndex))
66 for (
unsigned int sliceIndex = 0; sliceIndex < nSlices; ++sliceIndex)
69 if (!
features.IsFeatureVectorAvailable())
73 features.GetFeatureVector(featureVector);
80 this->
SelectPfosByProbability(pAlgorithm, nuSliceHypotheses, crSliceHypotheses, sliceFeaturesVector, selectedPfos);
89 for (
unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
90 sliceFeaturesVector.push_back(
SliceFeatures(nuSliceHypotheses.at(sliceIndex), crSliceHypotheses.at(sliceIndex), pTool));
97 const SliceHypotheses &crSliceHypotheses,
unsigned int &bestSliceIndex)
const 99 unsigned int nHitsInBestSlice(0), nNuHitsInBestSlice(0);
102 const CaloHitList *pAllReconstructedCaloHitList(
nullptr);
103 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pAllReconstructedCaloHitList));
105 const MCParticleList *pMCParticleList(
nullptr);
106 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pMCParticleList));
113 CaloHitList reconstructableCaloHitList;
119 const CaloHitSet reconstructableCaloHitSet(reconstructableCaloHitList.begin(), reconstructableCaloHitList.end());
121 for (
unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
123 CaloHitList reconstructedCaloHitList;
124 this->
Collect2DHits(crSliceHypotheses.at(sliceIndex), reconstructedCaloHitList, reconstructableCaloHitSet);
126 for (
const ParticleFlowObject *
const pNeutrino : nuSliceHypotheses.at(sliceIndex))
128 const PfoList &nuFinalStates(pNeutrino->GetDaughterPfoList());
129 this->
Collect2DHits(nuFinalStates, reconstructedCaloHitList, reconstructableCaloHitSet);
134 if (nNuHits > nNuHitsInBestSlice)
136 nNuHitsInBestSlice = nNuHits;
137 nHitsInBestSlice = reconstructedCaloHitList.size();
138 bestSliceIndex = sliceIndex;
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);
150 template <
typename T>
163 template <
typename T>
166 CaloHitList collectedHits;
171 for (
const CaloHit *
const pCaloHit : collectedHits)
173 const CaloHit *
const pParentHit =
static_cast<const CaloHit *
>(pCaloHit->GetParentAddress());
174 if (!reconstructableCaloHitSet.count(pParentHit))
178 if (std::find(reconstructedCaloHitList.begin(), reconstructedCaloHitList.end(), pParentHit) == reconstructedCaloHitList.end())
179 reconstructedCaloHitList.push_back(pParentHit);
185 template <
typename T>
188 unsigned int nNuHits(0);
189 for (
const CaloHit *
const pCaloHit : caloHitList)
196 catch (
const StatusCodeException &)
206 template <
typename T>
209 const MCParticleList *pMCParticleList =
nullptr;
210 PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*pAlgorithm, pMCParticleList));
215 if (trueNeutrinos.size() != 1)
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);
226 template <
typename T>
229 for (
const PfoList &pfos : hypotheses)
231 for (
const ParticleFlowObject *
const pPfo : pfos)
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));
244 template <
typename T>
249 std::vector<UintFloatPair> sliceIndexProbabilityPairs;
250 for (
unsigned int sliceIndex = 0, nSlices = nuSliceHypotheses.size(); sliceIndex < nSlices; ++sliceIndex)
252 const float nuProbability(sliceFeaturesVector.at(sliceIndex).GetNeutrinoProbability(
m_mva));
254 for (
const ParticleFlowObject *
const pPfo : crSliceHypotheses.at(sliceIndex))
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));
261 for (
const ParticleFlowObject *
const pPfo : nuSliceHypotheses.at(sliceIndex))
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));
270 this->
SelectPfos(crSliceHypotheses.at(sliceIndex), selectedPfos);
274 sliceIndexProbabilityPairs.push_back(
UintFloatPair(sliceIndex, nuProbability));
278 std::sort(sliceIndexProbabilityPairs.begin(), sliceIndexProbabilityPairs.end(),
282 unsigned int nNuSlices(0);
283 for (
const UintFloatPair &slice : sliceIndexProbabilityPairs)
287 this->
SelectPfos(nuSliceHypotheses.at(slice.first), selectedPfos);
292 this->
SelectPfos(crSliceHypotheses.at(slice.first), selectedPfos);
298 template <
typename T>
301 selectedPfos.insert(selectedPfos.end(), pfos.begin(), pfos.end());
308 template <
typename T>
310 m_isAvailable(false),
315 const ParticleFlowObject *
const pNeutrino(this->
GetNeutrino(nuPfos));
317 const PfoList &nuFinalStates(pNeutrino->GetDaughterPfoList());
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)
326 CartesianPointVector spacePoints;
329 nuAllSpacePoints.insert(nuAllSpacePoints.end(), spacePoints.begin(), spacePoints.end());
330 nuNHitsTotal += spacePoints.size();
332 if (spacePoints.size() < 5)
336 nuWeightedDirTotal += dir *
static_cast<float>(spacePoints.size());
337 nuNHitsUsedTotal += spacePoints.size();
340 if (nuNHitsUsedTotal == 0)
342 const CartesianVector nuWeightedDir(nuWeightedDirTotal * (1.
f / static_cast<float>(nuNHitsUsedTotal)));
344 CartesianPointVector pointsInSphere;
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()));
357 if (eigenValues.GetX() <= std::numeric_limits<float>::epsilon())
359 const float nuEigenRatioInSphere(eigenValues.GetY() / eigenValues.GetX());
362 unsigned int nCRHitsMax(0);
363 unsigned int nCRHitsTotal(0);
367 for (
const ParticleFlowObject *
const pPfo : crPfos)
369 CartesianPointVector spacePoints;
372 nCRHitsTotal += spacePoints.size();
374 if (spacePoints.size() < 5)
377 if (spacePoints.size() > nCRHitsMax)
379 nCRHitsMax = spacePoints.size();
383 crLongestTrackDirY = upperDir.GetY();
384 crLongestTrackDeflection = 1.f - upperDir.GetDotProduct(lowerDir * (-1.
f));
390 if (nCRHitsTotal == 0)
393 const float crFracHitsInLongestTrack =
static_cast<float>(nCRHitsMax) / static_cast<float>(nCRHitsTotal);
409 catch (StatusCodeException &)
417 template <
typename T>
425 template <
typename T>
429 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
436 template <
typename T>
450 template <
typename T>
454 if (nuPfos.size() != 1)
455 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
457 return nuPfos.front();
462 template <
typename T>
465 ClusterList clusters3D;
468 if (clusters3D.size() > 1)
469 throw StatusCodeException(STATUS_CODE_OUT_OF_RANGE);
471 if (clusters3D.empty())
474 CaloHitList caloHits;
475 clusters3D.front()->GetOrderedCaloHitList().FillCaloHitList(caloHits);
477 for (
const CaloHit *
const pCaloHit : caloHits)
478 spacePoints.push_back(pCaloHit->GetPositionVector());
483 template <
typename T>
486 return this->
GetDirection(spacePoints, [&](
const CartesianVector &pointA,
const CartesianVector &pointB) {
487 return ((pointA - vertex).GetMagnitude() < (pointB - vertex).GetMagnitude());
493 template <
typename T>
497 spacePoints, [&](
const CartesianVector &pointA,
const CartesianVector &pointB) {
return (pointA.GetY() > pointB.GetY()); });
502 template <
typename T>
506 spacePoints, [&](
const CartesianVector &pointA,
const CartesianVector &pointB) {
return (pointA.GetY() < pointB.GetY()); });
511 template <
typename T>
513 std::function<
bool(
const CartesianVector &pointA,
const CartesianVector &pointB)> fShouldChooseA)
const 516 const LArTPC *
const pFirstLArTPC(
m_pTool->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
517 const float layerPitch(pFirstLArTPC->GetWirePitchW());
520 const CartesianVector endMin(fit.GetGlobalMinLayerPosition());
521 const CartesianVector endMax(fit.GetGlobalMaxLayerPosition());
522 const CartesianVector dirMin(fit.GetGlobalMinLayerDirection());
523 const CartesianVector dirMax(fit.GetGlobalMaxLayerDirection());
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);
530 const bool shouldFlip((endPoint - startPoint).GetUnitVector().GetDotProduct(startDir) < 0.
f);
531 return (shouldFlip ? startDir * (-1.
f) : startDir);
536 template <
typename T>
538 const float radius, CartesianPointVector &spacePointsInSphere)
const 540 for (
const CartesianVector &point : spacePoints)
542 if ((point - vertex).GetMagnitudeSquared() <= radius * radius)
543 spacePointsInSphere.push_back(point);
549 template <
typename T>
552 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"UseTrainingMode",
m_useTrainingMode));
556 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"TrainingOutputFileName",
m_trainingOutputFile));
559 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinimumPurity",
m_minPurity));
561 PANDORA_RETURN_RESULT_IF_AND_IF(
562 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinimumCompleteness",
m_minCompleteness));
564 PANDORA_RETURN_RESULT_IF_AND_IF(
565 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"SelectNuanceCode",
m_selectNuanceCode));
569 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"NuanceCode",
m_nuance));
572 PANDORA_RETURN_RESULT_IF_AND_IF(
573 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinimumNeutrinoProbability",
m_minProbability));
575 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MaximumNeutrinos",
m_maxNeutrinos));
577 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
583 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"MvaName", mvaName));
586 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
"MvaFileName", mvaFileName));
589 m_mva.Initialize(fullMvaFileName, mvaName);
592 return STATUS_CODE_SUCCESS;
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.
Header file for the pfo helper class.
bool m_selectInputHits
whether to select input hits
MvaTypes::MvaFeatureVector MvaFeatureVector
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.
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
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.
Header file for the principal curve analysis helper class.
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
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.
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.
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...
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.
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 ¢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...
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
ThreeDSlidingFitResult class.
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...