PionCrossSectionAnalyzer_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: PionCrossSectionAnalyzer
3 // Plugin Type: analyzer (art v3_01_02)
4 // File: PionCrossSectionAnalyzer_module.cc
5 //
6 // Generated at Wed Mar 6 14:10:55 2019 by Jacob Calcutt using cetskelgen
7 // from cetlib version v3_05_01.
8 ////////////////////////////////////////////////////////////////////////
9 
17 #include "fhiclcpp/ParameterSet.h"
19 
30 
32 //#include "protoduneana/Utilities/ProtoDUNETrackUtils.h"
33 //#include "protoduneana/Utilities/ProtoDUNEShowerUtils.h"
34 //#include "protoduneana/Utilities/ProtoDUNEPFParticleUtils.h"
35 //#include "protoduneana/Utilities/ProtoDUNEBeamlineUtils.h"
36 
40 
42 #include "dune/DuneObj/ProtoDUNEBeamEvent.h"
43 
44 #include "art_root_io/TFileService.h"
45 
46 // ROOT includes
47 #include "TTree.h"
48 #include "TH1D.h"
49 
51 
52 
54 public:
56  // The compiler-generated destructor is fine for non-base
57  // classes without bare pointers or other resource use.
58 
59  // Plugins should not be copied or assigned.
64 
65  // Required functions.
66  void analyze(art::Event const& e) override;
67 
68  void beginJob() override;
69  void endJob() override;
70 
71  double distance(double x1, double y1, double z1, double x2, double y2, double z2);
72 
73  void reset();
74 
75 private:
76 
83  TH1D *hIncidentKE;
84 
85  double minX = -360.0;
86  double maxX = 360.0;
87  double minY =0.0;
88  double maxY = 600.0;
89  double minZ = 0.0; // G10 at z=1.2
90  double maxZ = 695.0;
91 
93 
94 };
95 
96 double PionCrossSectionAnalyzer::distance(double x1, double y1, double z1, double x2, double y2, double z2){
97  double d = TMath::Sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
98  return d;
99 }
100 
102  : EDAnalyzer{p} ,
103  fGeneratorTag(p.get<std::string>("GeneratorTag"))
104  // More initializers here.
105 {
106  // Call appropriate consumes<>() for any products to be retrieved by this module.
107 }
108 
111  hIncidentKE = tfs->make<TH1D>("hIncidentKE" , "Incident Kinetic Energy [MeV]" , 420, -100, 2000);
112  hInteractingKEInel = tfs->make<TH1D>("hInteractingKEInel", "Inelastic Interacting Kinetic Energy [MeV]", 420, -100, 2000);
113  hInteractingKEQE = tfs->make<TH1D>("hInteractingKEQE", "Quasi-elastic Interacting Kinetic Energy [MeV]", 420, -100, 2000);
114  hInteractingKEAbs = tfs->make<TH1D>("hInteractingKEAbs", "Absorption Interacting Kinetic Energy [MeV]", 420, -100, 2000);
115  hInteractingKECex = tfs->make<TH1D>("hInteractingKECex", "Charge Exchange Interacting Kinetic Energy [MeV]", 420, -100, 2000);
116  hInteractingKEDCex = tfs->make<TH1D>("hInteractingKEDCex", "Double Charge Exchange Interacting Kinetic Energy [MeV]", 420, -100, 2000);
117  hInteractingKEProd = tfs->make<TH1D>("hInteractingKEProd", "Pion Production Interacting Kinetic Energy [MeV]", 420, -100, 2000);
118 
119 }
121 
122 }
123 
127  const sim::ParticleList & plist = pi_serv->ParticleList();
128 
129  // Get the truth utility to help us out
131  // Firstly we need to get the list of MCTruth objects from the generator. The standard protoDUNE
132  // simulation has fGeneratorTag = "generator"
133  auto mcTruths = evt.getValidHandle<std::vector<simb::MCTruth>>(fGeneratorTag);
134  // mcTruths is basically a pointer to an std::vector of simb::MCTruth objects. There should only be one
135  // of these, so we pass the first element into the function to get the good particle
136  const simb::MCParticle* geantGoodParticle = truthUtil.GetGeantGoodParticle((*mcTruths)[0],evt);
137 
138  bool keepInteraction = false;
139 
140  if(geantGoodParticle != 0x0){
141  std::cout << "Found GEANT particle corresponding to the good particle with pdg = " << geantGoodParticle->PdgCode() << std::endl;
142  std::cout << "ID: " << geantGoodParticle->TrackId() << std::endl;
143  std::cout << "Mother: " << geantGoodParticle->Mother() << std::endl;
144 
145  if(geantGoodParticle->PdgCode()==211 && geantGoodParticle->Process()=="primary" && geantGoodParticle->NumberDaughters()!=0){
146  std::cout<<"Track ID of the geantGoodParticle "<<geantGoodParticle->TrackId()<<std::endl;
147  std::cout<<"Process:"<<geantGoodParticle->Process()<<std::endl;
148 
150  simb::MCTrajectory truetraj=geantGoodParticle->Trajectory();
151 
152  geo::View_t view = geom->View(2);
153  auto simIDE_prim=bt_serv->TrackIdToSimIDEs_Ps(geantGoodParticle->TrackId(),view);
154  std::map<double, sim::IDE> orderedSimIDE;
155  for (auto& ide : simIDE_prim) orderedSimIDE[ide->z]= *ide;
156 
157  std::string interactionLabel="";
158  double mass=geantGoodParticle->Mass();
159  //Store the kinetic energy and momentum on z at WC4. Just for cross check
160  auto inTPCPoint = truetraj.begin();
161 
162  //--------------------------------------------------------
163  // Identify the first trajectory point inside the TPC
164  // Loop From First TrajPoint --> First Point in TPC
165  // Stop when you get into the TPC
166  for ( auto t = truetraj.begin(); t!= std::prev(truetraj.end()); t++){
167  auto pos = t->first;
168  if (pos.Z() < minZ) continue;
169  else if (pos.X() < minX || pos.X() > maxX ) continue;
170  else if (pos.Y() < minY || pos.Y() > maxY ) continue;
171  else {
172  inTPCPoint = t;
173  break;
174  }
175  }
176 
177  if (inTPCPoint !=truetraj.begin()) {
178 
179  // Identify the last interesting trajectory point in TPC
180  auto finTPCPoint = std::prev(truetraj.end());
181  // The last point is a bit more complicated:
182  // if there's no interaction, then it is simply the last point in the TPC
183  // if there's one or more interaction points, it's the first interaction point deemed interesting (no coulomb)
184  // Take the interaction Map... check if there's something there
185  auto thisTracjectoryProcessMap = truetraj.TrajectoryProcesses();
186  std::cout<<"thisTrajectoryProcessMap size: "<<thisTracjectoryProcessMap.size()<<std::endl;
187 
188  int inel=0;
189  for(auto const& couple: thisTracjectoryProcessMap) {
190  // I'm not interested in the CoulombScattering, discard this case
191  if ((truetraj.KeyToProcess(couple.second)).find("CoulombScat")!= std::string::npos) continue;
192 
193  // Let's check if the interaction is in the the TPC
194  auto interactionPos4D = (truetraj.at(couple.first)).first ;
195  if (interactionPos4D.Z() < minZ || interactionPos4D.Z() > maxZ ) continue;
196  else if (interactionPos4D.X() < minX || interactionPos4D.X() > maxX ) continue;
197  else if (interactionPos4D.Y() < minY || interactionPos4D.Y() > maxY ) continue;
198  if ((truetraj.KeyToProcess(couple.second)).find("InElastic")!= std::string::npos) inel++;
199 
200  // If we made it here, then this is the first interesting interaction in the TPC
201  // Our job is done!!! Great! Store the interaction label and the iterator for the final point
202  std::cout << "key: " << size_t(couple.second) << std::endl;
203  interactionLabel = truetraj.KeyToProcess(couple.second);
204  std::cout<<"interaction Label "<<interactionLabel<<" EndProcess "<<geantGoodParticle->EndProcess()<<std::endl;
205  finTPCPoint = truetraj.begin() + couple.first;
206  keepInteraction=true;
207  break;
208  }
209 
210  sim::ParticleList::const_iterator itPart=plist.begin();
211 
212  // If I didn't find anything interesting in the intereaction map, let's loop back!
213  if (!keepInteraction) {
214  //Loop on the daughters
215  for(size_t iPart1=0;(iPart1<plist.size()) && (plist.begin()!=plist.end());++iPart1){
216  const simb::MCParticle* pPart=(itPart++)->second;
217  // art::Ptr<simb::MCTruth> const& mcDaught=pi_serv->ParticleToMCTruth_P(pPart)
218  //We keep only the dauthers of the primary not coming from elastic or inelastic scattering
219  if (pPart->Mother() != 1 ) continue;
220  // std::cout<<"pPart mother "<<pPart->Mother()<<std::endl;
221  if ((pPart->Process()).find("astic")!= std::string::npos) continue;
222  if ((pPart->Process()).find("CoulombScat")!= std::string::npos) continue;
223  //Is the daughter born inside the TPC? If yes, store the process which created it
224  simb::MCTrajectory trueDaugthTraj = pPart->Trajectory();
225  if (trueDaugthTraj.begin()->first.Z() < minZ || trueDaugthTraj.begin()->first.Z() > maxZ) continue;
226  else if (trueDaugthTraj.begin()->first.X() < minX || trueDaugthTraj.begin()->first.X() > maxX ) continue;
227  else if (trueDaugthTraj.begin()->first.Y() < minY || trueDaugthTraj.begin()->first.Y() > maxY ) continue;
228  else {
229  interactionLabel = pPart->Process();
230 
231  break;
232  }
233  }
234  for ( auto t = std::prev(truetraj.end()); t!= truetraj.begin(); t--){
235  auto pos = t->first;
236 
237  if (pos.Z() > maxZ) continue;
238  else if (pos.X() < minX || pos.X() > maxX ) continue;
239  else if (pos.Y() < minY || pos.Y() > maxY ) continue;
240  else {
241  finTPCPoint = t;
242  break;
243  }
244  }
245  }
246 
247  if (finTPCPoint != inTPCPoint){
248  auto posFin = finTPCPoint->first;
249  auto posIni = inTPCPoint->first;
250  //Let's record what the initial and final points are.
251 
252  auto totLength = distance(posFin.X(), posFin.Y(), posFin.Z(),posIni.X(), posIni.Y(), posIni.Z() );
253 
254 
255  // We want to chop up the points between the first and last uniformly
256  // and ordered by Z
257  // Order them in order of increasing Z
258  std::map<double, TVector3> orderedUniformTrjPts;
259  // We want the first and uniform point to coincide with the
260  // the first and last points we just found
261  auto positionVector0 = (inTPCPoint ->first).Vect();
262  auto positionVector1 = (finTPCPoint->first).Vect();
263  orderedUniformTrjPts[positionVector0.Z()] = positionVector0;
264  orderedUniformTrjPts[positionVector1.Z()] = positionVector1;
265 
266  const double trackPitch = 0.4792;
267  // I do have space for at least one extra point, so let's put it there!
268  // Calculate how many extra points I need to put between the new first point and the second TrajPoint
269  int nPts = (int) (totLength/trackPitch);
270  for (int iPt = 1; iPt <= nPts; iPt++ ){
271  auto newPoint = positionVector0 + iPt*(trackPitch/totLength) * (positionVector1 - positionVector0);
272  orderedUniformTrjPts[newPoint.Z()] = newPoint;
273  }
274 
275  // If the distance between the last point and the second to last is less then 0.235
276  // eliminate the second to last point
277  auto lastPt = (orderedUniformTrjPts.rbegin())->second;
278  auto secondtoLastPt = (std::next(orderedUniformTrjPts.rbegin()))->second;
279  double lastDist = distance(lastPt.X(),lastPt.Y(),lastPt.Z(),secondtoLastPt.X(),secondtoLastPt.Y(),secondtoLastPt.Z());
280  if (lastDist < 0.240){
281  orderedUniformTrjPts.erase((std::next(orderedUniformTrjPts.rbegin()))->first );
282  }
283 
284  // Calculate the initial kinetic energy
285  auto initialMom = inTPCPoint->second;
286  double initialKE = 1000*(TMath::Sqrt(initialMom.X()*initialMom.X() + initialMom.Y()*initialMom.Y() + initialMom.Z()*initialMom.Z() + mass*mass ) - mass);
287  double kineticEnergy = initialKE;
288  auto old_it = orderedUniformTrjPts.begin();
289  for (auto it = std::next(orderedUniformTrjPts.begin()); it != orderedUniformTrjPts.end(); it++, old_it++ ){
290 
291  auto oldPos = old_it->second;
292  auto currentPos = it->second;
293 
294  double uniformDist = (currentPos - oldPos).Mag();
295 
296  //Calculate the energy deposited in this slice
297  auto old_iter = orderedSimIDE.begin();
298  double currentDepEnergy = 0.;
299  for ( auto iter= orderedSimIDE.begin(); iter!= orderedSimIDE.end(); iter++,old_iter++){
300  auto currentIde = iter->second;
301  // std::cout<<"Z position of the trajectory hits "<<currentIde.z<<std::endl;
302  if ( currentIde.z < oldPos.Z()) continue;
303  if ( currentIde.z > currentPos.Z()) continue;
304  currentDepEnergy += currentIde.energy;
305  }
306 
307  // avoid overfilling super tiny energy depositions
308  if (currentDepEnergy/uniformDist < 0.1 ) continue;
309 
310  //Calculate the current kinetic energy
311  kineticEnergy -= currentDepEnergy;
312  hIncidentKE->Fill(kineticEnergy);
313  }
314 
315  if(interactionLabel.find("Inelastic")!= std::string::npos ){
316  hInteractingKEInel->Fill(kineticEnergy);
317 
318  int nPiPlus_truth = 0;
319  int nPiMinus_truth = 0;
320  int nPi0_truth = 0;
321  int nProton_truth = 0;
322  int nNeutron_truth = 0;
323 
324 
325  std::cout << "NDaughters: " << geantGoodParticle->NumberDaughters() << std::endl;
326  for( int i = 0; i < geantGoodParticle->NumberDaughters(); ++i ){
327  std::cout << "Checking " << i << std::endl;
328  int daughterID = geantGoodParticle->Daughter(i);
329 
330  std::cout << "Daughter " << i << " ID: " << daughterID << std::endl;
331  //Skip photons, neutrons, the nucleus
332  if( plist[ daughterID ]->PdgCode() == 22 || /*plist[ daughterID ]->PdgCode() == 2112 ||*/ plist[ daughterID ]->PdgCode() > 1000000000 ) continue;
333 
334  auto part = plist[ daughterID ];
335  int pid = part->PdgCode();
336  std::cout << "PID: " << pid << std::endl;
337  std::cout << "Process: " << part->Process() << std::endl;
338 
339  if( pid == 211 ) nPiPlus_truth++;
340  else if( pid == -211 ) nPiMinus_truth++;
341  else if( pid == 111 ) nPi0_truth++;
342  else if( pid == 2212 ) nProton_truth++;
343  else if( pid == 2112 ) nNeutron_truth++;
344 
345  }
346 
347  if( nPiPlus_truth == 1 && nPiMinus_truth == 0 && nPi0_truth == 0 ){
348  std::cout << "Filling QE" << std::endl;
349  hInteractingKEQE->Fill(kineticEnergy);
350  }
351  else if( nPiPlus_truth == 0 && nPiMinus_truth == 0 && nPi0_truth == 0 ){
352  std::cout << "Filling Abs" << std::endl;
353  hInteractingKEAbs->Fill(kineticEnergy);
354  }
355  else if( nPiPlus_truth == 0 && nPiMinus_truth == 0 && nPi0_truth == 1 ){
356  std::cout << "Filling Cex" << std::endl;
357  hInteractingKECex->Fill(kineticEnergy);
358  }
359  else if( nPiPlus_truth == 0 && nPiMinus_truth == 1 && nPi0_truth == 0 ){
360  std::cout << "Filling DCex" << std::endl;
361  hInteractingKEDCex->Fill(kineticEnergy);
362  }
363  else{
364  std::cout << "Filling Prod" << std::endl;
365  hInteractingKEProd->Fill(kineticEnergy);
366  }
367  }
368 
369  keepInteraction = false;
370 
371  }
372  }
373  }
374 
375 
376 
377  }
378 
379 }
380 
const simb::MCParticle * GetGeantGoodParticle(const simb::MCTruth &genTruth, const art::Event &evt) const
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
const simb::MCTrajectory & Trajectory() const
Definition: MCParticle.h:253
int Mother() const
Definition: MCParticle.h:213
const value_type & at(const size_type i) const
Definition: MCTrajectory.h:175
std::string KeyToProcess(unsigned char const &key) const
std::vector< const sim::IDE * > TrackIdToSimIDEs_Ps(int const &id) const
Information about charge reconstructed in the active volume.
intermediate_table::const_iterator const_iterator
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
std::string Process() const
Definition: MCParticle.h:215
Particle class.
const double e
int PdgCode(Resonance_t res, int Q)
(resonance id, charge) -> PDG code
void analyze(art::Event const &e) override
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
ProcessMap const & TrajectoryProcesses() const
Definition: MCTrajectory.h:188
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
const sim::ParticleList & ParticleList() const
Declaration of signal hit object.
Provides recob::Track data product.
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
TCEvent evt
Definition: DataStructs.cxx:7
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:85
PionCrossSectionAnalyzer(fhicl::ParameterSet const &p)
QTextStream & endl(QTextStream &s)
PionCrossSectionAnalyzer & operator=(PionCrossSectionAnalyzer const &)=delete