StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
GammaKinematics.cc
1 // GammaKinematics.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2020 Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
4 // Please respect the MCnet Guidelines, see GUIDELINES for details.
5 
6 // Function definitions (not found in the header) for the GammaKinematics
7 // class.
8 
9 #include "Pythia8/GammaKinematics.h"
10 
11 namespace Pythia8 {
12 
13 //==========================================================================
14 
15 // The GammaKinematics class.
16 // Generates the kinematics of emitted photons according to phase space limits.
17 
18 //--------------------------------------------------------------------------
19 
20 // Initialize phase space limits.
21 
22 bool GammaKinematics::init() {
23 
24  // Rejection based on theta only when beams set in CM frame.
25  bool rejectTheta = mode("Beams:frameType") == 1;
26 
27  // Save the applied cuts.
28  Q2maxGamma = parm("Photon:Q2max");
29  Wmin = parm("Photon:Wmin");
30  Wmax = parm("Photon:Wmax");
31  theta1Max = rejectTheta ? parm("Photon:thetaAMax") : -1.0;
32  theta2Max = rejectTheta ? parm("Photon:thetaBMax") : -1.0;
33 
34  // Initial choice for the process type and whether to use over-estimated
35  // flux for sampling.
36  gammaMode = mode("Photon:ProcessType");
37  hasApproxFluxA = beamAPtr->hasApproxGammaFlux();
38  hasApproxFluxB = beamBPtr->hasApproxGammaFlux();
39 
40  // Flag from virtuality sampling.
41  sampleQ2 = flag("Photon:sampleQ2");
42 
43  // Check if photons from both beams or only from one beam.
44  hasGammaA = flag("PDF:beamA2gamma");
45  hasGammaB = flag("PDF:beamB2gamma");
46 
47  // Get the masses and collision energy and derive useful ratios.
48  eCM = infoPtr->eCM();
49  sCM = pow2( eCM);
50  m2BeamA = pow2( beamAPtr->m() );
51  m2BeamB = pow2( beamBPtr->m() );
52  sHatNew = 0.;
53 
54  // Id of the beam if not a photon inside the beam.
55  subInA = (beamAPtr->isGamma() || hasGammaA) ? 22 : beamAPtr->id();
56  subInB = (beamBPtr->isGamma() || hasGammaB) ? 22 : beamBPtr->id();
57 
58  // Calculate the CM-energies of incoming beams.
59  eCM2A = 0.25 * pow2( sCM + m2BeamA - m2BeamB ) / sCM;
60  eCM2B = 0.25 * pow2( sCM - m2BeamA + m2BeamB ) / sCM;
61 
62  // Derive ratios used often.
63  m2eA = m2BeamA / eCM2A;
64  m2eB = m2BeamB / eCM2B;
65 
66  // Derive the kinematic limits.
67  xGammaMax1 = 2. * ( 1. - 0.25 * Q2maxGamma / eCM2A - m2eA)
68  / ( 1. + sqrt((1. + 4. * m2BeamA / Q2maxGamma) * (1. - m2eA)) );
69  xGammaMax2 = 2. * ( 1. - 0.25 * Q2maxGamma / eCM2B - m2eB)
70  / ( 1. + sqrt((1. + 4. * m2BeamB / Q2maxGamma) * (1. - m2eB)) );
71 
72  // No limits for xGamma if Q2-integrated flux.
73  if (!sampleQ2) {
74  xGammaMax1 = 1.;
75  xGammaMax2 = 1.;
76  }
77 
78  // If Wmax below Wmin (negative by default) use the total invariant mass.
79  if ( Wmax < Wmin ) Wmax = eCM;
80 
81  // Done.
82  return true;
83 }
84 
85 //--------------------------------------------------------------------------
86 
87 // Sample kinematics of one or two photon beams from the original beams.
88 
89 bool GammaKinematics::sampleKTgamma(bool nonDiff) {
90 
91  // Get the sampled x_gamma values from beams.
92  xGamma1 = beamAPtr->xGamma();
93  xGamma2 = beamBPtr->xGamma();
94 
95  // Type of current process.
96  gammaMode = infoPtr->photonMode();
97 
98  // Reject already sampled x_gamma values outside kinematic bounds.
99  if ( hasGammaA && (!hasApproxFluxA || ( hasApproxFluxA
100  && (gammaMode == 3 || gammaMode == 4) ) ) && (xGamma1 > xGammaMax1) )
101  return false;
102  if ( hasGammaB && (!hasApproxFluxB || ( hasApproxFluxB
103  && (gammaMode == 2 || gammaMode == 4) ) ) && (xGamma2 > xGammaMax2) )
104  return false;
105 
106  // Sample virtuality for photon A.
107  if ( hasGammaA ) {
108 
109  // Sample the x_gamma value if needed and check that value is valid.
110  if ( hasApproxFluxA && (gammaMode == 1 || gammaMode == 2) ) {
111  double xMinA = nonDiff ? -1. : beamAPtr->xGammaHadr();
112  xGamma1 = beamAPtr->sampleXgamma(xMinA);
113  if ( xGamma1 > xGammaMax1 ) return false;
114  }
115 
116  // Derive the accurate lower Q2 limit and sample value.
117  Q2min1 = 2. * m2BeamA * pow2(xGamma1) / ( 1. - xGamma1 - m2eA
118  + sqrt(1. - m2eA) * sqrt( pow2(1. - xGamma1) - m2eA ) );
119 
120  // Sample the Q2 if requested, otherwise pick use the maximum value.
121  if (sampleQ2) Q2gamma1 = beamAPtr->sampleQ2gamma(Q2min1);
122  else Q2gamma1 = 0.;
123 
124  // Reject sampled values outside limits (relevant for external flux).
125  if ( sampleQ2 && (Q2gamma1 < Q2min1) ) return false;
126  }
127 
128  // Sample virtuality for photon B.
129  if ( hasGammaB ) {
130 
131  // Sample the x_gamma value if needed and check that value is valid.
132  if ( hasApproxFluxB && (gammaMode == 1 || gammaMode == 3) ) {
133  double xMinB = nonDiff ? -1. : beamBPtr->xGammaHadr();
134  xGamma2 = beamBPtr->sampleXgamma(xMinB);
135  if ( xGamma2 > xGammaMax2 ) return false;
136  }
137 
138  // Derive the accurate lower Q2 limit and sample value.
139  Q2min2 = 2. * m2BeamB * pow2(xGamma2) / ( 1. - xGamma2 - m2eB
140  + sqrt(1. - m2eB) * sqrt( pow2(1. - xGamma2) - m2eB ) );
141 
142  // Sample the Q2 if requested, otherwise pick use the maximum value.
143  if (sampleQ2) Q2gamma2 = beamBPtr->sampleQ2gamma(Q2min2);
144  else Q2gamma2 = 0.;
145 
146  // Reject sampled values outside limits (relevant for external flux).
147  if ( sampleQ2 && (Q2gamma2 < Q2min2) ) return false;
148  }
149 
150  // Derive the full photon momenta from the sampled values.
151  if ( hasGammaA) {
152  if ( !deriveKin(xGamma1, Q2gamma1, m2BeamA, eCM2A) ) return false;
153  kT1 = kT;
154  kz1 = kz;
155  phi1 = phi;
156  theta1 = theta;
157 
158  // Reject kinematics if a scattering angle above cut.
159  if ( theta1Max > 0 && ( theta1 > theta1Max ) ) return false;
160  }
161  if ( hasGammaB) {
162  if ( !deriveKin(xGamma2, Q2gamma2, m2BeamB, eCM2B) ) return false;
163  kT2 = kT;
164  kz2 = kz;
165  phi2 = phi;
166  theta2 = theta;
167 
168  // Reject kinematics if a scattering angle above cut.
169  if ( theta2Max > 0 && ( theta2 > theta2Max ) ) return false;
170  }
171 
172  // Invariant mass of photon-photon system.
173  if ( hasGammaA && hasGammaB) {
174 
175  // Derive the invariant mass and check the kinematic limits.
176  double cosPhi12 = cos(phi1 - phi2);
177  m2GmGm = 2. * sqrt(eCM2A * eCM2B) * xGamma1 * xGamma2 - Q2gamma1 - Q2gamma2
178  + 2. * kz1 * kz2 - 2. * kT1 * kT2 * cosPhi12;
179 
180  // Check if derived value within bounds set by user.
181  if ( ( m2GmGm < pow2(Wmin) ) || ( m2GmGm > pow2(Wmax) ) ) return false;
182 
183  // Calculate invariant mass now that the square is positive.
184  mGmGm = sqrt(m2GmGm);
185 
186  return true;
187 
188  // Invariant mass of photon-hadron system.
189  } else if (hasGammaA || hasGammaB) {
190 
191  // Derive the invariant mass and check the limits.
192  // Solve the longitudinal momentum of beam particles in CM frame.
193  double pz2 = ( pow2(sCM - m2BeamA - m2BeamB) - 4. * m2BeamA * m2BeamB )
194  * 0.25 / sCM;
195  double pz = sqrtpos( pz2);
196 
197  // Pick the correct beam mass and photon kinematics.
198  double m2Beam = hasGammaA ? m2BeamB : m2BeamA;
199  double xGamma = hasGammaA ? xGamma1 : xGamma2;
200  double Q2gamma = hasGammaA ? Q2gamma1 : Q2gamma2;
201 
202  // Calculate the invariant mass of the photon-hadron pair and check limits.
203  m2GmGm = m2Beam - Q2gamma + 2. * ( xGamma * sqrt(eCM2A) * sqrt(eCM2B)
204  + kz * pz );
205  if ( ( m2GmGm < pow2(Wmin) ) || ( m2GmGm > pow2(Wmax) ) ) return false;
206  mGmGm = sqrt(m2GmGm);
207 
208  return true;
209  }
210 
211  else return false;
212 
213 }
214 
215 //--------------------------------------------------------------------------
216 
217 // Sample the Q2 values and phi angles for each beam and derive kT according
218 // to sampled x_gamma. Check that sampled values within required limits.
219 
220 bool GammaKinematics::deriveKin(double xGamma, double Q2gamma,
221  double m2Beam, double eCM2) {
222 
223  // Sample azimuthal angle from flat [0,2*pi[.
224  phi = 2. * M_PI * rndmPtr->flat();
225 
226  // Calculate kT^2 for photon from particle with non-zero mass.
227  double kT2gamma = ( ( 1. - xGamma - 0.25 * Q2gamma / eCM2 ) * Q2gamma
228  - m2Beam * ( Q2gamma / eCM2 + pow2(xGamma) ) ) / (1.- m2Beam / eCM2);
229 
230  // If no virtuality sampled set transverse momentum to zero.
231  if ( !sampleQ2 ) kT2gamma = 0.;
232 
233  // Check that physical values for kT (very rarely fails if ever but may
234  // cause numerical issues).
235  if ( kT2gamma < 0. ) {
236  infoPtr->errorMsg("Error in gammaKinematics::sampleKTgamma: "
237  "unphysical kT value.");
238  return false;
239  }
240 
241  // Calculate the transverse and longitudinal momenta and scattering angle
242  // of the beam particle.
243  kT = sqrt( kT2gamma );
244  theta = atan( sqrt( eCM2 * ( Q2gamma * ( 1. - xGamma )
245  - m2Beam * pow2(xGamma) ) - m2Beam * Q2gamma - pow2( 0.5 * Q2gamma) )
246  / ( eCM2 * ( 1. - xGamma) - m2Beam - 0.5 * Q2gamma ) );
247  kz = (xGamma * eCM2 + 0.5 * Q2gamma) / ( sqrt(eCM2 - m2Beam) );
248 
249  // Done.
250  return true;
251 }
252 
253 //--------------------------------------------------------------------------
254 
255 // Calculates the new sHat for direct-direct and direct-resolved processes.
256 
257 double GammaKinematics::calcNewSHat(double sHatOld){
258 
259  // Need to recalculate only if two photons.
260  if ( hasGammaA && hasGammaB) {
261 
262  // Calculate the new sHat for direct-resolved system.
263  gammaMode = infoPtr->photonMode();
264  if (gammaMode == 4) {
265  sHatNew = m2GmGm;
266  sHatScaled = true;
267  } else if (gammaMode == 2 || gammaMode == 3) {
268  sHatNew = sHatOld * m2GmGm / ( xGamma1 * xGamma2 * sCM);
269  sHatScaled = true;
270  } else {
271  sHatNew = sHatOld;
272  sHatScaled = false;
273  }
274 
275  // Otherwise no need for a new value.
276  } else {
277  sHatNew = sHatOld;
278  sHatScaled = false;
279  }
280 
281  return sHatNew;
282 }
283 
284 //--------------------------------------------------------------------------
285 
286 // Calculate weight from oversampling with approximated flux.
287 
288 double GammaKinematics::fluxWeight() {
289 
290  // Initially unit weight.
291  double wtFlux = 1.;
292 
293  // Calculate the weight according to accurate flux.
294  if ( sampleQ2) {
295  if (hasGammaA && hasApproxFluxA)
296  wtFlux *= beamAPtr->xfFlux(22, xGamma1, Q2gamma1)
297  / beamAPtr->xfApprox(22, xGamma1, Q2gamma1);
298  if (hasGammaB && hasApproxFluxB)
299  wtFlux *= beamBPtr->xfFlux(22, xGamma2, Q2gamma2)
300  / beamBPtr->xfApprox(22, xGamma2, Q2gamma2);
301 
302  // When no sampling of virtuality use the Q2-integrated flux.
303  } else {
304  if (hasGammaA && hasApproxFluxA)
305  wtFlux *= beamAPtr->xfFlux(22, xGamma1, Q2gamma1)
306  / beamAPtr->xf(22, xGamma1, Q2gamma1);
307  if (hasGammaB && hasApproxFluxB)
308  wtFlux *= beamBPtr->xfFlux(22, xGamma2, Q2gamma2)
309  / beamBPtr->xf(22, xGamma2, Q2gamma2);
310  }
311 
312  // Done.
313  return wtFlux;
314 }
315 
316 //--------------------------------------------------------------------------
317 
318 // Save the accepted values for further use.
319 
320 bool GammaKinematics::finalize(){
321 
322  // Propagate the sampled values for beam particles.
323  beamAPtr->newGammaKTPhi(kT1, phi1);
324  beamBPtr->newGammaKTPhi(kT2, phi2);
325  beamAPtr->Q2Gamma(Q2gamma1);
326  beamBPtr->Q2Gamma(Q2gamma2);
327 
328  // Set the sampled values also to Info object.
329  infoPtr->setQ2Gamma1(Q2gamma1);
330  infoPtr->setQ2Gamma2(Q2gamma2);
331  infoPtr->setX1Gamma(xGamma1);
332  infoPtr->setX2Gamma(xGamma2);
333 
334  // Keep old mGmGm for 2->1 processes with direct photons.
335  if ( (infoPtr->nFinal() > 1) || (gammaMode != 4)) {
336  infoPtr->setTheta1(theta1);
337  infoPtr->setTheta2(theta2);
338  infoPtr->setECMsub(mGmGm);
339  infoPtr->setsHatNew(sHatNew);
340  }
341 
342  // Done.
343  return true;
344 }
345 
346 //--------------------------------------------------------------------------
347 
348 // Set up phase-space sampling for soft events.
349 
350 double GammaKinematics::setupSoftPhaseSpaceSampling(double sigmaMax) {
351 
352  // Classification, constant and initial value.
353  sigmaEstimate = sigmaMax;
354  alphaEM = coupSMPtr->alphaEM(Q2maxGamma);
355  gammaA = beamAPtr->isGamma() || hasGammaA;
356  gammaB = beamBPtr->isGamma() || hasGammaB;
357 
358  // Get the masses of beam particles and derive useful ratios.
359  double m2sA = 4. * m2BeamA / sCM;
360  double m2sB = 4. * m2BeamB / sCM;
361 
362  // Calculate the square of the minimum invariant mass for sampling.
363  double m2GmGmMin = pow2(Wmin);
364  double xGamAMax = 1.;
365  double xGamBMax = 1.;
366  double xGamAMin = m2GmGmMin / sCM ;
367  double xGamBMin = m2GmGmMin / sCM ;
368 
369  // Default values to be modified.
370  xGamma1 = 1.;
371  xGamma2 = 1.;
372  log2xMinA = 0.;
373  log2xMaxA = 0.;
374  log2xMinB = 0.;
375  log2xMaxB = 0.;
376 
377  // Calculate limit for x1 (if applicable) and derive useful logs.
378  if (gammaA) {
379  xGamAMax = 2. * ( 1. - 0.25 * Q2maxGamma / eCM2A - m2sA )
380  / ( 1. + sqrt( (1. + 4. * m2BeamA / Q2maxGamma) * (1. - m2sA) ) );
381  if ( !hasApproxFluxA) {
382  log2xMinA = pow2( log( Q2maxGamma/ ( m2BeamA * pow2(xGamAMin) ) ) );
383  log2xMaxA = pow2( log( Q2maxGamma/ ( m2BeamA * pow2(xGamAMax) ) ) );
384  }
385  }
386 
387  // Calculate limit for x2 (if applicable) and derive useful logs.
388  if (gammaB) {
389  xGamBMax = 2. * ( 1. - 0.25 * Q2maxGamma / eCM2B - m2sB )
390  / ( 1. + sqrt( (1. + 4. * m2BeamB / Q2maxGamma) * (1. - m2sB) ) );
391  if ( !hasApproxFluxB) {
392  log2xMinB = pow2( log( Q2maxGamma/ ( m2BeamB * pow2(xGamBMin) ) ) );
393  log2xMaxB = pow2( log( Q2maxGamma/ ( m2BeamB * pow2(xGamBMax) ) ) );
394  }
395  }
396 
397  // Derive the over-estimates either with accurate or approximated fluxes.
398  if (gammaA) {
399  if (hasApproxFluxA) sigmaEstimate *= beamAPtr->gammaFluxIntApprox();
400  else sigmaEstimate *= 0.5 * alphaEM / M_PI
401  * 0.5 * (log2xMinA - log2xMaxA);
402  }
403  if (gammaB) {
404  if (hasApproxFluxB) sigmaEstimate *= beamBPtr->gammaFluxIntApprox();
405  else sigmaEstimate *= 0.5 * alphaEM / M_PI
406  * 0.5 * (log2xMinB - log2xMaxB);
407  }
408 
409  // Return the estimate.
410  return sigmaEstimate;
411 }
412 
413 //--------------------------------------------------------------------------
414 
415 // Sample photon kinematics for soft events.
416 
417 bool GammaKinematics::trialKinSoftPhaseSpaceSampling(){
418 
419  // Current weight.
420  wt = 1.0;
421 
422  // Sample x_gamma's when using an accurate photon flux.
423  if ( !hasApproxFluxA) {
424  if (gammaA) xGamma1 = sqrt( (Q2maxGamma / m2BeamA) * exp( -sqrt(
425  log2xMinA + rndmPtr->flat() * (log2xMaxA - log2xMinA) ) ) );
426 
427  // Save the x_gamma values to beam particles for further use.
428  beamAPtr->xGamma(xGamma1);
429  }
430 
431  // Sample x_gamma's when using an accurate photon flux.
432  if ( !hasApproxFluxB) {
433  if (gammaB) xGamma2 = sqrt( (Q2maxGamma / m2BeamB) * exp( -sqrt(
434  log2xMinB + rndmPtr->flat() * (log2xMaxB - log2xMinB) ) ) );
435 
436  // Save the x_gamma values to beam particles for further use.
437  beamBPtr->xGamma(xGamma2);
438  }
439 
440  // Sample the kT of photons, special behaviour for non-diffractive events.
441  if ( !(sampleKTgamma(true)) ) return false;
442 
443  // Save the sampled x_gamma values with over-estimated fluxes.
444  if (hasApproxFluxA) xGamma1 = beamAPtr->xGamma();
445  if (hasApproxFluxB) xGamma2 = beamBPtr->xGamma();
446 
447  // Correct for x1 and x2 oversampling.
448  double wt1 = 1.;
449  double wt2 = 1.;
450 
451  // Calculate the weight for beam A from oversampling.
452  if ( gammaA) {
453  if ( !hasApproxFluxA ) {
454  wt1 = ( 0.5 * ( 1. + pow2(1 - xGamma1) ) ) * log( Q2maxGamma/Q2min1 )
455  / log( Q2maxGamma / ( m2BeamA * pow2( xGamma1 ) ) );
456 
457  // For external flux weight depends whether Q2 is sampled.
458  } else {
459  wt1 = sampleQ2 ? beamAPtr->xfFlux(22, xGamma1, Q2gamma1)
460  / beamAPtr->xfApprox(22, xGamma1, Q2gamma1)
461  : beamAPtr->xfFlux(22, xGamma1, Q2gamma1)
462  / beamAPtr->xf(22, xGamma1, Q2gamma1);
463  }
464  }
465 
466  // Calculate the weight for beam B from oversampling.
467  if ( gammaB) {
468  if ( !hasApproxFluxB ) {
469  wt2 = ( 0.5 * ( 1. + pow2(1 - xGamma2) ) ) * log( Q2maxGamma/Q2min2 )
470  / log( Q2maxGamma / ( m2BeamB * pow2( xGamma2 ) ) );
471 
472  // For external flux weight depends whether Q2 is sampled.
473  } else {
474  wt2 = sampleQ2 ? beamBPtr->xfFlux(22, xGamma2, Q2gamma2)
475  / beamBPtr->xfApprox(22, xGamma2, Q2gamma2)
476  : beamBPtr->xfFlux(22, xGamma2, Q2gamma2)
477  / beamBPtr->xf(22, xGamma2, Q2gamma2);
478  }
479  }
480 
481  // Correct for alpha_EM with the sampled Q2 values.
482  double wtAlphaEM1 = (gammaA && !hasApproxFluxA)
483  ? coupSMPtr->alphaEM(Q2gamma1) / alphaEM : 1.;
484  double wtAlphaEM2 = (gammaB && !hasApproxFluxB)
485  ? coupSMPtr->alphaEM(Q2gamma2) / alphaEM : 1.;
486  double wtAlphaEM = wtAlphaEM1 * wtAlphaEM2;
487 
488  // Combine weights.
489  wt = wt1 * wt2 * wtAlphaEM;
490 
491  return true;
492 }
493 
494 //==========================================================================
495 
496 } // end namespace Pythia8