Belle II Software  release-06-00-14
HEPEVT_struct.cc
1 #include <vector>
2 #include <cmath>
3 #include "PhotosBranch.h"
4 #include "PhotosParticle.h"
5 #include "HEPEVT_struct.h"
6 #include "Log.h"
7 using namespace std;
8 
9 namespace Photospp {
10 
11  vector<PhotosParticle*> HEPEVT_struct::m_particle_list;
12  int HEPEVT_struct::ME_channel = 0;
13  int HEPEVT_struct::decay_idx = 0;
14 
15  void HEPEVT_struct::clear()
16  {
17 
18  m_particle_list.clear();
19 
20  hep.nevhep = 0;
21  hep.nhep = 0;
22 
23 
43  }
44 
45  void HEPEVT_struct::add_particle(int i, PhotosParticle* particle,
46  int first_mother, int last_mother,
47  int first_daughter, int last_daughter)
48  {
49 
50  if (i > 0)
51  i--; //account for fortran indicies begining at 1
52  else
53  Log::Warning() << "Index given to HEPEVT_struct::add_particle "
54  << "is too low (it must be > 0)." << endl;
55 
56  //add to our internal list of pointer/index pairs
57  m_particle_list.push_back(particle);
58 
59  //now set the element of HEPEVT struct
60  hep.nevhep = 0; //dummy
61  hep.nhep = hep.nhep + 1; // 1.II.2014: fix for gcc 4.8.1. Previously it was:
62  // hep.nhep = hep.nhep++; which technically is an undefined operation
63  hep.isthep[i] = particle->getStatus();
64  hep.idhep[i] = particle->getPdgID();
65 
66  hep.jmohep[i][0] = first_mother;
67  hep.jmohep[i][1] = last_mother;
68 
69  hep.jdahep[i][0] = first_daughter;
70  hep.jdahep[i][1] = last_daughter;
71 
72  hep.phep[i][0] = particle->getPx();
73  hep.phep[i][1] = particle->getPy();
74  hep.phep[i][2] = particle->getPz();
75  hep.phep[i][3] = particle->getE();
76 
77  // if massFrom4Vector=true (default) - get sqrt(e^2-p^2)
78  // otherwise - get mass from event record
79  if (!Photos::massFrom4Vector) hep.phep[i][4] = particle->getMass();
80  else hep.phep[i][4] = particle->getVirtuality();
81 
82  int pdgid = abs(particle->getPdgID());
83 
84  // if 'forceMass' for this PDGID was used - overwrite mass
85  if (Photos::forceMassList) {
86  for (unsigned int j = 0; j < Photos::forceMassList->size(); j++) {
87  if (pdgid == abs(Photos::forceMassList->at(j)->first)) {
88  double mass = Photos::forceMassList->at(j)->second;
89 
90  // when 'forceMass' is used the mass provided is larger than 0.0
91  // when 'forceMassFromEventRecord' is used mass is -1.0
92  // in this case - get mass from event record
93  if (mass < 0.0) mass = particle->getMass();
94  hep.phep[i][4] = mass;
95  }
96  }
97  }
98 
99  hep.vhep[i][0] = 0;
100  hep.vhep[i][1] = 0;
101  hep.vhep[i][2] = 0;
102  hep.vhep[i][3] = 0;
103 
104  hep.qedrad[i] = 1;
105 
106  }
107 
108  int HEPEVT_struct::set(PhotosBranch* branch)
109  {
110  HEPEVT_struct::clear();
111  int idx = 1;
112 
113  //get mothers
114  vector<PhotosParticle*> mothers = branch->getMothers();
115  int nmothers = mothers.size();
116 
117  //check if mid-particle exist
118  decay_idx = 0;
119  PhotosParticle* decay_particle = branch->getDecayingParticle();
120  if (decay_particle) decay_idx = nmothers + 1;
121 
122  //get daughters
123  vector<PhotosParticle*> daughters = branch->getDaughters();
124  int ndaughters = daughters.size();
125 
126  for (int i = 0; i < nmothers; i++) {
127  if (decay_idx)
128  add_particle(idx++, mothers.at(i),
129  0, 0, //mothers
130  decay_idx, decay_idx); //daughters
131  else
132  add_particle(idx++, mothers.at(i),
133  0, 0, //mothers
134  nmothers + 1, nmothers + ndaughters); //daughters
135  }
136 
137  if (decay_particle)
138  add_particle(idx++, decay_particle,
139  1, nmothers, //mothers
140  nmothers + 2, nmothers + 1 + ndaughters); //daughters
141 
142  for (int i = 0; i < ndaughters; i++) {
143  if (decay_idx)
144  add_particle(idx++, daughters.at(i),
145  decay_idx, decay_idx, //mothers
146  0, 0); //daughters
147  else
148  add_particle(idx++, daughters.at(i),
149  1, nmothers, //mothers
150  0, 0); //daughters
151  }
152  //Log::RedirectOutput( phodmp_ , Log::Debug(1000) );
153  Log::Debug(1000, false) << "HEPEVT_struct returning: " << ((decay_idx) ? decay_idx : 1) << " from " << idx - 1 << " particles." <<
154  endl;
155  return (decay_idx) ? decay_idx : 1;
156  }
157 
158  void HEPEVT_struct::get()
159  {
160 
161  int index = 0;
162 
163  //if no new particles have been added to the event record, do nothing.
164  if (hep.nhep == (int) m_particle_list.size())
165  return;
166 
167  //phodmp_();
168 
169  // Index of first new particle is the size of original particle count
170  int first_new = (int) m_particle_list.size();
171 
172  int particle_count = m_particle_list.size();
173  int daughters_start = hep.jmohep[first_new][0];
174  int new_particles = hep.nhep - m_particle_list.size();
175  bool isParticleCreated = (new_particles > 0);
176 
177  std::vector<PhotosParticle*> new_particles_list; // list of added particles
178  // which need kinematical treatment
179  // in special case
180 
181  // we decipher daughters_start from first entry
182  // that is first daughter in ph_hepevt_
183  // we used to decipher it from last daughter
184  // but this caused issues if cascade decay has been generated
185  // another option of this functionality may be
186  // hep.jdahep[ hep.jmohep[hep.nhep-1][0]-1][0];
187  // Update daughters_start if there are two mothers
188  // NOTE: daughters_start is index for C++ arrays, while hep.jmohep
189  // contains indices for Fortran arrays.
190  if (hep.jmohep[first_new][1] > 0)
191  daughters_start = hep.jmohep[first_new][1];
192 
193  index = particle_count;
194 
195  // Add new particles
196  for (; new_particles > 0; new_particles--, index++) {
197 
198  // 27.11.2014: This sanity check is no longer useful (or needed)
199  // We now allow photos to produce particles other than gamma
200  //if(hep.idhep[index]!=PhotosParticle::GAMMA)
201  // Log::Fatal("HEPEVT_struct::get(): Extra particle added to the HEPEVT struct in not a photon!",6);
202 
203  //create a new particle
204  PhotosParticle* new_particle;
205  new_particle = m_particle_list.at(0)->createNewParticle(hep.idhep[index],
206  hep.isthep[index],
207  hep.phep[index][4],
208  hep.phep[index][0],
209  hep.phep[index][1],
210  hep.phep[index][2],
211  hep.phep[index][3]);
212 
213  //add into the event record
214  //get mother particle of new particle
215  PhotosParticle* mother = m_particle_list.at(hep.jmohep[index][0] - 1);
216  mother->addDaughter(new_particle);
217 
218  //add to list of new_particles
219  new_particles_list.push_back(new_particle);
220 
221  //add to list of existing particles - needed in cascade decay generation
222  //where next particles can reference this one as its mother
223  m_particle_list.push_back(new_particle);
224  }
225 
226  // Before we update particles, we check for special cases
227  // At this step, particles are yet unmodified
228  // but new particles are already in the event record
229  bool special = false;
230  PhotosParticle* p1 = NULL;
231  PhotosParticle* p2 = NULL;
232 
233  if (isParticleCreated) {
234  std::vector<PhotosParticle*> daughters;
235 
236  // in the following we create list of daughters,
237  // later we calculate bool special which is true only if all
238  // daughters self-decay
239  // at peresent warning for mixed self-decay and not self decay
240  // daughters is not printed.
241 
242  for (int i = daughters_start; i < particle_count; i++) {
243  PhotosParticle* p = m_particle_list.at(i);
244 
245  daughters.push_back(p);
246  }
247 
248  // Check if this is a special case
249  special = true;
250 
251  if (daughters.size() == 0) special = false;
252 
253  // special = false if there is a stable particle on the list
254  // or there is a particle without self-decay
255  for (unsigned int i = 0; i < daughters.size(); i++) {
256  if (daughters[i]->getStatus() == 1) {
257  special = false;
258  break;
259  }
260 
261  // NOTE: We can use 'getDaughters' here, because vertices
262  // of daughters are not being modified by Photos right now
263  // (so there will be no caching)
264  std::vector<PhotosParticle*> daughters2 = daughters[i]->getDaughters();
265 
266  if (daughters2.size() != 1 ||
267  daughters2[0]->getPdgID() != daughters[i]->getPdgID()) {
268  special = false;
269  break;
270  }
271  }
272 
273  if (special) {
274  double px1 = 0.0, py1 = 0.0, pz1 = 0.0, e1 = 0.0;
275  double px2 = 0.0, py2 = 0.0, pz2 = 0.0, e2 = 0.0;
276 
277  // get sum of 4-momenta of unmodified particles
278  // 27.11.2014: range changed. Now it does not depend on added particles
279  for (int i = 0; i < particle_count - daughters_start; i++) {
280  px1 += daughters[i]->getPx();
281  py1 += daughters[i]->getPy();
282  pz1 += daughters[i]->getPz();
283  e1 += daughters[i]->getE();
284  }
285 
286  // get sum of 4-momenta of particles in self-decay vertices
287  // 27.11.2014: range changed. Now it does not depend on added particles
288  for (int i = 0; i < particle_count - daughters_start; i++) {
289  // since 'allDaughtersSelfDecay()' is true
290  // each of these particles has exactly one daughter
291  px2 += daughters[i]->getDaughters().at(0)->getPx();
292  py2 += daughters[i]->getDaughters().at(0)->getPy();
293  pz2 += daughters[i]->getDaughters().at(0)->getPz();
294  e2 += daughters[i]->getDaughters().at(0)->getE();
295  }
296 
297  //cout<<"ORIG: "<<px1<<" "<<py1<<" "<<pz1<<" "<<e1<<endl;
298  //cout<<"SELF: "<<px2<<" "<<py2<<" "<<pz2<<" "<<e2<<endl;
299 
300  p1 = m_particle_list.at(0)->createNewParticle(0, -1, 0.0, px1, py1, pz1, e1);
301  p2 = m_particle_list.at(0)->createNewParticle(0, -2, 0.0, px2, py2, pz2, e2);
302 
303  // Finally, boost new particles to appropriate frame
304  for (unsigned int i = 0; i < new_particles_list.size(); i++) {
305  PhotosParticle* boosted = new_particles_list[i]->createNewParticle(22, 1,
306  0.0,
307  new_particles_list[i]->getPx(),
308  new_particles_list[i]->getPy(),
309  new_particles_list[i]->getPz(),
310  new_particles_list[i]->getE());
311 
312  boosted->boostToRestFrame(p1);
313  boosted->boostFromRestFrame(p2);
314 
315  new_particles_list[i]->createSelfDecayVertex(boosted);
316 
317  delete boosted;
318  }
319 
320  Log::Warning() << "Hidden interaction, all daughters self decay."
321  << "Potentially over simplified solution applied." << endl;
322  }
323  }
324 
325  //otherwise loop over particles which are already in the
326  //event record and modify their 4 momentum
327  //4.03.2012: Fix to prevent kinematical trap in vertex of simultaneous:
328  // z-collinear and non-conservation pf E,p for dauthters of grandmothers
329  for (index = daughters_start; index < particle_count && index < (int) m_particle_list.size(); index++) {
330 
331  PhotosParticle* particle = m_particle_list.at(index);
332 
333  if (hep.idhep[index] != particle->getPdgID())
334  Log::Fatal("HEPEVT_struct::get(): Something is wrong with the HEPEVT struct", 5);
335 
336  // If new particles were added - for each daughter create a history entry
337  if (isParticleCreated && Photos::isCreateHistoryEntries) {
338  particle->createHistoryEntry();
339  }
340 
341  //check to see if this particle's 4-momentum has been modified
342  bool update = false;
343 
344  // don't update particle if difference lower than THRESHOLD * particle energy (default threshold = 10e-8)
345  double threshold = NO_BOOST_THRESHOLD * hep.phep[index][3];
346  if (fabs(hep.phep[index][0] - particle->getPx()) > threshold ||
347  fabs(hep.phep[index][1] - particle->getPy()) > threshold ||
348  fabs(hep.phep[index][2] - particle->getPz()) > threshold ||
349  fabs(hep.phep[index][3] - particle->getE()) > threshold) update = true;
350 
351  if (update) {
352 
353  //modify this particle's momentum and it's daughters momentum
354  //Steps 1., 2. and 3. must be executed in order.
355 
356  //1. boost the particles daughters into it's (old) rest frame
357  particle->boostDaughtersToRestFrame(particle);
358 
359  //2. change this particles 4 momentum
360  particle->setPx(hep.phep[index][0]);
361  particle->setPy(hep.phep[index][1]);
362  particle->setPz(hep.phep[index][2]);
363  particle->setE(hep.phep[index][3]);
364 
365  //3. boost the particles daughters back into the lab frame
366  particle->boostDaughtersFromRestFrame(particle);
367 
368  if (special && particle->getDaughters().size() > 0) {
369 
370  // Algorithm for special case:
371  // a. get self-daughter of 'particle'
372  PhotosParticle* particled = particle->getDaughters().at(0);
373 
374  // b. boost 'particled' daughters to rest frame
375  particled->boostDaughtersToRestFrame(particled);
376 
377  // c. copy four momentum of 'particle' into four momentum of
378  // its self-daughter 'particled'
379 
380  particled->setPx(particle->getPx());
381  particled->setPy(particle->getPy());
382  particled->setPz(particle->getPz());
383  particled->setE(particle->getE());
384 
385  // d. boost self daughter to rest-frame of <e1>
386  // boost self daughter from rest-frame of <e2>
387 
388  particled->boostToRestFrame(p1);
389  particled->boostFromRestFrame(p2);
390 
391  // e. boost the 'particled' daughters back into the lab frame
392  particled->boostDaughtersFromRestFrame(particled);
393  }
394 
395  }
396  }
397 
398  // cleanup
399  if (p1) delete p1;
400  if (p2) delete p2;
401  }
402 
403  void HEPEVT_struct::prepare()
404  {
405  check_ME_channel();
406  }
407 
408  void HEPEVT_struct::complete()
409  {
410 
411  }
412 
413  void HEPEVT_struct::check_ME_channel()
414  {
415  ME_channel = 0;
416 
417 // Check mothers:
418 
419  if (decay_idx == 2) return; // Only one mother present
420  if (hep.idhep[0]*hep.idhep[1] > 0) return; // Mothers have same sign
421 
422  Log::Debug(900) << "ME_channel: Mothers PDG: " << hep.idhep[0] << " " << hep.idhep[1] << endl;
423  if (decay_idx)
424  Log::Debug(900, false) << " Intermediate: " << hep.idhep[decay_idx - 1] << endl;
425 
426  int firstDaughter = 3;
427  if (decay_idx == 0) firstDaughter = 2; // if no intermediate particle - daughters start at idx 2
428 
429  // Are mothers in range +/- 1-6; +/- 11-16?
430  int mother1 = abs(hep.idhep[0]);
431  int mother2 = abs(hep.idhep[1]);
432  if (mother1 < 1 || (mother1 > 6 && mother1 < 11) || mother1 > 16) return;
433  if (mother2 < 1 || (mother2 > 6 && mother2 < 11) || mother2 > 16) return;
434 
435 //Check daughters
436 
437  // Z: check for pairs 11 -11 ; 13 -13 ; 15 -15
438  // -------------------------------------------
439  int firstPDG = 0;
440  int secondPDG = 0;
441  for (int i = firstDaughter; i < hep.nhep; i++) {
442  int pdg = abs(hep.idhep[i]);
443  if (pdg == 11 || pdg == 13 || pdg == 15) {
444  if (firstPDG == 0) firstPDG = hep.idhep[i];
445  else {
446  secondPDG = hep.idhep[i];
447  // Just in case two pairs are genereted - verify that we have a pair with oposite signs
448  if (firstPDG * secondPDG > 0) secondPDG = 0;
449  break;
450  }
451  }
452  }
453 
454  if (ME_channel == 0 && firstPDG != 0 && secondPDG != 0 &&
455  firstPDG == -secondPDG) ME_channel = 1;
456 
457  // W: check for pairs 11 -12; -11 12; 13 -14; -13 14; 15 -16; -15 16
458  // -----------------------------------------------------------------
459  firstPDG = 0;
460  secondPDG = 0;
461  for (int i = firstDaughter; i < hep.nhep; i++) {
462  int pdg = abs(hep.idhep[i]);
463  if (pdg >= 11 && pdg <= 16) {
464  if (firstPDG == 0) firstPDG = hep.idhep[i];
465  else {
466  secondPDG = hep.idhep[i];
467  // Just in case two pairs are genereted - verify that we have a pair with oposite signs
468  if (firstPDG * secondPDG > 0) secondPDG = 0;
469  break;
470  }
471  }
472  }
473 
474  firstPDG = abs(firstPDG);
475  secondPDG = abs(secondPDG);
476 
477  if (ME_channel == 0 && firstPDG != 0 && secondPDG != 0 &&
478  ((firstPDG == 11 && secondPDG == 12) || (firstPDG == 12 && secondPDG == 11) ||
479  (firstPDG == 13 && secondPDG == 14) || (firstPDG == 14 && secondPDG == 13) ||
480  (firstPDG == 15 && secondPDG == 16) || (firstPDG == 16 && secondPDG == 15)
481  )
482  ) ME_channel = 2;
483 
484  Log::Debug(901) << "ME_channel: Found ME_channel: " << ME_channel << endl;
485 
486 // Check intermediate particle (if exists):
487 
488  // Verify that intermediate particle PDG matches ME_channel found
489  if (ME_channel > 0 && decay_idx) {
490  int pdg = hep.idhep[decay_idx - 1];
491 
492  if (ME_channel == 1 && !(pdg == 22 || pdg == 23)) ME_channel = 0; //gamma/Z
493  if (ME_channel == 2 && !(pdg == 24 || pdg == -24)) ME_channel = 0; //W+/W-
494 
495  if (ME_channel == 0)
496  Log::Debug(901, false) << " but set to 0: wrong intermediate particle: " << pdg << endl;
497  }
498 
499 // Check flags
500 
501  switch (ME_channel) {
502  case 0: break; // Ok - no channel found
503  case 1: if (!Photos::meCorrectionWtForZ) ME_channel = 0; break;
504  case 2: if (!Photos::meCorrectionWtForW) ME_channel = 0; break;
505  default: Log::Error() << "Unimplemented ME channel: " << ME_channel << endl; break;
506  }
507  Log::Debug(902) << "ME_channel: Finally, after flag check, ME_channel is: " << ME_channel << endl;
508  }
509 
510 
511 } // namespace Photospp
PhotosParticle * getDecayingParticle()
Return decaying particle.
Definition: PhotosBranch.h:28
vector< PhotosParticle * > getMothers()
Get list of mothers.
Definition: PhotosBranch.h:31
vector< PhotosParticle * > getDaughters()
Get list of daughters.
Definition: PhotosBranch.h:34
virtual void setE(double e)=0
Set the energy component of the four vector.
void boostToRestFrame(PhotosParticle *boost)
Transform this particles four momentum from the lab frome into the rest frame of the paramter PhotosP...
virtual void setPy(double py)=0
Set the px component of the four vector.
virtual void setPx(double px)=0
Set the px component of the four vector.
virtual void setPz(double pz)=0
Set the pz component of the four vector.
virtual PhotosParticle * createNewParticle(int pdg_id, int status, double mass, double px, double py, double pz, double e)=0
Create a new particle of the same type, with the given properties.
void boostDaughtersFromRestFrame(PhotosParticle *boost)
Transform this particles four momentum from the lab frame to the rest frame of the parameter PhotosPa...
void boostFromRestFrame(PhotosParticle *boost)
Transform this particles four momentum from the rest frame of the paramter PhotosParticle,...
void boostDaughtersToRestFrame(PhotosParticle *boost)
Transform the four momentum of all the daughters recursively into the frame of the "particle" PhotosP...