flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
numerics.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY 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// FlexibleSUSY 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 FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
28// #define USE_LOOPTOOLS
29
30#include "numerics.h"
31#include "numerics2.hpp"
32#ifdef USE_LOOPTOOLS
33#include <clooptools.h>
34#endif
35#include <algorithm>
36#include <cmath>
37
38namespace softsusy {
39
40namespace {
41
42constexpr double EPSTOL = 1.0e-11;
43constexpr double TOL = 1e-4;
44
45constexpr double dabs(double a) noexcept { return a >= 0. ? a : -a; }
46constexpr double sqr(double a) noexcept { return a*a; }
47constexpr double pow3(double a) noexcept { return a*a*a; }
48constexpr double pow6(double a) noexcept { return sqr(pow3(a)); }
49
50constexpr bool is_zero(double m, double tol) noexcept
51{
52 const double am = dabs(m);
53 const double mtol = tol * am;
54
55 if (mtol == 0.0 && am != 0.0 && tol != 0.0)
56 return am <= tol;
57
58 return am <= mtol;
59}
60
61constexpr bool is_close(double m1, double m2, double tol) noexcept
62{
63 const double mmax = std::max(dabs(m1), dabs(m2));
64 const double mmin = std::min(dabs(m1), dabs(m2));
65 const double max_tol = tol * mmax;
66
67 if (max_tol == 0.0 && mmax != 0.0 && tol != 0.0)
68 return mmax - mmin <= tol;
69
70 return mmax - mmin <= max_tol;
71}
72
73double sign(double x) noexcept
74{
75 return x >= 0.0 ? 1.0 : -1.0;
76}
77
78// can be made constexpr in C++20
79double fB(const std::complex<double>& x) noexcept
80{
82
83 const double re = std::real(x);
84 const double im = std::imag(x);
85
86 if ((std::abs(re) == 0.0 || std::abs(re) == 1.0) && im == 0.0) {
87 return -1.0;
88 }
89
90 return std::real(-1.0 + fast_log(1.0 - x) - x*fast_log(1.0 - 1.0/x));
91}
92
94double fB(const std::complex<double>& xp, const std::complex<double>& xm) noexcept
95{
97
98 const double rep = std::real(xp);
99 const double imp = std::imag(xp);
100
101 if ((std::abs(rep) == 0.0 || std::abs(rep) == 1.0) && imp == 0.0) {
102 return -1.0 + fB(xm);
103 }
104
105 const double rem = std::real(xm);
106 const double imm = std::imag(xm);
107
108 if ((std::abs(rem) == 0.0 || std::abs(rem) == 1.0) && imm == 0.0) {
109 return -1.0 + fB(xp);
110 }
111
112 return std::real(-2.0 + fast_log((1.0 - xp)*(1.0 - xm))
113 - xp*fast_log(1.0 - 1.0/xp) - xm*fast_log(1.0 - 1.0/xm));
114}
115
116} // anonymous namespace
117
118/*
119 * Real part of A0 1-loop function.
120 *
121 * @param m mass
122 * @param q renormalization scale, q > 0
123 * @return Re[A0(m, q)]
124 */
125double a0(double m, double q) noexcept
126{
127 return rea0(m*m, q*q);
128}
129
130/*
131 * Real part of A0 1-loop function.
132 *
133 * Note: Returns correct result even for x < 0.
134 *
135 * @param x squared mass
136 * @param q squared renormalization scale, q > 0
137 * @return Re[A0(x, q)]
138 */
139double rea0(double x, double q) noexcept
140{
141 if (q <= 0) {
142 return std::numeric_limits<double>::quiet_NaN();
143 }
144
145 if (x == 0) {
146 return 0;
147 }
148
149 return x * (1 - 2*std::log(std::sqrt(std::abs(x/q))));
150}
151
152double ffn(double p, double m1, double m2, double q) noexcept {
153 return a0(m1, q) - 2.0 * a0(m2, q) -
154 (2.0 * sqr(p) + 2.0 * sqr(m1) - sqr(m2)) *
155 b0(p, m1, m2, q);
156}
157
158double gfn(double p, double m1, double m2, double q) noexcept {
159 return (sqr(p) - sqr(m1) - sqr(m2)) * b0(p, m1, m2, q) - a0(m1, q)
160 - a0(m2, q);
161}
162
163double hfn(double p, double m1, double m2, double q) noexcept {
164 return 4.0 * b22(p, m1, m2, q) + gfn(p, m1, m2, q);
165}
166
167double b22bar(double p, double m1, double m2, double q) noexcept {
168 return b22(p, m1, m2, q) - 0.25 * a0(m1, q) - 0.25 * a0(m2, q);
169}
170
174double b0(double p, double m1, double m2, double q) noexcept
175{
176#ifdef USE_LOOPTOOLS
177 setmudim(q*q);
178 double b0l = B0(p*p, m1*m1, m2*m2).real();
179 // return B0(p*p, m1*m1, m2*m2).real();
180#endif
181
182 m1 = std::abs(m1);
183 m2 = std::abs(m2);
184 p = std::abs(p);
185 q = std::abs(q);
186
187 if (m1 > m2) {
188 std::swap(m1, m2);
189 }
190
191 // protect against infrared divergence
192 if (is_zero(p, EPSTOL) && is_zero(m1, EPSTOL) && is_zero(m2, EPSTOL)) {
193 return 0.0;
194 }
195
196 // p is not 0
197 if (p > 1.0e-5 * m2) {
198 const double m12 = sqr(m1), m22 = sqr(m2), p2 = sqr(p);
199 const double s = p2 - m22 + m12;
200 const std::complex<double> imin(m12, -EPSTOL);
201 const std::complex<double> x = std::sqrt(sqr(s) - 4.0 * p2 * imin);
202 const std::complex<double> xp = (s + sign(s)*x) / (2*p2);
203 const std::complex<double> xm = imin / (xp*p2);
204
205 return -2.0*std::log(p/q) - fB(xp, xm);
206 }
207
208 if (is_close(m1, m2, EPSTOL)) {
209 return -2.0*std::log(m1/q);
210 }
211
212 if (m1 < 1.0e-15) {
213 return 1.0 - 2.0*std::log(m2/q);
214 }
215
216 const double m12 = sqr(m1), m22 = sqr(m2);
217
218 return 1.0 - 2.0 * std::log(m2/q)
219 + 2.0 * m12 * std::log(m2/m1) / (m12 - m22);
220}
221
233double db0(double /* s */, double x, double y) noexcept
234{
235 if ((std::abs(x) < 0.0001) != (std::abs(y) < 0.0001)) {
236 return (x + y)/(2*sqr(x - y));
237 } else if ((std::abs(x) < 0.0001) && (std::abs(y) < 0.0001)) {
238 return 0;
239 } else if (std::abs(y - x) < 0.001) {
240 return (1./12*(1 - y/x) + 1./6)/x;
241 }
242 return ((x - y)*(x + y) + 2*x*y*std::log(y/x))/(2*pow3(x - y));
243}
244
246double b1(double p, double m1, double m2, double q) noexcept
247{
248#ifdef USE_LOOPTOOLS
249 setmudim(q*q);
250 double b1l = -B1(p*p, m1*m1, m2*m2).real();
251 // return b1l;
252#endif
253
254 // protect against infrared divergence
255 if (is_zero(p, EPSTOL) && is_zero(m1, EPSTOL) && is_zero(m2, EPSTOL))
256 return 0.0;
257
258 const double p2 = sqr(p), m12 = sqr(m1), m22 = sqr(m2), q2 = sqr(q);
259
261 const double pTolerance = 1.0e-4;
262
263 if (p2 > pTolerance * std::max(m12, m22)) {
264 return (a0(m2, q) - a0(m1, q) + (p2 + m12 - m22)
265 * b0(p, m1, m2, q)) / (2.0 * p2);
266 }
267
268 if (std::abs(m1) > 1.0e-15 && std::abs(m2) > 1.0e-15) {
269 const double m14 = sqr(m12), m24 = sqr(m22);
270 const double m16 = m12*m14 , m26 = m22*m24;
271 const double m18 = sqr(m14), m28 = sqr(m24);
272 const double p4 = sqr(p2);
273 const double diff = m12 - m22;
274
275 if (std::abs(diff) < pTolerance * std::max(m12, m22)) {
276 return
277 - 0.5*std::log(m22/q2)
278 + 1.0/12.0*p2/m22 + 1.0/120.0*p4/m24
279 + diff*(-1.0/6.0/m22 - 1.0/30.0*p2/m24 - 1.0/140.0*p4/m26)
280 + sqr(diff)*(1.0/24.0/m24 + 1.0/60.0*p2/m26 + 3.0/560.0*p4/m28);
281 }
282
283 const double l12 = std::log(m12/m22);
284
285 return (3*m14 - 4*m12*m22 + m24 - 2*m14*l12)/(4.*sqr(diff))
286 + (p2*(4*pow3(diff)*
287 (2*m14 + 5*m12*m22 - m24) +
288 (3*m18 + 44*m16*m22 - 36*m14*m24 - 12*m12*m26 + m28)*p2
289 - 12*m14*m22*(2*sqr(diff) + (2*m12 + 3*m22)*p2)*l12))/
290 (24.*pow6(diff)) - 0.5*std::log(m22/q2);
291 }
292
293 return (m12 > m22)
294 ? -0.5*std::log(m12/q2) + 0.75
295 : -0.5*std::log(m22/q2) + 0.25;
296}
297
298double b22(double p, double m1, double m2, double q) noexcept
299{
300#ifdef USE_LOOPTOOLS
301 setmudim(q*q);
302 double b22l = B00(p*p, m1*m1, m2*m2).real();
303#endif
304
305 p = std::abs(p);
306 m1 = std::abs(m1);
307 m2 = std::abs(m2);
308 q = std::abs(q);
309
310 // protect against infrared divergence
311 if (is_zero(p, EPSTOL) && is_zero(m1, EPSTOL) && is_zero(m2, EPSTOL))
312 return 0.0;
313
315 const double p2 = sqr(p), m12 = sqr(m1), m22 = sqr(m2);
316 const double pTolerance = 1.0e-10;
317
318 if (p2 < pTolerance * std::max(m12, m22)) {
319 // m1 == m2 with good accuracy
320 if (is_close(m1, m2, EPSTOL)) {
321 return -m12 * std::log(m1/q) + m12 * 0.5;
322 }
323 // p == 0 limit
324 if (m1 > EPSTOL && m2 > EPSTOL) {
325 return 0.375 * (m12 + m22) - 0.5 *
326 (sqr(m22) * std::log(m2/q) -
327 sqr(m12) * std::log(m1/q)) / (m22 - m12);
328 }
329 return (m1 < EPSTOL)
330 ? 0.375 * m22 - 0.5 * m22 * std::log(m2/q)
331 : 0.375 * m12 - 0.5 * m12 * std::log(m1/q);
332 }
333
334 const double b0Save = b0(p, m1, m2, q);
335 const double a01 = a0(m1, q);
336 const double a02 = a0(m2, q);
337
338 return 1.0 / 6.0 *
339 (0.5 * (a01 + a02) + (m12 + m22 - 0.5 * p2)
340 * b0Save + (m22 - m12) / (2.0 * p2) *
341 (a02 - a01 - (m22 - m12) * b0Save) +
342 m12 + m22 - p2 / 3.0);
343}
344
345double d0(double m1, double m2, double m3, double m4) noexcept
346{
347 const double m1sq = sqr(m1);
348 const double m2sq = sqr(m2);
349
350 if (is_close(m1, m2, EPSTOL)) {
351 const double m3sq = sqr(m3);
352 const double m4sq = sqr(m4);
353
354 if (is_zero(m2, EPSTOL)) {
355 // d0 is undefined for m1 == m2 == 0
356 return 0.;
357 } else if (is_zero(m3, EPSTOL)) {
358 return (-m2sq + m4sq - m2sq * std::log(m4sq/m2sq))/
359 sqr(m2 * m2sq - m2 * m4sq);
360 } else if (is_zero(m4, EPSTOL)) {
361 return (-m2sq + m3sq - m2sq * std::log(m3sq/m2sq))/
362 sqr(m2 * m2sq - m2 * m3sq);
363 } else if (is_close(m2, m3, EPSTOL) && is_close(m2, m4, EPSTOL)) {
364 return 1.0 / (6.0 * sqr(m2sq));
365 } else if (is_close(m2, m3, EPSTOL)) {
366 return (sqr(m2sq) - sqr(m4sq) + 2.0 * m4sq * m2sq * std::log(m4sq / m2sq)) /
367 (2.0 * m2sq * sqr(m2sq - m4sq) * (m2sq - m4sq));
368 } else if (is_close(m2, m4, EPSTOL)) {
369 return (sqr(m2sq) - sqr(m3sq) + 2.0 * m3sq * m2sq * std::log(m3sq / m2sq)) /
370 (2.0 * m2sq * sqr(m2sq - m3sq) * (m2sq - m3sq));
371 } else if (is_close(m3, m4, EPSTOL)) {
372 return -1.0 / sqr(m2sq - m3sq) *
373 ((m2sq + m3sq) / (m2sq - m3sq) * std::log(m3sq / m2sq) + 2.0);
374 }
375
376 return
377 (m4sq / sqr(m2sq - m4sq) * std::log(m4sq / m2sq) +
378 m4sq / (m2sq * (m2sq - m4sq)) -
379 m3sq / sqr(m2sq - m3sq) * std::log(m3sq / m2sq) -
380 m3sq / (m2sq * (m2sq - m3sq))) / (m3sq - m4sq);
381 }
382 return (c0(m1, m3, m4) - c0(m2, m3, m4)) / (m1sq - m2sq);
383}
384
385double d27(double m1, double m2, double m3, double m4) noexcept
386{
387 if (is_close(m1, m2, EPSTOL))
388 m1 += TOL * 0.01;
389
390 const double m12 = sqr(m1), m22 = sqr(m2);
391
392 return (m12 * c0(m1, m3, m4) - m22 * c0(m2, m3, m4))
393 / (4.0 * (m12 - m22));
394}
395
396double c0(double m1, double m2, double m3) noexcept
397{
398#ifdef USE_LOOPTOOLS
399 double q = 100.;
400 setmudim(q*q);
401 double psq = 0.;
402 double c0l = C0(psq, psq, psq, m1*m1, m2*m2, m3*m3).real();
403#endif
404
405 const double m12 = sqr(m1), m22 = sqr(m2), m32 = sqr(m3);
406 const bool m1_is_zero = is_zero(m1, EPSTOL);
407 const bool m2_is_zero = is_zero(m2, EPSTOL);
408 const bool m3_is_zero = is_zero(m3, EPSTOL);
409
410 if ((m1_is_zero && m2_is_zero && m3_is_zero) ||
411 (m2_is_zero && m3_is_zero) ||
412 (m1_is_zero && m3_is_zero) ||
413 (m1_is_zero && m2_is_zero)) {
414 return 0.;
415 }
416
417 if (m1_is_zero) {
418 if (is_close(m2,m3,EPSTOL))
419 return -1./m22;
420 return std::log(m32/m22)/(m22 - m32);
421 }
422
423 if (m2_is_zero) {
424 if (is_close(m1,m3,EPSTOL))
425 return -1./m12;
426 return std::log(m32/m12)/(m12 - m32);
427 }
428
429 if (m3_is_zero) {
430 if (is_close(m1,m2,EPSTOL))
431 return -1./m12;
432 return std::log(m22/m12)/(m12 - m22);
433 }
434
435 if (is_close(m2, m3, EPSTOL)) {
436 if (is_close(m1, m2, EPSTOL))
437 return - 0.5 / m22;
438 return m12 / sqr(m12-m22) * std::log(m22/m12) + 1.0 / (m12 - m22);
439 }
440
441 if (is_close(m1, m2, EPSTOL)) {
442 return - (1.0 + m32 / (m22-m32) * std::log(m32/m22)) / (m22-m32);
443 }
444
445 if (is_close(m1, m3, EPSTOL)) {
446 return - (1.0 + m22 / (m32-m22) * std::log(m22/m32)) / (m32-m22);
447 }
448
449 return (m22 / (m12 - m22) * std::log(m22 / m12) -
450 m32 / (m12 - m32) * std::log(m32 / m12)) / (m22 - m32);
451}
452
464double d1_b0(double /* p2 */, double m2a, double m2b) noexcept
465{
466 m2a = std::abs(m2a);
467 m2b = std::abs(m2b);
468
469 if ((m2a < 0.0001) != (m2b < 0.0001)) {
470 return (m2a - m2b) * (m2a + m2b) / (2 * pow3(m2a - m2b));
471 } else if (m2a < 0.0001 && m2b < 0.0001) {
472 return 0.;
473 } else if (std::abs(m2b - m2a) < 0.001) {
474 return 1. / (6 * m2a) + (m2a - m2b) / (12 * sqr(m2a));
475 }
476
477 return ((m2a - m2b) * (m2a + m2b) + 2 * m2a * m2b * std::log(m2b / m2a)) /
478 (2 * pow3(m2a - m2b));
479}
480
481double c00(double m1, double m2, double m3, double q) noexcept
482{
483 // taken from Package X
484 const double m12 = sqr(m1), m22 = sqr(m2), m32 = sqr(m3), q2 = sqr(q);
485
486 double ans = 0.;
487
488 if (is_close(m1, 0., EPSTOL) && is_close(m2, 0., EPSTOL)
489 && is_close(m3, 0., EPSTOL)) {
490 // IR singularity
491 ans = 0.;
492 } else if (is_close(m2, 0., EPSTOL) && is_close(m3, 0., EPSTOL)) {
493 ans = 3./8. + 1./4*std::log(q2/m12);
494 } else if (is_close(m1, 0., EPSTOL) && is_close(m3, 0., EPSTOL)) {
495 ans = 3./8. + 1./4*std::log(q2/m22);
496 } else if (is_close(m1, 0., EPSTOL) && is_close(m2, 0., EPSTOL)) {
497 ans = 3./8. + 1./4*std::log(q2/m32);
498 } else if (is_close(m1, 0., EPSTOL)) {
499 if (is_close(m2, m3, EPSTOL)) {
500 ans = 1./8 + 1./4*std::log(q2/m22);
501 } else {
502 ans = 3./8 - m22*std::log(m22/m32)/(4*(m22-m32)) + 1./4*std::log(q2/m32);
503 }
504 } else if (is_close(m2, 0., EPSTOL)) {
505 if (is_close(m1, m3, EPSTOL)) {
506 ans = 1./8 + 1./4*std::log(q2/m12);
507 } else {
508 ans = 3./8 - m12*std::log(m12/m32)/(4*(m12-m32)) + 1./4*std::log(q2/m32);
509 }
510 } else if (is_close(m3, 0., EPSTOL)) {
511 if (is_close(m1, m2, EPSTOL)) {
512 ans = 1./8 + 1./4*std::log(q2/m12);
513 } else {
514 ans = 3./8 - m22*std::log(m12/m22)/(4*(m12-m22)) + 1./4*std::log(q2/m12);
515 }
516 } else if (is_close(m2, m3, EPSTOL)) {
517 if (is_close(m1, m2, EPSTOL)) {
518 ans = 1./4*std::log(q2/m12);
519 } else {
520 ans = (3*m12-m22)/(8*(m12-m22))
521 - 1./4*(sqr(m12)*std::log(m12/m22))/sqr(m12-m22) + 1./4*std::log(q2/m22);
522 }
523 } else if (is_close(m1, m2, EPSTOL)) {
524 ans = (3*m32-m12)/(8*(m32-m12)) - 1./4*(sqr(m32)*std::log(m32/m12))/sqr(m32-m12)
525 + 1./4*std::log(q2/m12);
526 } else if (is_close(m1, m3, EPSTOL)) {
527 ans = (3*m22-m12)/(8*(m22-m12)) - 1./4*(sqr(m22)*std::log(m22/m12))/sqr(m22-m12)
528 + 1./4*std::log(q2/m12);
529 } else {
530 ans = 3./8 - 1./4*sqr(m12)*std::log(m12/m32)/((m12-m22)*(m12-m32))
531 - 1./4*sqr(m22)*std::log(m22/m32)/((m22-m12)*(m22-m32)) + 1./4*std::log(q2/m32);
532 }
533
534 return ans;
535}
536
537} // namespace softsusy
std::complex< T > fast_log(const std::complex< T > &z) noexcept
fast implementation of complex logarithm
double fB(const std::complex< double > &x) noexcept
Definition numerics.cpp:79
constexpr double pow6(double a) noexcept
Definition numerics.cpp:48
constexpr double dabs(double a) noexcept
Definition numerics.cpp:45
constexpr bool is_close(double m1, double m2, double tol) noexcept
Definition numerics.cpp:61
Comment if you want default softsusy behaviour.
Definition lowe.cpp:37
double gfn(double p, double m1, double m2, double q) noexcept
Definition numerics.cpp:158
double b1(double p, double m1, double m2, double q) noexcept
Note that b1 is NOT symmetric in m1 <-> m2!!!
Definition numerics.cpp:246
double c00(double m1, double m2, double m3, double q) noexcept
Definition numerics.cpp:481
double rea0(double x, double q) noexcept
Definition numerics.cpp:139
double c0(double m1, double m2, double m3) noexcept
Definition numerics.cpp:396
double a0(double m, double q) noexcept
Definition numerics.cpp:125
double b22(double p, double m1, double m2, double q) noexcept
Definition numerics.cpp:298
double d27(double m1, double m2, double m3, double m4) noexcept
Definition numerics.cpp:385
double hfn(double p, double m1, double m2, double q) noexcept
Definition numerics.cpp:163
double ffn(double p, double m1, double m2, double q) noexcept
Definition numerics.cpp:152
double b22bar(double p, double m1, double m2, double q) noexcept
Definition numerics.cpp:167
double b0(double p, double m1, double m2, double q) noexcept
Definition numerics.cpp:174
double d0(double m1, double m2, double m3, double m4) noexcept
Definition numerics.cpp:345
double db0(double, double x, double y) noexcept
Definition numerics.cpp:233
double d1_b0(double, double m2a, double m2b) noexcept
Definition numerics.cpp:464
void swap(nlohmann::basic_json< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType, CustomBaseClass > &j1, nlohmann::basic_json< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType, CustomBaseClass > &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::basic_json< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType, CustomBaseClass > >::value &&//NOLINT(misc-redundant-expression, cppcoreguidelines-noexcept-swap, performance-noexcept-swap) is_nothrow_move_assignable< nlohmann::basic_json< ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType, CustomBaseClass > >::value)
exchanges the values of two JSON objects
Definition json.hpp:24537
loop functions