Line data Source code
1 : // PartonDistributions.cc is a part of the PYTHIA event generator.
2 : // Copyright (C) 2015 Torbjorn Sjostrand.
3 : // PYTHIA is licenced under the GNU GPL version 2, 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 PDF, LHAPDF,
7 : // GRV94L, CTEQ5L, MSTWpdf, CTEQ6pdf, GRVpiL, PomFix, PomH1FitAB,
8 : // PomH1Jets, Lepton and NNPDF classes.
9 :
10 : #include "Pythia8/PartonDistributions.h"
11 :
12 : namespace Pythia8 {
13 :
14 : //==========================================================================
15 :
16 : // Base class for parton distribution functions.
17 :
18 : //--------------------------------------------------------------------------
19 :
20 : // Resolve valence content for assumed meson. Possibly modified later.
21 :
22 : void PDF::setValenceContent() {
23 :
24 : // Subdivide meson by flavour content.
25 0 : if (idBeamAbs < 100 || idBeamAbs > 1000) return;
26 0 : int idTmp1 = idBeamAbs/100;
27 0 : int idTmp2 = (idBeamAbs/10)%10;
28 :
29 : // Find which is quark and which antiquark.
30 0 : if (idTmp1%2 == 0) {
31 0 : idVal1 = idTmp1;
32 0 : idVal2 = -idTmp2;
33 0 : } else {
34 0 : idVal1 = idTmp2;
35 0 : idVal2 = -idTmp1;
36 : }
37 0 : if (idBeam < 0) {
38 0 : idVal1 = -idVal1;
39 0 : idVal2 = -idVal2;
40 0 : }
41 :
42 : // Special case for Pomeron, to start off.
43 0 : if (idBeamAbs == 990) {
44 0 : idVal1 = 1;
45 0 : idVal2 = -1;
46 0 : }
47 0 : }
48 :
49 : //--------------------------------------------------------------------------
50 :
51 : // Standard parton densities.
52 :
53 : double PDF::xf(int id, double x, double Q2) {
54 :
55 : // Need to update if flavour, x or Q2 changed.
56 : // Use idSav = 9 to indicate that ALL flavours are up-to-date.
57 : // Assume that flavour and antiflavour always updated simultaneously.
58 0 : if ( (abs(idSav) != abs(id) && idSav != 9) || x != xSav || Q2 != Q2Sav)
59 0 : {idSav = id; xfUpdate(id, x, Q2); xSav = x; Q2Sav = Q2;}
60 :
61 : // Baryon and nondiagonal meson beams: only p, pbar, pi+, pi- for now.
62 0 : if (idBeamAbs == 2212 || idBeamAbs == 211) {
63 0 : int idNow = (idBeam > 0) ? id : -id;
64 : int idAbs = abs(id);
65 0 : if (idNow == 0 || idAbs == 21) return max(0., xg);
66 0 : if (idNow == 1) return max(0., xd);
67 0 : if (idNow == -1) return max(0., xdbar);
68 0 : if (idNow == 2) return max(0., xu);
69 0 : if (idNow == -2) return max(0., xubar);
70 0 : if (idNow == 3) return max(0., xs);
71 0 : if (idNow == -3) return max(0., xsbar);
72 0 : if (idAbs == 4) return max(0., xc);
73 0 : if (idAbs == 5) return max(0., xb);
74 0 : if (idAbs == 22) return max(0., xgamma);
75 0 : return 0.;
76 :
77 : // Baryon beams: n and nbar by isospin conjugation of p and pbar.
78 0 : } else if (idBeamAbs == 2112) {
79 0 : int idNow = (idBeam > 0) ? id : -id;
80 : int idAbs = abs(id);
81 0 : if (idNow == 0 || idAbs == 21) return max(0., xg);
82 0 : if (idNow == 1) return max(0., xu);
83 0 : if (idNow == -1) return max(0., xubar);
84 0 : if (idNow == 2) return max(0., xd);
85 0 : if (idNow == -2) return max(0., xdbar);
86 0 : if (idNow == 3) return max(0., xs);
87 0 : if (idNow == -3) return max(0., xsbar);
88 0 : if (idAbs == 4) return max(0., xc);
89 0 : if (idAbs == 5) return max(0., xb);
90 0 : if (idAbs == 22) return max(0., xgamma);
91 0 : return 0.;
92 :
93 : // Diagonal meson beams: only pi0, Pomeron for now.
94 0 : } else if (idBeam == 111 || idBeam == 990) {
95 : int idAbs = abs(id);
96 0 : if (id == 0 || idAbs == 21) return max(0., xg);
97 0 : if (id == idVal1 || id == idVal2) return max(0., xu);
98 0 : if (idAbs <= 2) return max(0., xubar);
99 0 : if (idAbs == 3) return max(0., xs);
100 0 : if (idAbs == 4) return max(0., xc);
101 0 : if (idAbs == 5) return max(0., xb);
102 0 : if (idAbs == 22) return max(0., xgamma);
103 0 : return 0.;
104 :
105 :
106 : // Lepton beam.
107 : } else {
108 0 : if (id == idBeam ) return max(0., xlepton);
109 0 : if (abs(id) == 22) return max(0., xgamma);
110 0 : return 0.;
111 : }
112 :
113 0 : }
114 :
115 : //--------------------------------------------------------------------------
116 :
117 : // Only valence part of parton densities.
118 :
119 : double PDF::xfVal(int id, double x, double Q2) {
120 :
121 : // Need to update if flavour, x or Q2 changed.
122 : // Use idSav = 9 to indicate that ALL flavours are up-to-date.
123 : // Assume that flavour and antiflavour always updated simultaneously.
124 0 : if ( (abs(idSav) != abs(id) && idSav != 9) || x != xSav || Q2 != Q2Sav)
125 0 : {idSav = id; xfUpdate(id, x, Q2); xSav = x; Q2Sav = Q2;}
126 :
127 : // Baryon and nondiagonal meson beams: only p, pbar, n, nbar, pi+, pi-.
128 0 : if (idBeamAbs == 2212) {
129 0 : int idNow = (idBeam > 0) ? id : -id;
130 0 : if (idNow == 1) return max(0., xdVal);
131 0 : if (idNow == 2) return max(0., xuVal);
132 0 : return 0.;
133 0 : } else if (idBeamAbs == 2112) {
134 0 : int idNow = (idBeam > 0) ? id : -id;
135 0 : if (idNow == 1) return max(0., xuVal);
136 0 : if (idNow == 2) return max(0., xdVal);
137 0 : return 0.;
138 0 : } else if (idBeamAbs == 211) {
139 0 : int idNow = (idBeam > 0) ? id : -id;
140 0 : if (idNow == 2 || idNow == -1) return max(0., xuVal);
141 0 : return 0.;
142 :
143 : // Diagonal meson beams: only pi0, Pomeron for now.
144 0 : } else if (idBeam == 111 || idBeam == 990) {
145 0 : if (id == idVal1 || id == idVal2) return max(0., xuVal);
146 0 : return 0.;
147 :
148 : // Lepton beam.
149 : } else {
150 0 : if (id == idBeam) return max(0., xlepton);
151 0 : return 0.;
152 : }
153 :
154 0 : }
155 :
156 : //--------------------------------------------------------------------------
157 :
158 : // Only sea part of parton densities.
159 :
160 : double PDF::xfSea(int id, double x, double Q2) {
161 :
162 : // Need to update if flavour, x or Q2 changed.
163 : // Use idSav = 9 to indicate that ALL flavours are up-to-date.
164 : // Assume that flavour and antiflavour always updated simultaneously.
165 0 : if ( (abs(idSav) != abs(id) && idSav != 9) || x != xSav || Q2 != Q2Sav)
166 0 : {idSav = id; xfUpdate(id, x, Q2); xSav = x; Q2Sav = Q2;}
167 :
168 : // Hadron beams.
169 0 : if (idBeamAbs > 100) {
170 0 : int idNow = (idBeam > 0) ? id : -id;
171 : int idAbs = abs(id);
172 0 : if (idNow == 0 || idAbs == 21) return max(0., xg);
173 0 : if (idBeamAbs == 2212) {
174 0 : if (idNow == 1) return max(0., xdSea);
175 0 : if (idNow == -1) return max(0., xdbar);
176 0 : if (idNow == 2) return max(0., xuSea);
177 0 : if (idNow == -2) return max(0., xubar);
178 0 : } else if (idBeamAbs == 2112) {
179 0 : if (idNow == 1) return max(0., xuSea);
180 0 : if (idNow == -1) return max(0., xubar);
181 0 : if (idNow == 2) return max(0., xdSea);
182 0 : if (idNow == -2) return max(0., xdbar);
183 : } else {
184 0 : if (idAbs <= 2) return max(0., xuSea);
185 : }
186 0 : if (idNow == 3) return max(0., xs);
187 0 : if (idNow == -3) return max(0., xsbar);
188 0 : if (idAbs == 4) return max(0., xc);
189 0 : if (idAbs == 5) return max(0., xb);
190 0 : if (idAbs == 22) return max(0., xgamma);
191 0 : return 0.;
192 :
193 : // Lepton beam.
194 : } else {
195 0 : if (abs(id) == 22) return max(0., xgamma);
196 0 : return 0.;
197 : }
198 :
199 0 : }
200 :
201 : //==========================================================================
202 :
203 : // Gives the GRV 94 L (leading order) parton distribution function set
204 : // in parametrized form. Authors: M. Glueck, E. Reya and A. Vogt.
205 : // Ref: M. Glueck, E. Reya and A. Vogt, Z.Phys. C67 (1995) 433.
206 :
207 : void GRV94L::xfUpdate(int , double x, double Q2) {
208 :
209 : // Common expressions. Constrain Q2 for which parametrization is valid.
210 : double mu2 = 0.23;
211 : double lam2 = 0.2322 * 0.2322;
212 0 : double s = (Q2 > mu2) ? log( log(Q2/lam2) / log(mu2/lam2) ) : 0.;
213 0 : double ds = sqrt(s);
214 0 : double s2 = s * s;
215 0 : double s3 = s2 * s;
216 :
217 : // uv :
218 0 : double nu = 2.284 + 0.802 * s + 0.055 * s2;
219 0 : double aku = 0.590 - 0.024 * s;
220 0 : double bku = 0.131 + 0.063 * s;
221 0 : double au = -0.449 - 0.138 * s - 0.076 * s2;
222 0 : double bu = 0.213 + 2.669 * s - 0.728 * s2;
223 0 : double cu = 8.854 - 9.135 * s + 1.979 * s2;
224 0 : double du = 2.997 + 0.753 * s - 0.076 * s2;
225 0 : double uv = grvv (x, nu, aku, bku, au, bu, cu, du);
226 :
227 : // dv :
228 0 : double nd = 0.371 + 0.083 * s + 0.039 * s2;
229 : double akd = 0.376;
230 0 : double bkd = 0.486 + 0.062 * s;
231 0 : double ad = -0.509 + 3.310 * s - 1.248 * s2;
232 0 : double bd = 12.41 - 10.52 * s + 2.267 * s2;
233 0 : double cd = 6.373 - 6.208 * s + 1.418 * s2;
234 0 : double dd = 3.691 + 0.799 * s - 0.071 * s2;
235 0 : double dv = grvv (x, nd, akd, bkd, ad, bd, cd, dd);
236 :
237 : // udb :
238 : double alx = 1.451;
239 : double bex = 0.271;
240 0 : double akx = 0.410 - 0.232 * s;
241 0 : double bkx = 0.534 - 0.457 * s;
242 0 : double agx = 0.890 - 0.140 * s;
243 : double bgx = -0.981;
244 0 : double cx = 0.320 + 0.683 * s;
245 0 : double dx = 4.752 + 1.164 * s + 0.286 * s2;
246 0 : double ex = 4.119 + 1.713 * s;
247 0 : double esx = 0.682 + 2.978 * s;
248 0 : double udb = grvw (x, s, alx, bex, akx, bkx, agx, bgx, cx,
249 : dx, ex, esx);
250 :
251 : // del :
252 0 : double ne = 0.082 + 0.014 * s + 0.008 * s2;
253 0 : double ake = 0.409 - 0.005 * s;
254 0 : double bke = 0.799 + 0.071 * s;
255 0 : double ae = -38.07 + 36.13 * s - 0.656 * s2;
256 0 : double be = 90.31 - 74.15 * s + 7.645 * s2;
257 : double ce = 0.;
258 0 : double de = 7.486 + 1.217 * s - 0.159 * s2;
259 0 : double del = grvv (x, ne, ake, bke, ae, be, ce, de);
260 :
261 : // sb :
262 : double sts = 0.;
263 : double als = 0.914;
264 : double bes = 0.577;
265 0 : double aks = 1.798 - 0.596 * s;
266 0 : double as = -5.548 + 3.669 * ds - 0.616 * s;
267 0 : double bs = 18.92 - 16.73 * ds + 5.168 * s;
268 0 : double dst = 6.379 - 0.350 * s + 0.142 * s2;
269 0 : double est = 3.981 + 1.638 * s;
270 : double ess = 6.402;
271 0 : double sb = grvs (x, s, sts, als, bes, aks, as, bs, dst, est, ess);
272 :
273 : // cb :
274 : double stc = 0.888;
275 : double alc = 1.01;
276 : double bec = 0.37;
277 : double akc = 0.;
278 : double ac = 0.;
279 0 : double bc = 4.24 - 0.804 * s;
280 0 : double dct = 3.46 - 1.076 * s;
281 0 : double ect = 4.61 + 1.49 * s;
282 0 : double esc = 2.555 + 1.961 * s;
283 0 : double chm = grvs (x, s, stc, alc, bec, akc, ac, bc, dct, ect, esc);
284 :
285 : // bb :
286 : double stb = 1.351;
287 : double alb = 1.00;
288 : double beb = 0.51;
289 : double akb = 0.;
290 : double ab = 0.;
291 : double bb = 1.848;
292 0 : double dbt = 2.929 + 1.396 * s;
293 0 : double ebt = 4.71 + 1.514 * s;
294 0 : double esb = 4.02 + 1.239 * s;
295 0 : double bot = grvs (x, s, stb, alb, beb, akb, ab, bb, dbt, ebt, esb);
296 :
297 : // gl :
298 : double alg = 0.524;
299 : double beg = 1.088;
300 0 : double akg = 1.742 - 0.930 * s;
301 0 : double bkg = - 0.399 * s2;
302 0 : double ag = 7.486 - 2.185 * s;
303 0 : double bg = 16.69 - 22.74 * s + 5.779 * s2;
304 0 : double cg = -25.59 + 29.71 * s - 7.296 * s2;
305 0 : double dg = 2.792 + 2.215 * s + 0.422 * s2 - 0.104 * s3;
306 0 : double eg = 0.807 + 2.005 * s;
307 0 : double esg = 3.841 + 0.316 * s;
308 0 : double gl = grvw (x, s, alg, beg, akg, bkg, ag, bg, cg,
309 : dg, eg, esg);
310 :
311 : // Update values
312 0 : xg = gl;
313 0 : xu = uv + 0.5*(udb - del);
314 0 : xd = dv + 0.5*(udb + del);
315 0 : xubar = 0.5*(udb - del);
316 0 : xdbar = 0.5*(udb + del);
317 0 : xs = sb;
318 0 : xsbar = sb;
319 0 : xc = chm;
320 0 : xb = bot;
321 :
322 : // Subdivision of valence and sea.
323 0 : xuVal = uv;
324 0 : xuSea = xubar;
325 0 : xdVal = dv;
326 0 : xdSea = xdbar;
327 :
328 : // idSav = 9 to indicate that all flavours reset.
329 0 : idSav = 9;
330 :
331 0 : }
332 :
333 : //--------------------------------------------------------------------------
334 :
335 : double GRV94L::grvv (double x, double n, double ak, double bk, double a,
336 : double b, double c, double d) {
337 :
338 0 : double dx = sqrt(x);
339 0 : return n * pow(x, ak) * (1. + a * pow(x, bk) + x * (b + c * dx)) *
340 0 : pow(1. - x, d);
341 :
342 : }
343 :
344 : //--------------------------------------------------------------------------
345 :
346 : double GRV94L::grvw (double x, double s, double al, double be, double ak,
347 : double bk, double a, double b, double c, double d, double e, double es) {
348 :
349 0 : double lx = log(1./x);
350 0 : return (pow(x, ak) * (a + x * (b + x * c)) * pow(lx, bk) + pow(s, al)
351 0 : * exp(-e + sqrt(es * pow(s, be) * lx))) * pow(1. - x, d);
352 :
353 : }
354 :
355 : //--------------------------------------------------------------------------
356 :
357 : double GRV94L::grvs (double x, double s, double sth, double al, double be,
358 : double ak, double ag, double b, double d, double e, double es) {
359 :
360 0 : if(s <= sth) {
361 0 : return 0.;
362 : } else {
363 0 : double dx = sqrt(x);
364 0 : double lx = log(1./x);
365 0 : return pow(s - sth, al) / pow(lx, ak) * (1. + ag * dx + b * x) *
366 0 : pow(1. - x, d) * exp(-e + sqrt(es * pow(s, be) * lx));
367 : }
368 :
369 0 : }
370 :
371 : //==========================================================================
372 :
373 : // Gives the CTEQ 5 L (leading order) parton distribution function set
374 : // in parametrized form. Parametrization by J. Pumplin.
375 : // Ref: CTEQ Collaboration, H.L. Lai et al., Eur.Phys.J. C12 (2000) 375.
376 :
377 : // The range of (x, Q) covered by this parametrization of the QCD
378 : // evolved parton distributions is 1E-6 < x < 1, 1.1 GeV < Q < 10 TeV.
379 : // In the current implementation, densities are frozen at borders.
380 :
381 : void CTEQ5L::xfUpdate(int , double x, double Q2) {
382 :
383 : // Constrain x and Q2 to range for which parametrization is valid.
384 0 : double Q = sqrt( max( 1., min( 1e8, Q2) ) );
385 0 : x = max( 1e-6, min( 1.-1e-10, x) );
386 :
387 : // Derived kinematical quantities.
388 0 : double y = - log(x);
389 0 : double u = log( x / 0.00001);
390 0 : double x1 = 1. - x;
391 0 : double x1L = log(1. - x);
392 : double sumUbarDbar = 0.;
393 :
394 : // Parameters of parametrizations.
395 : const double Qmin[8] = { 0., 0., 0., 0., 0., 0., 1.3, 4.5};
396 : const double alpha[8] = { 0.2987216, 0.3407552, 0.4491863, 0.2457668,
397 : 0.5293999, 0.3713141, 0.03712017, 0.004952010 };
398 : const double ut1[8] = { 4.971265, 2.612618, -0.4656819, 3.862583,
399 : 0.1895615, 3.753257, 4.400772, 5.562568 };
400 : const double ut2[8] = { -1.105128, -1.258304e5, -274.2390, -1.265969,
401 : -3.069097, -1.113085, -1.356116, -1.801317 };
402 : const double am[8][9][3] = {
403 : // d.
404 : { { 0.5292616E+01, -0.2751910E+01, -0.2488990E+01 },
405 : { 0.9714424E+00, 0.1011827E-01, -0.1023660E-01 },
406 : { -0.1651006E+02, 0.7959721E+01, 0.8810563E+01 },
407 : { -0.1643394E+02, 0.5892854E+01, 0.9348874E+01 },
408 : { 0.3067422E+02, 0.4235796E+01, -0.5112136E+00 },
409 : { 0.2352526E+02, -0.5305168E+01, -0.1169174E+02 },
410 : { -0.1095451E+02, 0.3006577E+01, 0.5638136E+01 },
411 : { -0.1172251E+02, -0.2183624E+01, 0.4955794E+01 },
412 : { 0.1662533E-01, 0.7622870E-02, -0.4895887E-03 } },
413 : // u.
414 : { { 0.9905300E+00, -0.4502235E+00, 0.1624441E+00 },
415 : { 0.8867534E+00, 0.1630829E-01, -0.4049085E-01 },
416 : { 0.8547974E+00, 0.3336301E+00, 0.1371388E+00 },
417 : { 0.2941113E+00, -0.1527905E+01, 0.2331879E+00 },
418 : { 0.3384235E+02, 0.3715315E+01, 0.8276930E+00 },
419 : { 0.6230115E+01, 0.3134639E+01, -0.1729099E+01 },
420 : { -0.1186928E+01, -0.3282460E+00, 0.1052020E+00 },
421 : { -0.8545702E+01, -0.6247947E+01, 0.3692561E+01 },
422 : { 0.1724598E-01, 0.7120465E-02, 0.4003646E-04 } },
423 : // g.
424 : { { 0.1193572E+03, -0.3886845E+01, -0.1133965E+01 },
425 : { -0.9421449E+02, 0.3995885E+01, 0.1607363E+01 },
426 : { 0.4206383E+01, 0.2485954E+00, 0.2497468E+00 },
427 : { 0.1210557E+03, -0.3015765E+01, -0.1423651E+01 },
428 : { -0.1013897E+03, -0.7113478E+00, 0.2621865E+00 },
429 : { -0.1312404E+01, -0.9297691E+00, -0.1562531E+00 },
430 : { 0.1627137E+01, 0.4954111E+00, -0.6387009E+00 },
431 : { 0.1537698E+00, -0.2487878E+00, 0.8305947E+00 },
432 : { 0.2496448E-01, 0.2457823E-02, 0.8234276E-03 } },
433 : // ubar + dbar.
434 : { { 0.2647441E+02, 0.1059277E+02, -0.9176654E+00 },
435 : { 0.1990636E+01, 0.8558918E-01, 0.4248667E-01 },
436 : { -0.1476095E+02, -0.3276255E+02, 0.1558110E+01 },
437 : { -0.2966889E+01, -0.3649037E+02, 0.1195914E+01 },
438 : { -0.1000519E+03, -0.2464635E+01, 0.1964849E+00 },
439 : { 0.3718331E+02, 0.4700389E+02, -0.2772142E+01 },
440 : { -0.1872722E+02, -0.2291189E+02, 0.1089052E+01 },
441 : { -0.1628146E+02, -0.1823993E+02, 0.2537369E+01 },
442 : { -0.1156300E+01, -0.1280495E+00, 0.5153245E-01 } },
443 : // dbar/ubar.
444 : { { -0.6556775E+00, 0.2490190E+00, 0.3966485E-01 },
445 : { 0.1305102E+01, -0.1188925E+00, -0.4600870E-02 },
446 : { -0.2371436E+01, 0.3566814E+00, -0.2834683E+00 },
447 : { -0.6152826E+01, 0.8339877E+00, -0.7233230E+00 },
448 : { -0.8346558E+01, 0.2892168E+01, 0.2137099E+00 },
449 : { 0.1279530E+02, 0.1021114E+00, 0.5787439E+00 },
450 : { 0.5858816E+00, -0.1940375E+01, -0.4029269E+00 },
451 : { -0.2795725E+02, -0.5263392E+00, 0.1290229E+01 },
452 : { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } },
453 : // sbar.
454 : { { 0.1580931E+01, -0.2273826E+01, -0.1822245E+01 },
455 : { 0.2702644E+01, 0.6763243E+00, 0.7231586E-02 },
456 : { -0.1857924E+02, 0.3907500E+01, 0.5850109E+01 },
457 : { -0.3044793E+02, 0.2639332E+01, 0.5566644E+01 },
458 : { -0.4258011E+01, -0.5429244E+01, 0.4418946E+00 },
459 : { 0.3465259E+02, -0.5532604E+01, -0.4904153E+01 },
460 : { -0.1658858E+02, 0.2923275E+01, 0.2266286E+01 },
461 : { -0.1149263E+02, 0.2877475E+01, -0.7999105E+00 },
462 : { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } },
463 : // cbar.
464 : { { -0.8293661E+00, -0.3982375E+01, -0.6494283E-01 },
465 : { 0.2754618E+01, 0.8338636E+00, -0.6885160E-01 },
466 : { -0.1657987E+02, 0.1439143E+02, -0.6887240E+00 },
467 : { -0.2800703E+02, 0.1535966E+02, -0.7377693E+00 },
468 : { -0.6460216E+01, -0.4783019E+01, 0.4913297E+00 },
469 : { 0.3141830E+02, -0.3178031E+02, 0.7136013E+01 },
470 : { -0.1802509E+02, 0.1862163E+02, -0.4632843E+01 },
471 : { -0.1240412E+02, 0.2565386E+02, -0.1066570E+02 },
472 : { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } },
473 : // bbar.
474 : { { -0.6031237E+01, 0.1992727E+01, -0.1076331E+01 },
475 : { 0.2933912E+01, 0.5839674E+00, 0.7509435E-01 },
476 : { -0.8284919E+01, 0.1488593E+01, -0.8251678E+00 },
477 : { -0.1925986E+02, 0.2805753E+01, -0.3015446E+01 },
478 : { -0.9480483E+01, -0.9767837E+00, -0.1165544E+01 },
479 : { 0.2193195E+02, -0.1788518E+02, 0.9460908E+01 },
480 : { -0.1327377E+02, 0.1201754E+02, -0.6277844E+01 },
481 : { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 },
482 : { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } } };
483 :
484 : // Loop over 8 different parametrizations. Check if inside allowed region.
485 0 : for (int i = 0; i < 8; ++i) {
486 : double answer = 0.;
487 0 : if (Q > max(Qmin[i], alpha[i])) {
488 :
489 : // Evaluate answer.
490 0 : double tmp = log(Q / alpha[i]);
491 0 : double sb = log(tmp);
492 0 : double sb1 = sb - 1.2;
493 0 : double sb2 = sb1*sb1;
494 0 : double af[9];
495 0 : for (int j = 0; j < 9; ++j)
496 0 : af[j] = am[i][j][0] + sb1 * am[i][j][1] + sb2 * am[i][j][2];
497 0 : double part1 = af[1] * pow( y, 1. + 0.01 * af[4]) * (1. + af[8] * u);
498 0 : double part2 = af[0] * x1 + af[3] * x;
499 0 : double part3 = x * x1 * (af[5] + af[6] * x1 + af[7] * x * x1);
500 0 : double part4 = (ut2[i] < -100.) ? ut1[i] * x1L + af[2] * x1L
501 0 : : ut1[i] * x1L + af[2] * log(x1 + exp(ut2[i]));
502 0 : answer = x * exp( part1 + part2 + part3 + part4);
503 0 : answer *= 1. - Qmin[i] / Q;
504 0 : }
505 :
506 : // Store results.
507 0 : if (i == 0) xd = x * answer;
508 0 : else if (i == 1) xu = x * answer;
509 0 : else if (i == 2) xg = x * answer;
510 0 : else if (i == 3) sumUbarDbar = x * answer;
511 0 : else if (i == 4) { xubar = sumUbarDbar / (1. + answer);
512 0 : xdbar = sumUbarDbar * answer / (1. + answer); }
513 0 : else if (i == 5) {xs = x * answer; xsbar = xs;}
514 0 : else if (i == 6) xc = x * answer;
515 0 : else if (i == 7) xb = x * answer;
516 : }
517 :
518 : // Subdivision of valence and sea.
519 0 : xuVal = xu - xubar;
520 0 : xuSea = xubar;
521 0 : xdVal = xd - xdbar;
522 0 : xdSea = xdbar;
523 :
524 : // idSav = 9 to indicate that all flavours reset.
525 0 : idSav = 9;
526 :
527 0 : }
528 :
529 : //==========================================================================
530 :
531 : // The MSTWpdf class.
532 : // MSTW 2008 PDF's, specifically the LO one.
533 : // Original C++ version by Jeppe Andersen.
534 : // Modified by Graeme Watt <watt(at)hep.ucl.ac.uk>.
535 :
536 : //--------------------------------------------------------------------------
537 :
538 : // Constants: could be changed here if desired, but normally should not.
539 : // These are of technical nature, as described for each.
540 :
541 : // Number of parton flavours, x and Q2 grid points,
542 : // bins below c and b thresholds.
543 : const int MSTWpdf::np = 12;
544 : const int MSTWpdf::nx = 64;
545 : const int MSTWpdf::nq = 48;
546 : const int MSTWpdf::nqc0 = 4;
547 : const int MSTWpdf::nqb0 = 14;
548 :
549 : // Range of (x, Q2) grid.
550 : const double MSTWpdf::xmin = 1e-6;
551 : const double MSTWpdf::xmax = 1.0;
552 : const double MSTWpdf::qsqmin = 1.0;
553 : const double MSTWpdf::qsqmax = 1e9;
554 :
555 : // Array of x values.
556 : const double MSTWpdf::xxInit[65] = {0., 1e-6, 2e-6, 4e-6, 6e-6, 8e-6,
557 : 1e-5, 2e-5, 4e-5, 6e-5, 8e-5, 1e-4, 2e-4, 4e-4, 6e-4, 8e-4,
558 : 1e-3, 2e-3, 4e-3, 6e-3, 8e-3, 1e-2, 1.4e-2, 2e-2, 3e-2, 4e-2, 6e-2,
559 : 8e-2, 0.10, 0.125, 0.15, 0.175, 0.20, 0.225, 0.25, 0.275, 0.30,
560 : 0.325, 0.35, 0.375, 0.40, 0.425, 0.45, 0.475, 0.50, 0.525, 0.55,
561 : 0.575, 0.60, 0.625, 0.65, 0.675, 0.70, 0.725, 0.75, 0.775, 0.80,
562 : 0.825, 0.85, 0.875, 0.90, 0.925, 0.95, 0.975, 1.0 };
563 :
564 : // Array of Q values.
565 : const double MSTWpdf::qqInit[49] = {0., 1.0, 1.25, 1.5, 0., 0., 2.5, 3.2,
566 : 4.0, 5.0, 6.4, 8.0, 10., 12., 0., 0., 26.0, 40.0, 64.0, 1e2, 1.6e2,
567 : 2.4e2, 4e2, 6.4e2, 1e3, 1.8e3, 3.2e3, 5.6e3, 1e4, 1.8e4, 3.2e4, 5.6e4,
568 : 1e5, 1.8e5, 3.2e5, 5.6e5, 1e6, 1.8e6, 3.2e6, 5.6e6, 1e7, 1.8e7, 3.2e7,
569 : 5.6e7, 1e8, 1.8e8, 3.2e8, 5.6e8, 1e9 };
570 :
571 : //--------------------------------------------------------------------------
572 :
573 : // Initialize PDF: read in data grid from file and set up interpolation.
574 :
575 : void MSTWpdf::init(int iFitIn, string xmlPath, Info* infoPtr) {
576 :
577 : // Choice of fit among possibilities. Counters and temporary variables.
578 0 : iFit = iFitIn;
579 : int i,n,m,k,l,j;
580 0 : double dtemp;
581 :
582 : // Variables used for initialising c_ij array:
583 0 : double f[np+1][nx+1][nq+1];
584 0 : double f1[np+1][nx+1][nq+1]; // derivative w.r.t. x
585 0 : double f2[np+1][nx+1][nq+1]; // derivative w.r.t. q
586 0 : double f12[np+1][nx+1][nq+1];// cross derivative
587 0 : double f21[np+1][nx+1][nq+1];// cross derivative
588 0 : int wt[16][16]={{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
589 : {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
590 : {-3,0,0,3,0,0,0,0,-2,0,0,-1,0,0,0,0},
591 : {2,0,0,-2,0,0,0,0,1,0,0,1,0,0,0,0},
592 : {0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
593 : {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0},
594 : {0,0,0,0,-3,0,0,3,0,0,0,0,-2,0,0,-1},
595 : {0,0,0,0,2,0,0,-2,0,0,0,0,1,0,0,1},
596 : {-3,3,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0},
597 : {0,0,0,0,0,0,0,0,-3,3,0,0,-2,-1,0,0},
598 : {9,-9,9,-9,6,3,-3,-6,6,-6,-3,3,4,2,1,2},
599 : {-6,6,-6,6,-4,-2,2,4,-3,3,3,-3,-2,-1,-1,-2},
600 : {2,-2,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
601 : {0,0,0,0,0,0,0,0,2,-2,0,0,1,1,0,0},
602 : {-6,6,-6,6,-3,-3,3,3,-4,4,2,-2,-2,-2,-1,-1},
603 : {4,-4,4,-4,2,2,-2,-2,2,-2,-2,2,1,1,1,1}};
604 0 : double xxd,d1d2,cl[16],x[16],d1,d2,y[5],y1[5],y2[5],y12[5];
605 : double mc2,mb2,eps=1e-6; // q^2 grid points at mc2+eps, mb2+eps
606 :
607 : // Select which data file to read for current fit.
608 0 : if (xmlPath[ xmlPath.length() - 1 ] != '/') xmlPath += "/";
609 0 : string fileName = " ";
610 0 : if (iFit == 1) fileName = "mrstlostar.00.dat";
611 0 : if (iFit == 2) fileName = "mrstlostarstar.00.dat";
612 0 : if (iFit == 3) fileName = "mstw2008lo.00.dat";
613 0 : if (iFit == 4) fileName = "mstw2008nlo.00.dat";
614 :
615 : // Open data file.
616 0 : ifstream data_file( (xmlPath + fileName).c_str() );
617 0 : if (!data_file.good()) {
618 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from MSTWpdf::init: "
619 0 : "did not find parametrization file ", fileName);
620 0 : else cout << " Error from MSTWpdf::init: "
621 0 : << "did not find parametrization file " << fileName << endl;
622 0 : isSet = false;
623 0 : return;
624 : }
625 :
626 : // Read distance, tolerance, heavy quark masses
627 : // and alphaS values from file.
628 0 : char comma;
629 0 : int nExtraFlavours;
630 0 : data_file.ignore(256,'\n');
631 0 : data_file.ignore(256,'\n');
632 0 : data_file.ignore(256,'='); data_file >> distance >> tolerance;
633 0 : data_file.ignore(256,'='); data_file >> mCharm;
634 0 : data_file.ignore(256,'='); data_file >> mBottom;
635 0 : data_file.ignore(256,'='); data_file >> alphaSQ0;
636 0 : data_file.ignore(256,'='); data_file >> alphaSMZ;
637 0 : data_file.ignore(256,'='); data_file >> alphaSorder >> comma >> alphaSnfmax;
638 0 : data_file.ignore(256,'='); data_file >> nExtraFlavours;
639 0 : data_file.ignore(256,'\n');
640 0 : data_file.ignore(256,'\n');
641 0 : data_file.ignore(256,'\n');
642 :
643 : // Use c and b quark masses for outlay of qq array.
644 0 : for (int iqq = 0; iqq < 49; ++iqq) qq[iqq] = qqInit[iqq];
645 0 : mc2=mCharm*mCharm;
646 0 : mb2=mBottom*mBottom;
647 0 : qq[4]=mc2;
648 0 : qq[5]=mc2+eps;
649 0 : qq[14]=mb2;
650 0 : qq[15]=mb2+eps;
651 :
652 : // Check that the heavy quark masses are sensible.
653 0 : if (mc2 < qq[3] || mc2 > qq[6]) {
654 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from MSTWpdf::init: "
655 : "invalid mCharm");
656 0 : else cout << " Error from MSTWpdf::init: invalid mCharm" << endl;
657 0 : isSet = false;
658 0 : return;
659 : }
660 0 : if (mb2 < qq[13] || mb2 > qq[16]) {
661 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from MSTWpdf::init: "
662 : "invalid mBottom");
663 0 : else cout << " Error from MSTWpdf::init: invalid mBottom" << endl;
664 0 : isSet = false;
665 0 : return;
666 : }
667 :
668 : // The nExtraFlavours variable is provided to aid compatibility
669 : // with future grids where, for example, a photon distribution
670 : // might be provided (cf. the MRST2004QED PDFs).
671 0 : if (nExtraFlavours < 0 || nExtraFlavours > 1) {
672 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from MSTWpdf::init: "
673 : "invalid nExtraFlavours");
674 0 : else cout << " Error from MSTWpdf::init: invalid nExtraFlavours" << endl;
675 0 : isSet = false;
676 0 : return;
677 : }
678 :
679 : // Now read in the grids from the grid file.
680 0 : for (n=1;n<=nx-1;n++)
681 0 : for (m=1;m<=nq;m++) {
682 0 : for (i=1;i<=9;i++)
683 0 : data_file >> f[i][n][m];
684 0 : if (alphaSorder==2) { // only at NNLO
685 0 : data_file >> f[10][n][m]; // = chm-cbar
686 0 : data_file >> f[11][n][m]; // = bot-bbar
687 : }
688 : else {
689 0 : f[10][n][m] = 0.; // = chm-cbar
690 0 : f[11][n][m] = 0.; // = bot-bbar
691 : }
692 0 : if (nExtraFlavours>0)
693 0 : data_file >> f[12][n][m]; // = photon
694 : else
695 0 : f[12][n][m] = 0.; // photon
696 0 : if (data_file.eof()) {
697 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from MSTWpdf::init: "
698 : "failed to read in data file");
699 0 : else cout << " Error from MSTWpdf::init: failed to read in data file"
700 0 : << endl;
701 0 : isSet = false;
702 0 : return;
703 : }
704 : }
705 :
706 : // Check that ALL the file contents have been read in.
707 0 : data_file >> dtemp;
708 0 : if (!data_file.eof()) {
709 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from MSTWpdf::init: "
710 : "failed to read in data file");
711 0 : else cout << " Error from MSTWpdf::init: failed to read in data file"
712 0 : << endl;
713 0 : isSet = false;
714 0 : return;
715 : }
716 :
717 : // Close the datafile.
718 0 : data_file.close();
719 :
720 : // PDFs are identically zero at x = 1.
721 0 : for (i=1;i<=np;i++)
722 0 : for (m=1;m<=nq;m++)
723 0 : f[i][nx][m]=0.0;
724 :
725 : // Set up the new array in log10(x) and log10(qsq).
726 0 : for (i=1;i<=nx;i++)
727 0 : xx[i]=log10(xxInit[i]);
728 0 : for (m=1;m<=nq;m++)
729 0 : qq[m]=log10(qq[m]);
730 :
731 : // Now calculate the derivatives used for bicubic interpolation.
732 0 : for (i=1;i<=np;i++) {
733 :
734 : // Start by calculating the first x derivatives
735 : // along the first x value:
736 0 : for (m=1;m<=nq;m++) {
737 0 : f1[i][1][m]=polderivative1(xx[1],xx[2],xx[3],f[i][1][m],f[i][2][m],
738 0 : f[i][3][m]);
739 : // Then along the rest (up to the last):
740 0 : for (k=2;k<nx;k++)
741 0 : f1[i][k][m]=polderivative2(xx[k-1],xx[k],xx[k+1],f[i][k-1][m],
742 0 : f[i][k][m],f[i][k+1][m]);
743 : // Then for the last column:
744 0 : f1[i][nx][m]=polderivative3(xx[nx-2],xx[nx-1],xx[nx],f[i][nx-2][m],
745 0 : f[i][nx-1][m],f[i][nx][m]);
746 : }
747 :
748 : // Then calculate the qq derivatives. At NNLO there are
749 : // discontinuities in the PDFs at mc2 and mb2, so calculate
750 : // the derivatives at q^2 = mc2, mc2+eps, mb2, mb2+eps in
751 : // the same way as at the endpoints qsqmin and qsqmax.
752 0 : for (m=1;m<=nq;m++) {
753 0 : if (m==1 || m==nqc0+1 || m==nqb0+1) {
754 0 : for (k=1;k<=nx;k++)
755 0 : f2[i][k][m]=polderivative1(qq[m],qq[m+1],qq[m+2],
756 0 : f[i][k][m],f[i][k][m+1],f[i][k][m+2]);
757 : }
758 0 : else if (m==nq || m==nqc0 || m==nqb0) {
759 0 : for (k=1;k<=nx;k++)
760 0 : f2[i][k][m]=polderivative3(qq[m-2],qq[m-1],qq[m],
761 0 : f[i][k][m-2],f[i][k][m-1],f[i][k][m]);
762 : }
763 : else {
764 : // The rest:
765 0 : for (k=1;k<=nx;k++)
766 0 : f2[i][k][m]=polderivative2(qq[m-1],qq[m],qq[m+1],
767 0 : f[i][k][m-1],f[i][k][m],f[i][k][m+1]);
768 : }
769 : }
770 :
771 : // Now, calculate the cross derivatives.
772 : // Calculate these as the average between (d/dx)(d/dy) and (d/dy)(d/dx).
773 :
774 : // First calculate (d/dx)(d/dy).
775 : // Start by calculating the first x derivatives
776 : // along the first x value:
777 0 : for (m=1;m<=nq;m++)
778 0 : f12[i][1][m]=polderivative1(xx[1],xx[2],xx[3],f2[i][1][m],
779 0 : f2[i][2][m],f2[i][3][m]);
780 : // Then along the rest (up to the last):
781 0 : for (k=2;k<nx;k++) {
782 0 : for (m=1;m<=nq;m++)
783 0 : f12[i][k][m]=polderivative2(xx[k-1],xx[k],xx[k+1],f2[i][k-1][m],
784 0 : f2[i][k][m],f2[i][k+1][m]);
785 : }
786 : // Then for the last column:
787 0 : for (m=1;m<=nq;m++)
788 0 : f12[i][nx][m]=polderivative3(xx[nx-2],xx[nx-1],xx[nx],
789 0 : f2[i][nx-2][m],f2[i][nx-1][m],f2[i][nx][m]);
790 :
791 : // Now calculate (d/dy)(d/dx).
792 0 : for (m=1;m<=nq;m++) {
793 0 : if (m==1 || m==nqc0+1 || m==nqb0+1) {
794 0 : for (k=1;k<=nx;k++)
795 0 : f21[i][k][m]=polderivative1(qq[m],qq[m+1],qq[m+2],
796 0 : f1[i][k][m],f1[i][k][m+1],f1[i][k][m+2]);
797 : }
798 0 : else if (m==nq || m==nqc0 || m==nqb0) {
799 0 : for (k=1;k<=nx;k++)
800 0 : f21[i][k][m]=polderivative3(qq[m-2],qq[m-1],qq[m],
801 0 : f1[i][k][m-2],f1[i][k][m-1],f1[i][k][m]);
802 : }
803 : else {
804 : // The rest:
805 0 : for (k=1;k<=nx;k++)
806 0 : f21[i][k][m]=polderivative2(qq[m-1],qq[m],qq[m+1],
807 0 : f1[i][k][m-1],f1[i][k][m],f1[i][k][m+1]);
808 : }
809 : }
810 :
811 : // Now take the average of (d/dx)(d/dy) and (d/dy)(d/dx).
812 0 : for (k=1;k<=nx;k++) {
813 0 : for (m=1;m<=nq;m++) {
814 0 : f12[i][k][m] = 0.5*(f12[i][k][m]+f21[i][k][m]);
815 : }
816 : }
817 :
818 : // Now calculate the coefficients c_ij.
819 0 : for (n=1;n<=nx-1;n++) {
820 0 : for (m=1;m<=nq-1;m++) {
821 0 : d1=xx[n+1]-xx[n];
822 0 : d2=qq[m+1]-qq[m];
823 0 : d1d2=d1*d2;
824 :
825 0 : y[1]=f[i][n][m];
826 0 : y[2]=f[i][n+1][m];
827 0 : y[3]=f[i][n+1][m+1];
828 0 : y[4]=f[i][n][m+1];
829 :
830 0 : y1[1]=f1[i][n][m];
831 0 : y1[2]=f1[i][n+1][m];
832 0 : y1[3]=f1[i][n+1][m+1];
833 0 : y1[4]=f1[i][n][m+1];
834 :
835 0 : y2[1]=f2[i][n][m];
836 0 : y2[2]=f2[i][n+1][m];
837 0 : y2[3]=f2[i][n+1][m+1];
838 0 : y2[4]=f2[i][n][m+1];
839 :
840 0 : y12[1]=f12[i][n][m];
841 0 : y12[2]=f12[i][n+1][m];
842 0 : y12[3]=f12[i][n+1][m+1];
843 0 : y12[4]=f12[i][n][m+1];
844 :
845 0 : for (k=1;k<=4;k++) {
846 0 : x[k-1]=y[k];
847 0 : x[k+3]=y1[k]*d1;
848 0 : x[k+7]=y2[k]*d2;
849 0 : x[k+11]=y12[k]*d1d2;
850 : }
851 :
852 0 : for (l=0;l<=15;l++) {
853 : xxd=0.0;
854 0 : for (k=0;k<=15;k++) xxd+= wt[l][k]*x[k];
855 0 : cl[l]=xxd;
856 : }
857 :
858 : l=0;
859 0 : for (k=1;k<=4;k++)
860 0 : for (j=1;j<=4;j++) c[i][n][m][k][j]=cl[l++];
861 : } //m
862 : } //n
863 : } // i
864 :
865 0 : }
866 :
867 : //--------------------------------------------------------------------------
868 :
869 : // Update PDF values.
870 :
871 : void MSTWpdf::xfUpdate(int , double x, double Q2) {
872 :
873 : // Update using MSTW routine.
874 0 : double q = sqrtpos(Q2);
875 : // Quarks:
876 0 : double dn = parton(1,x,q);
877 0 : double up = parton(2,x,q);
878 0 : double str = parton(3,x,q);
879 0 : double chm = parton(4,x,q);
880 0 : double bot = parton(5,x,q);
881 : // Valence quarks:
882 0 : double dnv = parton(7,x,q);
883 0 : double upv = parton(8,x,q);
884 0 : double sv = parton(9,x,q);
885 0 : double cv = parton(10,x,q);
886 0 : double bv = parton(11,x,q);
887 : // Antiquarks = quarks - valence quarks:
888 0 : double dsea = dn - dnv;
889 0 : double usea = up - upv;
890 0 : double sbar = str - sv;
891 0 : double cbar = chm - cv;
892 0 : double bbar = bot - bv;
893 : // Gluon:
894 0 : double glu = parton(0,x,q);
895 : // Photon (= zero unless considering QED contributions):
896 0 : double phot = parton(13,x,q);
897 :
898 : // Transfer to Pythia notation.
899 0 : xg = glu;
900 0 : xu = up;
901 0 : xd = dn;
902 0 : xubar = usea;
903 0 : xdbar = dsea;
904 0 : xs = str;
905 0 : xsbar = sbar;
906 0 : xc = 0.5 * (chm + cbar);
907 0 : xb = 0.5 * (bot + bbar);
908 0 : xgamma = phot;
909 :
910 : // Subdivision of valence and sea.
911 0 : xuVal = upv;
912 0 : xuSea = xubar;
913 0 : xdVal = dnv;
914 0 : xdSea = xdbar;
915 :
916 : // idSav = 9 to indicate that all flavours reset.
917 0 : idSav = 9;
918 :
919 0 : }
920 :
921 : //--------------------------------------------------------------------------
922 :
923 : // Returns the PDF value for parton of flavour 'f' at x,q.
924 :
925 : double MSTWpdf::parton(int f,double x,double q) {
926 :
927 : double qsq;
928 : int ip;
929 : int interpolate(1);
930 : double parton_pdf=0,parton_pdf1=0,anom;
931 : double xxx,qqq;
932 :
933 0 : qsq=q*q;
934 :
935 : // If mc2 < qsq < mc2+eps, then qsq = mc2+eps.
936 0 : if (qsq>pow(10.,qq[nqc0]) && qsq<pow(10.,qq[nqc0+1])) {
937 : qsq = pow(10.,qq[nqc0+1]);
938 0 : }
939 :
940 : // If mb2 < qsq < mb2+eps, then qsq = mb2+eps.
941 0 : if (qsq>pow(10.,qq[nqb0]) && qsq<pow(10.,qq[nqb0+1])) {
942 : qsq = pow(10.,qq[nqb0+1]);
943 0 : }
944 :
945 0 : if (x<xmin) {
946 : interpolate=0;
947 0 : if (x<=0.) return 0.;
948 : }
949 0 : else if (x>xmax) return 0.;
950 :
951 0 : if (qsq<qsqmin) {
952 : interpolate=-1;
953 0 : if (q<=0.) return 0.;
954 : }
955 0 : else if (qsq>qsqmax) {
956 : interpolate=0;
957 0 : }
958 :
959 0 : if (f==0) ip=1;
960 0 : else if (f>=1 && f<=5) ip=f+1;
961 0 : else if (f<=-1 && f>=-5) ip=-f+1;
962 0 : else if (f>=7 && f<=11) ip=f;
963 0 : else if (f==13) ip=12;
964 0 : else if (abs(f)==6 || f==12) return 0.;
965 : else return 0.;
966 :
967 : // Interpolation in log10(x), log10(qsq):
968 0 : xxx=log10(x);
969 0 : qqq=log10(qsq);
970 :
971 0 : if (interpolate==1) { // do usual interpolation
972 0 : parton_pdf=parton_interpolate(ip,xxx,qqq);
973 0 : if (f<=-1 && f>=-5) // antiquark = quark - valence
974 0 : parton_pdf -= parton_interpolate(ip+5,xxx,qqq);
975 : }
976 0 : else if (interpolate==-1) { // extrapolate to low Q^2
977 :
978 0 : if (x<xmin) { // extrapolate to low x
979 0 : parton_pdf = parton_extrapolate(ip,xxx,log10(qsqmin));
980 0 : parton_pdf1 = parton_extrapolate(ip,xxx,log10(1.01*qsqmin));
981 0 : if (f<=-1 && f>=-5) { // antiquark = quark - valence
982 0 : parton_pdf -= parton_extrapolate(ip+5,xxx,log10(qsqmin));
983 0 : parton_pdf1 -= parton_extrapolate(ip+5,xxx,log10(1.01*qsqmin));
984 0 : }
985 : }
986 : else { // do usual interpolation
987 0 : parton_pdf = parton_interpolate(ip,xxx,log10(qsqmin));
988 0 : parton_pdf1 = parton_interpolate(ip,xxx,log10(1.01*qsqmin));
989 0 : if (f<=-1 && f>=-5) { // antiquark = quark - valence
990 0 : parton_pdf -= parton_interpolate(ip+5,xxx,log10(qsqmin));
991 0 : parton_pdf1 -= parton_interpolate(ip+5,xxx,log10(1.01*qsqmin));
992 0 : }
993 : }
994 : // Calculate the anomalous dimension, dlog(xf)/dlog(qsq),
995 : // evaluated at qsqmin. Then extrapolate the PDFs to low
996 : // qsq < qsqmin by interpolating the anomalous dimenion between
997 : // the value at qsqmin and a value of 1 for qsq << qsqmin.
998 : // If value of PDF at qsqmin is very small, just set
999 : // anomalous dimension to 1 to prevent rounding errors.
1000 0 : if (fabs(parton_pdf) >= 1.e-5)
1001 0 : anom = max(-2.5, (parton_pdf1-parton_pdf)/parton_pdf/0.01);
1002 : else anom = 1.;
1003 0 : parton_pdf = parton_pdf*pow(qsq/qsqmin,anom*qsq/qsqmin+1.-qsq/qsqmin);
1004 :
1005 0 : }
1006 : else { // extrapolate outside PDF grid to low x or high Q^2
1007 0 : parton_pdf = parton_extrapolate(ip,xxx,qqq);
1008 0 : if (f<=-1 && f>=-5) // antiquark = quark - valence
1009 0 : parton_pdf -= parton_extrapolate(ip+5,xxx,qqq);
1010 : }
1011 :
1012 0 : return parton_pdf;
1013 0 : }
1014 :
1015 : //--------------------------------------------------------------------------
1016 :
1017 : // Interpolate PDF value inside data grid.
1018 :
1019 : double MSTWpdf::parton_interpolate(int ip, double xxx, double qqq) {
1020 :
1021 : double g, t, u;
1022 : int n, m, l;
1023 :
1024 0 : n=locate(xx,nx,xxx); // 0: below xmin, nx: above xmax
1025 0 : m=locate(qq,nq,qqq); // 0: below qsqmin, nq: above qsqmax
1026 :
1027 0 : t=(xxx-xx[n])/(xx[n+1]-xx[n]);
1028 0 : u=(qqq-qq[m])/(qq[m+1]-qq[m]);
1029 :
1030 : // Assume PDF proportional to (1-x)^p as x -> 1.
1031 0 : if (n==nx-1) {
1032 0 : double g0=((c[ip][n][m][1][4]*u+c[ip][n][m][1][3])*u
1033 0 : +c[ip][n][m][1][2])*u+c[ip][n][m][1][1]; // value at xx[n]
1034 0 : double g1=((c[ip][n-1][m][1][4]*u+c[ip][n-1][m][1][3])*u
1035 0 : +c[ip][n-1][m][1][2])*u+c[ip][n-1][m][1][1]; // value at xx[n-1]
1036 : double p = 1.0;
1037 0 : if (g0>0.0&&g1>0.0) p = log(g1/g0)/log((xx[n+1]-xx[n-1])/(xx[n+1]-xx[n]));
1038 0 : if (p<=1.0) p=1.0;
1039 0 : g=g0*pow((xx[n+1]-xxx)/(xx[n+1]-xx[n]),p);
1040 0 : }
1041 :
1042 : // Usual interpolation.
1043 : else {
1044 : g=0.0;
1045 0 : for (l=4;l>=1;l--) {
1046 0 : g=t*g+((c[ip][n][m][l][4]*u+c[ip][n][m][l][3])*u
1047 0 : +c[ip][n][m][l][2])*u+c[ip][n][m][l][1];
1048 : }
1049 : }
1050 :
1051 0 : return g;
1052 : }
1053 :
1054 : //--------------------------------------------------------------------------
1055 :
1056 : // Extrapolate PDF value outside data grid.
1057 :
1058 :
1059 : double MSTWpdf::parton_extrapolate(int ip, double xxx, double qqq) {
1060 :
1061 : double parton_pdf=0.;
1062 : int n,m;
1063 :
1064 0 : n=locate(xx,nx,xxx); // 0: below xmin, nx: above xmax
1065 0 : m=locate(qq,nq,qqq); // 0: below qsqmin, nq: above qsqmax
1066 :
1067 0 : if (n==0&&(m>0&&m<nq)) { // if extrapolation in small x only
1068 :
1069 : double f0,f1;
1070 0 : f0=parton_interpolate(ip,xx[1],qqq);
1071 0 : f1=parton_interpolate(ip,xx[2],qqq);
1072 0 : if ( f0>1e-3 && f1>1e-3 ) { // if values are positive, keep them so
1073 0 : f0=log(f0);
1074 0 : f1=log(f1);
1075 0 : parton_pdf=exp(f0+(f1-f0)/(xx[2]-xx[1])*(xxx-xx[1]));
1076 0 : } else // otherwise just extrapolate in the value
1077 0 : parton_pdf=f0+(f1-f0)/(xx[2]-xx[1])*(xxx-xx[1]);
1078 :
1079 0 : } if (n>0&&m==nq) { // if extrapolation into large q only
1080 :
1081 : double f0,f1;
1082 0 : f0=parton_interpolate(ip,xxx,qq[nq]);
1083 0 : f1=parton_interpolate(ip,xxx,qq[nq-1]);
1084 0 : if ( f0>1e-3 && f1>1e-3 ) { // if values are positive, keep them so
1085 0 : f0=log(f0);
1086 0 : f1=log(f1);
1087 0 : parton_pdf=exp(f0+(f0-f1)/(qq[nq]-qq[nq-1])*(qqq-qq[nq]));
1088 0 : } else // otherwise just extrapolate in the value
1089 0 : parton_pdf=f0+(f0-f1)/(qq[nq]-qq[nq-1])*(qqq-qq[nq]);
1090 :
1091 0 : } if (n==0&&m==nq) { // if extrapolation into large q AND small x
1092 :
1093 : double f0,f1;
1094 0 : f0=parton_extrapolate(ip,xx[1],qqq);
1095 0 : f1=parton_extrapolate(ip,xx[2],qqq);
1096 0 : if ( f0>1e-3 && f1>1e-3 ) { // if values are positive, keep them so
1097 0 : f0=log(f0);
1098 0 : f1=log(f1);
1099 0 : parton_pdf=exp(f0+(f1-f0)/(xx[2]-xx[1])*(xxx-xx[1]));
1100 0 : } else // otherwise just extrapolate in the value
1101 0 : parton_pdf=f0+(f1-f0)/(xx[2]-xx[1])*(xxx-xx[1]);
1102 :
1103 0 : }
1104 :
1105 0 : return parton_pdf;
1106 : }
1107 :
1108 : //--------------------------------------------------------------------------
1109 :
1110 : // Returns an integer j such that x lies inbetween xloc[j] and xloc[j+1].
1111 : // unit offset of increasing ordered array xloc assumed.
1112 : // n is the length of the array (xloc[n] highest element).
1113 :
1114 : int MSTWpdf::locate(double xloc[],int n,double x) {
1115 : int ju,jm,jl(0),j;
1116 0 : ju=n+1;
1117 :
1118 0 : while (ju-jl>1) {
1119 0 : jm=(ju+jl)/2; // compute a mid point.
1120 0 : if ( x>= xloc[jm])
1121 0 : jl=jm;
1122 : else ju=jm;
1123 : }
1124 0 : if (x==xloc[1]) j=1;
1125 0 : else if (x==xloc[n]) j=n-1;
1126 : else j=jl;
1127 :
1128 0 : return j;
1129 : }
1130 :
1131 : //--------------------------------------------------------------------------
1132 :
1133 : // Returns the estimate of the derivative at x1 obtained by a polynomial
1134 : // interpolation using the three points (x_i,y_i).
1135 :
1136 : double MSTWpdf::polderivative1(double x1, double x2, double x3, double y1,
1137 : double y2, double y3) {
1138 :
1139 0 : return (x3*x3*(y1-y2)+2.0*x1*(x3*(-y1+y2)+x2*(y1-y3))+x2*x2*(-y1+y3)
1140 0 : +x1*x1*(-y2+y3))/((x1-x2)*(x1-x3)*(x2-x3));
1141 :
1142 : }
1143 :
1144 : //--------------------------------------------------------------------------
1145 :
1146 : // Returns the estimate of the derivative at x2 obtained by a polynomial
1147 : // interpolation using the three points (x_i,y_i).
1148 :
1149 : double MSTWpdf::polderivative2(double x1, double x2, double x3, double y1,
1150 : double y2, double y3) {
1151 :
1152 0 : return (x3*x3*(y1-y2)-2.0*x2*(x3*(y1-y2)+x1*(y2-y3))+x2*x2*(y1-y3)
1153 0 : +x1*x1*(y2-y3))/((x1-x2)*(x1-x3)*(x2-x3));
1154 :
1155 : }
1156 :
1157 : //--------------------------------------------------------------------------
1158 :
1159 : // Returns the estimate of the derivative at x3 obtained by a polynomial
1160 : // interpolation using the three points (x_i,y_i).
1161 :
1162 : double MSTWpdf::polderivative3(double x1, double x2, double x3, double y1,
1163 : double y2, double y3) {
1164 :
1165 0 : return (x3*x3*(-y1+y2)+2.0*x2*x3*(y1-y3)+x1*x1*(y2-y3)+x2*x2*(-y1+y3)
1166 0 : +2.0*x1*x3*(-y2+y3))/((x1-x2)*(x1-x3)*(x2-x3));
1167 :
1168 : }
1169 :
1170 : //==========================================================================
1171 :
1172 : // The CTEQ6pdf class.
1173 : // Code for handling CTEQ6L, CTEQ6L1, CTEQ66.00, CT09MC1, CT09MC2, (CT09MCS?).
1174 :
1175 : // Constants: could be changed here if desired, but normally should not.
1176 : // These are of technical nature, as described for each.
1177 :
1178 : // Stay away from xMin, xMax, Qmin, Qmax limits.
1179 : const double CTEQ6pdf::EPSILON = 1e-6;
1180 :
1181 : // Assumed approximate power of small-x behaviour for interpolation.
1182 : const double CTEQ6pdf::XPOWER = 0.3;
1183 :
1184 : //--------------------------------------------------------------------------
1185 :
1186 : // Initialize PDF: read in data grid from file.
1187 :
1188 : void CTEQ6pdf::init(int iFitIn, string xmlPath, Info* infoPtr) {
1189 :
1190 : // Choice of fit among possibilities.
1191 0 : iFit = iFitIn;
1192 :
1193 : // Select which data file to read for current fit.
1194 0 : if (xmlPath[ xmlPath.length() - 1 ] != '/') xmlPath += "/";
1195 0 : string fileName = " ";
1196 0 : if (iFit == 1) fileName = "cteq6l.tbl";
1197 0 : if (iFit == 2) fileName = "cteq6l1.tbl";
1198 0 : if (iFit == 3) fileName = "ctq66.00.pds";
1199 0 : if (iFit == 4) fileName = "ct09mc1.pds";
1200 0 : if (iFit == 5) fileName = "ct09mc2.pds";
1201 0 : if (iFit == 6) fileName = "ct09mcs.pds";
1202 0 : bool isPdsGrid = (iFit > 2);
1203 :
1204 : // Open data file.
1205 0 : ifstream pdfgrid( (xmlPath + fileName).c_str() );
1206 0 : if (!pdfgrid.good()) {
1207 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from CTEQ6pdf::init: "
1208 0 : "did not find parametrization file ", fileName);
1209 0 : else cout << " Error from CTEQ6pdf::init: "
1210 0 : << "did not find parametrization file " << fileName << endl;
1211 0 : isSet = false;
1212 0 : return;
1213 : }
1214 :
1215 : // Read in common information.
1216 0 : int iDum;
1217 0 : double orderTmp, nQTmp, qTmp, rDum;
1218 0 : string line;
1219 0 : getline( pdfgrid, line);
1220 0 : getline( pdfgrid, line);
1221 0 : getline( pdfgrid, line);
1222 0 : istringstream is1(line);
1223 0 : is1 >> orderTmp >> nQTmp >> lambda >> mQ[1] >> mQ[2] >> mQ[3]
1224 0 : >> mQ[4] >> mQ[5] >> mQ[6];
1225 0 : order = int(orderTmp + 0.5);
1226 0 : nQuark = int(nQTmp + 0.5);
1227 0 : getline( pdfgrid, line);
1228 :
1229 : // Read in information for the .pds grid format.
1230 0 : if (isPdsGrid) {
1231 0 : getline( pdfgrid, line);
1232 0 : istringstream is2(line);
1233 0 : is2 >> iDum >> iDum >> iDum >> nfMx >> mxVal >> iDum;
1234 0 : if (mxVal > 4) mxVal = 3;
1235 0 : getline( pdfgrid, line);
1236 0 : getline( pdfgrid, line);
1237 0 : istringstream is3(line);
1238 0 : is3 >> nX >> nT >> iDum >> nG >> iDum;
1239 0 : for (int i = 0; i < nG + 2; ++i) getline( pdfgrid, line);
1240 0 : getline( pdfgrid, line);
1241 0 : istringstream is4(line);
1242 0 : is4 >> qIni >> qMax;
1243 0 : for (int iT = 0; iT <= nT; ++iT) {
1244 0 : getline( pdfgrid, line);
1245 0 : istringstream is5(line);
1246 0 : is5 >> qTmp;
1247 0 : tv[iT] = log( log( qTmp/lambda));
1248 0 : }
1249 0 : getline( pdfgrid, line);
1250 0 : getline( pdfgrid, line);
1251 0 : istringstream is6(line);
1252 0 : is6 >> xMin >> rDum;
1253 : int nPackX = 6;
1254 0 : xv[0] = 0.;
1255 0 : for (int iXrng = 0; iXrng < int( (nX + nPackX - 1) / nPackX); ++iXrng) {
1256 0 : getline( pdfgrid, line);
1257 0 : istringstream is7(line);
1258 0 : for (int iX = nPackX * iXrng + 1; iX <= nPackX * (iXrng + 1); ++iX)
1259 0 : if (iX <= nX) is7 >> xv[iX];
1260 0 : }
1261 0 : }
1262 :
1263 : // Read in information for the .tbl grid format.
1264 : else {
1265 0 : mxVal = 2;
1266 0 : getline( pdfgrid, line);
1267 0 : istringstream is2(line);
1268 0 : is2 >> nX >> nT >> nfMx;
1269 0 : getline( pdfgrid, line);
1270 0 : getline( pdfgrid, line);
1271 0 : istringstream is3(line);
1272 0 : is3 >> qIni >> qMax;
1273 : int nPackT = 6;
1274 0 : for (int iTrng = 0; iTrng < int( (nT + nPackT) / nPackT); ++iTrng) {
1275 0 : getline( pdfgrid, line);
1276 0 : istringstream is4(line);
1277 0 : for (int iT = nPackT * iTrng; iT < nPackT * (iTrng + 1); ++iT)
1278 0 : if (iT <= nT) {
1279 0 : is4 >> qTmp;
1280 0 : tv[iT] = log( log( qTmp / lambda) );
1281 0 : }
1282 0 : }
1283 0 : getline( pdfgrid, line);
1284 0 : getline( pdfgrid, line);
1285 0 : istringstream is5(line);
1286 0 : is5 >> xMin;
1287 : int nPackX = 6;
1288 0 : for (int iXrng = 0; iXrng < int( (nX + nPackX) / nPackX); ++iXrng) {
1289 0 : getline( pdfgrid, line);
1290 0 : istringstream is6(line);
1291 0 : for (int iX = nPackX * iXrng; iX < nPackX * (iXrng + 1); ++iX)
1292 0 : if (iX <= nX) is6 >> xv[iX];
1293 0 : }
1294 0 : }
1295 :
1296 : // Read in the grid proper.
1297 0 : getline( pdfgrid, line);
1298 0 : int nBlk = (nX + 1) * (nT + 1);
1299 0 : int nPts = nBlk * (nfMx + 1 + mxVal);
1300 0 : int nPack = (isPdsGrid) ? 6 : 5;
1301 0 : for (int iRng = 0; iRng < int( (nPts + nPack - 1) / nPack); ++iRng) {
1302 0 : getline( pdfgrid, line);
1303 0 : istringstream is8(line);
1304 0 : for (int i = nPack * iRng + 1; i <= nPack * (iRng + 1); ++i)
1305 0 : if (i <= nPts) is8 >> upd[i];
1306 0 : }
1307 :
1308 : // Initialize x grid mapped to x^0.3.
1309 0 : xvpow[0] = 0.;
1310 0 : for (int iX = 1; iX <= nX; ++iX) xvpow[iX] = pow(xv[iX], XPOWER);
1311 :
1312 : // Set x and Q borders with some margin.
1313 0 : xMinEps = xMin * (1. + EPSILON);
1314 0 : xMaxEps = 1. - EPSILON;
1315 0 : qMinEps = qIni * (1. + EPSILON);
1316 0 : qMaxEps = qMax * (1. - EPSILON);
1317 :
1318 : // Initialize (x, Q) values of previous call.
1319 0 : xLast = 0.;
1320 0 : qLast = 0.;
1321 :
1322 0 : }
1323 :
1324 : //--------------------------------------------------------------------------
1325 :
1326 : // Update PDF values.
1327 :
1328 : void CTEQ6pdf::xfUpdate(int , double x, double Q2) {
1329 :
1330 : // Update using CTEQ6 routine, within allowed (x, q) range.
1331 0 : double xEps = max( xMinEps, x);
1332 0 : double qEps = max( qMinEps, min( qMaxEps, sqrtpos(Q2) ) );
1333 :
1334 : // Gluon:
1335 0 : double glu = xEps * parton6( 0, xEps, qEps);
1336 : // Sea quarks (note wrong order u, d):
1337 0 : double bot = xEps * parton6( 5, xEps, qEps);
1338 0 : double chm = xEps * parton6( 4, xEps, qEps);
1339 0 : double str = xEps * parton6( 3, xEps, qEps);
1340 0 : double usea = xEps * parton6(-1, xEps, qEps);
1341 0 : double dsea = xEps * parton6(-2, xEps, qEps);
1342 : // Valence quarks:
1343 0 : double upv = xEps * parton6( 1, xEps, qEps) - usea;
1344 0 : double dnv = xEps * parton6( 2, xEps, qEps) - dsea;
1345 :
1346 : // Transfer to Pythia notation.
1347 0 : xg = glu;
1348 0 : xu = upv + usea;
1349 0 : xd = dnv + dsea;
1350 0 : xubar = usea;
1351 0 : xdbar = dsea;
1352 0 : xs = str;
1353 0 : xsbar = str;
1354 0 : xc = chm;
1355 0 : xb = bot;
1356 0 : xgamma = 0.;
1357 :
1358 : // Subdivision of valence and sea.
1359 0 : xuVal = upv;
1360 0 : xuSea = usea;
1361 0 : xdVal = dnv;
1362 0 : xdSea = dsea;
1363 :
1364 : // idSav = 9 to indicate that all flavours reset.
1365 0 : idSav = 9;
1366 :
1367 0 : }
1368 :
1369 : //--------------------------------------------------------------------------
1370 :
1371 : // Returns the PDF value for parton of flavour iParton at x, q.
1372 :
1373 : double CTEQ6pdf::parton6(int iParton, double x, double q) {
1374 :
1375 : // Put zero for large x. Parton table and interpolation variables.
1376 0 : if (x > xMaxEps) return 0.;
1377 0 : int iP = (iParton > mxVal) ? -iParton : iParton;
1378 0 : double ss = pow( x, XPOWER);
1379 0 : double tt = log( log(q / lambda) );
1380 :
1381 : // Find location in grid.Skip if same as in latest call.
1382 0 : if (x != xLast || q != qLast) {
1383 :
1384 : // Binary search in x grid.
1385 0 : iGridX = 0;
1386 0 : iGridLX = -1;
1387 0 : int ju = nX + 1;
1388 : int jm = 0;
1389 0 : while (ju - iGridLX > 1 && jm >= 0) {
1390 0 : jm = (ju + iGridLX) / 2;
1391 0 : if (x >= xv[jm]) iGridLX = jm;
1392 : else ju = jm;
1393 : }
1394 :
1395 : // Separate acceptable from unacceptable grid points.
1396 0 : if (iGridLX <= -1) return 0.;
1397 0 : else if (iGridLX == 0) iGridX = 0;
1398 0 : else if (iGridLX <= nX - 2) iGridX = iGridLX - 1;
1399 0 : else if (iGridLX == nX - 1) iGridX = iGridLX - 2;
1400 0 : else return 0.;
1401 :
1402 : // Expressions for interpolation in x Grid.
1403 0 : if (iGridLX > 1 && iGridLX < nX - 1) {
1404 0 : double svec1 = xvpow[iGridX];
1405 0 : double svec2 = xvpow[iGridX+1];
1406 0 : double svec3 = xvpow[iGridX+2];
1407 0 : double svec4 = xvpow[iGridX+3];
1408 0 : double s12 = svec1 - svec2;
1409 0 : double s13 = svec1 - svec3;
1410 0 : xConst[8] = svec2 - svec3;
1411 0 : double s24 = svec2 - svec4;
1412 0 : double s34 = svec3 - svec4;
1413 0 : xConst[6] = ss - svec2;
1414 0 : xConst[7] = ss - svec3;
1415 0 : xConst[0] = s13 / xConst[8];
1416 0 : xConst[1] = s12 / xConst[8];
1417 0 : xConst[2] = s34 / xConst[8];
1418 0 : xConst[3] = s24 / xConst[8];
1419 0 : double s1213 = s12 + s13;
1420 0 : double s2434 = s24 + s34;
1421 0 : double sdet = s12 * s34 - s1213 * s2434;
1422 0 : double tmp = xConst[6] * xConst[7] / sdet;
1423 0 : xConst[4] = (s34 * xConst[6] - s2434 * xConst[7]) * tmp / s12;
1424 0 : xConst[5] = (s1213 * xConst[6] - s12 * xConst[7]) * tmp / s34;
1425 0 : }
1426 :
1427 : // Binary search in Q grid.
1428 0 : iGridQ = 0;
1429 0 : iGridLQ = -1;
1430 0 : ju = nT + 1;
1431 : jm = 0;
1432 0 : while (ju - iGridLQ > 1 && jm >= 0) {
1433 0 : jm = (ju + iGridLQ) / 2;
1434 0 : if (tt >= tv[jm]) iGridLQ = jm;
1435 : else ju = jm;
1436 : }
1437 0 : if (iGridLQ == 0) iGridQ = 0;
1438 0 : else if (iGridLQ <= nT - 2) iGridQ = iGridLQ - 1;
1439 0 : else iGridQ = nT - 3;
1440 :
1441 : // Expressions for interpolation in Q Grid.
1442 0 : if (iGridLQ > 0 && iGridLQ < nT - 1) {
1443 0 : double tvec1 = tv[iGridQ];
1444 0 : double tvec2 = tv[iGridQ+1];
1445 0 : double tvec3 = tv[iGridQ+2];
1446 0 : double tvec4 = tv[iGridQ+3];
1447 0 : double t12 = tvec1 - tvec2;
1448 0 : double t13 = tvec1 - tvec3;
1449 0 : tConst[8] = tvec2 - tvec3;
1450 0 : double t24 = tvec2 - tvec4;
1451 0 : double t34 = tvec3 - tvec4;
1452 0 : tConst[6] = tt - tvec2;
1453 0 : tConst[7] = tt - tvec3;
1454 0 : double tmp1 = t12 + t13;
1455 0 : double tmp2 = t24 + t34;
1456 0 : double tdet = t12 * t34 - tmp1 * tmp2;
1457 0 : tConst[0] = t13 / tConst[8];
1458 0 : tConst[1] = t12 / tConst[8];
1459 0 : tConst[2] = t34 / tConst[8];
1460 0 : tConst[3] = t24 / tConst[8];
1461 0 : tConst[4] = (t34 * tConst[6] - tmp2 * tConst[7]) / t12
1462 0 : * tConst[6] * tConst[7] / tdet;
1463 0 : tConst[5] = (tmp1 * tConst[6] - t12 * tConst[7]) / t34
1464 0 : * tConst[6] * tConst[7] / tdet;
1465 0 : }
1466 :
1467 : // Save x and q values so do not have to redo same again.
1468 0 : xLast = x;
1469 0 : qLast = q;
1470 0 : }
1471 :
1472 : // Jump to here if x and q are the same as for the last call.
1473 0 : int jtmp = ( (iP + nfMx) * (nT + 1) + (iGridQ - 1) ) * (nX + 1) + iGridX + 1;
1474 :
1475 : // Interpolate in x space for four different q values.
1476 0 : for(int it = 1; it <= 4; ++it) {
1477 0 : int j1 = jtmp + it * (nX + 1);
1478 0 : if (iGridX == 0) {
1479 0 : double fij[5];
1480 0 : fij[1] = 0.;
1481 0 : fij[2] = upd[j1+1] * pow2(xv[1]);
1482 0 : fij[3] = upd[j1+2] * pow2(xv[2]);
1483 0 : fij[4] = upd[j1+3] * pow2(xv[3]);
1484 0 : double fX = polint4F( &xvpow[0], &fij[1], ss);
1485 0 : fVec[it] = (x > 0.) ? fX / pow2(x) : 0.;
1486 0 : } else if (iGridLX==nX-1) {
1487 0 : fVec[it] = polint4F( &xvpow[nX-3], &upd[j1], ss);
1488 0 : } else {
1489 0 : double sf2 = upd[j1+1];
1490 0 : double sf3 = upd[j1+2];
1491 0 : double g1 = sf2 * xConst[0] - sf3 * xConst[1];
1492 0 : double g4 = -sf2 * xConst[2] + sf3 * xConst[3];
1493 0 : fVec[it] = (xConst[4] * (upd[j1] - g1) + xConst[5] * (upd[j1+3] - g4)
1494 0 : + sf2 * xConst[7] - sf3 * xConst[6]) / xConst[8];
1495 : }
1496 : }
1497 :
1498 : // Interpolate in q space for x-interpolated values found above.
1499 : double ff;
1500 0 : if( iGridLQ <= 0 ) {
1501 0 : ff = polint4F( &tv[0], &fVec[1], tt);
1502 0 : } else if (iGridLQ >= nT - 1) {
1503 0 : ff=polint4F( &tv[nT-3], &fVec[1], tt);
1504 0 : } else {
1505 0 : double tf2 = fVec[2];
1506 0 : double tf3 = fVec[3];
1507 0 : double g1 = tf2 * tConst[0] - tf3 * tConst[1];
1508 0 : double g4 = -tf2 * tConst[2] + tf3 * tConst[3];
1509 0 : ff = (tConst[4] * (fVec[1] - g1) + tConst[5] * (fVec[4] - g4)
1510 0 : + tf2 * tConst[7] - tf3 * tConst[6]) / tConst[8];
1511 : }
1512 :
1513 : // Done.
1514 : return ff;
1515 0 : }
1516 :
1517 : //--------------------------------------------------------------------------
1518 :
1519 : // The POLINT4 routine is based on the POLINT routine from "Numerical Recipes",
1520 : // but assuming N=4, and ignoring the error estimation.
1521 : // Suggested by Z. Sullivan.
1522 :
1523 : double CTEQ6pdf::polint4F(double xa[],double ya[],double x) {
1524 :
1525 : double y, h1, h2, h3, h4, w, den, d1, c1, d2, c2, d3, c3, cd1, cc1,
1526 : cd2, cc2, dd1, dc1;
1527 :
1528 0 : h1 = xa[0] - x;
1529 0 : h2 = xa[1] - x;
1530 0 : h3 = xa[2] - x;
1531 0 : h4 = xa[3] - x;
1532 :
1533 0 : w = ya[1] - ya[0];
1534 0 : den = w / (h1 - h2);
1535 0 : d1 = h2 * den;
1536 0 : c1 = h1 * den;
1537 :
1538 0 : w = ya[2] - ya[1];
1539 0 : den = w / (h2 - h3);
1540 0 : d2 = h3 * den;
1541 0 : c2 = h2 * den;
1542 :
1543 0 : w = ya[3] - ya[2];
1544 0 : den = w / (h3 - h4);
1545 0 : d3 = h4 * den;
1546 0 : c3 = h3 * den;
1547 :
1548 0 : w = c2 - d1;
1549 0 : den = w / (h1 - h3);
1550 0 : cd1 = h3 * den;
1551 0 : cc1 = h1 * den;
1552 :
1553 0 : w = c3 - d2;
1554 0 : den = w / (h2 - h4);
1555 0 : cd2 = h4 * den;
1556 0 : cc2 = h2 * den;
1557 :
1558 0 : w = cc2 - cd1;
1559 0 : den = w / (h1 - h4);
1560 0 : dd1 = h4 * den;
1561 0 : dc1 = h1 * den;
1562 :
1563 0 : if (h3 + h4 < 0.) y = ya[3] + d3 + cd2 + dd1;
1564 0 : else if (h2 + h3 < 0.) y = ya[2] + d2 + cd1 + dc1;
1565 0 : else if (h1 + h2 < 0.) y = ya[1] + c2 + cd1 + dc1;
1566 0 : else y = ya[0] + c1 + cc1 + dc1;
1567 :
1568 0 : return y;
1569 :
1570 : }
1571 :
1572 : //==========================================================================
1573 :
1574 : // SA Unresolved proton: equivalent photon spectrum from
1575 : // V.M. Budnev, I.F. Ginzburg, G.V. Meledin and V.G. Serbo,
1576 : // Phys. Rept. 15 (1974/1975) 181.
1577 :
1578 : // Constants:
1579 : const double ProtonPoint::ALPHAEM = 0.00729735;
1580 : const double ProtonPoint::Q2MAX = 2.0;
1581 : const double ProtonPoint::Q20 = 0.71;
1582 : const double ProtonPoint::A = 7.16;
1583 : const double ProtonPoint::B = -3.96;
1584 : const double ProtonPoint::C = 0.028;
1585 :
1586 : //--------------------------------------------------------------------------
1587 :
1588 : // Gives a generic Q2-independent equivalent photon spectrum.
1589 :
1590 : void ProtonPoint::xfUpdate(int , double x, double /*Q2*/ ) {
1591 :
1592 : // Photon spectrum
1593 0 : double tmpQ2Min = 0.88 * pow2(x);
1594 0 : double phiMax = phiFunc(x, Q2MAX / Q20);
1595 0 : double phiMin = phiFunc(x, tmpQ2Min / Q20);
1596 :
1597 : double fgm = 0;
1598 0 : if (phiMax < phiMin && m_infoPtr != 0) {
1599 0 : m_infoPtr->errorMsg("Error from ProtonPoint::xfUpdate: "
1600 : "phiMax - phiMin < 0!");
1601 0 : } else {
1602 : // Corresponds to: x*f(x)
1603 0 : fgm = (ALPHAEM / M_PI) * (1 - x) * (phiMax - phiMin);
1604 : }
1605 :
1606 : // Update values
1607 0 : xg = 0.;
1608 0 : xu = 0.;
1609 0 : xd = 0.;
1610 0 : xubar = 0.;
1611 0 : xdbar = 0.;
1612 0 : xs = 0.;
1613 0 : xsbar = 0.;
1614 0 : xc = 0.;
1615 0 : xb = 0.;
1616 0 : xgamma = fgm;
1617 :
1618 : // Subdivision of valence and sea.
1619 0 : xuVal = 0.;
1620 0 : xuSea = 0;
1621 0 : xdVal = 0.;
1622 0 : xdSea = 0;
1623 :
1624 : // idSav = 9 to indicate that all flavours reset.
1625 0 : idSav = 9;
1626 :
1627 0 : }
1628 :
1629 : //--------------------------------------------------------------------------
1630 :
1631 : // Function related to Q2 integration.
1632 :
1633 : double ProtonPoint::phiFunc(double x, double Q) {
1634 :
1635 0 : double tmpV = 1. + Q;
1636 : double tmpSum1 = 0;
1637 : double tmpSum2 = 0;
1638 0 : for (int k=1; k<4; ++k) {
1639 0 : tmpSum1 += 1. / (k * pow(tmpV, k));
1640 0 : tmpSum2 += pow(B, k) / (k * pow(tmpV, k));
1641 : }
1642 :
1643 0 : double tmpY = pow2(x) / (1 - x);
1644 0 : double funVal = (1 + A * tmpY) * (-1.*log(tmpV / Q) + tmpSum1)
1645 0 : + (1 - B) * tmpY / (4 * Q * pow(tmpV, 3))
1646 0 : + C * (1 + tmpY/4.)* (log((tmpV - B)/tmpV) + tmpSum2);
1647 :
1648 0 : return funVal;
1649 :
1650 : }
1651 :
1652 : //==========================================================================
1653 :
1654 : // Gives the GRV 1992 pi+ (leading order) parton distribution function set
1655 : // in parametrized form. Authors: Glueck, Reya and Vogt.
1656 : // Ref: M. Glueck, E. Reya and A. Vogt, Z. Phys. C53 (1992) 651.
1657 : // Allowed variable range: 0.25 GeV^2 < Q^2 < 10^8 GeV^2 and 10^-5 < x < 1.
1658 :
1659 : void GRVpiL::xfUpdate(int , double x, double Q2) {
1660 :
1661 : // Common expressions. Constrain Q2 for which parametrization is valid.
1662 : double mu2 = 0.25;
1663 : double lam2 = 0.232 * 0.232;
1664 0 : double s = (Q2 > mu2) ? log( log(Q2/lam2) / log(mu2/lam2) ) : 0.;
1665 0 : double s2 = s * s;
1666 0 : double x1 = 1. - x;
1667 0 : double xL = -log(x);
1668 0 : double xS = sqrt(x);
1669 :
1670 : // uv, dbarv.
1671 0 : double uv = (0.519 + 0.180 * s - 0.011 * s2) * pow(x, 0.499 - 0.027 * s)
1672 0 : * (1. + (0.381 - 0.419 * s) * xS) * pow(x1, 0.367 + 0.563 * s);
1673 :
1674 : // g.
1675 0 : double gl = ( pow(x, 0.482 + 0.341 * sqrt(s))
1676 0 : * ( (0.678 + 0.877 * s - 0.175 * s2) + (0.338 - 1.597 * s) * xS
1677 0 : + (-0.233 * s + 0.406 * s2) * x) + pow(s, 0.599)
1678 0 : * exp(-(0.618 + 2.070 * s) + sqrt(3.676 * pow(s, 1.263) * xL) ) )
1679 0 : * pow(x1, 0.390 + 1.053 * s);
1680 :
1681 : // sea: u, d, s.
1682 0 : double ub = pow(s, 0.55) * (1. - 0.748 * xS + (0.313 + 0.935 * s) * x)
1683 0 : * pow(x1, 3.359) * exp(-(4.433 + 1.301 * s) + sqrt((9.30 - 0.887 * s)
1684 0 : * pow(s, 0.56) * xL) ) / pow(xL, 2.538 - 0.763 * s);
1685 :
1686 : // c.
1687 0 : double chm = (s < 0.888) ? 0. : pow(s - 0.888, 1.02) * (1. + 1.008 * x)
1688 0 : * pow(x1, 1.208 + 0.771 * s) * exp(-(4.40 + 1.493 * s)
1689 0 : + sqrt( (2.032 + 1.901 * s) * pow(s, 0.39) * xL) );
1690 :
1691 : // b.
1692 0 : double bot = (s < 1.351) ? 0. : pow(s - 1.351, 1.03)
1693 0 : * pow(x1, 0.697 + 0.855 * s) * exp(-(4.51 + 1.490 * s)
1694 0 : + sqrt( (3.056 + 1.694 * s) * pow(s, 0.39) * xL) );
1695 :
1696 : // Update values.
1697 0 : xg = gl;
1698 0 : xu = uv + ub;
1699 0 : xd = ub;
1700 0 : xubar = ub;
1701 0 : xdbar = uv + ub;
1702 0 : xs = ub;
1703 0 : xsbar = ub;
1704 0 : xc = chm;
1705 0 : xb = bot;
1706 :
1707 : // Subdivision of valence and sea.
1708 0 : xuVal = uv;
1709 0 : xuSea = ub;
1710 0 : xdVal = uv;
1711 0 : xdSea = ub;
1712 :
1713 : // idSav = 9 to indicate that all flavours reset.
1714 0 : idSav = 9;
1715 :
1716 0 : }
1717 :
1718 : //==========================================================================
1719 :
1720 : // Pomeron PDF: simple Q2-independent parametrizations N x^a (1 - x)^b.
1721 :
1722 : //--------------------------------------------------------------------------
1723 :
1724 : // Calculate normalization factors once and for all.
1725 :
1726 : void PomFix::init() {
1727 :
1728 0 : normGluon = GammaReal(PomGluonA + PomGluonB + 2.)
1729 0 : / (GammaReal(PomGluonA + 1.) * GammaReal(PomGluonB + 1.));
1730 0 : normQuark = GammaReal(PomQuarkA + PomQuarkB + 2.)
1731 0 : / (GammaReal(PomQuarkA + 1.) * GammaReal(PomQuarkB + 1.));
1732 :
1733 0 : }
1734 :
1735 : //--------------------------------------------------------------------------
1736 :
1737 : // Gives a generic Q2-independent Pomeron PDF.
1738 :
1739 : void PomFix::xfUpdate(int , double x, double) {
1740 :
1741 : // Gluon and quark distributions.
1742 0 : double gl = normGluon * pow(x, PomGluonA) * pow( (1. - x), PomGluonB);
1743 0 : double qu = normQuark * pow(x, PomQuarkA) * pow( (1. - x), PomQuarkB);
1744 :
1745 : // Update values
1746 0 : xg = (1. - PomQuarkFrac) * gl;
1747 0 : xu = (PomQuarkFrac / (4. + 2. * PomStrangeSupp) ) * qu;
1748 0 : xd = xu;
1749 0 : xubar = xu;
1750 0 : xdbar = xu;
1751 0 : xs = PomStrangeSupp * xu;
1752 0 : xsbar = xs;
1753 0 : xc = 0.;
1754 0 : xb = 0.;
1755 :
1756 : // Subdivision of valence and sea.
1757 0 : xuVal = 0.;
1758 0 : xuSea = xu;
1759 0 : xdVal = 0.;
1760 0 : xdSea = xd;
1761 :
1762 : // idSav = 9 to indicate that all flavours reset.
1763 0 : idSav = 9;
1764 :
1765 0 : }
1766 :
1767 : //==========================================================================
1768 :
1769 : // Pomeron PDF: the H1 2006 Fit A and Fit B Q2-dependent parametrizations.
1770 :
1771 : //--------------------------------------------------------------------------
1772 :
1773 : void PomH1FitAB::init( int iFit, string xmlPath, Info* infoPtr) {
1774 :
1775 : // Open files from which grids should be read in.
1776 0 : if (xmlPath[ xmlPath.length() - 1 ] != '/') xmlPath += "/";
1777 0 : string dataFile = "pomH1FitBlo.data";
1778 0 : if (iFit == 1) dataFile = "pomH1FitA.data";
1779 0 : if (iFit == 2) dataFile = "pomH1FitB.data";
1780 0 : ifstream is( (xmlPath + dataFile).c_str() );
1781 0 : if (!is.good()) {
1782 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from PomH1FitAB::init: "
1783 : "the H1 Pomeron parametrization file was not found");
1784 0 : else cout << " Error from PomH1FitAB::init: "
1785 0 : << "the H1 Pomeron parametrization file was not found" << endl;
1786 0 : isSet = false;
1787 0 : return;
1788 : }
1789 :
1790 : // Lower and upper bounds. Bin widths for logarithmic spacing.
1791 0 : nx = 100;
1792 0 : xlow = 0.001;
1793 0 : xupp = 0.99;
1794 0 : dx = log(xupp / xlow) / (nx - 1.);
1795 0 : nQ2 = 30;
1796 0 : Q2low = 1.0;
1797 0 : Q2upp = 30000.;
1798 0 : dQ2 = log(Q2upp / Q2low) / (nQ2 - 1.);
1799 :
1800 : // Read in quark data grid.
1801 0 : for (int i = 0; i < nx; ++i)
1802 0 : for (int j = 0; j < nQ2; ++j)
1803 0 : is >> quarkGrid[i][j];
1804 :
1805 : // Read in gluon data grid.
1806 0 : for (int i = 0; i < nx; ++i)
1807 0 : for (int j = 0; j < nQ2; ++j)
1808 0 : is >> gluonGrid[i][j];
1809 :
1810 : // Check for errors during read-in of file.
1811 0 : if (!is) {
1812 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from PomH1FitAB::init: "
1813 : "the H1 Pomeron parametrization files could not be read");
1814 0 : else cout << " Error from PomH1FitAB::init: "
1815 0 : << "the H1 Pomeron parametrization files could not be read" << endl;
1816 0 : isSet = false;
1817 0 : return;
1818 : }
1819 :
1820 : // Done.
1821 0 : isSet = true;
1822 0 : return;
1823 0 : }
1824 :
1825 : //--------------------------------------------------------------------------
1826 :
1827 : void PomH1FitAB::xfUpdate(int , double x, double Q2) {
1828 :
1829 : // Retrict input to validity range.
1830 0 : double xt = min( xupp, max( xlow, x) );
1831 0 : double Q2t = min( Q2upp, max( Q2low, Q2) );
1832 :
1833 : // Lower grid point and distance above it.
1834 0 : double dlx = log( xt / xlow) / dx;
1835 0 : int i = min( nx - 2, int(dlx) );
1836 0 : dlx -= i;
1837 0 : double dlQ2 = log( Q2t / Q2low) / dQ2;
1838 0 : int j = min( nQ2 - 2, int(dlQ2) );
1839 0 : dlQ2 -= j;
1840 :
1841 : // Interpolate to derive quark PDF.
1842 0 : double qu = (1. - dlx) * (1. - dlQ2) * quarkGrid[i][j]
1843 0 : + dlx * (1. - dlQ2) * quarkGrid[i + 1][j]
1844 0 : + (1. - dlx) * dlQ2 * quarkGrid[i][j + 1]
1845 0 : + dlx * dlQ2 * quarkGrid[i + 1][j + 1];
1846 :
1847 : // Interpolate to derive gluon PDF.
1848 0 : double gl = (1. - dlx) * (1. - dlQ2) * gluonGrid[i][j]
1849 0 : + dlx * (1. - dlQ2) * gluonGrid[i + 1][j]
1850 0 : + (1. - dlx) * dlQ2 * gluonGrid[i][j + 1]
1851 0 : + dlx * dlQ2 * gluonGrid[i + 1][j + 1];
1852 :
1853 : // Update values.
1854 0 : xg = rescale * gl;
1855 0 : xu = rescale * qu;
1856 0 : xd = xu;
1857 0 : xubar = xu;
1858 0 : xdbar = xu;
1859 0 : xs = xu;
1860 0 : xsbar = xu;
1861 0 : xc = 0.;
1862 0 : xb = 0.;
1863 :
1864 : // Subdivision of valence and sea.
1865 0 : xuVal = 0.;
1866 0 : xuSea = xu;
1867 0 : xdVal = 0.;
1868 0 : xdSea = xu;
1869 :
1870 : // idSav = 9 to indicate that all flavours reset.
1871 0 : idSav = 9;
1872 :
1873 0 : }
1874 :
1875 : //==========================================================================
1876 :
1877 : // Pomeron PDF: the H1 2007 Jets Q2-dependent parametrization.
1878 :
1879 : //--------------------------------------------------------------------------
1880 :
1881 : void PomH1Jets::init( string xmlPath, Info* infoPtr) {
1882 :
1883 : // Open files from which grids should be read in.
1884 0 : if (xmlPath[ xmlPath.length() - 1 ] != '/') xmlPath += "/";
1885 0 : ifstream isg( (xmlPath + "pomH1JetsGluon.data").c_str() );
1886 0 : ifstream isq( (xmlPath + "pomH1JetsSinglet.data").c_str() );
1887 0 : ifstream isc( (xmlPath + "pomH1JetsCharm.data").c_str() );
1888 0 : if (!isg.good() || !isq.good() || !isc.good()) {
1889 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from PomH1Jets::init: "
1890 : "the H1 Pomeron parametrization files were not found");
1891 0 : else cout << " Error from PomH1Jets::init: "
1892 0 : << "the H1 Pomeron parametrization files were not found" << endl;
1893 0 : isSet = false;
1894 0 : return;
1895 : }
1896 :
1897 : // Read in x and Q grids. Do interpolation logarithmically in Q2.
1898 0 : for (int i = 0; i < 100; ++i) {
1899 0 : isg >> setw(13) >> xGrid[i];
1900 : }
1901 0 : for (int j = 0; j < 88; ++j) {
1902 0 : isg >> setw(13) >> Q2Grid[j];
1903 0 : Q2Grid[j] = log( Q2Grid[j] );
1904 : }
1905 :
1906 : // Read in gluon data grid.
1907 0 : for (int j = 0; j < 88; ++j) {
1908 0 : for (int i = 0; i < 100; ++i) {
1909 0 : isg >> setw(13) >> gluonGrid[i][j];
1910 : }
1911 : }
1912 :
1913 : // Identical x and Q2 grid for singlet, so skip ahead.
1914 0 : double dummy;
1915 0 : for (int i = 0; i < 188; ++i) isq >> setw(13) >> dummy;
1916 :
1917 : // Read in singlet data grid.
1918 0 : for (int j = 0; j < 88; ++j) {
1919 0 : for (int i = 0; i < 100; ++i) {
1920 0 : isq >> setw(13) >> singletGrid[i][j];
1921 : }
1922 : }
1923 :
1924 : // Identical x and Q2 grid for charm, so skip ahead.
1925 0 : for (int i = 0; i < 188; ++i) isc >> setw(13) >> dummy;
1926 :
1927 : // Read in charm data grid.
1928 0 : for (int j = 0; j < 88; ++j) {
1929 0 : for (int i = 0; i < 100; ++i) {
1930 0 : isc >> setw(13) >> charmGrid[i][j];
1931 : }
1932 : }
1933 :
1934 : // Check for errors during read-in of files.
1935 0 : if (!isg || !isq || !isc) {
1936 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from PomH1Jets::init: "
1937 : "the H1 Pomeron parametrization files could not be read");
1938 0 : else cout << " Error from PomH1Jets::init: "
1939 0 : << "the H1 Pomeron parametrization files could not be read" << endl;
1940 0 : isSet = false;
1941 0 : return;
1942 : }
1943 :
1944 : // Done.
1945 0 : isSet = true;
1946 0 : return;
1947 0 : }
1948 :
1949 : //--------------------------------------------------------------------------
1950 :
1951 : void PomH1Jets::xfUpdate(int , double x, double Q2) {
1952 :
1953 : // Find position in x array.
1954 0 : double xLog = log(x);
1955 : int i = 0;
1956 : double dx = 0.;
1957 0 : if (xLog <= xGrid[0]);
1958 0 : else if (xLog >= xGrid[99]) {
1959 : i = 98;
1960 : dx = 1.;
1961 0 : } else {
1962 0 : while (xLog > xGrid[i]) ++i;
1963 0 : --i;
1964 0 : dx = (xLog - xGrid[i]) / (xGrid[i + 1] - xGrid[i]);
1965 : }
1966 :
1967 : // Find position in y array.
1968 0 : double Q2Log = log(Q2);
1969 : int j = 0;
1970 : double dQ2 = 0.;
1971 0 : if (Q2Log <= Q2Grid[0]);
1972 0 : else if (Q2Log >= Q2Grid[87]) {
1973 : j = 86;
1974 : dQ2 = 1.;
1975 0 : } else {
1976 0 : while (Q2Log > Q2Grid[j]) ++j;
1977 0 : --j;
1978 0 : dQ2 = (Q2Log - Q2Grid[j]) / (Q2Grid[j + 1] - Q2Grid[j]);
1979 : }
1980 :
1981 : // Interpolate to derive gluon PDF.
1982 0 : double gl = (1. - dx) * (1. - dQ2) * gluonGrid[i][j]
1983 0 : + dx * (1. - dQ2) * gluonGrid[i + 1][j]
1984 0 : + (1. - dx) * dQ2 * gluonGrid[i][j + 1]
1985 0 : + dx * dQ2 * gluonGrid[i + 1][j + 1];
1986 :
1987 : // Interpolate to derive singlet PDF. (Sum of u, d, s, ubar, dbar, sbar.)
1988 0 : double sn = (1. - dx) * (1. - dQ2) * singletGrid[i][j]
1989 0 : + dx * (1. - dQ2) * singletGrid[i + 1][j]
1990 0 : + (1. - dx) * dQ2 * singletGrid[i][j + 1]
1991 0 : + dx * dQ2 * singletGrid[i + 1][j + 1];
1992 :
1993 : // Interpolate to derive charm PDF. (Charge-square times c and cbar.)
1994 0 : double ch = (1. - dx) * (1. - dQ2) * charmGrid[i][j]
1995 0 : + dx * (1. - dQ2) * charmGrid[i + 1][j]
1996 0 : + (1. - dx) * dQ2 * charmGrid[i][j + 1]
1997 0 : + dx * dQ2 * charmGrid[i + 1][j + 1];
1998 :
1999 : // Update values.
2000 0 : xg = rescale * gl;
2001 0 : xu = rescale * sn / 6.;
2002 0 : xd = xu;
2003 0 : xubar = xu;
2004 0 : xdbar = xu;
2005 0 : xs = xu;
2006 0 : xsbar = xu;
2007 0 : xc = rescale * ch * 9./8.;
2008 0 : xb = 0.;
2009 :
2010 : // Subdivision of valence and sea.
2011 0 : xuVal = 0.;
2012 0 : xuSea = xu;
2013 0 : xdVal = 0.;
2014 0 : xdSea = xd;
2015 :
2016 : // idSav = 9 to indicate that all flavours reset.
2017 0 : idSav = 9;
2018 :
2019 0 : }
2020 :
2021 : //==========================================================================
2022 :
2023 : // Gives electron (or muon, or tau) parton distribution.
2024 :
2025 : // Constants: alphaEM(0), m_e, m_mu, m_tau.
2026 : const double Lepton::ALPHAEM = 0.00729735;
2027 : const double Lepton::ME = 0.0005109989;
2028 : const double Lepton::MMU = 0.10566;
2029 : const double Lepton::MTAU = 1.77699;
2030 :
2031 : void Lepton::xfUpdate(int id, double x, double Q2) {
2032 :
2033 : // Squared mass of lepton species: electron, muon, tau.
2034 0 : if (!isInit) {
2035 0 : double mLep = ME;
2036 0 : if (abs(id) == 13) mLep = MMU;
2037 0 : if (abs(id) == 15) mLep = MTAU;
2038 0 : m2Lep = pow2( mLep );
2039 0 : isInit = true;
2040 0 : }
2041 :
2042 : // Electron inside electron, see R. Kleiss et al., in Z physics at
2043 : // LEP 1, CERN 89-08, p. 34
2044 0 : double xLog = log(max(1e-10,x));
2045 0 : double xMinusLog = log( max(1e-10, 1. - x) );
2046 0 : double Q2Log = log( max(3., Q2/m2Lep) );
2047 0 : double beta = (ALPHAEM / M_PI) * (Q2Log - 1.);
2048 0 : double delta = 1. + (ALPHAEM / M_PI) * (1.5 * Q2Log + 1.289868)
2049 0 : + pow2(ALPHAEM / M_PI) * (-2.164868 * Q2Log*Q2Log
2050 0 : + 9.840808 * Q2Log - 10.130464);
2051 0 : double fPrel = beta * pow(1. - x, beta - 1.) * sqrtpos( delta )
2052 0 : - 0.5 * beta * (1. + x) + 0.125 * beta*beta * ( (1. + x)
2053 0 : * (-4. * xMinusLog + 3. * xLog) - 4. * xLog / (1. - x) - 5. - x);
2054 :
2055 : // Zero distribution for very large x and rescale it for intermediate.
2056 0 : if (x > 1. - 1e-10) fPrel = 0.;
2057 0 : else if (x > 1. - 1e-7) fPrel *= pow(1000.,beta) / (pow(1000.,beta) - 1.);
2058 0 : xlepton = x * fPrel;
2059 :
2060 : // Photon inside electron (one possible scheme - primitive).
2061 0 : xgamma = (0.5 * ALPHAEM / M_PI) * Q2Log * (1. + pow2(1. - x));
2062 :
2063 : // idSav = 9 to indicate that all flavours reset.
2064 0 : idSav = 9;
2065 :
2066 0 : }
2067 :
2068 : //==========================================================================
2069 :
2070 : // The NNPDF class.
2071 : // Code for handling NNPDF2.3 QCD+QED LO
2072 : // Code provided by Juan Rojo and Stefano Carrazza.
2073 :
2074 : //--------------------------------------------------------------------------
2075 :
2076 : // Freeze PDFs below XMINGRID
2077 : const double NNPDF::fXMINGRID = 1e-9;
2078 :
2079 : //--------------------------------------------------------------------------
2080 :
2081 : // Initialize PDF: read in data grid from file.
2082 :
2083 : void NNPDF::init(int iFitIn, string xmlPath, Info* infoPtr) {
2084 :
2085 : // Choice of fit among possibilities.
2086 0 : iFit = iFitIn;
2087 :
2088 : // Select which data file to read for current fit.
2089 0 : if (xmlPath[ xmlPath.length() - 1 ] != '/') xmlPath += "/";
2090 0 : string fileName = " ";
2091 : // NNPDF2.3 LO QCD+QED, for two values of alphas
2092 0 : if (iFit == 1) fileName = "NNPDF23_lo_as_0130_qed_mem0.grid";
2093 0 : if (iFit == 2) fileName = "NNPDF23_lo_as_0119_qed_mem0.grid";
2094 : // NNPDF2.3 NLO QCD+QED
2095 0 : if (iFit == 3) fileName = "NNPDF23_nlo_as_0119_qed_mc_mem0.grid";
2096 : // NNPDF2.4 NLO QCD+QED
2097 0 : if (iFit == 4) fileName = "NNPDF23_nnlo_as_0119_qed_mc_mem0.grid";
2098 :
2099 : // Open data file.
2100 0 : fstream f;
2101 0 : f.open( (xmlPath + fileName).c_str(),ios::in);
2102 0 : if (f.fail()) {
2103 0 : if (infoPtr != 0) infoPtr->errorMsg("Error from NNPDF::init: "
2104 0 : "did not find data file ", fileName);
2105 0 : else cout << "Error: cannot open file " << (xmlPath + fileName) << endl;
2106 0 : isSet = false;
2107 0 : return;
2108 : }
2109 :
2110 : // Reading grid: removing header.
2111 0 : string tmp;
2112 0 : for (;;) {
2113 0 : getline(f,tmp);
2114 0 : if (tmp.find("NNPDF20intqed") != string::npos) {
2115 0 : getline(f,tmp);
2116 : break;
2117 : }
2118 : }
2119 :
2120 : // Get nx and x grid.
2121 0 : f >> fNX;
2122 0 : fXGrid = new double[fNX];
2123 0 : for (int ix = 0; ix < fNX; ix++) f >> fXGrid[ix];
2124 0 : fLogXGrid = new double[fNX];
2125 0 : for (int ix = 0; ix < fNX; ix++) fLogXGrid[ix] = log(fXGrid[ix]);
2126 :
2127 : // Get nQ2 and Q2 grid (ignorming first value).
2128 0 : f >> fNQ2;
2129 0 : f >> tmp;
2130 0 : fQ2Grid = new double[fNQ2];
2131 0 : for (int iq = 0; iq < fNQ2; iq++) f >> fQ2Grid[iq];
2132 0 : fLogQ2Grid = new double[fNQ2];
2133 0 : for (int iq = 0; iq < fNQ2; iq++) fLogQ2Grid[iq] = log(fQ2Grid[iq]);
2134 :
2135 : // Prepare grid array.
2136 0 : fPDFGrid = new double**[fNFL];
2137 0 : for (int i = 0; i < fNFL; i++) {
2138 0 : fPDFGrid[i] = new double*[fNX];
2139 0 : for (int j = 0; j < fNX; j++) {
2140 0 : fPDFGrid[i][j] = new double[fNQ2];
2141 0 : for (int z = 0; z < fNQ2; z++) fPDFGrid[i][j][z] = 0.0;
2142 : }
2143 : }
2144 :
2145 : // Check values of number of grid entries.
2146 0 : if (fNX<= 0 || fNX>100 || fNQ2<=0 || fNQ2>50) {
2147 0 : cout << "Error in NNPDF::init, Invalid grid values" << endl
2148 0 : << "fNX = " << fNX << endl << "fNQ2 = " << fNQ2 << endl
2149 0 : << "fNFL = " <<fNFL << endl;
2150 0 : isSet = false;
2151 0 : return;
2152 : }
2153 :
2154 : // Ignore replica number. Read PDF grid points.
2155 0 : f >> tmp;
2156 0 : for (int ix = 0; ix < fNX; ix++)
2157 0 : for (int iq = 0; iq < fNQ2; iq++)
2158 0 : for (int fl = 0; fl < fNFL; fl++)
2159 0 : f >> fPDFGrid[fl][ix][iq];
2160 0 : f.close();
2161 :
2162 : // Other vectors.
2163 0 : fRes = new double[fNFL];
2164 :
2165 0 : }
2166 :
2167 : //--------------------------------------------------------------------------
2168 :
2169 : void NNPDF::xfUpdate(int , double x, double Q2) {
2170 :
2171 : // Update using NNPDF routine, within allowed (x, q) range.
2172 0 : xfxevolve(x,Q2);
2173 :
2174 : // Then transfer to Pythia8 notation.
2175 0 : xg = fRes[6];
2176 0 : xu = fRes[8];
2177 0 : xd = fRes[7];
2178 0 : xubar = fRes[4];
2179 0 : xdbar = fRes[5];
2180 0 : xs = fRes[9];
2181 0 : xsbar = fRes[3];
2182 0 : xc = fRes[10];
2183 0 : xb = fRes[11];
2184 0 : xgamma = fRes[13];
2185 :
2186 : // Subdivision of valence and sea.
2187 0 : xuVal = xu - xubar;
2188 0 : xuSea = xubar;
2189 0 : xdVal = xd - xdbar;
2190 0 : xdSea = xdbar;
2191 :
2192 : // idSav = 9 to indicate that all flavours reset.
2193 0 : idSav = 9;
2194 :
2195 0 : }
2196 :
2197 : //--------------------------------------------------------------------------
2198 :
2199 : void NNPDF::xfxevolve(double x, double Q2) {
2200 :
2201 : // Freeze outside x-Q2 grid.
2202 0 : if (x < fXMINGRID || x > fXGrid[fNX-1]) {
2203 0 : if (x < fXMINGRID) x = fXMINGRID;
2204 0 : if (x > fXGrid[fNX-1]) x = fXGrid[fNX-1];
2205 : }
2206 0 : if (Q2 < fQ2Grid[0] || Q2 > fQ2Grid[fNQ2-1]) {
2207 0 : if (Q2 < fQ2Grid[0]) Q2 = fQ2Grid[0];
2208 0 : if (Q2 > fQ2Grid[fNQ2-1]) Q2 = fQ2Grid[fNQ2-1];
2209 : }
2210 :
2211 : // Find nearest points in the x-Q2 grid.
2212 : int minx = 0;
2213 0 : int maxx = fNX;
2214 0 : while (maxx-minx > 1) {
2215 0 : int midx = (minx+maxx)/2;
2216 0 : if (x < fXGrid[midx]) maxx = midx;
2217 : else minx = midx;
2218 : }
2219 : int ix = minx;
2220 : int minq = 0;
2221 0 : int maxq = fNQ2;
2222 0 : while (maxq-minq > 1) {
2223 0 : int midq = (minq+maxq)/2;
2224 0 : if (Q2 < fQ2Grid[midq]) maxq = midq;
2225 : else minq = midq;
2226 : }
2227 : int iq2 = minq;
2228 :
2229 : // Assign grid for interpolation. M,N -> order of polyN interpolation.
2230 0 : int ix1a[fM], ix2a[fN];
2231 0 : double x1a[fM], x2a[fN];
2232 0 : double ya[fM][fN];
2233 :
2234 0 : for (int i = 0; i < fM; i++) {
2235 0 : if (ix+1 >= fM/2 && ix+1 <= (fNX-fM/2)) ix1a[i] = ix+1 - fM/2 + i;
2236 0 : if (ix+1 < fM/2) ix1a[i] = i;
2237 0 : if (ix+1 > (fNX-fM/2)) ix1a[i] = (fNX-fM) + i;
2238 : // Check grids.
2239 0 : if (ix1a[i] < 0 || ix1a[i] >= fNX) {
2240 0 : cout << "Error in grids! i, ixia[i] = " << i << "\t" << ix1a[i] << endl;
2241 0 : return;
2242 : }
2243 : }
2244 :
2245 0 : for (int j = 0; j < fN; j++) {
2246 0 : if (iq2+1 >= fN/2 && iq2+1 <= (fNQ2-fN/2)) ix2a[j] = iq2+1 - fN/2 + j;
2247 0 : if (iq2+1 < fN/2) ix2a[j] = j;
2248 0 : if (iq2+1 > (fNQ2-fN/2)) ix2a[j] = (fNQ2-fN) + j;
2249 : // Check grids.
2250 0 : if (ix2a[j] < 0 || ix2a[j] >= fNQ2) {
2251 0 : cout << "Error in grids! j, ix2a[j] = " << j << "\t" << ix2a[j] << endl;
2252 0 : return;
2253 : }
2254 : }
2255 :
2256 : const double xch = 1e-1;
2257 : double x1;
2258 0 : if (x < xch) x1 = log(x);
2259 : else x1 = x;
2260 0 : double x2 = log(Q2);
2261 :
2262 0 : for (int ipdf = 0; ipdf < fNFL; ipdf++) {
2263 0 : fRes[ipdf] = 0.0;
2264 0 : for (int i = 0; i < fM; i++) {
2265 0 : if (x < xch) x1a[i] = fLogXGrid[ix1a[i]];
2266 0 : else x1a[i] = fXGrid[ix1a[i]];
2267 :
2268 0 : for (int j = 0; j < fN; j++) {
2269 0 : x2a[j] = fLogQ2Grid[ix2a[j]];
2270 0 : ya[i][j] = fPDFGrid[ipdf][ix1a[i]][ix2a[j]];
2271 : }
2272 : }
2273 :
2274 : // 2D polynomial interpolation.
2275 0 : double y = 0, dy = 0;
2276 0 : polin2(x1a,x2a,ya,x1,x2,y,dy);
2277 0 : fRes[ipdf] = y;
2278 0 : }
2279 :
2280 0 : }
2281 :
2282 : //--------------------------------------------------------------------------
2283 :
2284 : // 1D polynomial interpolation.
2285 :
2286 : void NNPDF::polint(double xa[], double yal[], int n, double x,
2287 : double& y, double& dy) {
2288 :
2289 : int ns = 0;
2290 0 : double dif = abs(x-xa[0]);
2291 0 : double c[fM > fN ? fM : fN];
2292 0 : double d[fM > fN ? fM : fN];
2293 :
2294 0 : for (int i = 0; i < n; i++) {
2295 0 : double dift = abs(x-xa[i]);
2296 0 : if (dift < dif) {
2297 : ns = i;
2298 : dif = dift;
2299 0 : }
2300 0 : c[i] = yal[i];
2301 0 : d[i] = yal[i];
2302 : }
2303 0 : y = yal[ns];
2304 0 : ns--;
2305 0 : for (int m = 1; m < n; m++) {
2306 0 : for (int i = 0; i < n-m; i++) {
2307 0 : double ho = xa[i]-x;
2308 0 : double hp = xa[i+m]-x;
2309 0 : double w = c[i+1]-d[i];
2310 0 : double den = ho-hp;
2311 0 : if (den == 0) {
2312 0 : cout << "NNPDF::polint, failure" << endl;
2313 0 : return;
2314 : }
2315 0 : den = w/den;
2316 0 : d[i] = hp*den;
2317 0 : c[i] = ho*den;
2318 0 : }
2319 0 : if (2*(ns+1) < n-m) dy = c[ns+1];
2320 : else {
2321 0 : dy = d[ns];
2322 0 : ns--;
2323 : }
2324 0 : y+=dy;
2325 : }
2326 0 : }
2327 :
2328 : //--------------------------------------------------------------------------
2329 :
2330 : // 2D polynomial interpolation.
2331 :
2332 : void NNPDF::polin2(double x1al[], double x2al[], double yal[][fN],
2333 : double x1, double x2, double& y, double& dy) {
2334 :
2335 0 : double yntmp[fN];
2336 0 : double ymtmp[fM];
2337 :
2338 0 : for (int j = 0; j < fM; j++) {
2339 0 : for (int k = 0; k < fN; k++) yntmp[k] = yal[j][k];
2340 0 : polint(x2al,yntmp,fN,x2,ymtmp[j],dy);
2341 : }
2342 0 : polint(x1al,ymtmp,fM,x1,y,dy);
2343 :
2344 0 : }
2345 :
2346 : //==========================================================================
2347 :
2348 : // LHAPDF plugin interface.
2349 :
2350 : //--------------------------------------------------------------------------
2351 :
2352 : // Constructor.
2353 :
2354 0 : LHAPDF::LHAPDF(int idIn, string pSet, Info* infoPtrIn) :
2355 0 : pdfPtr(0), infoPtr(infoPtrIn) {
2356 0 : isSet = false;
2357 0 : if (!infoPtr) return;
2358 :
2359 : // Determine the plugin library name.
2360 0 : if (pSet.size() < 8) {
2361 0 : infoPtr->errorMsg("Error from LHAPDF::LHAPDF: invalid pSet " + pSet);
2362 0 : return;
2363 : }
2364 0 : libName = pSet.substr(0, 7);
2365 0 : if (libName != "LHAPDF5" && libName != "LHAPDF6") {
2366 0 : infoPtr->errorMsg("Error from LHAPDF::LHAPDF: invalid pSet " + pSet);
2367 0 : return;
2368 : }
2369 0 : libName = "libpythia8lhapdf" + libName.substr(6) + ".so";
2370 :
2371 : // Determine the PDF set and member.
2372 0 : string set = pSet.substr(8);
2373 0 : int mem = 0;
2374 0 : size_t pos = set.find_last_of("/");
2375 0 : if (pos != string::npos) {
2376 0 : istringstream memStream(set.substr(pos + 1));
2377 0 : memStream >> mem;
2378 0 : }
2379 0 : set = set.substr(0, pos);
2380 :
2381 : // Load the PDF.
2382 0 : NewLHAPDF* newLHAPDF = (NewLHAPDF*)symbol("newLHAPDF");
2383 0 : if (!newLHAPDF) return;
2384 0 : pdfPtr = newLHAPDF(idIn, set, mem, infoPtr);
2385 0 : isSet = true;
2386 :
2387 0 : }
2388 :
2389 : //--------------------------------------------------------------------------
2390 :
2391 : // Destructor.
2392 :
2393 0 : LHAPDF::~LHAPDF() {
2394 0 : if (!infoPtr) return;
2395 0 : if (!isSet) return;
2396 :
2397 : // Delete the PDF.
2398 0 : DeleteLHAPDF* deleteLHAPDF = (DeleteLHAPDF*)symbol("deleteLHAPDF");
2399 0 : if (deleteLHAPDF) deleteLHAPDF(pdfPtr);
2400 :
2401 : // Close the plugin library if not needed by other instances.
2402 0 : map<string, pair<void*, int> >::iterator plugin =
2403 0 : infoPtr->plugins.find(libName);
2404 0 : if (plugin == infoPtr->plugins.end()) return;
2405 0 : --plugin->second.second;
2406 0 : if (plugin->second.first && plugin->second.second == 0) {
2407 0 : dlclose(plugin->second.first);
2408 0 : dlerror();
2409 0 : infoPtr->plugins.erase(plugin);
2410 0 : }
2411 :
2412 0 : }
2413 :
2414 : //--------------------------------------------------------------------------
2415 :
2416 : // Access a plugin library symbol.
2417 :
2418 : LHAPDF::Symbol LHAPDF::symbol(string symName) {
2419 0 : void *lib(0);
2420 : Symbol sym(0);
2421 : const char* error(0);
2422 0 : if (!infoPtr) return sym;
2423 :
2424 : // Load the library if not loaded.
2425 0 : map<string, pair<void*, int> >::iterator plugin =
2426 0 : infoPtr->plugins.find(libName);
2427 0 : if (plugin == infoPtr->plugins.end()) {
2428 0 : lib = dlopen(libName.c_str(), RTLD_LAZY);
2429 0 : error = dlerror();
2430 0 : }
2431 0 : if (error) {
2432 0 : infoPtr->errorMsg("Error from LHAPDF::symbol: " + string(error));
2433 0 : return sym;
2434 : }
2435 0 : if (plugin == infoPtr->plugins.end())
2436 0 : infoPtr->plugins[libName] = pair<void*, int>(lib, 1);
2437 : else {
2438 0 : lib = plugin->second.first;
2439 0 : ++plugin->second.second;
2440 : }
2441 0 : dlerror();
2442 :
2443 : // Load the symbol.
2444 0 : sym = (Symbol)dlsym(lib, symName.c_str());
2445 0 : error = dlerror();
2446 0 : if (error) infoPtr->errorMsg("Error from LHAPDF::symbol: " + string(error));
2447 0 : dlerror();
2448 0 : return sym;
2449 :
2450 0 : }
2451 :
2452 : //==========================================================================
2453 :
2454 : } // end namespace Pythia8
|