LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
ClusterAna_module.cc
Go to the documentation of this file.
1 //
3 // ClusterAna class
4 //
5 // Bruce Baller
6 //
8 
9 //#ifndef CLUSTERANA_H
10 //#define CLUSTERANA_H
11 
12 #include <iomanip>
13 #include <TH1F.h>
14 #include <TProfile.h>
15 #include <vector>
16 #include <string>
17 #include <array>
18 #include <fstream>
19 
20 //Framework includes
24 #include "fhiclcpp/ParameterSet.h"
32 
33 //LArSoft includes
43 // #include "RawData/RawDigit.h"
47 
49 
50 
51 
52 class TH1F;
53 class TH2F;
55 namespace cluster {
56 
57 
58  class ClusterAna : public art::EDAnalyzer {
59 
60  public:
61 
62  explicit ClusterAna(fhicl::ParameterSet const& pset);
63  virtual ~ClusterAna();
64 
66  void analyze(const art::Event& evt);
67  void beginJob();
68  void endJob();
69 
70  private:
71  TH1F* fNClusters;
73  // Cosmic Rays
74  TH1F* fCREP2;
75  TH1F* fCRE;
76  TH1F* fCRP;
77  // Neutrino interactions
78  TH1F* fNuKE_elec;
79  TH1F* fNuKE_muon;
80  TH1F* fNuKE_pion;
81  TH1F* fNuKE_kaon;
82  TH1F* fNuKE_prot;
83  // TH1F* fNuEP2;
84  TH1F* fNuEP2_elec;
85  TH1F* fNuEP2_muon;
86  TH1F* fNuEP2_pion;
87  TH1F* fNuEP2_kaon;
88  TH1F* fNuEP2_prot;
89  TH1F* fNuE_elec;
90  TH1F* fNuE_muon;
91  TH1F* fNuE_pion;
92  TH1F* fNuE_kaon;
93  TH1F* fNuE_prot;
94  TH1F* fNuP_elec;
95  TH1F* fNuP_muon;
96  TH1F* fNuP_pion;
97  TH1F* fNuP_kaon;
98  TH1F* fNuP_prot;
99 
100  TH1F* fNuVtx_dx;
101  TH1F* fNuVtx_dy;
102  TH1F* fNuVtx_dz;
103 
104  TProfile* fNuEP2_KE_elec;
105  TProfile* fNuEP2_KE_muon;
106  TProfile* fNuEP2_KE_pion;
107  TProfile* fNuEP2_KE_kaon;
108  TProfile* fNuEP2_KE_prot;
109 
110  std::string fHitsModuleLabel;
111  std::string fClusterModuleLabel;
112  std::string fVertexModuleLabel;
113  std::vector<float> fElecKERange;
114  std::vector<float> fMuonKERange;
115  std::vector<float> fPionKERange;
116  std::vector<float> fKaonKERange;
117  std::vector<float> fProtKERange;
120  // float fMergeAngleCut;
122  short fPrintLevel;
123  short moduleID;
124 
125  std::ofstream outFile;
126 
127  }; // class ClusterAna
128 
129 }
130 
131 //#endif
132 
133 namespace cluster{
134 
135  //--------------------------------------------------------------------
137  : EDAnalyzer(pset)
138  , fHitsModuleLabel (pset.get< std::string > ("HitsModuleLabel") )
139  , fClusterModuleLabel (pset.get< std::string > ("ClusterModuleLabel"))
140  , fVertexModuleLabel (pset.get< std::string > ("VertexModuleLabel") )
141  , fElecKERange (pset.get< std::vector<float>> ("ElecKERange"))
142  , fMuonKERange (pset.get< std::vector<float>> ("MuonKERange"))
143  , fPionKERange (pset.get< std::vector<float>> ("PionKERange"))
144  , fKaonKERange (pset.get< std::vector<float>> ("KaonKERange"))
145  , fProtKERange (pset.get< std::vector<float>> ("ProtKERange"))
146  , fTrackWeightOption (pset.get< short > ("TrackWeightOption"))
147  , fMergeDaughters (pset.get< bool > ("MergeDaughters"))
148  , fSkipCosmics (pset.get< bool > ("SkipCosmics"))
149  , fPrintLevel (pset.get< short > ("PrintLevel"))
150  {
151 
152  if(fPrintLevel == -1) {
153  // encode the clustermodule label into an integer
154  moduleID = 0;
155  size_t found = fClusterModuleLabel.find("traj"); if(found != std::string::npos) moduleID = 1;
156  found = fClusterModuleLabel.find("line"); if(found != std::string::npos) moduleID = 2;
157  found = fClusterModuleLabel.find("fuzz"); if(found != std::string::npos) moduleID = 3;
158  found = fClusterModuleLabel.find("pand"); if(found != std::string::npos) moduleID = 4;
159  std::cout<<"fClusterModuleLabel "<<fClusterModuleLabel<<" ID "<<moduleID<<"\n";
160 
161  std::string fileName = fClusterModuleLabel + ".tru";
162  outFile.open(fileName);
163  }
164 
165  }
166 
167  //------------------------------------------------------------------
169  {
170 
171  }
172 
174  {
175 
176  // get access to the TFile service
178 
179  fNClusters=tfs->make<TH1F>("fNoClustersInEvent","Number of Clusters", 40,0 ,400);
180  fNHitInCluster = tfs->make<TH1F>("fNHitInCluster","NHitInCluster",100,0,100);
181 
182  if(!fSkipCosmics) {
183  // Cosmic ray histos
184  fCREP2 = tfs->make<TH1F>("CREP2","CREP2",50,0,1);
185  fCRE = tfs->make<TH1F>("CRE","CR Efficiency",50,0,1);
186  fCRP = tfs->make<TH1F>("CRP","CR Purity",50,0,1);
187  }
188  // Neutrino Int histos
189  fNuKE_elec = tfs->make<TH1F>("NuKE_elec","NuKE electron",100,0,4000);
190  fNuKE_muon = tfs->make<TH1F>("NuKE_muon","NuKE muon",100,0,4000);
191  fNuKE_pion = tfs->make<TH1F>("NuKE_pion","NuKE pion",100,0,4000);
192  fNuKE_kaon = tfs->make<TH1F>("NuKE_kaon","NuKE kaon",100,0,4000);
193  fNuKE_prot = tfs->make<TH1F>("NuKE_prot","NuKE proton",100,0,4000);
194 
195  fNuEP2_elec = tfs->make<TH1F>("NuEP2_elec","NuEP2 electron",50,0,1);
196  fNuEP2_muon = tfs->make<TH1F>("NuEP2_muon","NuEP2 muon",50,0,1);
197  fNuEP2_pion = tfs->make<TH1F>("NuEP2_pion","NuEP2 pion",50,0,1);
198  fNuEP2_kaon = tfs->make<TH1F>("NuEP2_kaon","NuEP2 kaon",50,0,1);
199  fNuEP2_prot = tfs->make<TH1F>("NuEP2_prot","NuEP2 proton",50,0,1);
200 
201  fNuE_elec = tfs->make<TH1F>("NuE_elec","Nu Efficiency electron",50,0,1);
202  fNuE_muon = tfs->make<TH1F>("NuE_muon","Nu Efficiency muon",50,0,1);
203  fNuE_pion = tfs->make<TH1F>("NuE_pion","Nu Efficiency pion",50,0,1);
204  fNuE_kaon = tfs->make<TH1F>("NuE_kaon","Nu Efficiency kaon",50,0,1);
205  fNuE_prot = tfs->make<TH1F>("NuE_prot","Nu Efficiency proton",50,0,1);
206 
207  fNuP_elec = tfs->make<TH1F>("NuP_elec","Nu Purity electron",50,0,1);
208  fNuP_muon = tfs->make<TH1F>("NuP_muon","Nu Purity muon",50,0,1);
209  fNuP_pion = tfs->make<TH1F>("NuP_pion","Nu Purity pion",50,0,1);
210  fNuP_kaon = tfs->make<TH1F>("NuP_kaon","Nu Purity kaon",50,0,1);
211  fNuP_prot = tfs->make<TH1F>("NuP_prot","Nu Purity proton",50,0,1);
212 
213  // True - Reco vertex difference
214  fNuVtx_dx = tfs->make<TH1F>("Vtx dx","Vtx dx",80,-10,10);
215  fNuVtx_dy = tfs->make<TH1F>("Vtx dy","Vtx dy",80,-10,10);
216  fNuVtx_dz = tfs->make<TH1F>("Vtx dz","Vtx dz",80,-10,10);
217 
218  fNuEP2_KE_elec = tfs->make<TProfile>("NuEP2_KE_elec","NuEP2 electron vs KE",200,0,2000);
219  fNuEP2_KE_muon = tfs->make<TProfile>("NuEP2_KE_muon","NuEP2 muon vs KE",200,0,2000);
220  fNuEP2_KE_pion = tfs->make<TProfile>("NuEP2_KE_pion","NuEP2 pion vs KE",200,0,2000);
221  fNuEP2_KE_kaon = tfs->make<TProfile>("NuEP2_KE_kaon","NuEP2 kaon vs KE",200,0,2000);
222  fNuEP2_KE_prot = tfs->make<TProfile>("NuEP2_KE_prot","NuEP2 proton vs KE",200,0,2000);
223 
224  }
225 
227  {
228  if(fPrintLevel == -1) outFile.close();
229  }
230 
231 
233  {
234 
235  // code stolen from TrackAna_module.cc
237  if(geom->Nplanes() > 3) {
238  mf::LogError("ClusterAna")<<"Too many planes for this code...";
239  return;
240  }
241 
242  // get all hits in the event
243  art::Handle< std::vector<recob::Hit> > hitListHandle;
244  evt.getByLabel(fHitsModuleLabel, hitListHandle);
245  std::vector< art::Ptr<recob::Hit> > allhits;
246  art::fill_ptr_vector(allhits, hitListHandle);
247  if(allhits.size() == 0) return;
248 
249  // get clusters and cluster-hit associations
250  art::Handle< std::vector<recob::Cluster> > clusterListHandle;
251  evt.getByLabel(fClusterModuleLabel,clusterListHandle);
252  art::FindManyP<recob::Hit> fmh(clusterListHandle, evt, fClusterModuleLabel);
253  if(clusterListHandle->size() == 0) {
254  std::cout<<"No clusters in event. Hits size "<<allhits.size()<<"\n";
255  // don't return or the statistics will be off
256 // return;
257  }
258 
259  // get 3D vertices
260  art::Handle< std::vector<recob::Vertex> > vertexListHandle;
261  double xyz[3] = {0,0,0};
262  art::PtrVector<recob::Vertex> recoVtxList;
263  if(vertexListHandle.isValid()) {
264  evt.getByLabel(fVertexModuleLabel,vertexListHandle);
265  for(unsigned int ii = 0; ii < vertexListHandle->size(); ++ii){
266  art::Ptr<recob::Vertex> vertex(vertexListHandle, ii);
267  recoVtxList.push_back(vertex);
268  vertex->XYZ(xyz);
269  } // ii
270  } // vertexListHandle
271 
272  // list of all true particles
275  sim::ParticleList const& plist = pi_serv->ParticleList();
276  // list of all true particles that will be considered
277  std::vector<const simb::MCParticle*> plist2;
278  // true (reconstructed) hits for each particle in plist2
279  std::vector<std::vector<art::Ptr<recob::Hit>>> hlist2;
280  // index of cluster matched to each particle in plist2 in each plane
281  std::vector<std::vector<short>> truToCl;
282  // number of true hits in each plane and cluster
283  std::vector<std::vector<unsigned short>> nTruHitInCl;
284  //number of reconstructed hits in all clusters
285  std::vector<unsigned short> nRecHitInCl;
286 
287  // calculate average EP2 for every event to facilitate code development
288  // Beam Neutrinos - muons and not-muons
289 
290  float aveNuEP2mu = 0.;
291  float numNuEP2mu = 0.;
292  float aveNuEP2nm = 0.;
293  float numNuEP2nm = 0.;
294  // Cosmic Rays
295  float aveCREP2 = 0.;
296  float numCREP2 = 0.;
297 
298  // track ID of the neutrino (or single particle)
299  int neutTrackID = -1;
300  std::vector<int> tidlist;
301  float neutEnergy = -1.;
302  int neutIntType = -1;
303  int neutCCNC = -1;
304  bool isNeutrino = false;
305  bool isSingleParticle = false;
306  for(sim::ParticleList::const_iterator ipart = plist.begin(); ipart != plist.end(); ++ipart) {
307  const simb::MCParticle* part = (*ipart).second;
308  assert(part != 0);
309  int pdg = abs(part->PdgCode());
310  int trackID = part->TrackId();
311  art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
312  if(fSkipCosmics && theTruth->Origin() == simb::kCosmicRay) continue;
313  if(theTruth->Origin() == simb::kBeamNeutrino) isNeutrino = true;
314  if(theTruth->Origin() == simb::kSingleParticle) isSingleParticle = true;
315  float KE = 1000 * (part->E() - part->Mass());
316 
317  // Get the neutrino track ID. Assume that there is only one neutrino
318  // interaction and it is first in the list of BeamNeutrino particles
319  if((isNeutrino || isSingleParticle) && neutTrackID < 0) {
320  neutTrackID = trackID;
321  if(isNeutrino) {
322  simb::MCNeutrino theNeutrino = theTruth->GetNeutrino();
323  neutEnergy = 1000. * theNeutrino.Nu().E();
324  neutIntType = theNeutrino.InteractionType();
325  neutCCNC = theNeutrino.CCNC();
326  }
327 // mf::LogVerbatim("ClusterAna")
328 // <<"True Vtx "<<part->Vx()<<" "<<part->Vy()<<" "<<part->Vz();
329  for(unsigned short iv = 0; iv < recoVtxList.size(); ++iv) {
330  recoVtxList[iv]->XYZ(xyz);
331  fNuVtx_dx->Fill(part->Vx() - xyz[0]);
332  fNuVtx_dy->Fill(part->Vy() - xyz[1]);
333  fNuVtx_dz->Fill(part->Vz() - xyz[2]);
334  } // iv
335  } // theTruth->Origin() == simb::kBeamNeutrino && neutTrackID <
336 
337  if(fPrintLevel > 3) mf::LogVerbatim("ClusterAna")
338  <<"Origin "<<theTruth->Origin()<<" trackID "<<trackID
339  <<" PDG "<<part->PdgCode()
340  <<" KE "<<(int)KE<<" MeV "
341  <<" neutTrackID "<<neutTrackID
342  <<" Mother "<<part->Mother()
343  <<" Proc "<<part->Process();
344 
345  bool isCharged = (pdg == 11) || (pdg == 13) || (pdg == 211)
346  || (pdg == 321) || (pdg == 2212);
347 
348 
349  if(!isCharged) continue;
350 
351  // KE (MeV) cuts
352  if(pdg == 11) {
353  if(fElecKERange[0] < 0) continue;
354  // only allow primary electrons
355  if(part->Process() != "primary") continue;
356  if(KE < fElecKERange[0] || KE > fElecKERange[1]) continue;
357  }
358  if(pdg == 13) {
359  if(fMuonKERange[0] < 0) continue;
360  if(KE < fMuonKERange[0] || KE > fMuonKERange[1]) continue;
361  }
362  if(pdg == 211) {
363  if(fPionKERange[0] < 0) continue;
364  if(KE < fPionKERange[0] || KE > fPionKERange[1]) continue;
365  }
366  if(pdg == 321) {
367  if(fKaonKERange[0] < 0) continue;
368  if(KE < fKaonKERange[0] || KE > fKaonKERange[1]) continue;
369  }
370  if(pdg == 2212) {
371  if(fProtKERange[0] < 0) continue;
372  if(KE < fProtKERange[0] || KE > fProtKERange[1]) continue;
373  }
374  // ignore secondaries from neutron interactions
375  if(part->Process() == "NeutronInelastic") continue;
376  plist2.push_back(part);
377  tidlist.push_back(trackID);
378  // initialize the true->(cluster,plane) association
379  std::vector<short> temp {-1, -1, -1};
380  truToCl.push_back(temp);
381  // initialize the true hit count
382  std::vector<unsigned short> temp2(3);
383  nTruHitInCl.push_back(temp2);
384 
385  if(fPrintLevel > 2) mf::LogVerbatim("ClusterAna")
386  <<"plist2["<<plist2.size() - 1<<"]"
387  <<" Origin "<<theTruth->Origin()<<" trackID "<<trackID
388  <<" PDG "<<part->PdgCode()
389  <<" KE "<<(int)KE
390  <<" Mother "<<part->Mother() + neutTrackID - 1
391  <<" Proc "<<part->Process();
392  }
393 
394  if(plist2.size() == 0) return;
395 
396  // get the hits (in all planes) that are matched to the true tracks
397  hlist2 = bt_serv->TrackIdsToHits_Ps( tidlist,allhits);
398  if(hlist2.size() != plist2.size()) {
399  mf::LogError("ClusterAna")
400  <<"MC particle list size "<<plist2.size()
401  <<" != size of MC particle true hits lists "<<hlist2.size();
402  return;
403  }
404  tidlist.clear();
405 
406  // vector of (mother, daughter) pairs
407  std::vector<std::pair<unsigned short, unsigned short>> moda;
408  // Deal with mother-daughter tracks
409  if(fMergeDaughters && neutTrackID >= 0) {
410  // Assume that daughters appear later in the list. Step backwards
411  // to accumulate all generations of daughters
412  unsigned short ii, dpl, jj, jpl, kpl;
413  for(ii = 0; ii < plist2.size(); ++ii) {
414  dpl = plist2.size() - 1 - ii;
415  // no mother
416  if(plist2[dpl]->Mother() == 0) continue;
417  // electron
418  if(abs(plist2[dpl]->PdgCode()) == 11) continue;
419  // the actual mother trackID is offset from the neutrino trackID
420  int motherID = neutTrackID + plist2[dpl]->Mother() - 1;
421  // ensure that we are only looking at BeamNeutrino or single particle daughters
422  if(motherID != neutTrackID) continue;
423  // count the number of daughters
424  int ndtr = 0;
425  for(kpl = 0; kpl < plist2.size(); ++kpl) {
426  if(plist2[kpl]->Mother() == motherID) ++ndtr;
427  }
428  // require only one daughter
429  if(ndtr > 1) continue;
430  // find the mother in the list
431  int mpl = -1;
432  for(jj = 0; jj < plist2.size(); ++jj) {
433  jpl = plist2.size() - 1 - jj;
434  if(plist2[jpl]->TrackId() == motherID) {
435  mpl = jpl;
436  break;
437  }
438  } // jpl
439  // mother not found for some reason
440  if(mpl < 0) {
441  mf::LogVerbatim("ClusterAna")<<" mother of daughter "<<dpl<<" not found. mpl = "<<mpl;
442  continue;
443  }
444  // ensure that PDG code for mother and daughter are the same
445  if(plist2[dpl]->PdgCode() != plist2[mpl]->PdgCode()) continue;
446  moda.push_back(std::make_pair(mpl, dpl));
447  } // dpl
448  } // MergeDaughters
449 
450  // Now match reconstructed clusters to true particles.
452  for (unsigned int ii = 0; ii < clusterListHandle->size(); ++ii){
453  art::Ptr<recob::Cluster> clusterHolder(clusterListHandle,ii);
454  clusters.push_back(clusterHolder);
455  }
456 
457  fNClusters->Fill(clusterListHandle->size());
458  nRecHitInCl.resize(clusters.size());
459 
460  // get the plane from the view. Perhaps there is a method that does
461  // this somewhere...
462  std::map< geo::View_t, unsigned int > ViewToPlane;
463  for(unsigned int plane=0; plane < geom->Nplanes(); ++plane){
464  geo::View_t view = geom->Plane(plane).View();
465  ViewToPlane[view] = plane;
466  }
467  for(size_t icl = 0; icl < clusters.size(); ++icl){
468  unsigned int plane = ViewToPlane[clusters[icl]->View()];
469  std::vector< art::Ptr<recob::Hit> > cluhits = fmh.at(icl);
470  fNHitInCluster->Fill(cluhits.size());
471  nRecHitInCl[icl] = cluhits.size();
472  // count the number of hits matched to each true particle in plist2
473  std::vector<unsigned short> nHitInPl2(plist2.size());
474  for(size_t iht = 0; iht < cluhits.size(); ++iht){
475 
476 // mf::LogVerbatim("ClusterAna")<<"Clus Hit "<<cluhits[iht]->View()<<":"<<cluhits[iht]->WireID().Wire<<":"<<(int)cluhits[iht]->PeakTime();
477 
478  // look for this hit in all of the truth hit lists
479  short hitInPl2 = -1;
480  for(unsigned short ipl = 0; ipl < plist2.size(); ++ipl) {
481  unsigned short imat = 0;
482  for(imat = 0; imat < hlist2[ipl].size(); ++imat) {
483  if(cluhits[iht] == hlist2[ipl][imat]) break;
484  } // imat
485  if(imat < hlist2[ipl].size()) {
486  hitInPl2 = ipl;
487  break;
488  }
489  } // ipl
490  if(hitInPl2 < 0) continue;
491  // Assign the hit count to the mother if this is a daughter.
492  // Mother-daughter pairs are entered in the moda vector in reverse
493  // order, so assign daughter hits to the highest generation mother.
494  for(unsigned short imd = 0; imd < moda.size(); ++imd) {
495  if(moda[imd].second == hitInPl2) hitInPl2 = moda[imd].first;
496  }
497  // count
498  ++nHitInPl2[hitInPl2];
499  } // iht
500  // Associate the cluster with the truth particle that has the highest
501  // number of cluster hits
502  unsigned short nhit = 0;
503  short imtru = -1;
504  for(unsigned int ipl = 0; ipl < nHitInPl2.size(); ++ipl) {
505  if(nHitInPl2[ipl] > nhit) {
506  nhit = nHitInPl2[ipl];
507  imtru = ipl;
508  }
509  } // ipl
510  // make the cluster->(true,plane) association and save the
511  // number of true hits in the cluster
512  if(imtru != -1) {
513  // clobber a previously made association?
514  if(nhit > nTruHitInCl[imtru][plane]) {
515  truToCl[imtru][plane] = icl;
516  nTruHitInCl[imtru][plane] = nhit;
517  }
518  } // imtru != 1
519  } // icl
520 
521  // ready to calculate Efficiency, Purity in each plane and EP2
522  for(unsigned short ipl = 0; ipl < plist2.size(); ++ipl) {
523  // ignore daughters
524  bool skipit = false;
525  for(unsigned short ii = 0; ii < moda.size(); ++ii) {
526  if(moda[ii].second == ipl) {
527  skipit = true;
528  break;
529  }
530  } // ii
531  if(skipit) continue;
532  // ignore true particles with few true hits. Outside the detector
533  // or not reconstructable?
534  if(hlist2[ipl].size() < 3) continue;
535 
536  int trackID = plist2[ipl]->TrackId();
537  art::Ptr<simb::MCTruth> theTruth = pi_serv->TrackIdToMCTruth_P(trackID);
538  bool isCosmic = (theTruth->Origin() == simb::kCosmicRay);
539  float KE = 1000 * (plist2[ipl]->E() - plist2[ipl]->Mass());
540  int PDG = abs(plist2[ipl]->PdgCode());
541 
542  std::vector<short> nTru(geom->Nplanes());
543  std::vector<short> nRec(geom->Nplanes());
544  std::vector<short> nTruRec(geom->Nplanes());
545  std::vector<float> eff(geom->Nplanes());
546  std::vector<float> pur(geom->Nplanes());
547  std::vector<float> ep(geom->Nplanes());
548  for(unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
549  // count the number of true hits in this plane for the true particle.
550  // First count the mother hits
551  for(unsigned short ii = 0; ii < hlist2[ipl].size(); ++ii){
552  if(ViewToPlane[hlist2[ipl][ii]->View()] == plane) ++nTru[plane];
553  } // ii
554 // mf::LogVerbatim("ClusterAna")<<"Chk mom "<<ipl<<" plane "<<plane<<" nTru hits "<<nTru[plane];
555  // next look for daughters and count those hits in all generations
556  unsigned short mom = ipl;
557  std::vector<std::pair<unsigned short, unsigned short>>::reverse_iterator
558  rit = moda.rbegin();
559  while(rit != moda.rend()) {
560  if((*rit).first == mom) {
561  unsigned short dau = (*rit).second;
562  for(unsigned short jj = 0; jj < hlist2[dau].size(); ++jj) {
563  if(ViewToPlane[hlist2[dau][jj]->View()] == plane) ++nTru[plane];
564  } // jj
565  // It is likely that one hit appears in the mother list
566  // as well as the daughter list, so subtract one from the count
567 // --nTru[plane];
568  mom = (*rit).second;
569 // mf::LogVerbatim("ClusterAna")<<"new mom "<<mom<<" nTru "<<nTru[plane];
570  } // (*rit).first == mom
571  ++rit;
572  } // rit
573 // mf::LogVerbatim("ClusterAna")<<"Chk dau "<<nTru[plane];
574  if(nTru[plane] == 0) continue;
575  // Ignore short truth clusters
576  if(nTru[plane] < 3) continue;
577  short icl = truToCl[ipl][plane];
578  if(icl < 0) {
579  nRec[plane] = 0;
580  } else {
581  nRec[plane] = nRecHitInCl[icl];
582  }
583  nTruRec[plane] = nTruHitInCl[ipl][plane];
584  eff[plane] = 0;
585  pur[plane] = 0;
586  if(nTru[plane] > 0) eff[plane] = (float)nTruRec[plane] / (float)nTru[plane];
587  if(nRec[plane] > 0) pur[plane] = (float)nTruRec[plane] / (float)nRec[plane];
588  // do this to prevent histogram under/over flow
589  if(eff[plane] == 0) { eff[plane] = 0.001; }
590  if(pur[plane] == 0) { pur[plane] = 0.001; }
591  if(eff[plane] >= 1) { eff[plane] = 0.999; }
592  if(pur[plane] >= 1) { pur[plane] = 0.999; }
593  ep[plane] = eff[plane] * pur[plane];
594  if(fPrintLevel == -1) outFile<<moduleID<<" "<<evt.id().event()<<" "<<trackID<<" "<<PDG<<" "<<(int)KE<<" "<<plane<<" "<<nTru[plane]<<" "<<std::setprecision(3)<<eff[plane]<<" "<<pur[plane]<<"\n";
595 // mf::LogVerbatim("ClusterAna")<<"Cluster "<<icl<<" nRec hits "<<nRec[plane]<<" nTruRec hits "<<nTruRec[plane]<<" eff "<<eff[plane]<<" pur "<<pur[plane];
596  } // plane
597  // sort the ep values in ascending order
598  std::vector<float> temp;
599  temp = ep;
600  std::sort(temp.begin(), temp.end());
601  // EP2 is the second highest value
602  unsigned short ii = temp.size() - 2;
603  float ep2 = temp[ii];
604  // find the plane that defined EP2
605  short ep2Plane = 0;
606  short ep2Cluster = 0;
607  for(unsigned short jj = 0; jj < temp.size(); ++jj) {
608  if(ep[jj] == ep2) {
609  ep2Plane = jj;
610  ep2Cluster = truToCl[ipl][ep2Plane];
611  break;
612  }
613  } // jj
614  // find the US and DS ends of the cluster for printing
615  std::array<double, 2> clBeg, clEnd;
616  if(ep2Cluster >= 0) {
617  clBeg[0] = clusters[ep2Cluster]->StartWire();
618  clBeg[1] = clusters[ep2Cluster]->StartTick();
619  clEnd[0] = clusters[ep2Cluster]->EndWire();
620  clEnd[1] = clusters[ep2Cluster]->EndTick();
621  }
622  else {
623  clBeg.fill(0.);
624  clEnd.fill(0.);
625  }
626  // fill histograms
627  if(isCosmic) {
628  fCREP2->Fill(ep2);
629  fCRE->Fill(eff[ep2Plane]);
630  fCRP->Fill(pur[ep2Plane]);
631  aveCREP2 += ep2;
632  numCREP2 += 1.;
633  if(fPrintLevel > 1) mf::LogVerbatim("ClusterAna")
634  <<">>>CREP2 "<<std::fixed<<std::setprecision(2)<<ep2
635  <<" E "<<eff[ep2Plane]<<std::setprecision(2)<<" P "<<pur[ep2Plane]
636  <<" P:W:T "<<ep2Plane<<":"<<(int)clBeg[0]<<":"<<(int)clBeg[1]
637  <<"-"<<ep2Plane<<":"<<(int)clEnd[0]<<":"<<(int)clEnd[1]
638  <<" PDG "<<PDG<<" KE "<<(int)KE<<" MeV";
639  } // isCosmic
640  else {
641  float wght = 1.;
642  if(fTrackWeightOption == 1) wght = KE;
643  // accumulate statistics for muons and not-muons
644  if(PDG == 13) {
645  aveNuEP2mu += ep2 * wght;
646  numNuEP2mu += wght;
647  } else {
648  aveNuEP2nm += ep2 * wght;
649  numNuEP2nm += wght;
650  }
651  if(PDG == 11) {
652  fNuKE_elec->Fill(KE, wght);
653  fNuE_elec->Fill(eff[ep2Plane], wght);
654  fNuP_elec->Fill(pur[ep2Plane], wght);
655  fNuEP2_elec->Fill(ep2, wght);
656  fNuEP2_KE_elec->Fill(KE, ep2, wght);
657  } else if(PDG == 13) {
658  fNuKE_muon->Fill(KE, wght);
659  fNuE_muon->Fill(eff[ep2Plane], wght);
660  fNuP_muon->Fill(pur[ep2Plane], wght);
661  fNuEP2_muon->Fill(ep2, wght);
662  fNuEP2_KE_muon->Fill(KE, ep2, wght);
663  } else if(PDG == 211) {
664  fNuKE_pion->Fill(KE, wght);
665  fNuE_pion->Fill(eff[ep2Plane], wght);
666  fNuP_pion->Fill(pur[ep2Plane], wght);
667  fNuEP2_pion->Fill(ep2, wght);
668  fNuEP2_KE_pion->Fill(KE, ep2, wght);
669  } else if(PDG == 321) {
670  fNuKE_kaon->Fill(KE, wght);
671  fNuE_kaon->Fill(eff[ep2Plane], wght);
672  fNuP_kaon->Fill(pur[ep2Plane], wght);
673  fNuEP2_kaon->Fill(ep2, wght);
674  fNuEP2_KE_kaon->Fill(KE, ep2, wght);
675  } else if(PDG == 2212) {
676  fNuKE_prot->Fill(KE, wght);
677  fNuE_prot->Fill(eff[ep2Plane], wght);
678  fNuP_prot->Fill(pur[ep2Plane], wght);
679  fNuEP2_prot->Fill(ep2, wght);
680  fNuEP2_KE_prot->Fill(KE, ep2, wght);
681  }
682  if(fPrintLevel > 1) mf::LogVerbatim("ClusterAna")
683  <<">>>NuEP2 "<<std::fixed<<std::setprecision(2)<<ep2
684  <<" E "<<eff[ep2Plane]<<std::setprecision(2)<<" P "<<pur[ep2Plane]
685  <<" P:W:T "<<ep2Plane<<":"<<(int)clBeg[0]<<":"<<(int)clBeg[1]
686  <<"-"<<ep2Plane<<":"<<(int)clEnd[0]<<":"<<(int)clEnd[1]
687  <<" PDG "<<PDG<<" KE "<<(int)KE<<" MeV ";
688  if(fPrintLevel > 2) {
689  // print out the begin/end true hits
690  mf::LogVerbatim mfp("ClusterAna");
691  mfp<<" Truth P:W:T ";
692  for(unsigned int plane = 0; plane < geom->Nplanes(); ++plane) {
693  unsigned short loW = 9999;
694  unsigned short loT = 0;
695  unsigned short hiW = 0;
696  unsigned short hiT = 0;
697  for(unsigned short ii = 0; ii < hlist2[ipl].size(); ++ii){
698  if(ViewToPlane[hlist2[ipl][ii]->View()] == plane) {
699  art::Ptr<recob::Hit> theHit = hlist2[ipl][ii];
700  if(theHit->WireID().Wire < loW) {
701  loW = theHit->WireID().Wire;
702  loT = theHit->PeakTime();
703  }
704  if(theHit->WireID().Wire > hiW) {
705  hiW = theHit->WireID().Wire;
706  hiT = theHit->PeakTime();
707  }
708  } // correct view
709  } // ii
710  mfp<<plane<<":"<<loW<<":"<<loT<<"-"<<plane<<":"<<hiW<<":"<<hiT<<" ";
711  } // plane
712  } // fPrintLevel > 2
713  } // !isCosmic
714  } // ipl
715 
716  float ave1 = -1.;
717  if(numNuEP2mu > 0.) ave1 = aveNuEP2mu/numNuEP2mu;
718 
719  float ave2 = -1.;
720  if(numNuEP2nm > 0.) ave2 = aveNuEP2nm/numNuEP2nm;
721 
722  float ave3 = -1.;
723  if(numCREP2 > 0.) ave3 = aveCREP2/numCREP2;
724 
725 
726 
727  if(fPrintLevel > 0) {
728  std::string nuType = "Other";
729  if(neutCCNC == simb::kCC) {
730  if(neutIntType == 1001) nuType = "CCQE";
731  if(neutIntType == 1091) nuType = "DIS";
732  if(neutIntType == 1097) nuType = "COH";
733  if(neutIntType > 1002 && neutIntType < 1091) nuType = "RES";
734  } else if(neutCCNC == simb::kNC) {
735  nuType = "NC";
736  } else {
737  nuType = "Unknown";
738  }
739  mf::LogVerbatim("ClusterAna")
740  <<"EvtEP2 "<<evt.id().event()
741  <<" NuType "<<nuType
742  <<" Enu "<<std::fixed<<std::setprecision(0)<<neutEnergy
743  <<std::right<<std::fixed<<std::setprecision(2)
744  <<" NuMuons "<<ave1
745  <<" NuPiKp "<<ave2
746  <<" CosmicRays "<<ave3
747  <<" CCNC "<<neutCCNC<<" IntType "<<neutIntType;
748  }
749  } // analyze
750 
751 } //end namespace
752 
753 
754 namespace cluster{
755 
757 
758 }
759 
double E(const int i=0) const
Definition: MCParticle.h:237
void XYZ(double *xyz) const
Legacy method to access vertex position, preserved to avoid breaking code. Please try to use Vertex::...
Definition: Vertex.cxx:37
const std::vector< std::vector< art::Ptr< recob::Hit > > > TrackIdsToHits_Ps(std::vector< int > const &tkIds, std::vector< art::Ptr< recob::Hit > > const &hitsIn)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
int PdgCode() const
Definition: MCParticle.h:216
int CCNC() const
Definition: MCNeutrino.h:152
const simb::MCNeutrino & GetNeutrino() const
Definition: MCTruth.h:74
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
int Mother() const
Definition: MCParticle.h:217
Declaration of signal hit object.
const simb::MCParticle & Nu() const
Definition: MCNeutrino.h:150
list_type::const_iterator const_iterator
Definition: ParticleList.h:132
simb::Origin_t Origin() const
Definition: MCTruth.h:71
double Mass() const
Definition: MCParticle.h:243
STL namespace.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
Cluster finding and building.
std::string Process() const
Definition: MCParticle.h:219
int TrackId() const
Definition: MCParticle.h:214
std::vector< float > fElecKERange
bool isValid() const
Definition: Handle.h:190
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
int InteractionType() const
Definition: MCNeutrino.h:154
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:171
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
ClusterAna(fhicl::ParameterSet const &pset)
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
single particles thrown at the detector
Definition: MCTruth.h:24
TString part[npart]
Definition: Style.C:32
std::vector< float > fProtKERange
std::vector< float > fKaonKERange
iterator begin()
Definition: ParticleList.h:305
std::string fVertexModuleLabel
EDAnalyzer(Table< Config > const &config)
Definition: EDAnalyzer.h:100
Declaration of cluster object.
size_type size() const
Definition: PtrVector.h:308
void analyze(const art::Event &evt)
read access to event
double Vx(const int i=0) const
Definition: MCParticle.h:225
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
T * make(ARGS...args) const
Utility object to perform functions of association.
Encapsulate the construction of a single detector plane.
Example routine for calculating the "ultimate e-m mother" of a particle in a simulated event...
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
Int_t ipart
Definition: Style.C:10
double Vz(const int i=0) const
Definition: MCParticle.h:227
EventNumber_t event() const
Definition: EventID.h:117
Declaration of basic channel signal object.
std::string fClusterModuleLabel
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:464
Particle list in DetSim contains Monte Carlo particle information.
Event generator information.
Definition: MCNeutrino.h:18
std::vector< float > fPionKERange
std::vector< float > fMuonKERange
EventID id() const
Definition: Event.h:56
double Vy(const int i=0) const
Definition: MCParticle.h:226
art framework interface to geometry description
Cosmic rays.
Definition: MCTruth.h:22
const art::Ptr< simb::MCTruth > & TrackIdToMCTruth_P(int const &id)
Beam neutrinos.
Definition: MCTruth.h:21
vertex reconstruction