16 #include "art/Framework/Core/EDAnalyzer.h" 
   17 #include "art/Framework/Core/ModuleMacros.h" 
   18 #include "art/Framework/Principal/Event.h" 
   19 #include "art/Framework/Principal/Handle.h" 
   20 #include "art/Framework/Services/Registry/ServiceHandle.h" 
   21 #include "art_root_io/TFileService.h" 
   22 #include "canvas/Persistency/Common/FindManyP.h" 
   23 #include "canvas/Persistency/Common/Ptr.h" 
   24 #include "canvas/Persistency/Common/PtrVector.h" 
   25 #include "fhiclcpp/ParameterSet.h" 
   26 #include "messagefacility/MessageLogger/MessageLogger.h" 
   38 #include "nug4/ParticleNavigation/ParticleList.h" 
   39 #include "nusimdata/SimulationBase/MCTruth.h" 
   43   class PFPAna : 
public art::EDAnalyzer {
 
   45     explicit PFPAna(fhicl::ParameterSet 
const& pset);
 
  109     , fHitsModuleLabel(pset.
get<
std::string>(
"HitsModuleLabel"))
 
  110     , fClusterModuleLabel(pset.
get<
std::string>(
"ClusterModuleLabel"))
 
  111     , fTrackModuleLabel(pset.
get<
std::string>(
"TrackModuleLabel"))
 
  112     , fPFParticleModuleLabel(pset.
get<
std::string>(
"PFParticleModuleLabel"))
 
  113     , fVertexModuleLabel(pset.
get<
std::string>(
"VertexModuleLabel"))
 
  114     , fElecKERange(pset.
get<
std::
vector<float>>(
"ElecKERange"))
 
  115     , fMuonKERange(pset.
get<
std::
vector<float>>(
"MuonKERange"))
 
  116     , fPionKERange(pset.
get<
std::
vector<float>>(
"PionKERange"))
 
  117     , fKaonKERange(pset.
get<
std::
vector<float>>(
"KaonKERange"))
 
  118     , fProtKERange(pset.
get<
std::
vector<float>>(
"ProtKERange"))
 
  119     , fTrackWeightOption(pset.
get<short>(
"TrackWeightOption"))
 
  120     , fMergeDaughters(pset.
get<
bool>(
"MergeDaughters"))
 
  121     , fSkipCosmics(pset.
get<
bool>(
"SkipCosmics"))
 
  122     , fPrintLevel(pset.
get<short>(
"PrintLevel"))
 
  129     art::ServiceHandle<art::TFileService const> 
tfs;
 
  131     fNClusters = tfs->make<TH1F>(
"fNoClustersInEvent", 
"Number of Clusters", 40, 0, 400);
 
  132     fNHitInCluster = tfs->make<TH1F>(
"fNHitInCluster", 
"NHitInCluster", 100, 0, 100);
 
  136       fCREP2 = tfs->make<TH1F>(
"CREP2", 
"CREP2", 50, 0, 1);
 
  137       fCRE = tfs->make<TH1F>(
"CRE", 
"CR Efficiency", 50, 0, 1);
 
  138       fCRP = tfs->make<TH1F>(
"CRP", 
"CR Purity", 50, 0, 1);
 
  141     fNuKE_elec = tfs->make<TH1F>(
"NuKE_elec", 
"NuKE electron", 100, 0, 4000);
 
  142     fNuKE_muon = tfs->make<TH1F>(
"NuKE_muon", 
"NuKE muon", 100, 0, 4000);
 
  143     fNuKE_pion = tfs->make<TH1F>(
"NuKE_pion", 
"NuKE pion", 100, 0, 4000);
 
  144     fNuKE_kaon = tfs->make<TH1F>(
"NuKE_kaon", 
"NuKE kaon", 100, 0, 4000);
 
  145     fNuKE_prot = tfs->make<TH1F>(
"NuKE_prot", 
"NuKE proton", 100, 0, 4000);
 
  147     fNuEP2_elec = tfs->make<TH1F>(
"NuEP2_elec", 
"NuEP2 electron", 50, 0, 1);
 
  148     fNuEP2_muon = tfs->make<TH1F>(
"NuEP2_muon", 
"NuEP2 muon", 50, 0, 1);
 
  149     fNuEP2_pion = tfs->make<TH1F>(
"NuEP2_pion", 
"NuEP2 pion", 50, 0, 1);
 
  150     fNuEP2_kaon = tfs->make<TH1F>(
"NuEP2_kaon", 
"NuEP2 kaon", 50, 0, 1);
 
  151     fNuEP2_prot = tfs->make<TH1F>(
"NuEP2_prot", 
"NuEP2 proton", 50, 0, 1);
 
  153     fNuE_elec = tfs->make<TH1F>(
"NuE_elec", 
"Nu Efficiency electron", 50, 0, 1);
 
  154     fNuE_muon = tfs->make<TH1F>(
"NuE_muon", 
"Nu Efficiency muon", 50, 0, 1);
 
  155     fNuE_pion = tfs->make<TH1F>(
"NuE_pion", 
"Nu Efficiency pion", 50, 0, 1);
 
  156     fNuE_kaon = tfs->make<TH1F>(
"NuE_kaon", 
"Nu Efficiency kaon", 50, 0, 1);
 
  157     fNuE_prot = tfs->make<TH1F>(
"NuE_prot", 
"Nu Efficiency proton", 50, 0, 1);
 
  159     fNuP_elec = tfs->make<TH1F>(
"NuP_elec", 
"Nu Purity electron", 50, 0, 1);
 
  160     fNuP_muon = tfs->make<TH1F>(
"NuP_muon", 
"Nu Purity muon", 50, 0, 1);
 
  161     fNuP_pion = tfs->make<TH1F>(
"NuP_pion", 
"Nu Purity pion", 50, 0, 1);
 
  162     fNuP_kaon = tfs->make<TH1F>(
"NuP_kaon", 
"Nu Purity kaon", 50, 0, 1);
 
  163     fNuP_prot = tfs->make<TH1F>(
"NuP_prot", 
"Nu Purity proton", 50, 0, 1);
 
  166     fNuVtx_dx = tfs->make<TH1F>(
"Vtx dx", 
"Vtx dx", 80, -10, 10);
 
  167     fNuVtx_dy = tfs->make<TH1F>(
"Vtx dy", 
"Vtx dy", 80, -10, 10);
 
  168     fNuVtx_dz = tfs->make<TH1F>(
"Vtx dz", 
"Vtx dz", 80, -10, 10);
 
  170     fNuEP2_KE_elec = tfs->make<TProfile>(
"NuEP2_KE_elec", 
"NuEP2 electron vs KE", 20, 0, 2000);
 
  171     fNuEP2_KE_muon = tfs->make<TProfile>(
"NuEP2_KE_muon", 
"NuEP2 muon vs KE", 20, 0, 2000);
 
  172     fNuEP2_KE_pion = tfs->make<TProfile>(
"NuEP2_KE_pion", 
"NuEP2 pion vs KE", 20, 0, 2000);
 
  173     fNuEP2_KE_kaon = tfs->make<TProfile>(
"NuEP2_KE_kaon", 
"NuEP2 kaon vs KE", 20, 0, 2000);
 
  174     fNuEP2_KE_prot = tfs->make<TProfile>(
"NuEP2_KE_prot", 
"NuEP2 proton vs KE", 20, 0, 2000);
 
  181     art::ServiceHandle<geo::Geometry const> geom;
 
  182     if (geom->Nplanes() > 3) 
return;
 
  185     art::Handle<std::vector<recob::Hit>> hitListHandle;
 
  187     std::vector<art::Ptr<recob::Hit>> allhits;
 
  188     art::fill_ptr_vector(allhits, hitListHandle);
 
  189     if (
empty(allhits)) 
return;
 
  192     art::Handle<std::vector<recob::Cluster>> clusterListHandle;
 
  195     if (clusterListHandle->size() == 0) 
return;
 
  198     art::Handle<std::vector<recob::Vertex>> vertexListHandle;
 
  200     art::PtrVector<recob::Vertex> recoVtxList;
 
  201     double xyz[3] = {0, 0, 0};
 
  202     for (
unsigned int ii = 0; ii < vertexListHandle->size(); ++ii) {
 
  203       art::Ptr<recob::Vertex> 
vertex(vertexListHandle, ii);
 
  204       recoVtxList.push_back(vertex);
 
  209     art::Handle<std::vector<recob::PFParticle>> PFPListHandle;
 
  211     art::PtrVector<recob::PFParticle> recoPFPList;
 
  212     for (
unsigned int ii = 0; ii < PFPListHandle->size(); ++ii) {
 
  213       art::Ptr<recob::PFParticle> pfp(PFPListHandle, ii);
 
  214       recoPFPList.push_back(pfp);
 
  215       mf::LogVerbatim(
"PFPAna") << 
"PFParticle PDG " << pfp->PdgCode();
 
  219     art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
 
  220     art::ServiceHandle<cheat::ParticleInventoryService const> pi_serv;
 
  221     sim::ParticleList 
const& plist = pi_serv->ParticleList();
 
  223     std::vector<const simb::MCParticle*> plist2;
 
  225     std::vector<std::vector<art::Ptr<recob::Hit>>> hlist2;
 
  227     std::vector<std::vector<short>> truToCl;
 
  229     std::vector<std::vector<unsigned short>> nTruHitInCl;
 
  231     std::vector<unsigned short> nRecHitInCl;
 
  236     float aveNuEP2mu = 0.;
 
  237     float numNuEP2mu = 0.;
 
  238     float aveNuEP2nm = 0.;
 
  239     float numNuEP2nm = 0.;
 
  245     int neutTrackID = -1;
 
  246     std::vector<int> tidlist;
 
  247     float neutEnergy = -1.;
 
  248     int neutIntType = -1;
 
  251     auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
 
  253     for (sim::ParticleList::const_iterator ipart = plist.begin(); ipart != plist.end(); ++ipart) {
 
  254       const simb::MCParticle* part = (*ipart).second;
 
  256       int pdg = 
abs(part->PdgCode());
 
  257       int trackID = part->TrackId();
 
  258       art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
 
  262         mf::LogVerbatim(
"PFPAna") << 
"Pre-Cuts origin " << theTruth->Origin() << 
" trackID " 
  263                                   << trackID << 
" PDG " << part->PdgCode() << 
" E " << part->E()
 
  264                                   << 
" mass " << part->Mass() << 
" Mother " 
  265                                   << part->Mother() + neutTrackID << 
" Proc " << part->Process();
 
  269       if (theTruth->Origin() == simb::kBeamNeutrino && neutTrackID < 0) {
 
  270         neutTrackID = trackID;
 
  271         simb::MCNeutrino theNeutrino = theTruth->GetNeutrino();
 
  272         neutEnergy = 1000. * theNeutrino.Nu().E();
 
  273         neutIntType = theNeutrino.InteractionType();
 
  274         neutCCNC = theNeutrino.CCNC();
 
  275         for (
unsigned short iv = 0; iv < recoVtxList.size(); ++iv) {
 
  276           recoVtxList[iv]->XYZ(xyz);
 
  283       bool isCharged = (pdg == 11) || (pdg == 13) || (pdg == 211) || (pdg == 321) || (pdg == 2212);
 
  285       if (!isCharged) 
continue;
 
  287       float KE = 1000 * (part->E() - part->Mass());
 
  292         if (part->Process() != 
"primary") 
continue;
 
  312       if (part->Process() == 
"NeutronInelastic") 
continue;
 
  313       plist2.push_back(part);
 
  314       tidlist.push_back(trackID);
 
  316       std::vector<short> temp{-1, -1, -1};
 
  317       truToCl.push_back(temp);
 
  319       std::vector<unsigned short> temp2(3);
 
  320       nTruHitInCl.push_back(temp2);
 
  323         mf::LogVerbatim(
"PFPAna") << plist2.size() - 1 << 
" Origin " << theTruth->Origin()
 
  324                                   << 
" trackID " << trackID << 
" PDG " << part->PdgCode() << 
" KE " 
  325                                   << (int)KE << 
" Mother " << part->Mother() + neutTrackID
 
  326                                   << 
" Proc " << part->Process();
 
  329     if (
empty(plist2)) 
return;
 
  332     hlist2 = bt_serv->TrackIdsToHits_Ps(clockData, tidlist, allhits);
 
  333     if (hlist2.size() != plist2.size()) {
 
  334       mf::LogError(
"PFPAna") << 
"MC particle list size " << plist2.size()
 
  335                              << 
" != size of MC particle true hits lists " << hlist2.size();
 
  341     std::vector<std::pair<unsigned short, unsigned short>> moda;
 
  346       for (
unsigned short dpl = plist2.size() - 1; dpl > 0; --dpl) {
 
  348         if (plist2[dpl]->Mother() == 0) 
continue;
 
  350         if (
abs(plist2[dpl]->PdgCode()) == 11) 
continue;
 
  352         int motherID = neutTrackID + plist2[dpl]->Mother() - 1;
 
  354         if (motherID < 0) 
continue;
 
  357         for (
unsigned short kpl = 0; kpl < plist2.size(); ++kpl) {
 
  358           if (plist2[kpl]->Mother() == motherID) ++ndtr;
 
  361         if (ndtr > 1) 
continue;
 
  364         for (
unsigned short jpl = dpl - 1; jpl > 0; --jpl) {
 
  365           if (plist2[jpl]->TrackId() == motherID) {
 
  371         if (mpl < 0) 
continue;
 
  373         if (plist2[dpl]->PdgCode() != plist2[mpl]->PdgCode()) 
continue;
 
  374         moda.push_back(std::make_pair(mpl, dpl));
 
  379     art::PtrVector<recob::Cluster> clusters;
 
  380     for (
unsigned int ii = 0; ii < clusterListHandle->size(); ++ii) {
 
  381       art::Ptr<recob::Cluster> clusterHolder(clusterListHandle, ii);
 
  382       clusters.push_back(clusterHolder);
 
  386     nRecHitInCl.resize(clusters.size());
 
  390     std::map<geo::View_t, unsigned int> ViewToPlane;
 
  391     for (
unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
 
  393       ViewToPlane[view] = plane;
 
  395     for (
size_t icl = 0; icl < clusters.size(); ++icl) {
 
  396       unsigned int plane = ViewToPlane[clusters[icl]->View()];
 
  397       std::vector<art::Ptr<recob::Hit>> cluhits = fmh.at(icl);
 
  399       nRecHitInCl[icl] = cluhits.size();
 
  401       std::vector<unsigned short> nHitInPl2(plist2.size());
 
  402       for (
size_t iht = 0; iht < cluhits.size(); ++iht) {
 
  411         for (
unsigned short ipl = 0; ipl < plist2.size(); ++ipl) {
 
  412           unsigned short imat = 0;
 
  413           for (imat = 0; imat < hlist2[ipl].size(); ++imat) {
 
  414             if (cluhits[iht] == hlist2[ipl][imat]) 
break;
 
  416           if (imat < hlist2[ipl].
size()) {
 
  421         if (hitInPl2 < 0) 
continue;
 
  425         for (
unsigned short imd = 0; imd < moda.size(); ++imd) {
 
  426           if (moda[imd].
second == hitInPl2) hitInPl2 = moda[imd].first;
 
  429         ++nHitInPl2[hitInPl2];
 
  433       unsigned short nhit = 0;
 
  435       for (
unsigned int ipl = 0; ipl < nHitInPl2.size(); ++ipl) {
 
  436         if (nHitInPl2[ipl] > nhit) {
 
  437           nhit = nHitInPl2[ipl];
 
  445         if (nhit > nTruHitInCl[imtru][plane]) {
 
  446           truToCl[imtru][plane] = icl;
 
  447           nTruHitInCl[imtru][plane] = nhit;
 
  453     for (
unsigned short ipl = 0; ipl < plist2.size(); ++ipl) {
 
  456       for (
unsigned short ii = 0; ii < moda.size(); ++ii) {
 
  457         if (moda[ii].
second == ipl) {
 
  462       if (skipit) 
continue;
 
  465       if (hlist2[ipl].
size() < 3) 
continue;
 
  467       int trackID = plist2[ipl]->TrackId();
 
  468       art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
 
  470       float KE = 1000 * (plist2[ipl]->E() - plist2[ipl]->Mass());
 
  471       int PDG = 
abs(plist2[ipl]->PdgCode());
 
  473       std::vector<short> nTru(geom->Nplanes());
 
  474       std::vector<short> nRec(geom->Nplanes());
 
  475       std::vector<short> nTruRec(geom->Nplanes());
 
  476       std::vector<float> eff(geom->Nplanes());
 
  477       std::vector<float> pur(geom->Nplanes());
 
  478       std::vector<float> ep(geom->Nplanes());
 
  479       for (
unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
 
  482         for (
unsigned short ii = 0; ii < hlist2[ipl].size(); ++ii) {
 
  483           if (ViewToPlane[hlist2[ipl][ii]->View()] == plane) ++nTru[plane];
 
  488         unsigned short mom = ipl;
 
  489         std::vector<std::pair<unsigned short, unsigned short>>::reverse_iterator rit =
 
  491         while (rit != moda.rend()) {
 
  492           if ((*rit).first == mom) {
 
  493             unsigned short dau = (*rit).second;
 
  494             for (
unsigned short jj = 0; jj < hlist2[dau].size(); ++jj) {
 
  495               if (ViewToPlane[hlist2[dau][jj]->View()] == plane) ++nTru[plane];
 
  507         if (nTru[plane] == 0) {
 
  512         short icl = truToCl[ipl][plane];
 
  513         nRec[plane] = nRecHitInCl[icl];
 
  514         nTruRec[plane] = nTruHitInCl[ipl][plane];
 
  517         if (nTru[plane] > 0) eff[plane] = (float)nTruRec[plane] / (
float)nTru[plane];
 
  518         if (nRec[plane] > 0) pur[plane] = (float)nTruRec[plane] / (
float)nRec[plane];
 
  519         ep[plane] = eff[plane] * pur[plane];
 
  522       std::vector<float> temp;
 
  524       std::sort(temp.begin(), temp.end());
 
  526       unsigned short ii = temp.size() - 2;
 
  527       float ep2 = temp[ii];
 
  530       short ep2Cluster = 0;
 
  531       for (
unsigned short jj = 0; jj < temp.size(); ++jj) {
 
  534           ep2Cluster = truToCl[ipl][ep2Plane];
 
  539       std::array<double, 2> clBeg, clEnd;
 
  540       if (ep2Cluster >= 0) {
 
  541         clBeg[0] = clusters[ep2Cluster]->StartWire();
 
  542         clBeg[1] = clusters[ep2Cluster]->StartTick();
 
  543         clEnd[0] = clusters[ep2Cluster]->EndWire();
 
  544         clEnd[1] = clusters[ep2Cluster]->EndTick();
 
  553         fCRE->Fill(eff[ep2Plane]);
 
  554         fCRP->Fill(pur[ep2Plane]);
 
  558           mf::LogVerbatim(
"PFPAna")
 
  559             << 
">>>CREP2 " << std::fixed << std::setprecision(2) << ep2 << 
" E " << eff[ep2Plane]
 
  560             << std::setprecision(2) << 
" P " << pur[ep2Plane] << 
" P:W:T " << ep2Plane << 
":" 
  561             << (int)clBeg[0] << 
":" << (
int)clBeg[1] << 
"-" << ep2Plane << 
":" << (int)clEnd[0]
 
  562             << 
":" << (
int)clEnd[1] << 
" PDG " << PDG << 
" KE " << (int)KE << 
" MeV";
 
  569           aveNuEP2mu += ep2 * wght;
 
  573           aveNuEP2nm += ep2 * wght;
 
  583         else if (PDG == 13) {
 
  590         else if (PDG == 211) {
 
  597         else if (PDG == 321) {
 
  604         else if (PDG == 2212) {
 
  612           mf::LogVerbatim(
"PFPAna")
 
  613             << 
">>>NuEP2 " << std::fixed << std::setprecision(2) << ep2 << 
" E " << eff[ep2Plane]
 
  614             << std::setprecision(2) << 
" P " << pur[ep2Plane] << 
" P:W:T " << ep2Plane << 
":" 
  615             << (int)clBeg[0] << 
":" << (
int)clBeg[1] << 
"-" << ep2Plane << 
":" << (int)clEnd[0]
 
  616             << 
":" << (
int)clEnd[1] << 
" PDG " << PDG << 
" KE " << (int)KE << 
" MeV ";
 
  619           mf::LogVerbatim mfp(
"PFPAna");
 
  620           mfp << 
" Truth P:W:T ";
 
  621           for (
unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
 
  622             unsigned short loW = 9999;
 
  623             unsigned short loT = 0;
 
  624             unsigned short hiW = 0;
 
  625             unsigned short hiT = 0;
 
  626             for (
unsigned short ii = 0; ii < hlist2[ipl].size(); ++ii) {
 
  627               if (ViewToPlane[hlist2[ipl][ii]->View()] == plane) {
 
  628                 art::Ptr<recob::Hit> theHit = hlist2[ipl][ii];
 
  629                 if (theHit->WireID().Wire < loW) {
 
  630                   loW = theHit->WireID().Wire;
 
  631                   loT = theHit->PeakTime();
 
  633                 if (theHit->WireID().Wire > hiW) {
 
  634                   hiW = theHit->WireID().Wire;
 
  635                   hiT = theHit->PeakTime();
 
  639             mfp << plane << 
":" << loW << 
":" << loT << 
"-" << plane << 
":" << hiW << 
":" << hiT
 
  647     if (numNuEP2mu > 0.) ave1 = aveNuEP2mu / numNuEP2mu;
 
  650     if (numNuEP2nm > 0.) ave2 = aveNuEP2nm / numNuEP2nm;
 
  653     if (numCREP2 > 0.) ave3 = aveCREP2 / numCREP2;
 
  656       std::string nuType = 
"Other";
 
  658         if (neutIntType == 1001) nuType = 
"CCQE";
 
  659         if (neutIntType == 1091) nuType = 
"DIS";
 
  660         if (neutIntType == 1097) nuType = 
"COH";
 
  661         if (neutIntType > 1002 && neutIntType < 1091) nuType = 
"RES";
 
  669       mf::LogVerbatim(
"PFPAna") << 
"EvtEP2 " << evt.id().event() << 
" NuType " << nuType << 
" Enu " 
  670                                 << std::fixed << std::setprecision(0) << neutEnergy << 
std::right 
  671                                 << std::fixed << std::setprecision(2) << 
" NuMuons " << ave1
 
  672                                 << 
" NuPiKp " << ave2 << 
" CosmicRays " << ave3 << 
" CCNC " 
  673                                 << neutCCNC << 
" IntType " << neutIntType;
 
std::vector< float > fElecKERange
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
process_name stream1 can override from command line with o or output services DetectorPropertiesService services DetectorPropertiesService services DetectorPropertiesService services DetectorPropertiesService physics analyzers pmtresponse NeutronTrackingCut services LArG4Parameters gaussian physics producers generator PDG
std::string fVertexModuleLabel
enum geo::_plane_proj View_t
Enumerate the possible plane projections. 
Declaration of signal hit object. 
std::string fHitsModuleLabel
std::vector< float > fProtKERange
std::size_t size(FixedBins< T, C > const &) noexcept
std::string fClusterModuleLabel
std::vector< float > fPionKERange
TProfile * fNuEP2_KE_kaon
auto vector(Vector const &v)
Returns a manipulator which will print the specified array. 
Charged-current interactions. 
TProfile * fNuEP2_KE_elec
TProfile * fNuEP2_KE_pion
std::string fPFParticleModuleLabel
Declaration of cluster object. 
TProfile * fNuEP2_KE_prot
Encapsulate the construction of a single detector plane. 
TProfile * fNuEP2_KE_muon
PFPAna(fhicl::ParameterSet const &pset)
Neutral-current interactions. 
std::vector< float > fMuonKERange
std::string fTrackModuleLabel
art::ServiceHandle< art::TFileService > tfs
bool empty(FixedBins< T, C > const &) noexcept
void analyze(const art::Event &evt) override
art framework interface to geometry description 
std::vector< float > fKaonKERange