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 a*a*a*a*a*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 - std::log(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
223double b1(double p, double m1, double m2, double q) noexcept
224{
225#ifdef USE_LOOPTOOLS
226 setmudim(q*q);
227 double b1l = -B1(p*p, m1*m1, m2*m2).real();
228 // return b1l;
229#endif
230
231 // protect against infrared divergence
232 if (is_zero(p, EPSTOL) && is_zero(m1, EPSTOL) && is_zero(m2, EPSTOL))
233 return 0.0;
234
235 const double p2 = sqr(p), m12 = sqr(m1), m22 = sqr(m2), q2 = sqr(q);
236
238 const double pTolerance = 1.0e-4;
239
240 if (p2 > pTolerance * std::max(m12, m22)) {
241 return (a0(m2, q) - a0(m1, q) + (p2 + m12 - m22)
242 * b0(p, m1, m2, q)) / (2.0 * p2);
243 }
244
245 if (std::abs(m1) > 1.0e-15 && std::abs(m2) > 1.0e-15) {
246 const double m14 = sqr(m12), m24 = sqr(m22);
247 const double m16 = m12*m14 , m26 = m22*m24;
248 const double m18 = sqr(m14), m28 = sqr(m24);
249 const double p4 = sqr(p2);
250 const double diff = m12 - m22;
251
252 if (std::abs(diff) < pTolerance * std::max(m12, m22)) {
253 return
254 - 0.5*std::log(m22/q2)
255 + 1.0/12.0*p2/m22 + 1.0/120.0*p4/m24
256 + diff*(-1.0/6.0/m22 - 1.0/30.0*p2/m24 - 1.0/140.0*p4/m26)
257 + sqr(diff)*(1.0/24.0/m24 + 1.0/60.0*p2/m26 + 3.0/560.0*p4/m28);
258 }
259
260 const double l12 = std::log(m12/m22);
261
262 return (3*m14 - 4*m12*m22 + m24 - 2*m14*l12)/(4.*sqr(diff))
263 + (p2*(4*pow3(diff)*
264 (2*m14 + 5*m12*m22 - m24) +
265 (3*m18 + 44*m16*m22 - 36*m14*m24 - 12*m12*m26 + m28)*p2
266 - 12*m14*m22*(2*sqr(diff) + (2*m12 + 3*m22)*p2)*l12))/
267 (24.*pow6(diff)) - 0.5*std::log(m22/q2);
268 }
269
270 return (m12 > m22)
271 ? -0.5*std::log(m12/q2) + 0.75
272 : -0.5*std::log(m22/q2) + 0.25;
273}
274
275double b22(double p, double m1, double m2, double q) noexcept
276{
277#ifdef USE_LOOPTOOLS
278 setmudim(q*q);
279 double b22l = B00(p*p, m1*m1, m2*m2).real();
280#endif
281
282 p = std::abs(p);
283 m1 = std::abs(m1);
284 m2 = std::abs(m2);
285 q = std::abs(q);
286
287 // protect against infrared divergence
288 if (is_zero(p, EPSTOL) && is_zero(m1, EPSTOL) && is_zero(m2, EPSTOL))
289 return 0.0;
290
292 const double p2 = sqr(p), m12 = sqr(m1), m22 = sqr(m2);
293 const double pTolerance = 1.0e-10;
294
295 if (p2 < pTolerance * std::max(m12, m22)) {
296 // m1 == m2 with good accuracy
297 if (is_close(m1, m2, EPSTOL)) {
298 return -m12 * std::log(m1/q) + m12 * 0.5;
299 }
300 // p == 0 limit
301 if (m1 > EPSTOL && m2 > EPSTOL) {
302 return 0.375 * (m12 + m22) - 0.5 *
303 (sqr(m22) * std::log(m2/q) -
304 sqr(m12) * std::log(m1/q)) / (m22 - m12);
305 }
306 return (m1 < EPSTOL)
307 ? 0.375 * m22 - 0.5 * m22 * std::log(m2/q)
308 : 0.375 * m12 - 0.5 * m12 * std::log(m1/q);
309 }
310
311 const double b0Save = b0(p, m1, m2, q);
312 const double a01 = a0(m1, q);
313 const double a02 = a0(m2, q);
314
315 return 1.0 / 6.0 *
316 (0.5 * (a01 + a02) + (m12 + m22 - 0.5 * p2)
317 * b0Save + (m22 - m12) / (2.0 * p2) *
318 (a02 - a01 - (m22 - m12) * b0Save) +
319 m12 + m22 - p2 / 3.0);
320}
321
322double d0(double m1, double m2, double m3, double m4) noexcept
323{
324 const double m1sq = sqr(m1);
325 const double m2sq = sqr(m2);
326
327 if (is_close(m1, m2, EPSTOL)) {
328 const double m3sq = sqr(m3);
329 const double m4sq = sqr(m4);
330
331 if (is_zero(m2, EPSTOL)) {
332 // d0 is undefined for m1 == m2 == 0
333 return 0.;
334 } else if (is_zero(m3, EPSTOL)) {
335 return (-m2sq + m4sq - m2sq * std::log(m4sq/m2sq))/
336 sqr(m2 * m2sq - m2 * m4sq);
337 } else if (is_zero(m4, EPSTOL)) {
338 return (-m2sq + m3sq - m2sq * std::log(m3sq/m2sq))/
339 sqr(m2 * m2sq - m2 * m3sq);
340 } else if (is_close(m2, m3, EPSTOL) && is_close(m2, m4, EPSTOL)) {
341 return 1.0 / (6.0 * sqr(m2sq));
342 } else if (is_close(m2, m3, EPSTOL)) {
343 return (sqr(m2sq) - sqr(m4sq) + 2.0 * m4sq * m2sq * std::log(m4sq / m2sq)) /
344 (2.0 * m2sq * sqr(m2sq - m4sq) * (m2sq - m4sq));
345 } else if (is_close(m2, m4, EPSTOL)) {
346 return (sqr(m2sq) - sqr(m3sq) + 2.0 * m3sq * m2sq * std::log(m3sq / m2sq)) /
347 (2.0 * m2sq * sqr(m2sq - m3sq) * (m2sq - m3sq));
348 } else if (is_close(m3, m4, EPSTOL)) {
349 return -1.0 / sqr(m2sq - m3sq) *
350 ((m2sq + m3sq) / (m2sq - m3sq) * std::log(m3sq / m2sq) + 2.0);
351 }
352
353 return
354 (m4sq / sqr(m2sq - m4sq) * std::log(m4sq / m2sq) +
355 m4sq / (m2sq * (m2sq - m4sq)) -
356 m3sq / sqr(m2sq - m3sq) * std::log(m3sq / m2sq) -
357 m3sq / (m2sq * (m2sq - m3sq))) / (m3sq - m4sq);
358 }
359 return (c0(m1, m3, m4) - c0(m2, m3, m4)) / (m1sq - m2sq);
360}
361
362double d27(double m1, double m2, double m3, double m4) noexcept
363{
364 if (is_close(m1, m2, EPSTOL))
365 m1 += TOL * 0.01;
366
367 const double m12 = sqr(m1), m22 = sqr(m2);
368
369 return (m12 * c0(m1, m3, m4) - m22 * c0(m2, m3, m4))
370 / (4.0 * (m12 - m22));
371}
372
373double c0(double m1, double m2, double m3) noexcept
374{
375#ifdef USE_LOOPTOOLS
376 double q = 100.;
377 setmudim(q*q);
378 double psq = 0.;
379 double c0l = C0(psq, psq, psq, m1*m1, m2*m2, m3*m3).real();
380#endif
381
382 const double m12 = sqr(m1), m22 = sqr(m2), m32 = sqr(m3);
383 const bool m1_is_zero = is_zero(m1, EPSTOL);
384 const bool m2_is_zero = is_zero(m2, EPSTOL);
385 const bool m3_is_zero = is_zero(m3, EPSTOL);
386
387 if ((m1_is_zero && m2_is_zero && m3_is_zero) ||
388 (m2_is_zero && m3_is_zero) ||
389 (m1_is_zero && m3_is_zero) ||
390 (m1_is_zero && m2_is_zero)) {
391 return 0.;
392 }
393
394 if (m1_is_zero) {
395 if (is_close(m2,m3,EPSTOL))
396 return -1./m22;
397 return std::log(m32/m22)/(m22 - m32);
398 }
399
400 if (m2_is_zero) {
401 if (is_close(m1,m3,EPSTOL))
402 return -1./m12;
403 return std::log(m32/m12)/(m12 - m32);
404 }
405
406 if (m3_is_zero) {
407 if (is_close(m1,m2,EPSTOL))
408 return -1./m12;
409 return std::log(m22/m12)/(m12 - m22);
410 }
411
412 if (is_close(m2, m3, EPSTOL)) {
413 if (is_close(m1, m2, EPSTOL))
414 return - 0.5 / m22;
415 return m12 / sqr(m12-m22) * std::log(m22/m12) + 1.0 / (m12 - m22);
416 }
417
418 if (is_close(m1, m2, EPSTOL)) {
419 return - (1.0 + m32 / (m22-m32) * std::log(m32/m22)) / (m22-m32);
420 }
421
422 if (is_close(m1, m3, EPSTOL)) {
423 return - (1.0 + m22 / (m32-m22) * std::log(m22/m32)) / (m32-m22);
424 }
425
426 return (m22 / (m12 - m22) * std::log(m22 / m12) -
427 m32 / (m12 - m32) * std::log(m32 / m12)) / (m22 - m32);
428}
429
441double d1_b0(double /* p2 */, double m2a, double m2b) noexcept
442{
443 m2a = std::abs(m2a);
444 m2b = std::abs(m2b);
445
446 if ((m2a < 0.0001) != (m2b < 0.0001)) {
447 return (m2a - m2b) * (m2a + m2b) / (2 * pow3(m2a - m2b));
448 } else if (m2a < 0.0001 && m2b < 0.0001) {
449 return 0.;
450 } else if (std::abs(m2b - m2a) < 0.001) {
451 return 1. / (6 * m2a) + (m2a - m2b) / (12 * sqr(m2a));
452 }
453
454 return ((m2a - m2b) * (m2a + m2b) + 2 * m2a * m2b * std::log(m2b / m2a)) /
455 (2 * pow3(m2a - m2b));
456}
457
458double c00(double m1, double m2, double m3, double q) noexcept
459{
460 // taken from Package X
461 const double m12 = sqr(m1), m22 = sqr(m2), m32 = sqr(m3), q2 = sqr(q);
462
463 double ans = 0.;
464
465 if (is_close(m1, 0., EPSTOL) && is_close(m2, 0., EPSTOL)
466 && is_close(m3, 0., EPSTOL)) {
467 // IR singularity
468 ans = 0.;
469 } else if (is_close(m2, 0., EPSTOL) && is_close(m3, 0., EPSTOL)) {
470 ans = 3./8. + 1./4*std::log(q2/m12);
471 } else if (is_close(m1, 0., EPSTOL) && is_close(m3, 0., EPSTOL)) {
472 ans = 3./8. + 1./4*std::log(q2/m22);
473 } else if (is_close(m1, 0., EPSTOL) && is_close(m2, 0., EPSTOL)) {
474 ans = 3./8. + 1./4*std::log(q2/m32);
475 } else if (is_close(m1, 0., EPSTOL)) {
476 if (is_close(m2, m3, EPSTOL)) {
477 ans = 1./8 + 1./4*std::log(q2/m22);
478 } else {
479 ans = 3./8 - m22*std::log(m22/m32)/(4*(m22-m32)) + 1./4*std::log(q2/m32);
480 }
481 } else if (is_close(m2, 0., EPSTOL)) {
482 if (is_close(m1, m3, EPSTOL)) {
483 ans = 1./8 + 1./4*std::log(q2/m12);
484 } else {
485 ans = 3./8 - m12*std::log(m12/m32)/(4*(m12-m32)) + 1./4*std::log(q2/m32);
486 }
487 } else if (is_close(m3, 0., EPSTOL)) {
488 if (is_close(m1, m2, EPSTOL)) {
489 ans = 1./8 + 1./4*std::log(q2/m12);
490 } else {
491 ans = 3./8 - m22*std::log(m12/m22)/(4*(m12-m22)) + 1./4*std::log(q2/m12);
492 }
493 } else if (is_close(m2, m3, EPSTOL)) {
494 if (is_close(m1, m2, EPSTOL)) {
495 ans = 1./4*std::log(q2/m12);
496 } else {
497 ans = (3*m12-m22)/(8*(m12-m22))
498 - 1./4*(sqr(m12)*std::log(m12/m22))/sqr(m12-m22) + 1./4*std::log(q2/m22);
499 }
500 } else if (is_close(m1, m2, EPSTOL)) {
501 ans = (3*m32-m12)/(8*(m32-m12)) - 1./4*(sqr(m32)*std::log(m32/m12))/sqr(m32-m12)
502 + 1./4*std::log(q2/m12);
503 } else if (is_close(m1, m3, EPSTOL)) {
504 ans = (3*m22-m12)/(8*(m22-m12)) - 1./4*(sqr(m22)*std::log(m22/m12))/sqr(m22-m12)
505 + 1./4*std::log(q2/m12);
506 } else {
507 ans = 3./8 - 1./4*sqr(m12)*std::log(m12/m32)/((m12-m22)*(m12-m32))
508 - 1./4*sqr(m22)*std::log(m22/m32)/((m22-m12)*(m22-m32)) + 1./4*std::log(q2/m32);
509 }
510
511 return ans;
512}
513
514} // namespace softsusy
double C0(double m1, double m2, double m3) noexcept
(arguments are interpreted as unsquared)
double B0(double m1, double m2, double scale) noexcept
(arguments are interpreted as unsquared)
std::complex< T > fast_log(const std::complex< T > &z) noexcept
fast implementation of complex logarithm
Definition: numerics2.hpp:160
Complex< T > log(const Complex< T > &z) noexcept
Definition: complex.hpp:54
constexpr bool is_zero(double m, double tol) noexcept
Definition: numerics.cpp:50
constexpr double EPSTOL
underflow accuracy
Definition: numerics.cpp:42
constexpr double sqr(double a) noexcept
Definition: numerics.cpp:46
constexpr double pow6(double a) noexcept
Definition: numerics.cpp:48
double fB(const std::complex< double > &xp, const std::complex< double > &xm) noexcept
fB(xp) + fB(xm)
Definition: numerics.cpp:94
constexpr double pow3(double a) noexcept
Definition: numerics.cpp:47
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:223
double c00(double m1, double m2, double m3, double q) noexcept
Definition: numerics.cpp:458
double rea0(double x, double q) noexcept
Definition: numerics.cpp:139
double c0(double m1, double m2, double m3) noexcept
Definition: numerics.cpp:373
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:275
double d27(double m1, double m2, double m3, double m4) noexcept
Definition: numerics.cpp:362
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:322
double d1_b0(double, double m2a, double m2b) noexcept
Definition: numerics.cpp:441
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