16 #include "art/Framework/Core/ModuleMacros.h"
17 #include "art/Framework/Principal/Event.h"
18 #include "art/Framework/Principal/Handle.h"
19 #include "art/Framework/Services/Registry/ServiceHandle.h"
20 #include "art_root_io/TFileService.h"
21 #include "canvas/Persistency/Common/FindManyP.h"
22 #include "canvas/Persistency/Common/Ptr.h"
23 #include "canvas/Persistency/Common/PtrVector.h"
24 #include "fhiclcpp/ParameterSet.h"
25 #include "messagefacility/MessageLogger/MessageLogger.h"
36 #include "nug4/ParticleNavigation/ParticleList.h"
37 #include "nusimdata/SimulationBase/MCTruth.h"
39 #include "art/Framework/Core/EDAnalyzer.h"
46 explicit ClusterAna(fhicl::ParameterSet
const& pset);
118 , fHitsModuleLabel(pset.
get<
std::string>(
"HitsModuleLabel"))
119 , fClusterModuleLabel(pset.
get<
std::string>(
"ClusterModuleLabel"))
120 , fVertexModuleLabel(pset.
get<
std::string>(
"VertexModuleLabel"))
121 , fElecKERange(pset.
get<
std::
vector<float>>(
"ElecKERange"))
122 , fMuonKERange(pset.
get<
std::
vector<float>>(
"MuonKERange"))
123 , fPionKERange(pset.
get<
std::
vector<float>>(
"PionKERange"))
124 , fKaonKERange(pset.
get<
std::
vector<float>>(
"KaonKERange"))
125 , fProtKERange(pset.
get<
std::
vector<float>>(
"ProtKERange"))
126 , fTrackWeightOption(pset.
get<short>(
"TrackWeightOption"))
127 , fMergeDaughters(pset.
get<
bool>(
"MergeDaughters"))
128 , fSkipCosmics(pset.
get<
bool>(
"SkipCosmics"))
129 , fPrintLevel(pset.
get<short>(
"PrintLevel"))
136 if (found != std::string::npos)
moduleID = 1;
138 if (found != std::string::npos)
moduleID = 2;
140 if (found != std::string::npos)
moduleID = 3;
142 if (found != std::string::npos)
moduleID = 4;
156 art::ServiceHandle<art::TFileService const>
tfs;
158 fNClusters = tfs->make<TH1F>(
"fNoClustersInEvent",
"Number of Clusters", 40, 0, 400);
159 fNHitInCluster = tfs->make<TH1F>(
"fNHitInCluster",
"NHitInCluster", 100, 0, 100);
163 fCREP2 = tfs->make<TH1F>(
"CREP2",
"CREP2", 50, 0, 1);
164 fCRE = tfs->make<TH1F>(
"CRE",
"CR Efficiency", 50, 0, 1);
165 fCRP = tfs->make<TH1F>(
"CRP",
"CR Purity", 50, 0, 1);
168 fNuKE_elec = tfs->make<TH1F>(
"NuKE_elec",
"NuKE electron", 100, 0, 4000);
169 fNuKE_muon = tfs->make<TH1F>(
"NuKE_muon",
"NuKE muon", 100, 0, 4000);
170 fNuKE_pion = tfs->make<TH1F>(
"NuKE_pion",
"NuKE pion", 100, 0, 4000);
171 fNuKE_kaon = tfs->make<TH1F>(
"NuKE_kaon",
"NuKE kaon", 100, 0, 4000);
172 fNuKE_prot = tfs->make<TH1F>(
"NuKE_prot",
"NuKE proton", 100, 0, 4000);
174 fNuEP2_elec = tfs->make<TH1F>(
"NuEP2_elec",
"NuEP2 electron", 50, 0, 1);
175 fNuEP2_muon = tfs->make<TH1F>(
"NuEP2_muon",
"NuEP2 muon", 50, 0, 1);
176 fNuEP2_pion = tfs->make<TH1F>(
"NuEP2_pion",
"NuEP2 pion", 50, 0, 1);
177 fNuEP2_kaon = tfs->make<TH1F>(
"NuEP2_kaon",
"NuEP2 kaon", 50, 0, 1);
178 fNuEP2_prot = tfs->make<TH1F>(
"NuEP2_prot",
"NuEP2 proton", 50, 0, 1);
180 fNuE_elec = tfs->make<TH1F>(
"NuE_elec",
"Nu Efficiency electron", 50, 0, 1);
181 fNuE_muon = tfs->make<TH1F>(
"NuE_muon",
"Nu Efficiency muon", 50, 0, 1);
182 fNuE_pion = tfs->make<TH1F>(
"NuE_pion",
"Nu Efficiency pion", 50, 0, 1);
183 fNuE_kaon = tfs->make<TH1F>(
"NuE_kaon",
"Nu Efficiency kaon", 50, 0, 1);
184 fNuE_prot = tfs->make<TH1F>(
"NuE_prot",
"Nu Efficiency proton", 50, 0, 1);
186 fNuP_elec = tfs->make<TH1F>(
"NuP_elec",
"Nu Purity electron", 50, 0, 1);
187 fNuP_muon = tfs->make<TH1F>(
"NuP_muon",
"Nu Purity muon", 50, 0, 1);
188 fNuP_pion = tfs->make<TH1F>(
"NuP_pion",
"Nu Purity pion", 50, 0, 1);
189 fNuP_kaon = tfs->make<TH1F>(
"NuP_kaon",
"Nu Purity kaon", 50, 0, 1);
190 fNuP_prot = tfs->make<TH1F>(
"NuP_prot",
"Nu Purity proton", 50, 0, 1);
193 fNuVtx_dx = tfs->make<TH1F>(
"Vtx dx",
"Vtx dx", 80, -10, 10);
194 fNuVtx_dy = tfs->make<TH1F>(
"Vtx dy",
"Vtx dy", 80, -10, 10);
195 fNuVtx_dz = tfs->make<TH1F>(
"Vtx dz",
"Vtx dz", 80, -10, 10);
197 fNuEP2_KE_elec = tfs->make<TProfile>(
"NuEP2_KE_elec",
"NuEP2 electron vs KE", 200, 0, 2000);
198 fNuEP2_KE_muon = tfs->make<TProfile>(
"NuEP2_KE_muon",
"NuEP2 muon vs KE", 200, 0, 2000);
199 fNuEP2_KE_pion = tfs->make<TProfile>(
"NuEP2_KE_pion",
"NuEP2 pion vs KE", 200, 0, 2000);
200 fNuEP2_KE_kaon = tfs->make<TProfile>(
"NuEP2_KE_kaon",
"NuEP2 kaon vs KE", 200, 0, 2000);
201 fNuEP2_KE_prot = tfs->make<TProfile>(
"NuEP2_KE_prot",
"NuEP2 proton vs KE", 200, 0, 2000);
214 art::ServiceHandle<geo::Geometry const> geom;
215 if (geom->Nplanes() > 3) {
216 mf::LogError(
"ClusterAna") <<
"Too many planes for this code...";
221 art::Handle<std::vector<recob::Hit>> hitListHandle;
223 std::vector<art::Ptr<recob::Hit>> allhits;
224 art::fill_ptr_vector(allhits, hitListHandle);
225 if (allhits.size() == 0)
return;
228 art::Handle<std::vector<recob::Cluster>> clusterListHandle;
231 if (clusterListHandle->size() == 0) {
232 std::cout <<
"No clusters in event. Hits size " << allhits.size() <<
"\n";
237 art::Handle<std::vector<recob::Vertex>> vertexListHandle;
238 double xyz[3] = {0, 0, 0};
239 art::PtrVector<recob::Vertex> recoVtxList;
240 if (vertexListHandle.isValid()) {
242 for (
unsigned int ii = 0; ii < vertexListHandle->size(); ++ii) {
243 art::Ptr<recob::Vertex>
vertex(vertexListHandle, ii);
244 recoVtxList.push_back(vertex);
250 art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
251 art::ServiceHandle<cheat::ParticleInventoryService const> pi_serv;
252 sim::ParticleList
const& plist = pi_serv->ParticleList();
254 std::vector<const simb::MCParticle*> plist2;
256 std::vector<std::vector<art::Ptr<recob::Hit>>> hlist2;
258 std::vector<std::vector<short>> truToCl;
260 std::vector<std::vector<unsigned short>> nTruHitInCl;
262 std::vector<unsigned short> nRecHitInCl;
267 float aveNuEP2mu = 0.;
268 float numNuEP2mu = 0.;
269 float aveNuEP2nm = 0.;
270 float numNuEP2nm = 0.;
276 int neutTrackID = -1;
277 std::vector<int> tidlist;
278 float neutEnergy = -1.;
279 int neutIntType = -1;
281 bool isNeutrino =
false;
282 bool isSingleParticle =
false;
284 auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
286 for (sim::ParticleList::const_iterator ipart = plist.begin(); ipart != plist.end(); ++ipart) {
287 const simb::MCParticle* part = (*ipart).second;
289 int pdg =
abs(part->PdgCode());
290 int trackID = part->TrackId();
291 art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
293 if (theTruth->Origin() == simb::kBeamNeutrino) isNeutrino =
true;
294 if (theTruth->Origin() == simb::kSingleParticle) isSingleParticle =
true;
295 float KE = 1000 * (part->E() - part->Mass());
299 if ((isNeutrino || isSingleParticle) && neutTrackID < 0) {
300 neutTrackID = trackID;
302 simb::MCNeutrino theNeutrino = theTruth->GetNeutrino();
303 neutEnergy = 1000. * theNeutrino.Nu().E();
304 neutIntType = theNeutrino.InteractionType();
305 neutCCNC = theNeutrino.CCNC();
308 for (
unsigned short iv = 0; iv < recoVtxList.size(); ++iv) {
309 recoVtxList[iv]->XYZ(xyz);
317 mf::LogVerbatim(
"ClusterAna") <<
"Origin " << theTruth->Origin() <<
" trackID " << trackID
318 <<
" PDG " << part->PdgCode() <<
" KE " << (int)KE <<
" MeV "
319 <<
" neutTrackID " << neutTrackID <<
" Mother "
320 << part->Mother() <<
" Proc " << part->Process();
322 bool isCharged = (pdg == 11) || (pdg == 13) || (pdg == 211) || (pdg == 321) || (pdg == 2212);
324 if (!isCharged)
continue;
330 if (part->Process() !=
"primary")
continue;
350 if (part->Process() ==
"NeutronInelastic")
continue;
351 plist2.push_back(part);
352 tidlist.push_back(trackID);
354 std::vector<short> temp{-1, -1, -1};
355 truToCl.push_back(temp);
357 std::vector<unsigned short> temp2(3);
358 nTruHitInCl.push_back(temp2);
361 mf::LogVerbatim(
"ClusterAna")
362 <<
"plist2[" << plist2.size() - 1 <<
"]"
363 <<
" Origin " << theTruth->Origin() <<
" trackID " << trackID <<
" PDG "
364 << part->PdgCode() <<
" KE " << (int)KE <<
" Mother " << part->Mother() + neutTrackID - 1
365 <<
" Proc " << part->Process();
368 if (plist2.size() == 0)
return;
371 hlist2 = bt_serv->TrackIdsToHits_Ps(clockData, tidlist, allhits);
372 if (hlist2.size() != plist2.size()) {
373 mf::LogError(
"ClusterAna") <<
"MC particle list size " << plist2.size()
374 <<
" != size of MC particle true hits lists " << hlist2.size();
380 std::vector<std::pair<unsigned short, unsigned short>> moda;
385 unsigned short ii, dpl, jj, jpl, kpl;
386 for (ii = 0; ii < plist2.size(); ++ii) {
387 dpl = plist2.size() - 1 - ii;
389 if (plist2[dpl]->Mother() == 0)
continue;
391 if (
abs(plist2[dpl]->PdgCode()) == 11)
continue;
393 int motherID = neutTrackID + plist2[dpl]->Mother() - 1;
395 if (motherID != neutTrackID)
continue;
398 for (kpl = 0; kpl < plist2.size(); ++kpl) {
399 if (plist2[kpl]->Mother() == motherID) ++ndtr;
402 if (ndtr > 1)
continue;
405 for (jj = 0; jj < plist2.size(); ++jj) {
406 jpl = plist2.size() - 1 - jj;
407 if (plist2[jpl]->TrackId() == motherID) {
414 mf::LogVerbatim(
"ClusterAna")
415 <<
" mother of daughter " << dpl <<
" not found. mpl = " << mpl;
419 if (plist2[dpl]->PdgCode() != plist2[mpl]->PdgCode())
continue;
420 moda.push_back(std::make_pair(mpl, dpl));
425 art::PtrVector<recob::Cluster> clusters;
426 for (
unsigned int ii = 0; ii < clusterListHandle->size(); ++ii) {
427 art::Ptr<recob::Cluster> clusterHolder(clusterListHandle, ii);
428 clusters.push_back(clusterHolder);
432 nRecHitInCl.resize(clusters.size());
436 std::map<geo::View_t, unsigned int> ViewToPlane;
437 for (
unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
439 ViewToPlane[view] = plane;
441 for (
size_t icl = 0; icl < clusters.size(); ++icl) {
442 unsigned int plane = ViewToPlane[clusters[icl]->View()];
443 std::vector<art::Ptr<recob::Hit>> cluhits = fmh.at(icl);
445 nRecHitInCl[icl] = cluhits.size();
447 std::vector<unsigned short> nHitInPl2(plist2.size());
448 for (
size_t iht = 0; iht < cluhits.size(); ++iht) {
452 for (
unsigned short ipl = 0; ipl < plist2.size(); ++ipl) {
453 unsigned short imat = 0;
454 for (imat = 0; imat < hlist2[ipl].size(); ++imat) {
455 if (cluhits[iht] == hlist2[ipl][imat])
break;
457 if (imat < hlist2[ipl].
size()) {
462 if (hitInPl2 < 0)
continue;
466 for (
unsigned short imd = 0; imd < moda.size(); ++imd) {
467 if (moda[imd].
second == hitInPl2) hitInPl2 = moda[imd].first;
470 ++nHitInPl2[hitInPl2];
474 unsigned short nhit = 0;
476 for (
unsigned int ipl = 0; ipl < nHitInPl2.size(); ++ipl) {
477 if (nHitInPl2[ipl] > nhit) {
478 nhit = nHitInPl2[ipl];
486 if (nhit > nTruHitInCl[imtru][plane]) {
487 truToCl[imtru][plane] = icl;
488 nTruHitInCl[imtru][plane] = nhit;
494 for (
unsigned short ipl = 0; ipl < plist2.size(); ++ipl) {
497 for (
unsigned short ii = 0; ii < moda.size(); ++ii) {
498 if (moda[ii].
second == ipl) {
503 if (skipit)
continue;
506 if (hlist2[ipl].
size() < 3)
continue;
508 int trackID = plist2[ipl]->TrackId();
509 art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
511 float KE = 1000 * (plist2[ipl]->E() - plist2[ipl]->Mass());
512 int PDG =
abs(plist2[ipl]->PdgCode());
514 std::vector<short> nTru(geom->Nplanes());
515 std::vector<short> nRec(geom->Nplanes());
516 std::vector<short> nTruRec(geom->Nplanes());
517 std::vector<float> eff(geom->Nplanes());
518 std::vector<float> pur(geom->Nplanes());
519 std::vector<float> ep(geom->Nplanes());
520 for (
unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
523 for (
unsigned short ii = 0; ii < hlist2[ipl].size(); ++ii) {
524 if (ViewToPlane[hlist2[ipl][ii]->View()] == plane) ++nTru[plane];
528 unsigned short mom = ipl;
529 std::vector<std::pair<unsigned short, unsigned short>>::reverse_iterator rit =
531 while (rit != moda.rend()) {
532 if ((*rit).first == mom) {
533 unsigned short dau = (*rit).second;
534 for (
unsigned short jj = 0; jj < hlist2[dau].size(); ++jj) {
535 if (ViewToPlane[hlist2[dau][jj]->View()] == plane) ++nTru[plane];
544 if (nTru[plane] == 0)
continue;
546 if (nTru[plane] < 3)
continue;
547 short icl = truToCl[ipl][plane];
548 if (icl < 0) { nRec[plane] = 0; }
550 nRec[plane] = nRecHitInCl[icl];
552 nTruRec[plane] = nTruHitInCl[ipl][plane];
555 if (nTru[plane] > 0) eff[plane] = (float)nTruRec[plane] / (
float)nTru[plane];
556 if (nRec[plane] > 0) pur[plane] = (float)nTruRec[plane] / (
float)nRec[plane];
558 if (eff[plane] == 0) { eff[plane] = 0.001; }
559 if (pur[plane] == 0) { pur[plane] = 0.001; }
560 if (eff[plane] >= 1) { eff[plane] = 0.999; }
561 if (pur[plane] >= 1) { pur[plane] = 0.999; }
562 ep[plane] = eff[plane] * pur[plane];
564 outFile <<
moduleID <<
" " << evt.id().event() <<
" " << trackID <<
" " << PDG <<
" "
565 << (int)KE <<
" " << plane <<
" " << nTru[plane] <<
" " << std::setprecision(3)
566 << eff[plane] <<
" " << pur[plane] <<
"\n";
569 std::vector<float> temp;
571 std::sort(temp.begin(), temp.end());
573 unsigned short ii = temp.size() - 2;
574 float ep2 = temp[ii];
577 short ep2Cluster = 0;
578 for (
unsigned short jj = 0; jj < temp.size(); ++jj) {
581 ep2Cluster = truToCl[ipl][ep2Plane];
586 std::array<double, 2> clBeg, clEnd;
587 if (ep2Cluster >= 0) {
588 clBeg[0] = clusters[ep2Cluster]->StartWire();
589 clBeg[1] = clusters[ep2Cluster]->StartTick();
590 clEnd[0] = clusters[ep2Cluster]->EndWire();
591 clEnd[1] = clusters[ep2Cluster]->EndTick();
600 fCRE->Fill(eff[ep2Plane]);
601 fCRP->Fill(pur[ep2Plane]);
605 mf::LogVerbatim(
"ClusterAna")
606 <<
">>>CREP2 " << std::fixed << std::setprecision(2) << ep2 <<
" E " << eff[ep2Plane]
607 << std::setprecision(2) <<
" P " << pur[ep2Plane] <<
" P:W:T " << ep2Plane <<
":"
608 << (int)clBeg[0] <<
":" << (
int)clBeg[1] <<
"-" << ep2Plane <<
":" << (int)clEnd[0]
609 <<
":" << (
int)clEnd[1] <<
" PDG " << PDG <<
" KE " << (int)KE <<
" MeV";
616 aveNuEP2mu += ep2 * wght;
620 aveNuEP2nm += ep2 * wght;
630 else if (PDG == 13) {
637 else if (PDG == 211) {
644 else if (PDG == 321) {
651 else if (PDG == 2212) {
659 mf::LogVerbatim(
"ClusterAna")
660 <<
">>>NuEP2 " << std::fixed << std::setprecision(2) << ep2 <<
" E " << eff[ep2Plane]
661 << std::setprecision(2) <<
" P " << pur[ep2Plane] <<
" P:W:T " << ep2Plane <<
":"
662 << (int)clBeg[0] <<
":" << (
int)clBeg[1] <<
"-" << ep2Plane <<
":" << (int)clEnd[0]
663 <<
":" << (
int)clEnd[1] <<
" PDG " << PDG <<
" KE " << (int)KE <<
" MeV ";
666 mf::LogVerbatim mfp(
"ClusterAna");
667 mfp <<
" Truth P:W:T ";
668 for (
unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
669 unsigned short loW = 9999;
670 unsigned short loT = 0;
671 unsigned short hiW = 0;
672 unsigned short hiT = 0;
673 for (
unsigned short ii = 0; ii < hlist2[ipl].size(); ++ii) {
674 if (ViewToPlane[hlist2[ipl][ii]->View()] == plane) {
675 art::Ptr<recob::Hit> theHit = hlist2[ipl][ii];
676 if (theHit->WireID().Wire < loW) {
677 loW = theHit->WireID().Wire;
678 loT = theHit->PeakTime();
680 if (theHit->WireID().Wire > hiW) {
681 hiW = theHit->WireID().Wire;
682 hiT = theHit->PeakTime();
686 mfp << plane <<
":" << loW <<
":" << loT <<
"-" << plane <<
":" << hiW <<
":" << hiT
694 if (numNuEP2mu > 0.) ave1 = aveNuEP2mu / numNuEP2mu;
697 if (numNuEP2nm > 0.) ave2 = aveNuEP2nm / numNuEP2nm;
700 if (numCREP2 > 0.) ave3 = aveCREP2 / numCREP2;
703 std::string nuType =
"Other";
705 if (neutIntType == 1001) nuType =
"CCQE";
706 if (neutIntType == 1091) nuType =
"DIS";
707 if (neutIntType == 1097) nuType =
"COH";
708 if (neutIntType > 1002 && neutIntType < 1091) nuType =
"RES";
716 mf::LogVerbatim(
"ClusterAna")
717 <<
"EvtEP2 " << evt.id().event() <<
" NuType " << nuType <<
" Enu " << std::fixed
718 << std::setprecision(0) << neutEnergy <<
std::right << std::fixed << std::setprecision(2)
719 <<
" NuMuons " << ave1 <<
" NuPiKp " << ave2 <<
" CosmicRays " << ave3 <<
" CCNC "
720 << neutCCNC <<
" IntType " << neutIntType;
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 fHitsModuleLabel
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Declaration of signal hit object.
std::size_t size(FixedBins< T, C > const &) noexcept
void analyze(const art::Event &evt) override
std::vector< float > fElecKERange
TProfile * fNuEP2_KE_muon
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Charged-current interactions.
ClusterAna(fhicl::ParameterSet const &pset)
TProfile * fNuEP2_KE_kaon
std::vector< float > fProtKERange
std::vector< float > fKaonKERange
std::string fVertexModuleLabel
Declaration of cluster object.
Encapsulate the construction of a single detector plane.
TProfile * fNuEP2_KE_pion
services TFileService fileName
Neutral-current interactions.
std::string fClusterModuleLabel
art::ServiceHandle< art::TFileService > tfs
TProfile * fNuEP2_KE_elec
std::vector< float > fPionKERange
std::vector< float > fMuonKERange
art framework interface to geometry description
BEGIN_PROLOG could also be cout
TProfile * fNuEP2_KE_prot