19 #include "art/Framework/Core/EDProducer.h"
20 #include "art/Framework/Core/ModuleMacros.h"
21 #include "art/Framework/Principal/DataViewImpl.h"
22 #include "art/Framework/Principal/Event.h"
23 #include "art/Framework/Principal/Handle.h"
24 #include "art/Framework/Principal/Run.h"
25 #include "art/Framework/Principal/SubRun.h"
26 #include "art_root_io/TFileService.h"
27 #include "canvas/Persistency/Common/FindManyP.h"
28 #include "canvas/Persistency/Common/Ptr.h"
29 #include "canvas/Persistency/Common/PtrVector.h"
30 #include "canvas/Utilities/InputTag.h"
31 #include "fhiclcpp/ParameterSet.h"
33 #include "messagefacility/MessageLogger/MessageLogger.h"
63 #include "TMVA/MethodCuts.h"
64 #include "TMVA/Reader.h"
65 #include "TMVA/Tools.h"
72 class Dazzle :
public art::EDProducer {
74 explicit Dazzle(fhicl::ParameterSet
const&
p);
85 void produce(art::Event&
e)
override;
90 art::ServiceHandle<art::TFileService>
tfs;
133 float startX,
startY,
startZ,
endX,
endY,
endZ,
trueStartX,
trueStartY,
trueStartZ,
trueEndX,
trueEndY,
trueEndZ,
truePx,
truePy,
truePz,
startDist,
endDist,
trueP,
trueEndP,
trueThetaXZ,
trueThetaYZ,
energyComp,
energyPurity;
138 void FillPFPMetrics(
const art::Ptr<recob::PFParticle>& pfp,
const std::map<
size_t, art::Ptr<recob::PFParticle>>& pfpMap,
139 const art::FindManyP<recob::Cluster>& fmCluster,
const art::FindManyP<recob::Hit>& fmHit,
const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta);
141 std::vector<art::Ptr<sim::SimChannel>>& simChannels);
151 std::map<size_t, art::Ptr<recob::PFParticle>>
GetPFPMap(
std::vector<art::Ptr<recob::PFParticle>>& pfps)
const;
152 unsigned int GetPFPHierarchyDepth(
const art::Ptr<recob::PFParticle>& pfp,
const std::map<
size_t, art::Ptr<recob::PFParticle>>& pfpMap)
const;
153 float GetPFPTrackScore(
const art::Ptr<recob::PFParticle>& pfp,
const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta)
const;
154 bool InFV(
const TVector3& pos)
const;
160 , fSimChannelLabel(
p.get<std::string>(
"SimChannelLabel"))
161 , fPFPLabel(
p.get<std::string>(
"PFPLabel"))
162 , fTrackLabel(
p.get<std::string>(
"TrackLabel"))
163 , fCaloLabel(
p.get<std::string>(
"CaloLabel"))
164 , fMCSLabel(
p.get<std::string>(
"MCSLabel"), std::string(
"muon"))
165 , fChi2Label(
p.get<std::string>(
"Chi2Label"))
166 , fRangeLabel(
p.get<std::string>(
"RangeLabel"), std::string(
"muon"))
168 , fClosestApproachLabel(
p.get<std::string>(
"ClosestApproachLabel"))
169 , fStoppingChi2Label(
p.get<std::string>(
"StoppingChi2Label"))
170 , fMinTrackLength(
p.get<
float>(
"MinTrackLength"))
171 , fMakeTree(
p.get<
bool>(
"MakeTree"))
172 , fRunMVA(
p.get<
bool>(
"RunMVA"))
173 , fMethodName(
p.get<std::string>(
"MethodName",
""))
174 , fWeightFile(
p.get<std::string>(
"WeightFile",
""))
175 , fXMin(
p.get<
float>(
"XMin"))
176 , fXMax(
p.get<
float>(
"XMax"))
177 , fYMin(
p.get<
float>(
"YMin"))
178 , fYMax(
p.get<
float>(
"YMax"))
179 , fZMin(
p.get<
float>(
"ZMin"))
180 , fZMax(
p.get<
float>(
"ZMax"))
183 if (!fMakeTree && !fRunMVA)
184 throw cet::exception(
"Dazzle") <<
"Configured to do nothing";
187 if (fMethodName ==
"" || fWeightFile ==
"")
188 throw cet::exception(
"Dazzle") <<
"Trying to run MVA with inputs not set: MethodName: " << fMethodName <<
" and WeightFile: " << fWeightFile;
190 cet::search_path searchPath(
"FW_SEARCH_PATH");
191 std::string fWeightFileFullPath;
192 if (!searchPath.find_file(fWeightFile, fWeightFileFullPath))
193 throw cet::exception(
"Dazzle") <<
"Unable to find weight file: " << fWeightFile <<
" in FW_SEARCH_PATH: " << searchPath.to_string();
195 reader =
new TMVA::Reader(
"V");
197 reader->AddVariable(
"recoLen", &recoLen);
199 reader->AddVariable(
"chi2PIDMuon", &chi2PIDMuon);
200 reader->AddVariable(
"chi2PIDProton", &chi2PIDProton);
201 reader->AddVariable(
"chi2PIDMuonPionDiff", &chi2PIDMuonPionDiff);
203 reader->AddVariable(
"mcsScatterMean", &mcsScatterMean);
204 reader->AddVariable(
"mcsScatterMaxRatio", &mcsScatterMaxRatio);
205 reader->AddVariable(
"meanDCA", &meanDCA);
207 reader->AddVariable(
"stoppingChi2Ratio", &stoppingChi2Ratio);
208 reader->AddVariable(
"chi2Pol0Fit", &chi2Pol0Fit);
210 reader->AddVariable(
"pDiff", &pDiff);
211 reader->AddVariable(
"numDaughters", &numDaughters);
212 reader->AddVariable(
"maxDaughterHits", &maxDaughterHits);
214 reader->BookMVA(fMethodName, fWeightFileFullPath);
217 produces<std::vector<MVAPID>>();
218 produces<art::Assns<recob::Track, MVAPID>>();
224 trackTree =
tfs->make<TTree>(
"trackTree",
"Tree filled per Track with PID variables");
321 auto const clockData(art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e));
323 auto const pfpHandle(e.getValidHandle<std::vector<recob::PFParticle>>(
fPFPLabel));
324 auto const clusterHandle(e.getValidHandle<std::vector<recob::Cluster>>(
fPFPLabel));
325 auto const simChannelHandle(e.getValidHandle<std::vector<sim::SimChannel>>(
fSimChannelLabel));
326 auto const trackHandle(e.getValidHandle<std::vector<recob::Track>>(
fTrackLabel));
328 std::vector<art::Ptr<recob::PFParticle>> pfps;
329 art::fill_ptr_vector(pfps, pfpHandle);
331 std::vector<art::Ptr<sim::SimChannel>> simChannels;
332 art::fill_ptr_vector(simChannels, simChannelHandle);
334 art::FindManyP<recob::Cluster> fmPFPCluster(pfpHandle, e,
fPFPLabel);
335 art::FindManyP<larpandoraobj::PFParticleMetadata> fmPFPMeta(pfpHandle, e,
fPFPLabel);
336 art::FindManyP<recob::Hit> fmClusterHit(clusterHandle, e,
fPFPLabel);
338 art::FindManyP<recob::Track> fmPFPTrack(pfpHandle, e,
fTrackLabel);
339 art::FindManyP<recob::Hit> fmTrackHit(trackHandle, e,
fTrackLabel);
340 art::FindManyP<anab::Calorimetry> fmTrackCalo(trackHandle, e,
fCaloLabel);
341 art::FindManyP<recob::MCSFitResult> fmTrackMCS(trackHandle, e,
fMCSLabel);
342 art::FindManyP<anab::ParticleID> fmTrackChi2(trackHandle, e,
fChi2Label);
345 art::FindManyP<RangeP> fmTrackRange(trackHandle, e,
fRangeLabel);
346 art::FindManyP<ScatterClosestApproach> fmTrackClosestApproach(trackHandle, e,
fClosestApproachLabel);
347 art::FindManyP<StoppingChi2Fit> fmTrackStoppingChi2(trackHandle, e,
fStoppingChi2Label);
349 auto mvaPIDVec = std::make_unique<std::vector<MVAPID>>();
350 auto trackAssns = std::make_unique<art::Assns<recob::Track, MVAPID>>();
352 const std::map<size_t, art::Ptr<recob::PFParticle>> pfpMap(this->
GetPFPMap(pfps));
354 for (
auto const& pfp : pfps) {
358 std::vector<art::Ptr<recob::Track>> pfpTrackVec(fmPFPTrack.at(pfp.key()));
361 if (pfpTrackVec.empty())
365 if (pfpTrackVec.size() > 1)
366 throw cet::exception(
"Dazzle") <<
"Too many tracks: " << pfpTrackVec.size();
368 art::Ptr<recob::Track>& pfpTrack(pfpTrackVec.front());
380 auto const caloVec(fmTrackCalo.at(pfpTrack.key()));
381 if (caloVec.size() != 3)
386 const unsigned int maxHits(std::max({ caloVec[0]->dEdx().size(), caloVec[1]->dEdx().size(), caloVec[2]->dEdx().size() }));
387 bestPlane = (caloVec[2]->dEdx().size() == maxHits) ? 2 : (caloVec[0]->
dEdx().size() == maxHits) ? 0 : (caloVec[1]->
dEdx().size() == maxHits) ? 1 : -1;
390 if (bestPlane < 0 || bestPlane > 3)
391 throw cet::exception(
"Dazzle") <<
"Best plane: " <<
bestPlane;
393 this->
FillPFPMetrics(pfp, pfpMap, fmPFPCluster, fmClusterHit, fmPFPMeta);
397 auto const mcsVec(fmTrackMCS.at(pfpTrack.key()));
398 if (mcsVec.size() == 1)
403 auto const rangeVec(fmTrackRange.at(pfpTrack.key()));
404 if (rangeVec.size() == 1)
408 auto const chi2Vec(fmTrackChi2.at(pfpTrack.key()));
409 if (chi2Vec.size() == 3)
416 auto const closestApproachVec(fmTrackClosestApproach.at(pfpTrack.key()));
417 if (closestApproachVec.size() == 1)
420 auto const stoppingChi2Vec(fmTrackStoppingChi2.at(pfpTrack.key()));
421 if (stoppingChi2Vec.size() == 1)
426 mvaPIDVec->push_back(mvaPID);
432 std::vector<art::Ptr<recob::Hit>> trackHitVec(fmTrackHit.at(pfpTrack.key()));
438 e.put(std::move(mvaPIDVec));
439 e.put(std::move(trackAssns));
521 void Dazzle::FillPFPMetrics(
const art::Ptr<recob::PFParticle>& pfp,
const std::map<
size_t, art::Ptr<recob::PFParticle>>& pfpMap,
522 const art::FindManyP<recob::Cluster>& fmCluster,
const art::FindManyP<recob::Hit>& fmHit,
const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta)
524 auto const parentId(pfp->Parent());
525 auto const& parentIter(pfpMap.find(parentId));
526 if (parentIter != pfpMap.end())
535 for (
auto const daughterId : pfp->Daughters()) {
536 auto const& daughterIter(pfpMap.find(daughterId));
537 if (daughterIter == pfpMap.end())
540 auto const& clusters(fmCluster.at(daughterIter->second.key()));
542 for (
auto const&
cluster : clusters) {
560 art::ServiceHandle<cheat::BackTrackerService> bt_serv;
566 float totalHitEnergy(0.f), totalTrueHitEnergy(0.f);
567 for (
auto const&
hit : hits) {
568 const std::vector<sim::TrackIDE> trackIDEs(bt_serv->HitToTrackIDEs(clockData,
hit));
569 totalHitEnergy = std::accumulate(trackIDEs.cbegin(), trackIDEs.cend(), totalHitEnergy,
570 [](
float sum,
auto const& ide) {
return sum + ide.energy; });
571 totalTrueHitEnergy = std::accumulate(trackIDEs.cbegin(), trackIDEs.cend(), totalTrueHitEnergy,
572 [bestMatch](
float sum,
auto const& ide) {
return (
std::abs(ide.trackID) == bestMatch) ? sum + ide.energy : sum; });
575 const std::vector<const sim::IDE*> trackIDEs(bt_serv->TrackIdToSimIDEs_Ps(bestMatch));
576 float totalTrueEnergy(std::accumulate(trackIDEs.cbegin(), trackIDEs.cend(), 0.f,
577 [](
float sum,
auto const& ide) {
return sum + ide->energy; }));
579 energyComp = totalTrueHitEnergy / totalTrueEnergy;
582 const simb::MCParticle*
const trueParticle(
particleInventory->TrackIdToParticle_P(bestMatch));
587 truePdg = trueParticle->PdgCode();
593 trueP = trueParticle->P();
594 trueEndP = trueParticle->P(trueParticle->NumberTrajectoryPoints() - 2);
596 const TVector3 trackStart(track.
Start<TVector3>());
597 const TVector3 trackEnd(track.
End<TVector3>());
599 const TVector3 trueStart(trueParticle->Position().Vect());
600 const TVector3 trueEnd(trueParticle->EndPosition().Vect());
617 startDist = (trueStart - trackStart).Mag();
618 endDist = (trueEnd - trackEnd).Mag();
625 const TVector3 start(track.
Start<TVector3>());
626 const TVector3
end(track.
End<TVector3>());
654 float maxScatter(0), meanScatter(0);
658 maxScatter = std::max(maxScatter,
angle);
659 meanScatter +=
angle;
721 pidResults.AddScore(13, mvaScores.at(0));
722 pidResults.AddScore(211, mvaScores.at(1));
723 pidResults.AddScore(2212, mvaScores.at(2));
724 pidResults.AddScore(0, mvaScores.at(3));
735 bestPDG = pidResults.BestPDG();
748 double chi2PIDBest = 0.;
755 for (
size_t i_algscore=0; i_algscore<AlgScoresVec.size(); i_algscore++){
760 if(AlgScore.
fValue < chi2PIDBest || chi2PIDBest == 0.) {
761 chi2PIDBest = AlgScore.
fValue;
765 else if (TMath::Abs(AlgScore.
fAssumedPdg) == 211) {
767 if(AlgScore.
fValue < chi2PIDBest || chi2PIDBest == 0.) {
768 chi2PIDBest = AlgScore.
fValue;
772 else if (TMath::Abs(AlgScore.
fAssumedPdg) == 321) {
774 if(AlgScore.
fValue < chi2PIDBest || chi2PIDBest == 0.) {
775 chi2PIDBest = AlgScore.
fValue;
779 else if (TMath::Abs(AlgScore.
fAssumedPdg) == 2212) {
781 if(AlgScore.
fValue < chi2PIDBest || chi2PIDBest == 0.) {
782 chi2PIDBest = AlgScore.
fValue;
812 std::map<size_t, art::Ptr<recob::PFParticle>> pfpMap;
813 for (
auto const& pfp : pfps) {
814 pfpMap[pfp->Self()] = pfp;
821 if (pfp->Daughters().empty()) {
824 unsigned int maxDepth(0);
825 for (
auto const daughter : pfp->Daughters()) {
831 float Dazzle::GetPFPTrackScore(
const art::Ptr<recob::PFParticle>& pfp,
const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta)
const
833 auto const pfpMetaVec(fmMeta.at(pfp.key()));
834 if (pfpMetaVec.size() != 1)
837 auto const& pfpTrackScoreIter = propertiesMap.find(
"TrackScore");
838 return pfpTrackScoreIter == propertiesMap.end() ? -5.f : pfpTrackScoreIter->second;
const std::string fWeightFile
Declaration of signal hit object.
void FillPFPMetrics(const art::Ptr< recob::PFParticle > &pfp, const std::map< size_t, art::Ptr< recob::PFParticle >> &pfpMap, const art::FindManyP< recob::Cluster > &fmCluster, const art::FindManyP< recob::Hit > &fmHit, const art::FindManyP< larpandoraobj::PFParticleMetadata > &fmMeta)
void FillStoppingChi2Metrics(const StoppingChi2Fit &stoppingChi2)
std::size_t size(FixedBins< T, C > const &) noexcept
const std::string fMethodName
const std::vector< float > & scatterAngles() const
vector of angles between the segments used in the fit
std::map< std::string, float > PropertiesMap
process_name use argoneut_mc_hitfinder track
Dazzle & operator=(Dazzle const &)=delete
art::InputTag fRangeLabel
float fValue
Result of Particle ID algorithm/test.
void FillTrueParticleMetrics(const detinfo::DetectorClocksData &clockData, const recob::Track &track, const std::vector< art::Ptr< recob::Hit >> &hits, std::vector< art::Ptr< sim::SimChannel >> &simChannels)
std::string fAlgName
< determined particle ID
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
void FillChi2PIDMetrics(const anab::ParticleID &pid)
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
const std::vector< anab::sParticleIDAlgScores > & ParticleIDAlgScores() const
double Length(size_t p=0) const
Access to various track properties.
Utilities for matching a recob::Hit or vector of recob::Hit to the ID of the most significantly contr...
Point_t const & Start() const
Access to track position at different points.
unsigned int GetPFPHierarchyDepth(const art::Ptr< recob::PFParticle > &pfp, const std::map< size_t, art::Ptr< recob::PFParticle >> &pfpMap) const
float chi2PIDMuonPionDiff
void FillTrackMetrics(const recob::Track &track)
std::string chi2PIDTypeNoKaon
void FillMCSMetrics(const recob::MCSFitResult &mcs)
Dazzle(fhicl::ParameterSet const &p)
std::string trueEndProcess
auto end(FixedBins< T, C > const &) noexcept
std::string PdgString(const int pdg) const
art::InputTag fClosestApproachLabel
float GetPFPTrackScore(const art::Ptr< recob::PFParticle > &pfp, const art::FindManyP< larpandoraobj::PFParticleMetadata > &fmMeta) const
Declaration of cluster object.
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Provides recob::Track data product.
void FillRangePMetrics(const RangeP &range)
bool Valid(const G4ID g4ID) noexcept
Test whether a G4ID returned by the TruthMatchUtils functions is valid.
Class storing the result of the Maximum Likelihood fit of Multiple Coulomb Scattering angles between ...
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
Contains all timing reference information for the detector.
G4ID TrueParticleIDFromTotalTrueEnergy(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit >> &pHits, const bool rollupUnsavedIDs)
The G4 ID of the true particle which deposits the most energy in a vector of recob::Hit.
Point_t const & End() const
bool InFV(const TVector3 &pos) const
finds tracks best matching by angle
void produce(art::Event &e) override
float fwdMomentum() const
momentum value from fit assuming a forward track direction
art::ServiceHandle< art::TFileService > tfs
std::map< size_t, art::Ptr< recob::PFParticle > > GetPFPMap(std::vector< art::Ptr< recob::PFParticle >> &pfps) const
art::InputTag fSimChannelLabel
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
art::ServiceHandle< cheat::ParticleInventoryService > particleInventory
int fAssumedPdg
PDG of particle hypothesis assumed by algorithm, if applicable. Set to 0 by default.
const float fMinTrackLength
art::InputTag fStoppingChi2Label
art::InputTag fTrackLabel
void FillClosestApproachMetrics(const ScatterClosestApproach &closestApproach)