Belle II Software  release-08-01-10
BBBrem.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <generators/bbbrem/BBBrem.h>
10 #include <framework/logging/Logger.h>
11 #include <framework/gearbox/Const.h>
12 #include <mdst/dataobjects/MCParticleGraph.h>
13 
14 #include <TRandom3.h>
15 //#include <cmath>
16 
17 using namespace std;
18 using namespace Belle2;
19 
20 
21 void BBBrem::init(double cmsEnergy, double minPhotonEFrac, bool unweighted, double maxWeight, int densitymode,
22  double densityparameter)
23 {
24  m_cmsEnergy = cmsEnergy;
25  m_photonEFrac = minPhotonEFrac;
26 
27  m_unweighted = unweighted;
28  m_maxWeight = maxWeight;
29  m_densityCorrectionMode = densitymode;
30  m_densityCorrectionParameter = densityparameter;
31 
32  m_maxWeightDelivered = 0.0;
33  m_sumWeightDelivered = 0.0;
34  m_sumWeightDeliveredSqr = 0.0;
35  m_weightCount = 0;
36 
37  if ((minPhotonEFrac <= 0.0) || (minPhotonEFrac >= 1.0)) {
38  B2ERROR("BBBrem: The minimum photon energy fraction has to be in the range ]0,1[ !");
39  return;
40  }
41 
42  B2DEBUG(100, "BBBrem: Center of mass energy: " << cmsEnergy);
43  B2DEBUG(100, "BBBrem: Minimum photon energy: " << minPhotonEFrac << " * beam energy");
44 
45  //Initialize the constants (in order to be consistent with the FORTRAN source code)
46  alpha = Const::fineStrConst;
47  rme = Const::electronMass;
48 
49  //Initialize the derived constants
50  s = cmsEnergy * cmsEnergy;
51  rme2 = rme * rme;
52  rme2s = rme2 / s;
53  rls = -log(rme2s);
54  z0 = minPhotonEFrac / (1.0 - minPhotonEFrac);
55 
56  //Approximate total cross section
57  a1 = log((1.0 + z0) / z0);
58 // a2 = (log(1.0 + z0)) / z0;
59 // Expression 'log(1 + x)' is replaced by 'log1p(x)' to avoid loss of precision.
60  a2 = (log1p(z0)) / z0;
61  ac = a1 / (a1 + a2);
62  sigapp = 8.0 * (alpha * alpha * alpha) / rme2 * (-log(rme2s)) * (a1 + a2) * tomb;
63  B2DEBUG(100, "BBBrem: Approximate cross section: " << sigapp << " millibarn");
64 
65  //Initial-state momenta
66  eb = 0.5 * cmsEnergy;
67  pb = sqrt(eb * eb - rme2);
68  rin2pb = 0.5 / pb;
69  p1[0] = 0.0;
70  p1[1] = 0.0;
71  p1[2] = -pb;
72  p1[3] = eb;
73  q1[0] = 0.0;
74  q1[1] = 0.0;
75  q1[2] = pb;
76  q1[3] = eb;
77 }
78 
79 
80 double BBBrem::generateEvent(MCParticleGraph& mcGraph, ROOT::Math::XYZVector vertex, ROOT::Math::LorentzRotation boost)
81 {
82 
83  if (m_unweighted) {
84  double ran = 0.0;
85  do {
86  calcOutgoingLeptonsAndWeight();
87  if (weight > m_maxWeightDelivered) m_maxWeightDelivered = weight;
88  if (weight > m_maxWeight) {
89  B2INFO("BBBrem: OVERWEIGHT, w=" << weight << ", nw=" << m_weightCountOver << ", sumw=" << m_sumWeightDeliveredOver);
90  m_weightCountOver++;
91  m_sumWeightDeliveredOver = m_sumWeightDeliveredOver + (weight - m_maxWeight);
92  m_sumWeightDeliveredSqrOver = m_sumWeightDeliveredSqrOver + (weight - m_maxWeight) * (weight - m_maxWeight);
93  }
94  m_weightCount++;
95  m_sumWeightDelivered += weight;
96  m_sumWeightDeliveredSqr += weight * weight;
97 
98  ran = gRandom->Uniform();
99  } while (weight <= ran * m_maxWeight);
100  } else {
101  calcOutgoingLeptonsAndWeight();
102  if (weight > m_maxWeightDelivered) m_maxWeightDelivered = weight;
103  m_weightCount++;
104  m_sumWeightDelivered += weight;
105  m_sumWeightDeliveredSqr += weight * weight;
106  }
107 
108  //Store the incoming particles as virtual particles, the outgoing particles as real particles
109  storeParticle(mcGraph, p1, 11, vertex, boost, false, true);
110  storeParticle(mcGraph, q1, -11, vertex, boost, false, true);
111 
112  // BBBrem emits gammma only from electron(p1)
113  // To emit gamma from positron we need to swap electron and positron here
114  bool swapflag = (gRandom->Uniform() > 0.5) ? true : false;
115  if (swapflag) {
116  double tmp[4];
117  for (int i = 0; i < 4; i++) tmp[i] = p2[i];
118  for (int i = 0; i < 4; i++) p2[i] = q2[i];
119  for (int i = 0; i < 4; i++) q2[i] = tmp[i];
120  p2[2] = -p2[2];
121  q2[2] = -q2[2];
122  qk[2] = -qk[2];
123  }
124 
125  //Store the outgoing particles as real particles
126  storeParticle(mcGraph, p2, 11, vertex, boost, false, false);
127  storeParticle(mcGraph, q2, -11, vertex, boost, false, false);
128  storeParticle(mcGraph, qk, 22, vertex, boost, false, false);
129 
130  if (!m_unweighted) return weight;
131  return 1.0;
132 }
133 
134 
135 void BBBrem::term()
136 {
137  if (m_weightCount > 0.0) {
138  m_crossSection = m_sumWeightDelivered / m_weightCount;
139  m_crossSectionError = sqrt(m_sumWeightDeliveredSqr - m_sumWeightDelivered * m_sumWeightDelivered / m_weightCount) /
140  m_weightCount;
141 
142  if (m_unweighted) {
143  m_crossSectionOver = m_sumWeightDeliveredOver / m_weightCount;
144  m_crossSectionErrorOver = sqrt(abs(((m_sumWeightDeliveredSqrOver) / m_weightCount - m_crossSectionOver * m_crossSectionOver) /
145  m_weightCount));
146  }
147  }
148 }
149 
150 
151 //=========================================================================
152 // Protected methods
153 //=========================================================================
154 
155 void BBBrem::calcOutgoingLeptonsAndWeight()
156 {
157  //Generate z
158  double z;
159  if (gRandom->Uniform() < ac) {
160  double temp1 = gRandom->Uniform();
161 // z = 1.0 / (temp1 * (exp(a1 * gRandom->Uniform()) - 1.0));
162 // Expression 'exp(x) - 1' is replaced by 'expm1(x)' to avoid loss of precision.
163  z = 1.0 / (temp1 * (expm1(a1 * gRandom->Uniform())));
164  } else {
165  z = z0 / gRandom->Uniform();
166  }
167 
168  //Bounds on t
169  double y = rme2s * z;
170  double q0 = eb * y;
171  double temp1 = pb * pb - eb * q0;
172  double temp2 = temp1 * temp1 - rme2 - q0 * q0;
173 
174  //If temp2<0 (very very rare): set weight to 0
175  if (temp2 < 0.0) {
176  B2WARNING("BBBrem: y too large: delta_t^2 = " << temp2 << " !!!");
177  weight = 0.0;
178  } else {
179  double tmin = -2.0 * (temp1 + sqrt(temp2));
180  double tmax = rme2 * s * y * y / tmin;
181 
182  //Generate t
183  double sy = s * y;
184  double w2 = sy + rme2;
185  temp1 = sy + tmax;
186  double rlamx = sqrt(temp1 * temp1 - 4.0 * w2 * tmax);
187 
188  if (temp1 <= 0.0) {
189  temp1 = rlamx - temp1;
190  } else {
191  temp1 = -4.0 * w2 * tmax / (rlamx + temp1);
192  }
193 
194  double t = 0.0;
195  do {
196  double b;
197 // b = exp(gRandom->Uniform() * log(1.0 + 2.0 * sy / temp1));
198 // Expression 'log(1 + x)' is replaced by 'log1p(x)' to avoid loss of precision.
199  b = exp(gRandom->Uniform() * log1p(2.0 * sy / temp1));
200  t = -b * z * z * rme2 / ((b - 1) * (b * z + b - 1));
201  } while (t <= tmin);
202 
203  //Generate cgam
204  double rlam = sqrt((sy - t) * (sy - t) - 4 * rme2 * t);
205  double eps = 4 * rme2 * w2 / (rlam * (rlam + w2 + rme2 - t));
206  double rl = log((2 + eps) / eps);
207 // double vgam = eps * (exp(gRandom->Uniform() * rl) - 1.0);
208 // Expression 'exp(x) - 1' is replaced by 'expm1(x)' to avoid loss of precision.
209  double vgam = eps * (expm1(gRandom->Uniform() * rl));
210  double cgam = 1.0 - vgam;
211  double sgam = sqrt(vgam * (2 - vgam));
212 
213  //Generate azimuthal angles
214  double phi = twopi * gRandom->Uniform();
215  double phig = twopi * gRandom->Uniform();
216 
217  //Construct momentum transfer q(mu)
218  double ql = (2.0 * eb * q0 - t) * rin2pb;
219  double qt = sqrt((tmax - t) * (t - tmin)) * rin2pb;
220  double q[4];
221  q[0] = qt * sin(phi);
222  q[1] = qt * cos(phi);
223  q[2] = ql;
224  q[3] = q0;
225 
226  //Construct momentum of outgoing positron in lab frame
227  q2[0] = q1[0] - q[0];
228  q2[1] = q1[1] - q[1];
229  q2[2] = q1[2] - q[2];
230  q2[3] = q1[3] - q[3];
231 
232  //Find euler angles of p1(mu) in cm frame
233  double r0 = eb + q0;
234  double w = sqrt(w2);
235  double rin2w = 0.5 / w;
236  double rinr0w = 1.0 / (r0 + w);
237  double eta = -(sy + 2 * w * q0 + t) * rin2w * rinr0w;
238  double phat1 = -q[0] * (1 + eta);
239  double phat2 = -q[1] * (1 + eta);
240  double phat3 = pb * eta - ql * (1 + eta);
241  double phatl = rlam * rin2w;
242  double phatt = sqrt(phat1 * phat1 + phat2 * phat2);
243  double sfhat = phat1 / phatt;
244  double cfhat = phat2 / phatt;
245  double sthat = phatt / phatl;
246  double vthat;
247  if (phat3 > 0.0) {
248  vthat = sthat * sthat / (1 - sqrt(1 - sthat * sthat));
249  } else {
250  vthat = sthat * sthat / (1 + sqrt(1 - sthat * sthat));
251  }
252  double cthat = vthat - 1.0;
253 
254  //Rotate using these euler angles to get the qk direction in the cm
255  double sfg = sin(phig);
256  double cfg = cos(phig);
257  temp1 = sgam * sfg;
258  temp2 = cthat * sgam * cfg + sthat * cgam;
259  double veg = vthat + vgam - vthat * vgam - sthat * sgam * cfg;
260  double qkhat[4];
261  qkhat[3] = sy * rin2w;
262  qkhat[0] = qkhat[3] * (cfhat * temp1 + sfhat * temp2);
263  qkhat[1] = qkhat[3] * (-sfhat * temp1 + cfhat * temp2);
264  qkhat[2] = qkhat[3] * (veg - 1.0);
265 
266  //Boost the photon momentum to the lab frame
267  temp1 = pb * qkhat[2];
268  if (temp1 > 0.0) {
269  temp2 = (rme2 * qkhat[3] * qkhat[3] + pb * pb * (qkhat[0] * qkhat[0] + qkhat[1] * qkhat[1])) / (eb * qkhat[3] + temp1);
270  } else {
271  temp2 = eb * qkhat[3] - temp1;
272  }
273 
274  qk[3] = (temp2 + qkhat[3] * q[3] + qkhat[0] * q[0] + qkhat[1] * q[1] + qkhat[2] * q[2]) / w;
275  temp1 = (qk[3] + qkhat[3]) * rinr0w;
276  qk[0] = qkhat[0] + temp1 * q[0];
277  qk[1] = qkhat[1] + temp1 * q[1];
278  qk[2] = qkhat[2] + temp1 * (-pb + ql);
279 
280  //Construct p2 by momentum conservation
281  p2[0] = -q2[0] - qk[0];
282  p2[1] = -q2[1] - qk[1];
283  p2[2] = -q2[2] - qk[2];
284  p2[3] = -q2[3] - qk[3] + m_cmsEnergy;
285 
286  //Impose cut on the photon energy: qk[3]>eb*rk0
287  if (qk[3] < eb * m_photonEFrac) {
288  weight = 0.0;
289  } else {
290  //The event is now accepted: compute matrix element and weight
291  //Compute fudge factor c1
292 // double c1 = log(1 + z) / log((2 + eps) / eps);
293 // Expression 'log(1 + x)' is replaced by 'log1p(x)' to avoid loss of precision.
294  double c1 = log1p(z) / log((2.0 + eps) / eps);
295 
296  //Compute fudge factor c2
297  temp1 = sy - tmax;
298  double vnumx = sqrt(temp1 * temp1 - 4.0 * rme2 * tmax) + temp1;
299  temp1 = sy + tmax;
300 
301  double vdenx;
302  if (temp1 < 0.0) {
303  vdenx = sqrt(temp1 * temp1 - 4.0 * w2 * tmax) - temp1;
304  } else {
305  vdenx = -4.0 * w2 * tmax / (sqrt(temp1 * temp1 - 4.0 * w2 * tmax) + temp1);
306  }
307  temp1 = sy - tmin;
308  double vnumn = sqrt(temp1 * temp1 - 4.0 * rme2 * tmin) + temp1;
309  temp1 = sy + tmin;
310 
311  double vdenn;
312  if (temp1 < 0.0) {
313  vdenn = sqrt(temp1 * temp1 - 4.0 * w2 * tmin) - temp1;
314  } else {
315  vdenn = -4.0 * w2 * tmin / (sqrt(temp1 * temp1 - 4.0 * w2 * tmin) + temp1);
316  }
317  double c2 = 2.0 * rls / log((vnumx * vdenn) / (vdenx * vnumn));
318 
319  //Compute vector (small) r in cm frame, and (big) z
320  double rlabl = (t - 2.0 * rme2 * y) * rin2pb;
321  double rhat4 = -(2.0 * rme2 * y + (1 - y) * t) * rin2w;
322  double etar = rhat4 * rinr0w;
323  double rhat1 = -q[0] * (1 + etar);
324  double rhat2 = -q[1] * (1 + etar);
325  double rhat3 = rlabl + (pb - ql) * etar;
326  double zz = s * (rhat4 * qkhat[3] - rhat1 * qkhat[0] - rhat2 * qkhat[1] - rhat3 * qkhat[2]);
327 
328  //The other invariants
329  double s1 = 4.0 * eb * (eb - qk[3]);
330  double d1 = sy * rlam * (eps + vgam) * rin2w * rin2w;
331  double d2 = 0.5 * sy;
332 
333  //The exact matrix element
334  //Kleiss-burkhardt cross section multiplied by t^2
335  double rind1 = 1.0 / d1;
336  double rind12 = rind1 * rind1;
337  double rind2 = 1.0 / d2;
338  double rind22 = rind2 * rind2;
339  temp1 = s + t - 2 * d2;
340  temp2 = s1 + t + 2 * d1;
341  double aa0 = (s * s + s1 * s1 + temp1 * temp1 + temp2 * temp2) * rind1 * rind2 * (-t);
342  double aa1 = -4.0 * rme2 * zz * zz * rind12 * rind22;
343  double aa2 = -8.0 * rme2 * (d1 * d1 + d2 * d2) * rind1 * rind2;
344  double aa3 = 16.0 * rme2 * rme2 * (d1 - d2) * zz * rind12 * rind22;
345  double aa4 = -16.0 * rme2 * rme2 * rme2 * (d1 - d2) * (d1 - d2) * rind12 * rind22;
346  double rmex = aa0 + aa1 + aa2 + aa3 + aa4;
347 
348  //The approximate matrix element without c1,2, multiplied by t^2
349  double rmap = 4.0 * s * s * rind1 * rind2 * (-t) * c1 * c2;
350 
351  //The weight
352  weight = rmex / rmap * sigapp;
353 
354  //Isnan check (not sure if this is ok)
355  if (std::isnan(weight)) {
356  B2WARNING("BBBrem: Weight is nan! Setting the weight to zero.");
357  weight = 0.0;
358  }
359 
360 
361  //========================================================
362  // beam size effect (or density effect)
363  // ref: arxiv:hep-ph/9401333
364 
365  // tc = (hbarc/simga_y)^2
366 // double tc = 1.68e-17; //SuperKEKB LER (sigma_y*=48nm)
367  //double tc = 9.81e-18; //SuperKEKB HER (sigma_y*=63nm)
368  double tc = m_densityCorrectionParameter;
369 // int cutflag = 0 ; // 0: no cut, 1: hard cut, 2: soft cut
370  if (m_densityCorrectionMode == 1) {
371  if (abs(t) < tc) weight = 0.0;
372  } else if (m_densityCorrectionMode == 2) {
373  if (t != tc) weight *= t * t / (t - tc) / (t - tc); // t<0<tc, always t!=tc
374  }
375  //========================================================
376 
377  }
378  }
379 }
380 
381 
382 void BBBrem::storeParticle(MCParticleGraph& mcGraph, const double* mom, int pdg, ROOT::Math::XYZVector vertex,
383  ROOT::Math::LorentzRotation boost,
384  bool isVirtual, bool isInitial)
385 {
386 
387  // RG 6/25/14 Add new flag for ISR "c_Initial"
389  if (isVirtual) {
390  part.setStatus(MCParticle::c_IsVirtual);
391  } else if (isInitial) {
392  part.setStatus(MCParticle::c_Initial);
393  }
394 
395  //all particles from a generator are primary
396  part.addStatus(MCParticle::c_PrimaryParticle);
397 
398  //all non virtual photons from BBBREM are ISR or FSR
399  if (pdg == 22 && !isVirtual) {
400  part.addStatus(MCParticle::c_IsISRPhoton);
401  part.addStatus(MCParticle::c_IsFSRPhoton);
402  }
403 
404  part.setPDG(pdg);
405  part.setFirstDaughter(0);
406  part.setLastDaughter(0);
407  part.setMomentum(ROOT::Math::XYZVector(mom[0], mom[1],
408  -mom[2])); //Switch direction, because electrons fly into the +z direction at Belle II
409  part.setEnergy(mom[3]);
410  part.setMassFromPDG();
411 // part.setDecayVertex(0.0, 0.0, 0.0);
412 
413  //set the production vertex of non initial particles
414  if (!isInitial) {
415  ROOT::Math::XYZVector v3 = part.getProductionVertex();
416  v3 = v3 + vertex;
417  part.setProductionVertex(v3);
418  part.setValidVertex(true);
419  }
420 
421  //If boosting is enable boost the particles to the lab frame
422  ROOT::Math::PxPyPzEVector p4 = part.get4Vector();
423  p4 = boost * p4;
424  part.set4Vector(p4);
425 }
Class to represent Particle data in graph.
Class to build, validate and sort a particle decay chain.
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
GraphParticle & addParticle()
Add new particle to the graph.
Abstract base class for different kinds of events.