LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
AssignLabels.cxx
Go to the documentation of this file.
2 
8 
11 
12 #include <iomanip>
13 #include <iostream>
14 #include <limits>
15 
16 namespace lcvn {
19  : nProton(0), nPion(0), nPizero(0), nNeutron(0), pdgCode(0), tauMode(0)
20  {}
21 
25  {
26 
27  int pdg = truth.Nu().PdgCode();
28  bool iscc = truth.CCNC() == simb::kCC;
29  int trueMode = truth.Mode();
30 
31  if (iscc) {
32  if (abs(pdg) == 14) {
33  switch (trueMode) {
34  case simb::kQE: return kNumuQE; break;
35  case simb::kRes: return kNumuRes; break;
36  case simb::kDIS: return kNumuDIS; break;
37  default: return kNumuOther;
38  }
39  }
40  else if (abs(pdg) == 12) {
41  switch (trueMode) {
42  case simb::kQE: return kNueQE; break;
43  case simb::kRes: return kNueRes; break;
44  case simb::kDIS: return kNueDIS; break;
45  default: return kNueOther;
46  }
47  }
48  else if (abs(pdg) == 16) {
49  switch (trueMode) {
50  case simb::kQE: return kNutauQE; break;
51  case simb::kRes: return kNutauRes; break;
52  case simb::kDIS: return kNutauDIS; break;
53  default: return kNutauOther;
54  }
55  }
56  }
57  else if (trueMode == simb::kNuElectronElastic) {
58  return kNuElectronElastic;
59  }
60 
61  return kNC;
62  }
63 
64  InteractionType AssignLabels::GetInteractionTypeFromSlice(int pdg, bool iscc, int trueMode) const
65  {
66 
67  if (iscc) {
68 
69  if (abs(pdg) == 14) {
70  switch (trueMode) {
71  case simb::kQE: return kNumuQE;
72  case simb::kRes: return kNumuRes;
73  case simb::kDIS: return kNumuDIS;
74  default: return kNumuOther;
75  }
76  }
77  else if (abs(pdg) == 12) {
78  switch (trueMode) {
79  case simb::kQE: return kNueQE;
80  case simb::kRes: return kNueRes;
81  case simb::kDIS: return kNueDIS;
82  default: return kNueOther;
83  }
84  }
85  else if (abs(pdg) == 16) {
86  switch (trueMode) {
87  case simb::kQE: return kNutauQE;
88  case simb::kRes: return kNutauRes;
89  case simb::kDIS: return kNutauDIS;
90  default: return kNutauOther;
91  }
92  }
93  }
94  else if (trueMode == simb::kNuElectronElastic) {
95  return kNuElectronElastic;
96  }
97 
98  return kNC;
99  }
100 
101  // This function uses purely the information from the neutrino generator to
102  // find all of the final-state particles that contribute to the event.
104  unsigned int nTopologyHits = 0)
105  {
106 
107  const simb::MCNeutrino& nu = truth->GetNeutrino();
108 
109  // Get neutrino flavour
110  if (nu.CCNC() == simb::kCC) { pdgCode = nu.Nu().PdgCode(); }
111  else {
112  pdgCode = 1;
113  }
114 
115  // Get tau topology, if necessary
116  tauMode = kNotNutau;
117  if (abs(pdgCode) == 16) {
118  tauMode = kNutauHad;
119  for (int p = 0; p < truth->NParticles(); ++p) {
120  if (truth->GetParticle(p).StatusCode() != 1) continue;
121  int pdg = abs(truth->GetParticle(p).PdgCode());
122  int parent = truth->GetParticle(p).Mother();
123  while (parent > 0)
124  parent = truth->GetParticle(parent).Mother();
125 
126  if (parent == 0) {
127  if (pdg == 11) {
128  tauMode = kNutauE;
129  break;
130  }
131  else if (pdg == 13) {
132  tauMode = kNutauMu;
133  break;
134  }
135  }
136  }
137  }
138 
139  // Now we need to do some final state particle counting.
140  // unsigned int nParticle = truth.NParticles();
141 
142  nProton = 0;
143  nPion = 0; // Charged pions, that is
144  nPizero = 0;
145  nNeutron = 0;
146 
147  // We need an instance of the backtracker to find the number of simulated hits for each track
150 
151  // Loop over all of the particles
152  for (auto const thisPart : partService->MCTruthToParticles_Ps(truth)) {
153 
154  const simb::MCParticle& part = *thisPart;
155 
156  int pdg = part.PdgCode();
157 
158  // Make sure this is a final state particle
159  if (part.StatusCode() != 1) { continue; }
160 
161  // Make sure this particle is a daughter of the neutrino
162  if (part.Mother() != 0) { continue; }
163 
164  // GENIE has some fake particles for energy conservation - eg nuclear binding energy. Ignore these
165  if (pdg > 2000000000) { continue; }
166 
167  // Also don't care about nuclear recoils
168  if (pdg > 1000000) { continue; }
169 
170  // Find how many SimIDEs the track has
171  unsigned int nSimIDE = backTrack->TrackIdToSimIDEs_Ps(part.TrackId()).size();
172 
173  // Check if we have more than 100 MeV of kinetic energy
174  // float ke = part.E() - part.Mass();
175  // if( ke < 0.0){
176  // continue;
177  // }
178 
179  // Special case for pi-zeros since it is the decay photons and their pair produced electrons that deposit energy
180  if (pdg == 111 || pdg == 2112) {
181  // Decay photons
182  for (int d = 0; d < part.NumberDaughters(); ++d) {
183  nSimIDE += backTrack->TrackIdToSimIDEs_Ps(part.Daughter(d)).size();
184  }
185  }
186 
187  // Do we pass the number of hits cut?
188  if (nSimIDE < nTopologyHits) { continue; }
189 
190  switch (abs(pdg)) {
191  case 111: ++nPizero; break;
192  case 211: ++nPion; break;
193  case 2112: ++nNeutron; break;
194  case 2212: ++nProton; break;
195  default: break;
196  }
197  }
198 
199  std::cout << "Particle counts: " << nProton << ", " << nPion << ", " << nPizero << ", "
200  << nNeutron << std::endl;
201  }
202 
204  {
205 
206  std::cout << "== Topology Information ==" << std::endl;
207 
208  std::cout << " - Neutrino PDG code = " << pdgCode << std::endl;
209 
210  std::cout << " - Number of protons (3 means >2) = " << nProton << std::endl;
211 
212  std::cout << " - Number of charged pions (3 means >2) = " << nPion << std::endl;
213 
214  std::cout << " - Number of pizeros (3 means >2) = " << nPizero << std::endl;
215 
216  std::cout << " - Number of neutrons (3 means >2) = " << nNeutron << std::endl;
217 
218  std::cout << " - Topology type is " << GetTopologyType() << std::endl;
219 
220  std::cout << " - Alternate topology type is " << GetTopologyTypeAlt() << std::endl;
221  }
222 
223  unsigned short AssignLabels::GetTopologyType() const
224  {
225 
226  if (abs(pdgCode) == 12) return kTopNue;
227  if (abs(pdgCode) == 14) return kTopNumu;
228  if (abs(pdgCode) == 16) {
229  if (tauMode == kNutauE) return kTopNutauE;
230  if (tauMode == kNutauMu) return kTopNutauMu;
231  if (tauMode == kNutauHad) return kTopNutauHad;
232  }
233  if (pdgCode == 1) return kTopNC;
234  throw std::runtime_error("Topology type not recognised!");
235  }
236 
237  unsigned short AssignLabels::GetTopologyTypeAlt() const
238  {
239 
240  if (abs(pdgCode) == 12) return kTopNueLike;
241  if (abs(pdgCode) == 14) return kTopNumuLike;
242  if (abs(pdgCode) == 16) {
243  if (tauMode == kNutauE) return kTopNueLike;
244  if (tauMode == kNutauMu) return kTopNumuLike;
245  if (tauMode == kNutauHad) return kTopNutauLike;
246  }
247  if (pdgCode == 1) return kTopNCLike;
248  throw std::runtime_error("Topology type not recognised!");
249  }
250 
251  // Get the beam interaction mode for ProtoDUNE specific code
253  const simb::MCParticle& particle) const
254  {
255 
256  unsigned short baseProcess = std::numeric_limits<unsigned short>::max();
257 
258  // The first thing we can do is look at the process key
259  std::string processName = particle.EndProcess();
260 
261  if (GetProcessKey(processName) > -1) {
262  // Base process gives us a value from 0 to 44
263  baseProcess = static_cast<unsigned int>(GetProcessKey(processName));
264  }
265 
266  std::cout << "What interaction type, then? " << processName << std::endl;
267 
268  // In the case that we have an inelastic interaction, maybe we can do more.
270 
271  unsigned int nPi0 = 0; // Pi-zeros
272  unsigned int nPiM = 0; // Pi-minuses
273  unsigned int nPiP = 0; // Pi-pluses
274  unsigned int nNeu = 0; // Neutrons
275  unsigned int nPro = 0; // Protons
276  unsigned int nOth = 0; // Everything else
277 
278  for (int i = 0; i < particle.NumberDaughters(); ++i) {
279  const simb::MCParticle* daughter = piService->TrackIdToParticle_P(particle.Daughter(i));
280  switch (daughter->PdgCode()) {
281  case 111: ++nPi0; break;
282  case -211: ++nPiM; break;
283  case 211: ++nPiP; break;
284  case 2112: ++nNeu; break;
285  case 2212: ++nPro; break;
286  default: ++nOth; break;
287  }
288  }
289 
290  std::cout << "Base process = " << baseProcess << std::endl;
291  std::cout << "Daughters = " << nPi0 << " pi0s, " << nPiM << " pi-s, " << nPiP << " pi+s, "
292  << nNeu << " neutrons, " << nPro << " protons and " << nOth << " other particles."
293  << std::endl;
294 
295  // If we have a pion with a pi0 in the final state we can flag it as charge exchange
296  if (abs(particle.PdgCode()) == 211 && nPi0 == 1) {
297  return 45; // First free value after those from the truth utility
298  }
299  else {
300  return baseProcess;
301  }
302  }
303 
304  // Get process key.
305  int lcvn::AssignLabels::GetProcessKey(std::string process) const
306  {
307 
308  if (process.compare("primary") == 0) return 0;
309  if (process.compare("hadElastic") == 0) return 1;
310  if (process.compare("pi-Inelastic") == 0) return 2;
311  if (process.compare("pi+Inelastic") == 0) return 3;
312  if (process.compare("kaon-Inelastic") == 0) return 4;
313  if (process.compare("kaon+Inelastic") == 0) return 5;
314  if (process.compare("protonInelastic") == 0) return 6;
315  if (process.compare("neutronInelastic") == 0) return 7;
316  if (process.compare("kaon0SInelastic") == 0) return 8;
317  if (process.compare("kaon0LInelastic") == 0) return 9;
318  if (process.compare("lambdaInelastic") == 0) return 10;
319  if (process.compare("omega-Inelastic") == 0) return 11;
320  if (process.compare("sigma+Inelastic") == 0) return 12;
321  if (process.compare("sigma-Inelastic") == 0) return 13;
322  if (process.compare("sigma0Inelastic") == 0) return 14;
323  if (process.compare("xi-Inelastic") == 0) return 15;
324  if (process.compare("xi0Inelastic") == 0) return 16;
325  if (process.compare("anti_protonInelastic") == 0) return 20;
326  if (process.compare("anti_neutronInelastic") == 0) return 21;
327  if (process.compare("anti_lambdaInelastic") == 0) return 22;
328  if (process.compare("anti_omega-Inelastic") == 0) return 23;
329  if (process.compare("anti_sigma+Inelastic") == 0) return 24;
330  if (process.compare("anti_sigma-Inelastic") == 0) return 25;
331  if (process.compare("anti_xi-Inelastic") == 0) return 26;
332  if (process.compare("anti_xi0Inelastic") == 0) return 27;
333 
334  if (process.compare("Decay") == 0) return 30;
335  if (process.compare("FastScintillation") == 0) return 31;
336  if (process.compare("nKiller") == 0)
337  return 32; // Remove unwanted neutrons: neutron kinetic energy threshold (default 0) or time limit for neutron track
338  if (process.compare("nCapture") == 0) return 33; // Neutron capture
339 
340  if (process.compare("compt") == 0) return 40; // Compton Scattering
341  if (process.compare("rayleigh") == 0) return 41; // Rayleigh Scattering
342  if (process.compare("phot") == 0) return 42; // Photoelectric Effect
343  if (process.compare("conv") == 0) return 43; // Pair production
344  if (process.compare("CoupledTransportation") == 0) return 44; //
345 
346  return -1;
347  }
348 
349  // Recursive function to get all hits from daughters of a given neutral particle
351  {
352 
353  unsigned int nSimIDEs = 0;
354 
355  // The backtrack and particle inventory service will be useful here
358 
359  for (int d = 0; d < particle.NumberDaughters(); ++d) {
360 
361  const simb::MCParticle* daughter = partService->TrackIdToParticle_P(particle.Daughter(d));
362  unsigned int localSimIDEs = backTrack->TrackIdToSimIDEs_Ps(daughter->TrackId()).size();
363  std::cout << "Got " << localSimIDEs << " hits from " << daughter->PdgCode() << std::endl;
364  if (localSimIDEs == 0) localSimIDEs = GetNeutralDaughterHitsRecursive(*daughter);
365 
366  nSimIDEs += localSimIDEs;
367  }
368 
369  return nSimIDEs;
370  }
371 
372 }
int GetProcessKey(std::string process) const
int PdgCode() const
Definition: MCParticle.h:213
int CCNC() const
Definition: MCNeutrino.h:148
NC interaction.
const simb::MCNeutrino & GetNeutrino() const
Definition: MCTruth.h:77
InteractionType GetInteractionType(simb::MCNeutrino &truth) const
unsigned short nPion
Definition: AssignLabels.h:49
neutrino electron elastic scatter
Definition: MCNeutrino.h:140
const simb::MCParticle * TrackIdToParticle_P(int id) const
int Mother() const
Definition: MCParticle.h:214
unsigned short nProton
Definition: AssignLabels.h:48
const simb::MCParticle & Nu() const
Definition: MCNeutrino.h:146
unsigned short nNeutron
Definition: AssignLabels.h:51
constexpr auto abs(T v)
Returns the absolute value of the argument.
Nutau CC QE interaction.
std::vector< const simb::MCParticle * > MCTruthToParticles_Ps(art::Ptr< simb::MCTruth > const &mct) const
Utility class for truth labels.
std::vector< const sim::IDE * > TrackIdToSimIDEs_Ps(int const &id) const
int StatusCode() const
Definition: MCParticle.h:212
int NParticles() const
Definition: MCTruth.h:75
Nue CC Resonant interaction.
Particle class.
unsigned short GetTopologyTypeAlt() const
int NumberDaughters() const
Definition: MCParticle.h:218
int TrackId() const
Definition: MCParticle.h:211
int Daughter(const int i) const
Definition: MCParticle.cxx:118
unsigned short GetTopologyType() const
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
TString part[npart]
Definition: Style.C:32
Nue CC QE interaction.
Nutau CC Resonant interaction.
std::string EndProcess() const
Definition: MCParticle.h:217
Nutau CC DIS interaction.
Numu CC, other than above.
AssignLabels()
Default constructor.
unsigned short tauMode
Definition: AssignLabels.h:53
Numu CC QE interaction.
Float_t d
Definition: plot.C:235
NC Nu On E Scattering.
const simb::MCParticle & GetParticle(int i) const
Definition: MCTruth.h:76
void GetTopology(const art::Ptr< simb::MCTruth > truth, unsigned int nTopologyHits)
Nue CC, other than above.
unsigned int GetNeutralDaughterHitsRecursive(const simb::MCParticle &particle) const
unsigned short nPizero
Definition: AssignLabels.h:50
Numu CC Resonant interaction.
InteractionType GetInteractionTypeFromSlice(int nuPDG, bool nuCCNC, int nuMode) const
Nutau CC, other than above.
unsigned short GetProtoDUNEBeamInteractionType(const simb::MCParticle &particle) const
Nue CC DIS interaction.
Event generator information.
Definition: MCNeutrino.h:18
int Mode() const
Definition: MCNeutrino.h:149
Numu CC DIS interaction.