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) 2018 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(Info* infoPtrIn, Settings* settingsPtrIn,
23  Rndm* rndmPtrIn, BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn){
24 
25  // Store input pointers for future use.
26  infoPtr = infoPtrIn;
27  settingsPtr = settingsPtrIn;
28  rndmPtr = rndmPtrIn;
29  beamAPtr = beamAPtrIn;
30  beamBPtr = beamBPtrIn;
31 
32  // Rejection based on theta only when beams set in CM frame.
33  bool rejectTheta = settingsPtr->mode("Beams:frameType") == 1;
34 
35  // Save the applied cuts.
36  Q2maxGamma = settingsPtr->parm("Photon:Q2max");
37  Wmin = settingsPtr->parm("Photon:Wmin");
38  Wmax = settingsPtr->parm("Photon:Wmax");
39  theta1Max = rejectTheta ? settingsPtr->parm("Photon:thetaAMax") : -1.0;
40  theta2Max = rejectTheta ? settingsPtr->parm("Photon:thetaBMax") : -1.0;
41 
42  // Initial choice for the process type and whether to use external flux.
43  gammaMode = settingsPtr->mode("Photon:ProcessType");
44  externalFlux = settingsPtr->mode("PDF:lepton2gammaSet") == 2;
45 
46  // Flag from virtuality sampling.
47  sampleQ2 = settingsPtr->flag("Photon:sampleQ2");
48 
49  // Check if photons from both beams or only from one beam.
50  hasGammaA = beamAPtr->isLepton();
51  hasGammaB = beamBPtr->isLepton();
52 
53  // Get the masses and collision energy and derive useful ratios.
54  eCM = infoPtr->eCM();
55  sCM = pow2( eCM);
56  m2BeamA = pow2( beamAPtr->m() );
57  m2BeamB = pow2( beamBPtr->m() );
58  sHatNew = 0.;
59 
60  // Calculate the CM-energies of incoming beams.
61  eCM2A = 0.25 * pow2( sCM + m2BeamA - m2BeamB ) / sCM;
62  eCM2B = 0.25 * pow2( sCM - m2BeamA + m2BeamB ) / sCM;
63 
64  // Derive ratios used often.
65  m2eA = m2BeamA / eCM2A;
66  m2eB = m2BeamB / eCM2B;
67 
68  // Derive the kinematic limits.
69  xGammaMax1 = 2. * ( 1. - 0.25 * Q2maxGamma / eCM2A - m2eA)
70  / ( 1. + sqrt((1. + 4. * m2BeamA / Q2maxGamma) * (1. - m2eA)) );
71  xGammaMax2 = 2. * ( 1. - 0.25 * Q2maxGamma / eCM2B - m2eB)
72  / ( 1. + sqrt((1. + 4. * m2BeamB / Q2maxGamma) * (1. - m2eB)) );
73 
74  // No limits for xGamma if Q2-integrated flux.
75  if (!sampleQ2) {
76  xGammaMax1 = 1.;
77  xGammaMax2 = 1.;
78  }
79 
80  // If Wmax below Wmin (negative by default) use the total invariant mass.
81  if ( Wmax < Wmin ) Wmax = eCM;
82 
83  // Done.
84  return true;
85 }
86 
87 //--------------------------------------------------------------------------
88 
89 // Sample kinematics of one or two photon beams from the original beams.
90 
91 bool GammaKinematics::sampleKTgamma(bool nonDiff){
92 
93  // Get the sampled x_gamma values from beams.
94  xGamma1 = beamAPtr->xGamma();
95  xGamma2 = beamBPtr->xGamma();
96 
97  // Type of current process.
98  gammaMode = infoPtr->photonMode();
99 
100  // Reject already sampled x_gamma values outside kinematic bounds.
101  if ( hasGammaA && (!externalFlux || ( externalFlux
102  && (gammaMode == 3 || gammaMode == 4) ) ) && (xGamma1 > xGammaMax1) )
103  return false;
104  if ( hasGammaB && (!externalFlux || ( externalFlux
105  && (gammaMode == 2 || gammaMode == 4) ) ) && (xGamma2 > xGammaMax2) )
106  return false;
107 
108  // Sample virtuality for photon A.
109  if ( hasGammaA ) {
110 
111  // Sample the x_gamma value if needed and check that value is valid.
112  if ( externalFlux && (gammaMode == 1 || gammaMode == 2) ) {
113  double xMinA = nonDiff ? -1. : beamAPtr->xGammaHadr();
114  xGamma1 = beamAPtr->sampleXgamma(xMinA);
115  if ( xGamma1 > xGammaMax1 ) return false;
116  }
117 
118  // Derive the accurate lower Q2 limit and sample value.
119  Q2min1 = 2. * m2BeamA * pow2(xGamma1) / ( 1. - xGamma1 - m2eA
120  + sqrt(1. - m2eA) * sqrt( pow2(1. - xGamma1) - m2eA ) );
121 
122  // Sample the Q2 if requested, otherwise pick use the maximum value.
123  if (sampleQ2) Q2gamma1 = beamAPtr->sampleQ2gamma(Q2min1);
124  else Q2gamma1 = 0.;
125 
126  // Reject sampled values outside limits (relevant for external flux).
127  if ( sampleQ2 && (Q2gamma1 < Q2min1) ) return false;
128  }
129 
130  // Sample virtuality for photon B.
131  if ( hasGammaB ) {
132 
133  // Sample the x_gamma value if needed and check that value is valid.
134  if ( externalFlux && (gammaMode == 1 || gammaMode == 3) ) {
135  double xMinB = nonDiff ? -1. : beamBPtr->xGammaHadr();
136  xGamma2 = beamBPtr->sampleXgamma(xMinB);
137  if ( xGamma2 > xGammaMax2 ) return false;
138  }
139 
140  // Derive the accurate lower Q2 limit and sample value.
141  Q2min2 = 2. * m2BeamB * pow2(xGamma2) / ( 1. - xGamma2 - m2eB
142  + sqrt(1. - m2eB) * sqrt( pow2(1. - xGamma2) - m2eB ) );
143 
144  // Sample the Q2 if requested, otherwise pick use the maximum value.
145  if (sampleQ2) Q2gamma2 = beamBPtr->sampleQ2gamma(Q2min2);
146  else Q2gamma2 = 0.;
147 
148  // Reject sampled values outside limits (relevant for external flux).
149  if ( sampleQ2 && (Q2gamma2 < Q2min2) ) return false;
150  }
151 
152  // Derive the full photon momenta from the sampled values.
153  if ( hasGammaA) {
154  if ( !deriveKin(xGamma1, Q2gamma1, m2BeamA, eCM2A) ) return false;
155  kT1 = kT;
156  kz1 = kz;
157  phi1 = phi;
158  theta1 = theta;
159 
160  // Reject kinematics if a scattering angle above cut.
161  if ( theta1Max > 0 && ( theta1 > theta1Max ) ) return false;
162  }
163  if ( hasGammaB) {
164  if ( !deriveKin(xGamma2, Q2gamma2, m2BeamB, eCM2B) ) return false;
165  kT2 = kT;
166  kz2 = kz;
167  phi2 = phi;
168  theta2 = theta;
169 
170  // Reject kinematics if a scattering angle above cut.
171  if ( theta2Max > 0 && ( theta2 > theta2Max ) ) return false;
172  }
173 
174  // Invariant mass of photon-photon system.
175  if ( hasGammaA && hasGammaB) {
176 
177  // Derive the invariant mass and check the kinematic limits.
178  double cosPhi12 = cos(phi1 - phi2);
179  m2GmGm = 2. * sqrt(eCM2A * eCM2B) * xGamma1 * xGamma2 - Q2gamma1 - Q2gamma2
180  + 2. * kz1 * kz2 - 2. * kT1 * kT2 * cosPhi12;
181 
182  // Check if derived value within bounds set by user.
183  if ( ( m2GmGm < pow2(Wmin) ) || ( m2GmGm > pow2(Wmax) ) ) return false;
184 
185  // Calculate invariant mass now that the square is positive.
186  mGmGm = sqrt(m2GmGm);
187 
188  return true;
189 
190  // Invariant mass of photon-hadron system.
191  } else if (hasGammaA || hasGammaB) {
192 
193  // Derive the invariant mass and check the limits.
194  // Solve the longitudinal momentum of beam particles in CM frame.
195  double pz2 = ( pow2(sCM - m2BeamA - m2BeamB) - 4. * m2BeamA * m2BeamB )
196  * 0.25 / sCM;
197  double pz = sqrtpos( pz2);
198 
199  // Pick the correct beam mass and photon kinematics.
200  double m2Beam = hasGammaA ? m2BeamB : m2BeamA;
201  double xGamma = hasGammaA ? xGamma1 : xGamma2;
202  double Q2gamma = hasGammaA ? Q2gamma1 : Q2gamma2;
203 
204  // Calculate the invariant mass of the photon-hadron pair and check limits.
205  m2GmGm = m2Beam - Q2gamma + 2. * ( xGamma * sqrt(eCM2A) * sqrt(eCM2B)
206  + kz * pz );
207  if ( ( m2GmGm < pow2(Wmin) ) || ( m2GmGm > pow2(Wmax) ) ) return false;
208  mGmGm = sqrt(m2GmGm);
209 
210  return true;
211  }
212 
213  else return false;
214 
215 }
216 
217 //--------------------------------------------------------------------------
218 
219 // Sample the Q2 values and phi angles for each beam and derive kT according
220 // to sampled x_gamma. Check that sampled values within required limits.
221 
222 bool GammaKinematics::deriveKin(double xGamma, double Q2gamma,
223  double m2Beam, double eCM2) {
224 
225  // Sample azimuthal angle from flat [0,2*pi[.
226  phi = 2. * M_PI * rndmPtr->flat();
227 
228  // Calculate kT^2 for photon from particle with non-zero mass.
229  double kT2gamma = ( ( 1. - xGamma - 0.25 * Q2gamma / eCM2 ) * Q2gamma
230  - m2Beam * ( Q2gamma / eCM2 + pow2(xGamma) ) ) / (1.- m2Beam / eCM2);
231 
232  // If no virtuality sampled set transverse momentum to zero.
233  if ( !sampleQ2 ) kT2gamma = 0.;
234 
235  // Check that physical values for kT (very rarely fails if ever but may
236  // cause numerical issues).
237  if ( kT2gamma < 0. ) {
238  infoPtr->errorMsg("Error in gammaKinematics::sampleKTgamma: "
239  "unphysical kT value.");
240  return false;
241  }
242 
243  // Calculate the transverse and longitudinal momenta and scattering angle
244  // of the beam particle.
245  kT = sqrt( kT2gamma );
246  theta = atan( sqrt( eCM2 * ( Q2gamma * ( 1. - xGamma )
247  - m2Beam * pow2(xGamma) ) - m2Beam * Q2gamma - pow2( 0.5 * Q2gamma) )
248  / ( eCM2 * ( 1. - xGamma) - m2Beam - 0.5 * Q2gamma ) );
249  kz = (xGamma * eCM2 + 0.5 * Q2gamma) / ( sqrt(eCM2 - m2Beam) );
250 
251  // Done.
252  return true;
253 }
254 
255 //--------------------------------------------------------------------------
256 
257 // Calculates the new sHat for direct-direct and direct-resolved processes.
258 
259 double GammaKinematics::calcNewSHat(double sHatOld){
260 
261  // Need to recalculate only if two photons.
262  if ( hasGammaA && hasGammaB) {
263 
264  // Calculate the new sHat for direct-resolved system.
265  gammaMode = infoPtr->photonMode();
266  if (gammaMode == 4) sHatNew = m2GmGm;
267  else if (gammaMode == 2 || gammaMode == 3)
268  sHatNew = sHatOld * m2GmGm / ( xGamma1 * xGamma2 * sCM);
269  }
270 
271  // Otherwise no need for a new value.
272  else sHatNew = sHatOld;
273 
274  return sHatNew;
275 }
276 
277 //--------------------------------------------------------------------------
278 
279 // Calculate weight from oversampling with approximated flux.
280 
281 double GammaKinematics::fluxWeight() {
282 
283  // Initially unit weight.
284  double wt = 1.;
285 
286  // Calculate the weight according to accurate flux.
287  if ( sampleQ2) {
288  if (hasGammaA) wt *= beamAPtr->xfFlux(22, xGamma1, Q2gamma1) /
289  beamAPtr->xfApprox(22, xGamma1, Q2gamma1);
290  if (hasGammaB) wt *= beamBPtr->xfFlux(22, xGamma2, Q2gamma2) /
291  beamBPtr->xfApprox(22, xGamma2, Q2gamma2);
292 
293  // When no sampling of virtuality use the Q2-integrated flux.
294  } else {
295  if (hasGammaA) wt *= beamAPtr->xfFlux(22, xGamma1, Q2gamma1) /
296  beamAPtr->xf(22, xGamma1, Q2gamma1);
297  if (hasGammaB) wt *= beamBPtr->xfFlux(22, xGamma2, Q2gamma2) /
298  beamBPtr->xf(22, xGamma2, Q2gamma2);
299  }
300 
301  // Done.
302  return wt;
303 }
304 
305 //--------------------------------------------------------------------------
306 
307 // Save the accepted values for further use.
308 
309 bool GammaKinematics::finalize(){
310 
311  // Propagate the sampled values for beam particles.
312  beamAPtr->newGammaKTPhi(kT1, phi1);
313  beamBPtr->newGammaKTPhi(kT2, phi2);
314  beamAPtr->Q2Gamma(Q2gamma1);
315  beamBPtr->Q2Gamma(Q2gamma2);
316 
317  // Set the sampled values also to Info object.
318  infoPtr->setQ2Gamma1(Q2gamma1);
319  infoPtr->setQ2Gamma2(Q2gamma2);
320  infoPtr->setX1Gamma(xGamma1);
321  infoPtr->setX2Gamma(xGamma2);
322 
323  // Keep old mGmGm for 2->1 processes with direct photons.
324  if ( (infoPtr->nFinal() > 1) || (gammaMode != 4)) {
325  infoPtr->setTheta1(theta1);
326  infoPtr->setTheta2(theta2);
327  infoPtr->setECMsub(mGmGm);
328  infoPtr->setsHatNew(sHatNew);
329  }
330 
331  // Done.
332  return true;
333 }
334 
335 //==========================================================================
336 
337 } // end namespace Pythia8