GM2Calc 2.3.0
Loading...
Searching...
No Matches
gm2_ffunctions.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of GM2Calc.
3//
4// GM2Calc is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// GM2Calc is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with GM2Calc. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
19#include "gm2_ffunctions.hpp"
20#include "gm2_dilog.hpp"
21#include "gm2_log.hpp"
22#include "gm2_numerics.hpp"
23
24#include <algorithm>
25#include <cmath>
26#include <limits>
27#include <tuple>
28
29namespace gm2calc {
30
31namespace {
32 constexpr double eps = 10.0*std::numeric_limits<double>::epsilon();
33 const double qdrt_eps = std::pow(eps, 0.25);
34
35 /// shift values symmetrically away from equality, if they are close
36 void shift(double& x, double& y, double rel_diff) noexcept
37 {
38 if (is_equal_rel(x, y, rel_diff)) {
39 const double mid = 0.5*std::abs(y + x);
40 if (x < y) {
41 x = (1 - rel_diff)*mid;
42 y = (1 + rel_diff)*mid;
43 } else {
44 x = (1 + rel_diff)*mid;
45 y = (1 - rel_diff)*mid;
46 }
47 }
48 }
49
50 void sort(double& x, double& y) noexcept
51 {
52 if (x > y) { std::swap(x, y); }
53 }
54
55 void sort(double& x, double& y, double& z) noexcept
56 {
57 if (x > y) { std::swap(x, y); }
58 if (y > z) { std::swap(y, z); }
59 if (x > y) { std::swap(x, y); }
60 }
61
62 /// calculates phi(xd, xu, 1)/y with y = (xu - xd)^2 - 2*(xu + xd) + 1,
63 /// properly handle the case y = 0
64 double phi_over_y(double xu, double xd) noexcept
65 {
66 const double sqrtxd = std::sqrt(xd);
67 const double ixd = 1/xd;
68 constexpr double eps = 1e-8;
69
70 // test two cases where y == 0
71 if (std::abs((xu - 1)*ixd + 2/sqrtxd - 1) < eps) {
72 return -std::log(std::abs(-1 + sqrtxd))/sqrtxd + std::log(xd)/(2*(-1 + sqrtxd));
73 } else if (std::abs((xu - 1)*ixd - 2/sqrtxd - 1) < eps) {
74 return std::log(1 + sqrtxd)/sqrtxd - std::log(xd)/(2*(1 + sqrtxd));
75 }
76
77 const double y = sqr(xu - xd) - 2*(xu + xd) + 1;
78 const double phi = Phi(xd, xu, 1);
79
80 return phi/y;
81 }
82
83 /// lambda^2(u,v)
84 double lambda_2(double u, double v) noexcept
85 {
86 return sqr(1 - u - v) - 4*u*v;
87 }
88
89 /// expansion of (1 - lambda + u - v)/2 for u ~ v ~ 0 up to including O(u^3 v^3)
90 double l00(double u, double v) noexcept
91 {
92 return v*(1 + u*(1 + u*(1 + u)) + v*(u*(1 + u*(3 + 6*u)) + u*(1 + u*(6 + 20*u))*v));
93 }
94
95 /// expansion of (1 - lambda + u - v)/2 for u ~ 0 and v < 1 up to including O(u^3 v^3)
96 double l0v(double u, double v) noexcept
97 {
98 const double a = 1 - v;
99 const double a2 = a*a;
100 const double a3 = a2*a;
101 return u*(0.5*(1 + (1 + v)/a) + u*(v + u*v*(1 + v)/a2)/a3);
102 }
103
104 /// expansion of (1 - lambda - u + v)/2 for u ~ 0 and v < 1 up to including O(u^3 v^3)
105 double lv0(double u, double v) noexcept
106 {
107 const double a = 1 - v;
108 const double a2 = a*a;
109 const double a3 = a2*a;
110 return v + u*(0.5*(-1 + (1 + v)/a) + u*(v + u*v*(1 + v)/a2)/a3);
111 }
112
113 /// returns tuple (0.5*(1 - lambda + u - v), 0.5*(1 - lambda - u + v))
114 std::tuple<double,double> luv(double lambda, double u, double v) noexcept
115 {
116 if (v < qdrt_eps) {
117 return std::make_tuple(l00(u, v), l00(v, u));
118 } else if (u < qdrt_eps) {
119 return std::make_tuple(l0v(u, v), lv0(u, v));
120 }
121 return std::make_tuple(0.5*(1 - lambda + u - v),
122 0.5*(1 - lambda - u + v));
123 }
124
125 /// u < 1 && v < 1, lambda^2(u,v) > 0; note: phi_pos(u,v) = phi_pos(v,u)
126 double phi_pos(double u, double v) noexcept
127 {
128 if (is_equal_rel(u, 1.0, eps) && is_equal_rel(v, 1.0, eps)) {
129 return 2.343907238689459;
130 }
131
132 const double pi23 = 3.2898681336964529; // Pi^2/3
133 const auto lambda = std::sqrt(lambda_2(u,v));
134
135 if (is_equal_rel(u, v, eps)) {
136 const double x = u < qdrt_eps ? u*(1 + u*(1 + u*(2 + 5*u))) : 0.5*(1 - lambda);
137
138 return (- sqr(std::log(u)) + 2*sqr(std::log(x))
139 - 4*dilog(x) + pi23)/lambda;
140 }
141
142 double x = 0, y = 0;
143 std::tie(x, y) = luv(lambda, u, v);
144
145 return (- std::log(u)*std::log(v) + 2*std::log(x)*std::log(y)
146 - 2*dilog(x) - 2*dilog(y) + pi23)/lambda;
147 }
148
149 /// clausen_2(2*acos(x))
150 double cl2acos(double x) noexcept
151 {
152 return clausen_2(2*std::acos(x));
153 }
154
155 /// lambda^2(u,v) < 0, u = 1
156 double phi_neg_1v(double v) noexcept
157 {
158 return 2*(cl2acos(1 - 0.5*v) + 2*cl2acos(0.5*std::sqrt(v)));
159 }
160
161 /// lambda^2(u,v) < 0; note: phi_neg(u,v) = phi_neg(v,u)
162 double phi_neg(double u, double v) noexcept
163 {
164 if (is_equal_rel(u, 1.0, eps) && is_equal_rel(v, 1.0, eps)) {
165 // -I/9 (Pi^2 - 36 PolyLog[2, (1 - I Sqrt[3])/2])/Sqrt[3]
166 return 2.343907238689459;
167 }
168
169 const auto lambda = std::sqrt(-lambda_2(u,v));
170
171 if (is_equal_rel(u, v, eps)) {
172 return 4*clausen_2(2*std::asin(std::sqrt(0.25/u)))/lambda;
173 }
174
175 if (is_equal_rel(u, 1.0, eps)) {
176 return phi_neg_1v(v)/lambda;
177 }
178
179 if (is_equal_rel(v, 1.0, eps)) {
180 return phi_neg_1v(u)/lambda;
181 }
182
183 const auto sqrtu = std::sqrt(u);
184 const auto sqrtv = std::sqrt(v);
185
186 return 2*(+ cl2acos(0.5*(1 + u - v)/sqrtu)
187 + cl2acos(0.5*(1 - u + v)/sqrtv)
188 + cl2acos(0.5*(-1 + u + v)/(sqrtu*sqrtv)))/lambda;
189 }
190
191 /**
192 * Phi(u,v) with u = x/z, v = y/z.
193 *
194 * The following identities hold:
195 * Phi(u,v) = Phi(v,u) = Phi(1/u,v/u)/u = Phi(1/v,u/v)/v
196 */
197 double phi_uv(double u, double v) noexcept
198 {
199 const auto lambda = lambda_2(u,v);
200
201 if (is_zero(lambda, eps)) {
202 // phi_uv is always multiplied by lambda. So, in order to
203 // avoid nans if lambda == 0, we simply return 0
204 return 0.0;
205 }
206
207 if (lambda > 0.) {
208 if (u <= 1 && v <= 1) {
209 return phi_pos(u,v);
210 }
211 const auto vou = v/u;
212 if (u >= 1 && vou <= 1) {
213 const auto oou = 1/u;
214 return phi_pos(oou,vou)*oou;
215 }
216 // v >= 1 && u/v <= 1
217 const auto oov = 1/v;
218 return phi_pos(oov,1/vou)*oov;
219 }
220
221 return phi_neg(u,v);
222 }
223
224} // anonymous namespace
225
226double F1C(double x) noexcept {
227 if (is_zero(x, eps)) {
228 return 4.0;
229 }
230
231 const double d = x - 1.0;
232
233 if (is_equal_rel(x, 1.0, 0.03)) {
234 return 1.0 + d*(-0.6 + d*(0.4 + d*(-2.0/7.0
235 + d*(3.0/14.0 + d*(-1.0/6.0
236 + 2.0/15.0*d)))));
237 }
238
239 return 2.0/pow4(d)*(2.0 + x*(3.0 + 6.0*std::log(x) + x*(-6.0 + x)));
240}
241
242double F2C(double x) noexcept {
243 if (is_zero(x, eps)) {
244 return 0.0;
245 }
246
247 if (is_equal_rel(x, 1.0, 0.03)) {
248 const double d = x - 1.0;
249
250 return 1.0 + d*(-0.75 + d*(0.6 + d*(-0.5 + d*(3.0/7.0
251 + d*(-0.375 + 1.0/3.0*d)))));
252 }
253
254 return 3.0/(2.0*pow3(1.0 - x))*(-3.0 - 2.0*std::log(x) + x*(4.0 - x));
255}
256
257double F3C(double x) noexcept {
258 const double d = x - 1.0;
259
260 if (is_equal_rel(x, 1.0, 0.03)) {
261 return 1.0
262 + d*(1059.0/1175.0
263 + d*(-4313.0/3525.0
264 + d*(70701.0/57575.0
265 + d*(-265541.0/230300.0
266 + d*(+48919.0/46060.0
267 - 80755.0/82908.0*d)))));
268 }
269
270 const double lx = std::log(x);
271 const double x2 = sqr(x);
272
273 return 4.0/(141.0*pow4(d)) * (
274 + (1.0 - x) * (151.0 * x2 - 335.0 * x + 592.0)
275 + 6.0 * (21.0 * pow3(x) - 108.0 * x2 - 93.0 * x + 50.0) * lx
276 - 54.0 * x * (x2 - 2.0 * x - 2.0) * sqr(lx)
277 - 108.0 * x * (x2 - 2.0 * x + 12.0) * dilog(1.0 - x)
278 );
279}
280
281double F4C(double x) noexcept {
282 if (is_zero(x, eps)) {
283 return 0.0;
284 }
285
286 if (is_equal_rel(x, 1.0, 0.03)) {
287 const double d = x - 1.0;
288
289 return 1.0
290 + d*(-45.0/122.0
291 + d*(941.0/6100.0
292 + d*(-17.0/305.0
293 + d*(+282.0/74725.0
294 + d*(+177.0/6832.0 - 47021.0/1076040.0*d)))));
295 }
296
297 const double lx = std::log(x);
298 const double x2 = sqr(x);
299
300 return -9.0/(122.0 * pow3(1.0 - x)) * (
301 + 8.0 * (x2 - 3.0 * x + 2.0)
302 + (11.0 * x2 - 40.0 * x + 5.0) * lx
303 - 2.0 * (x2 - 2.0 * x - 2.0) * sqr(lx)
304 - 4.0 * (x2 - 2.0 * x + 9.0) * dilog(1.0 - x)
305 );
306}
307
308double F1N(double x) noexcept {
309 if (is_zero(x, eps)) {
310 return 2.0;
311 }
312
313 const double d = x - 1.0;
314
315 if (is_equal_rel(x, 1.0, 0.03)) {
316 return 1.0 + d*(-0.4 + d*(0.2 + d*(-4.0/35.0
317 + d*(1.0/14.0 + d*(-1.0/21.0 + 1.0/30.0*d)))));
318 }
319
320 return 2.0/pow4(d)*(1.0 + x*(-6.0 + x*(+3.0 - 6.0 * std::log(x) + 2.0 * x)));
321}
322
323double F2N(double x) noexcept {
324 if (is_zero(x, eps)) {
325 return 3.0;
326 }
327
328 if (is_equal_rel(x, 1.0, 0.04)) {
329 const double d = x - 1.0;
330
331 return 1. + d*(-0.5 + d*(0.3 + d*(-0.2
332 + d*(1.0/7.0 + d*(-3.0/28.0 + 1.0/12.0*d)))));
333 }
334
335 return 3.0/pow3(1.0 - x) * (1.0 + x*(2.0 * std::log(x) - x));
336}
337
338double F3N(double x) noexcept {
339 if (is_zero(x, eps)) {
340 return 8.0/105.0;
341 }
342
343 const double d = x - 1.0;
344
345 if (is_equal_rel(x, 1.0, 0.03)) {
346 return 1.0 + d*(76/875.0 + d*(-431/2625.0 + d*(5858/42875.0
347 + d*(-3561/34300.0 + d*(23/294.0 - 4381/73500.0*d)))));
348 }
349
350 const double x2 = sqr(x);
351
352 return 4.0/105.0/pow4(d) * (
353 + (1.0 - x) * (-97.0 * x2 - 529.0 * x + 2.0)
354 + 6.0 * x2 * (13.0 * x + 81.0) * std::log(x)
355 + 108.0 * x * (7.0 * x + 4.0) * dilog(1.0 - x)
356 );
357}
358
359double F4N(double x) noexcept {
360 const double PI2 = 9.8696044010893586; // Pi^2
361
362 if (is_zero(x, eps)) {
363 return -3.0/4.0*(-9.0 + PI2);
364 }
365
366 if (is_equal_rel(x, 1.0, 0.03)) {
367 const double d = x - 1.0;
368
369 return 1.0 + sqr(d)*(-111.0/800.0 + d*(59.0/400.0 + d*(-129.0/980.0
370 + d*(177.0/1568.0 - 775.0/8064.0*d))));
371 }
372
373 return -2.25/pow3(1.0 - x) * (
374 + (x + 3.0) * (x * std::log(x) + x - 1.0)
375 + (6.0 * x + 2.0) * dilog(1.0 - x)
376 );
377}
378
379namespace {
380
381/// expansion of Fb(x,y) around x ~ 1 and y ~ 1 up to including O((x-1)^2 (y-1)^2)
382double Fb11(double x, double y) noexcept {
383 const double x1 = x - 1;
384 const double y1 = y - 1;
385
386 return
387 + 1.0/12 + (-0.05 + 1.0/30*y1)*y1
388 + x1*(-0.05 + (1.0/30 - 1.0/42*y1)*y1
389 + x1*(1.0/30 + (-1.0/42 + 1.0/56*y1)*y1));
390}
391
392/// expansion of Fb(x,y) around y ~ x, x != 0
393double Fbx(double x, double y) noexcept {
394 if (is_equal_rel(x, 1.0, 1e-2)) {
395 const double d = x - 1;
396 return 1.0/12 + d*(-0.1 + d*(0.1 + d*(-2.0/21 + d*(5.0/56 + d*(-1.0/12 + d*(7.0/90 - 4.0/55*d))))));
397 }
398
399 const double x1 = x - 1.0;
400 const double d = y - x;
401 const double lx = std::log(x);
402 const double x14 = pow4(x1);
403 const double x15 = x14*x1;
404 const double x16 = x15*x1;
405
406 return (-5 - 2*lx + x*(4 - 4*lx + x))/(2*x14)
407 - d*(-1 + x*(-9 - 6*lx + x*(9 - 6*lx + x)))/(2*x15*x)
408 - sqr(d)*(-1 + x*(12 + x*(36 + 36*lx + x*(-44 + 24*lx - 3*x))))/(6*x16*sqr(x));
409}
410
411} // anonymous namespace
412
413double Fb(double x, double y) noexcept {
414 if (x < 0 || y < 0) {
415 ERROR("Fb: x and y must not be negative!");
416 return std::numeric_limits<double>::quiet_NaN();
417 }
418
419 sort(x, y);
420
421 if (is_zero(y, eps)) {
422 return 0;
423 }
424
425 if (is_equal_rel(x, 1.0, 1e-4) && is_equal_rel(y, 1.0, 1e-4)) {
426 return Fb11(x, y);
427 }
428
429 if (is_equal_rel(x, y, 1e-5)) {
430 return Fbx(x, y);
431 }
432
433 return (G4(y) - G4(x))/(x - y);
434}
435
436namespace {
437
438/// expansion of Fa(x,y) around x ~ 1 and y ~ 1 up to including O((x-1)^2 (y-1)^2)
439double Fa11(double x, double y) noexcept {
440 const double x1 = x - 1;
441 const double y1 = y - 1;
442
443 return
444 0.25 + (-0.2 + 1.0/6*y1)*y1
445 + x1*(-0.2 + (1.0/6 - 1.0/7*y1)*y1
446 + x1*(1.0/6 + (-1.0/7 + 1.0/8*y1)*y1));
447}
448
449/// expansion of Fa(x,y) around y ~ x, x != 0
450double Fax(double x, double y) noexcept {
451 if (is_equal_rel(x, 1.0, 1e-2)) {
452 const double d = x - 1;
453 return 0.25 + d*(-0.4 + d*(0.5 + d*(-4.0/7 + d*(5.0/8 + d*(-2./3 + d*(0.7 - 8.0/11*d))))));
454 }
455
456 const double x1 = x - 1.0;
457 const double d = y - x;
458 const double lx = std::log(x);
459 const double x14 = pow4(x1);
460 const double x15 = x14*x1;
461 const double x16 = x15*x1;
462 const double x2 = sqr(x);
463 const double x3 = x2*x;
464
465 return (2 + x*(3 + 6*lx + x*(-6 + x)))/(2*x14*x)
466 - d*(-1 + x*(8 + x*(12*lx + x*(-8 + x))))/(2*x15*x2)
467 - sqr(d)*(-2 + x*(15 + x*(-60 + x*(20 - 60*lx + x*(30 - 3*x)))))/(6*x16*x3);
468}
469
470} // anonymous namespace
471
472double Fa(double x, double y) noexcept {
473 if (x < 0 || y < 0) {
474 ERROR("Fa: x and y must not be negative!");
475 return std::numeric_limits<double>::quiet_NaN();
476 }
477
478 sort(x, y);
479
480 if (is_zero(y, eps)) {
481 return 0;
482 }
483
484 if (is_equal_rel(x, 1.0, 1e-4) && is_equal_rel(y, 1.0, 1e-4)) {
485 return Fa11(x,y);
486 }
487
488 if (is_equal_rel(x, y, 1e-5)) {
489 return Fax(x,y);
490 }
491
492 return (G3(y) - G3(x))/(x - y);
493}
494
495double G3(double x) noexcept {
496 if (is_equal_rel(x, 1.0, 1e-2)) {
497 const double d = x - 1;
498 return 1.0/3 + d*(-0.25 + d*(0.2 + d*(-1.0/6 + d*(1.0/7 + d*(-1.0/8
499 + d*(1.0/9 + d*(-0.1 + 1.0/11*d)))))));
500 }
501
502 return ((x - 1)*(x - 3) + 2*std::log(x))/(2*pow3(x - 1));
503}
504
505double G4(double x) noexcept {
506 if (is_equal_rel(x, 1.0, 1e-2)) {
507 const double d = x - 1;
508 return 1.0/6 + d*(-1.0/12 + d*(0.05 + d*(-1.0/30 + d*(1.0/42
509 + d*(-1.0/56 + d*(1.0/72 + d*(-1.0/90 + 1.0/110*d)))))));
510 }
511
512 return ((x - 1)*(x + 1) - 2*x*std::log(x))/(2*pow3(x - 1));
513}
514
515namespace {
516
517/// Ixy(0,y), squared arguments, y != 0
518double I0y(double y) noexcept {
519 if (is_equal_rel(y, 1.0, eps)) {
520 const double d = y - 1;
521 return 1 + d*(-0.5 + 1./3*d);
522 }
523
524 return std::log(y)/(y - 1);
525}
526
527/// I(x,y), squared arguments, x == 1, y != 0
528double I1y(double x, double y) noexcept {
529 const double dy = y - 1;
530 const double dy2 = sqr(dy);
531 const double dx = (x - 1)/dy2;
532 const double y2 = sqr(y);
533 const double yly = y*std::log(y);
534
535 return (1 - y + yly)/dy2
536 + dx*(0.5 - 0.5*y2 + yly)/dy
537 + sqr(dx)*(1./3 + 0.5*y + yly + y2*(1./6*y - 1));
538}
539
540/// I(x,y), squared arguments, x == y, x != 0, y != 0
541double Ixx(double x, double y) noexcept {
542 const double eps_eq = 0.0001;
543
544 if (is_equal_rel(y, 1.0, eps_eq)) {
545 const double dx = x - 1;
546 const double dy = y - 1;
547 const double dy2 = sqr(dy);
548
549 return 0.5 + dx*(-1./6 + 1./12*dy - 1./20*dy2)
550 + sqr(dx)*(1./12 - 1./20*dy + 1./30*dy2)
551 - 1./6*dy + 1./12*dy2;
552 }
553
554 const double y2 = sqr(y);
555 const double dy = y - 1;
556 const double dy2 = sqr(dy);
557 const double dxy = (x - y)/dy2;
558 const double ly = std::log(y);
559
560 return (dy - ly)/dy2
561 + dxy*(0.5 - 0.5*y2 + y*ly)/(dy*y)
562 + sqr(dxy)*(1./6 - y + y2*(0.5 + 1./3*y - ly))/y2;
563}
564
565/// I(x,y), x < y, x and y are squared arguments
566double Ixy(double x, double y) noexcept {
567 const double eps_eq = 0.0001;
568
569 if (is_zero(y, eps)) {
570 return 0;
571 }
572
573 if (is_zero(x, eps)) {
574 return I0y(y);
575 }
576
577 if (is_equal_rel(x/y, 1.0, eps_eq)) {
578 return Ixx(x, y);
579 }
580
581 if (is_equal_rel(x, 1.0, eps_eq)) {
582 return I1y(x, y);
583 }
584
585 if (is_equal_rel(y, 1.0, eps_eq)) {
586 return I1y(y, x);
587 }
588
589 const double lx = std::log(x);
590 const double ly = std::log(y);
591
592 return (x*(y - 1)*lx - y*(x - 1)*ly)/((x - 1)*(x - y)*(y - 1));
593}
594
595/// I(x,y,z), x, y and z are squared arguments
596double Ixyz(double x, double y, double z) noexcept {
597 sort(x, y, z);
598
599 if (is_zero(z, eps)) {
600 return 0;
601 }
602
603 return Ixy(x/z, y/z)/z;
604}
605
606} // anonymous namespace
607
608double Iabc(double a, double b, double c) noexcept {
609 return Ixyz(sqr(a), sqr(b), sqr(c));
610}
611
612/**
613 * Calculates \f$f_{PS}(z)\f$, Eq (70) arXiv:hep-ph/0609168
614 * @author Alexander Voigt
615 */
616double f_PS(double z) noexcept {
617 if (z < 0.0) {
618 ERROR("f_PS: z must not be negative!");
619 return std::numeric_limits<double>::quiet_NaN();
620 } else if (z == 0.0) {
621 return 0.0;
622 } else if (z < std::numeric_limits<double>::epsilon()) {
623 const double pi23 = 3.2898681336964529; // Pi^2/3
624 const double lz = std::log(z);
625 return z*(pi23 + lz*lz);
626 } else if (z < 0.25) {
627 const double y = std::sqrt(1 - 4*z); // 0 < y < 1
628 const double c = -9.8696044010893586; // -Pi^2
629 const double q = (1 + y)/(1 - y);
630 const double lq = std::log(q);
631 return z/y*(4*dilog(1 + q) - lq*(2*std::log(z) - lq) + c);
632 } else if (z == 0.25) {
633 return 1.3862943611198906; // Log[4]
634 }
635
636 // z > 0.25
637 const double y = std::sqrt(-1 + 4*z);
638 const double theta = std::atan2(y, 2*z - 1);
639 return 4*z/y*clausen_2(theta);
640}
641
642/**
643 * Calculates \f$f_S(z)\f$, Eq (71) arXiv:hep-ph/0609168
644 */
645double f_S(double z) noexcept {
646 if (z < 0.0) {
647 ERROR("f_S: z must not be negative!");
648 return std::numeric_limits<double>::quiet_NaN();
649 } else if (z == 0.0) {
650 return 0.0;
651 } if (z > 1e2) {
652 const double lz = std::log(z);
653 const double iz = 1/z;
654 return (-13./9 - 2./3*lz) + iz*(-26./150 - 15./150*lz
655 + iz*(-673./22050 - 420./22050*lz + iz*(-971./158760 - 630./158760*lz)));
656 }
657
658 return (2*z - 1)*f_PS(z) - 2*z*(2 + std::log(z));
659}
660
661/**
662 * Calculates \f$f_{\tilde{f}}(z)\f$, Eq (72) arXiv:hep-ph/0609168
663 */
664double f_sferm(double z) noexcept {
665 if (z < 0.0) {
666 ERROR("f_sferm: z must not be negative!");
667 return std::numeric_limits<double>::quiet_NaN();
668 } else if (z == 0.0) {
669 return 0.0;
670 }
671
672 return 0.5*z*(2 + std::log(z) - f_PS(z));
673}
674
675/**
676 * Calculates Barr-Zee 2-loop function for diagram with lepton loop
677 * and charged Higgs and W boson mediators, Eq (60), arxiv:1607.06292,
678 * with extra global prefactor z.
679 */
680double f_CSl(double z) noexcept {
681 if (z < 0.0) {
682 ERROR("f_CSl: z must not be negative!");
683 return std::numeric_limits<double>::quiet_NaN();
684 } else if (z == 0) {
685 return 0.0;
686 }
687
688 constexpr double pi26 = 1.6449340668482264;
689
690 return z*(z + z*(z - 1)*(dilog(1 - 1/z) - pi26) + (z - 0.5)*std::log(z));
691}
692
693/**
694 * Eq (61), arxiv:1607.06292, with extra global prefactor xd
695 *
696 * @note There is a misprint in Eq (61), arxiv:1607.06292v2: There
697 * should be no Phi function in the 2nd line of (61).
698 */
699double f_CSd(double xu, double xd, double qu, double qd) noexcept
700{
701 if (xd < 0.0 || xu < 0.0) {
702 ERROR("f_CSd: xu and xd must not be negative!");
703 return std::numeric_limits<double>::quiet_NaN();
704 } else if (xd == 0.0) {
705 return 0.0;
706 }
707
708 const double s = 0.25*(qu + qd);
709 const double c = sqr(xu - xd) - qu*xu + qd*xd;
710 const double cbar = (xu - qu)*xu - (xd + qd)*xd;
711 const double lxu = std::log(xu);
712 const double lxd = std::log(xd);
713 const double phiy = phi_over_y(xu, xd);
714
715 return xd*(-(xu - xd) + (cbar - c*(xu - xd)) * phiy
716 + c*(dilog(1.0 - xd/xu) - 0.5*lxu*(lxd - lxu))
717 + (s + xd)*lxd + (s - xu)*lxu);
718}
719
720/// Eq (62), arxiv:1607.06292, with extra global prefactor xu
721double f_CSu(double xu, double xd, double qu, double qd) noexcept
722{
723 if (xd < 0.0 || xu < 0.0) {
724 ERROR("f_CSu: xu and xd must not be negative!");
725 return std::numeric_limits<double>::quiet_NaN();
726 }
727
728 const double s = 1 + 0.25*(qu + qd);
729 const double c = sqr(xu - xd) - (qu + 2)*xu + (qd + 2)*xd;
730 const double cbar = (xu - qu - 2)*xu - (xd + qd + 2)*xd;
731 const double lxu = std::log(xu);
732 const double lxd = std::log(xd);
733 const double phiy = phi_over_y(xu, xd);
734 const double fCSd = -(xu - xd) + (cbar - c*(xu - xd)) * phiy
735 + c*(dilog(1.0 - xd/xu) - 0.5*lxu*(lxd - lxu))
736 + (s + xd)*lxd + (s - xu)*lxu;
737
738 return xu*(fCSd - 4.0/3*(xu - xd - 1)*phiy
739 - 1.0/3*(lxd + lxu)*(lxd - lxu));
740}
741
742/**
743 * \f$\mathcal{F}_1(\omega)\f$, Eq (25) arxiv:1502.04199
744 */
745double F1(double w) noexcept {
746 if (w < 0.0) {
747 ERROR("F1: w must not be negative!");
748 return std::numeric_limits<double>::quiet_NaN();
749 } else if (w == 0.0) {
750 return 0.0;
751 } else if (w == 0.25) {
752 return -0.5;
753 }
754
755 return (w - 0.5)*f_PS(w) - w*(2 + std::log(w));
756}
757
758/**
759 * \f$\tilde{\mathcal{F}}_1(\omega)\f$, Eq (26) arxiv:1502.04199
760 */
761double F1t(double w) noexcept {
762 return 0.5*f_PS(w);
763}
764
765/**
766 * \f$\mathcal{F}_2(\omega)\f$, Eq (27) arxiv:1502.04199
767 */
768double F2(double w) noexcept {
769 if (w < 0.0) {
770 ERROR("F2: w must not be negative!");
771 return std::numeric_limits<double>::quiet_NaN();
772 } else if (w == 0.25) {
773 return -0.38629436111989062; // 1 - Log[4]
774 }
775
776 return 1 + 0.5*(std::log(w) - f_PS(w));
777}
778
779/**
780 * \f$\mathcal{F}_3(\omega)\f$, Eq (28) arxiv:1502.04199
781 * @author Alexander Voigt
782 */
783double F3(double w) noexcept {
784 if (w < 0.0) {
785 ERROR("F3: w must not be negative!");
786 return std::numeric_limits<double>::quiet_NaN();
787 } else if (w == 0.25) {
788 return 19.0/4.0;
789 } if (w >= 1e2) {
790 const double lw = std::log(w);
791 const double iw = 1/w;
792 return 89./12 + 42./12*lw + iw*(284./360 + 165./360*lw
793 + iw*(6199./44100 + 3885./44100*lw
794 + iw*(30017./1.0584e6 + 19530./1.0584e6*lw
795 + iw*(83351./1.37214e7 + 55440./1.37214e7*lw
796 + iw*(34978051./2.597186592e10 + 23603580./2.597186592e10*lw)))));
797 }
798
799 return (0.5 + 7.5*w)*(2 + std::log(w)) + (4.25 - 7.5*w)*f_PS(w);
800}
801
802/**
803 * Barr-Zee 2-loop function with fermion loop and pseudoscalar and Z
804 * boson mediators.
805 *
806 * @param x squared mass ratio (mf/ms)^2.
807 * @param y squared mass ratio (mf/mz)^2.
808 */
809double FPZ(double x, double y) noexcept
810{
811 if (x < 0 || y < 0) {
812 ERROR("FPZ: arguments must not be negative.");
813 return std::numeric_limits<double>::quiet_NaN();
814 }
815
816 sort(x, y);
817
818 constexpr double eps = 1e-8;
819
820 if (x == 0 || y == 0) {
821 return 0;
822 } else if (std::abs(1 - x/y) < eps) {
823 if (std::abs(x - 0.25) < eps) {
824 // -(1 + 2*Log[2])/3 + O(x - 1/4)
825 return -0.79543145370663021 - 1.7453806518612167*(x - 0.25);
826 }
827 return 2*x*(f_PS(x) + std::log(x))/(1 - 4*x);
828 }
829
830 return (y*f_PS(x) - x*f_PS(y))/(x - y);
831}
832
833/**
834 * Barr-Zee 2-loop function with fermion loop and scalar and Z boson
835 * mediators.
836 *
837 * @param x squared mass ratio (mf/ms)^2.
838 * @param y squared mass ratio (mf/mz)^2.
839 */
840double FSZ(double x, double y) noexcept
841{
842 if (x < 0 || y < 0) {
843 ERROR("FSZ: arguments must not be negative.");
844 return std::numeric_limits<double>::quiet_NaN();
845 }
846
847 sort(x, y);
848
849 constexpr double eps = 1e-8;
850
851 if (x == 0 || y == 0) {
852 return 0;
853 } else if (std::abs(1 - x/y) < eps) {
854 if (std::abs(x - 0.25) < eps) {
855 // (-1 + 4*Log[2])/3 + O(x - 1/4)
856 return 0.59086290741326041 + 1.2361419555836500*(x - 0.25);
857 } else if (x >= 1e3) {
858 const double ix = 1/x;
859 const double lx = std::log(x);
860 return 7./9 + 2./3*lx
861 + ix*(37./150 + 1./5*lx
862 + ix*(533./7350 + 2./35*lx
863 + ix*(1627./79380 + 1./63*lx
864 + ix*(18107./3201660 + 1./231*lx))));
865 }
866 return 2*x*(1 - 4*x + 2*x*f_PS(x) + std::log(x)*(1 - 2*x))/(4*x - 1);
867 }
868
869 return (y*f_S(x) - x*f_S(y))/(x - y);
870}
871
872/**
873 * Barr-Zee 2-loop function with lepton loop and charge scalar and W
874 * boson mediators.
875 *
876 * @param x squared mass ratio (mf/ms)^2.
877 * @param y squared mass ratio (mf/mw)^2.
878 */
879double FCWl(double x, double y) noexcept
880{
881 if (x < 0 || y < 0) {
882 ERROR("FCWl: arguments must not be negative.");
883 return std::numeric_limits<double>::quiet_NaN();
884 }
885
886 sort(x, y);
887
888 constexpr double eps = 1e-8;
889
890 if (x == 0 || y == 0) {
891 return 0;
892 } else if (std::abs(1 - x/y) < eps) {
893 const double pi26 = 1.6449340668482264;
894 return -f_CSl(x) + x*(-0.5 + x*(3 + (3*x - 2)*(dilog(1 - 1/x) - pi26))
895 + (3*x - 0.5)*std::log(x));
896 }
897
898 return (y*f_CSl(x) - x*f_CSl(y))/(x - y);
899}
900
901/**
902 * Barr-Zee 2-loop function with up-type quark loop and charge scalar
903 * and W boson mediators.
904 *
905 * @param xu squared mass ratio (mu/ms)^2.
906 * @param xd squared mass ratio (md/ms)^2.
907 * @param yu squared mass ratio (mu/mw)^2.
908 * @param yd squared mass ratio (md/mw)^2.
909 * @param qu electric charge count of up-type quark
910 * @param qd electric charge count of down-type quark
911 */
912double FCWu(double xu, double xd, double yu, double yd, double qu, double qd) noexcept
913{
914 if (xu < 0 || xd < 0 || yu < 0 || yd < 0) {
915 ERROR("FCWu: arguments must not be negative.");
916 return std::numeric_limits<double>::quiet_NaN();
917 }
918
919 constexpr double eps = 1e-8;
920
921 // Note: xd == yd <=> xu == yu, per definition
922 if (std::abs(1 - xu/yu) < eps) {
923 shift(xu, yu, eps);
924 shift(xd, yd, eps);
925 }
926
927 return (yu*f_CSu(xu, xd, qu, qd) - xu*f_CSu(yu, yd, qu, qd))/(xu - yu);
928}
929
930/**
931 * Barr-Zee 2-loop function with down-type quark loop and charge
932 * scalar and W boson mediators.
933 *
934 * @param xu squared mass ratio (mu/ms)^2.
935 * @param xd squared mass ratio (md/ms)^2.
936 * @param yu squared mass ratio (mu/mw)^2.
937 * @param yd squared mass ratio (md/mw)^2.
938 * @param qu electric charge count of up-type quark
939 * @param qd electric charge count of down-type quark
940 */
941double FCWd(double xu, double xd, double yu, double yd, double qu, double qd) noexcept
942{
943 if (xu < 0 || xd < 0 || yu < 0 || yd < 0) {
944 ERROR("FCWd: arguments must not be negative.");
945 return std::numeric_limits<double>::quiet_NaN();
946 }
947
948 constexpr double eps = 1e-8;
949
950 // Note: xd == yd <=> xu == yu, per definition
951 if (std::abs(1 - xu/yu) < eps) {
952 shift(xu, yu, eps);
953 shift(xd, yd, eps);
954 }
955
956 return (yd*f_CSd(xu, xd, qu, qd) - xd*f_CSd(yu, yd, qu, qd))/(xd - yd);
957}
958
959/**
960 * Källén lambda function \f$\lambda^2(x,y,z) = x^2 + y^2 + z^2 - 2xy - 2yz - 2xz\f$.
961 * The arguments u and v are interpreted as squared masses.
962 *
963 * @param x squared mass
964 * @param y squared mass
965 * @param z squared mass
966 *
967 * @return \f$\lambda^2(x,y,z)\f$
968 */
969double lambda_2(double x, double y, double z) noexcept
970{
971 return z*z*lambda_2(x/z, y/z);
972}
973
974/**
975 * \f$\Phi(x,y,z)\f$ function from arxiv:1607.06292 Eq.(68).
976
977 * @note The arguments x, y and z are interpreted as squared masses.
978 *
979 * @note Proportional to Phi from Davydychev and Tausk, Nucl. Phys. B397 (1993) 23
980 *
981 * @param x squared mass
982 * @param y squared mass
983 * @param z squared mass
984 *
985 * @return \f$\Phi(x,y,z)\f$
986 */
987double Phi(double x, double y, double z) noexcept
988{
989 sort(x, y, z);
990 const auto u = x/z, v = y/z;
991 return phi_uv(u,v)*z*lambda_2(u, v)/2;
992}
993
994} // namespace gm2calc
double qu
electromagnetic charge of down-type fermion
double qd
electromagnetic charge of up-type fermion
#define ERROR(message)
Definition gm2_log.hpp:24
double v
double lambda
double F1N(double x) noexcept
, Eq (52) arXiv:hep-ph/0609168
T pow4(T x) noexcept
returns number to the 4th power
double clausen_2(double x) noexcept
Clausen function .
double Phi(double x, double y, double z) noexcept
function from arxiv:1607.06292 Eq.
T sqr(T x) noexcept
returns number squared
double Fa(double x, double y) noexcept
, Eq (6.3a) arXiv:1311.1775
double FSZ(double x, double y) noexcept
Barr-Zee 2-loop function with fermion loop and scalar and Z boson mediators.
double f_CSl(double z) noexcept
Calculates Barr-Zee 2-loop function for diagram with lepton loop and charged Higgs and W boson mediat...
double G4(double x) noexcept
, Eq (6.4b) arXiv:1311.1775
double f_sferm(double z) noexcept
Calculates , Eq (72) arXiv:hep-ph/0609168.
double f_S(double z) noexcept
Calculates , Eq (71) arXiv:hep-ph/0609168.
double F4N(double x) noexcept
, Eq (40) arXiv:1003.5820
double FCWl(double x, double y) noexcept
Barr-Zee 2-loop function with lepton loop and charge scalar and W boson mediators.
double F4C(double x) noexcept
, Eq (38) arXiv:1003.5820
double F2N(double x) noexcept
, Eq (53) arXiv:hep-ph/0609168
bool is_zero(const Eigen::ArrayBase< Derived > &a, double eps)
T pow3(T x) noexcept
returns number to the third power
double f_CSu(double xu, double xd, double qu, double qd) noexcept
Eq (62), arxiv:1607.06292, with extra global prefactor xu.
double F3C(double x) noexcept
, Eq (37) arXiv:1003.5820
double Iabc(double a, double b, double c) noexcept
(arguments are interpreted as unsquared)
double F2(double w) noexcept
, Eq (27) arxiv:1502.04199
double f_CSd(double xu, double xd, double qu, double qd) noexcept
Eq (61), arxiv:1607.06292, with extra global prefactor xd.
double F3N(double x) noexcept
, Eq (39) arXiv:1003.5820
double G3(double x) noexcept
, Eq (6.4a) arXiv:1311.1775
double FCWu(double xu, double xd, double yu, double yd, double qu, double qd) noexcept
Barr-Zee 2-loop function with up-type quark loop and charge scalar and W boson mediators.
double Fb(double x, double y) noexcept
, Eq (6.3b) arXiv:1311.1775
double FPZ(double x, double y) noexcept
Barr-Zee 2-loop function with fermion loop and pseudoscalar and Z boson mediators.
double F1C(double x) noexcept
, Eq (54) arXiv:hep-ph/0609168
double F1t(double w) noexcept
, Eq (26) arxiv:1502.04199
double F1(double w) noexcept
, Eq (25) arxiv:1502.04199
double F2C(double x) noexcept
, Eq (55) arXiv:hep-ph/0609168
double lambda_2(double x, double y, double z) noexcept
Källén lambda function .
double f_PS(double z) noexcept
Calculates , Eq (70) arXiv:hep-ph/0609168.
bool is_equal_rel(T a, T b, T eps) noexcept
double FCWd(double xu, double xd, double yu, double yd, double qu, double qd) noexcept
Barr-Zee 2-loop function with down-type quark loop and charge scalar and W boson mediators.
double dilog(double x) noexcept
Real dilogarithm .
Definition gm2_dilog.cpp:75
double F3(double w) noexcept
, Eq (28) arxiv:1502.04199