Skip to content

Rustify N3LO Ad #443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7a4cc73
add logs function
giacomomagni Feb 12, 2025
81a8333
add n3lo ns ad
giacomomagni Feb 12, 2025
462f62c
rust: Change harmonics args just to the cache
felixhekhorn Feb 14, 2025
376228f
add log functions tests
giacomomagni Feb 17, 2025
fb6c230
adding gamma ps
giacomomagni Feb 17, 2025
353bba6
fix lm15 bug
giacomomagni Feb 17, 2025
491d689
move gsl to dev dep
giacomomagni Feb 17, 2025
407c1f2
add w5 to harmonics
giacomomagni Feb 17, 2025
0479ef8
complete ad translation
giacomomagni Feb 17, 2025
5433163
rust: Indent comment with one whitespace
felixhekhorn Feb 18, 2025
0e2c6d9
rust: Fix clippy warnings
felixhekhorn Feb 18, 2025
c30aa6c
rust: Change as4 visibilities
felixhekhorn Feb 18, 2025
397a281
rust: Update as4.nsv docs
felixhekhorn Feb 18, 2025
88769a2
rust: Push bib changes
felixhekhorn Feb 20, 2025
b0869d1
improve docs
giacomomagni Feb 24, 2025
1b3017b
more fix on docs
giacomomagni Feb 24, 2025
a776055
Add bibtexparser as docs dep
felixhekhorn Feb 24, 2025
ed14152
rust: Avoid repetition in ad.u.s.as4.ns docs
felixhekhorn Feb 24, 2025
3df416e
rust: Improve ad.u.s.as4 docs
felixhekhorn Feb 24, 2025
a72d78c
run poe rbib
giacomomagni Feb 24, 2025
f8eb85c
cast nf to float
giacomomagni Feb 27, 2025
e91e0bd
rust: Improve nf cast in ad.u.s.as4
felixhekhorn Feb 27, 2025
031ae4b
rust: Make cache only arg for logs
felixhekhorn Feb 27, 2025
6119619
init adding n3lo_ad_variation
giacomomagni Feb 27, 2025
ee8eba2
Merge branch 'rustfy_ad_as4' of https://github.com/N3PDF/eko into rus…
giacomomagni Feb 27, 2025
ef2ce1e
propagate n3lo_ad_variations
giacomomagni Feb 27, 2025
ce843bd
int to int8
giacomomagni Feb 27, 2025
5882487
some cleaning
giacomomagni Mar 3, 2025
80b31e7
Merge branch 'master' into rustfy_ad_as4
giacomomagni Apr 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! |NNLO| |QCD|.

use ::num::complex::Complex;
use num::complex::Complex;
use num::traits::Pow;

use crate::cmplx;
Expand Down
22 changes: 22 additions & 0 deletions crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! |N3LO| |QCD|.

// pub mod ggg;
// pub mod ggq;
// pub mod gqg;
// pub mod gps;

pub mod gnsm;
pub mod gnsp;
pub mod gnsv;

// /// Compute the singlet anomalous dimension matrix.
// pub fn gamma_singlet(c: &mut Cache, nf: u8, variation: [u8; 4]) -> [[Complex<f64>; 2]; 2] {
// let gamma_qq = gamma_nsp(c, nf, variation[3]) + gamma_ps(c, nf, variation[3]);
// [
// [gamma_qq, gamma_qg(c, nf, variation[2])],
// [gamma_gq(c, nf, variation[1]), gamma_gg(c, nf, variation[0])],
// ]
// }

#[cfg(test)]
mod tests {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
/// Compute the non-singlet-like non-singlet anomalous dimension.
use num::complex::Complex;
use num::traits::Pow;

use crate::cmplx;
use crate::constants::{CF, ZETA3};
use crate::harmonics::cache::{Cache, K};
use crate::harmonics::log_functions::{lm11, lm11m1, lm12m1, lm13m1};

// The routine is taken from [\[`Moch:2017uml\]][crate::bib:Moch:2017uml].

// The nf^{0,1} leading large-nc contributions and the nf^2 part are
// high-accuracy (0.1% or better) parametrizations of the exact
// results. The nf^3 expression is exact up to numerical truncations.

// The remaining nf^{0,1} terms are approximations based on the first
// eight odd moments together with small-x and large-x constraints.
// The two sets spanning the error estimate are called via IMOD = 1
// and IMOD = 2. Any other value of IMOD invokes their average.
pub fn gamma_nsm(c: &mut Cache, nf: u8, variation: u8) -> Complex<f64> {
let n = c.n();
let S1 = c.get(K::S1);
let S2 = c.get(K::S2);
let S3 = c.get(K::S3);
let S4 = c.get(K::S4);

// Leading large-n_c, nf^0 and nf^1, parametrized
#[rustfmt::skip]
let P3NSA0 = 360.0 / n.powu(7)
- 1920.0 / n.powu(6)
+ 7147.812 / n.powu(5)
- 17179.356 / n.powu(4)
+ 34241.9 / n.powu(3)
- 51671.329999999994 / n.powu(2)
+ 19069.8 * lm11(n, S1)
- (491664.8019540468 / n)
- 4533.0 / (1. + n).powu(3)
- 11825.0 / (1. + n).powu(2)
+ 129203.0 / (1. + n)
- 254965.0 / (2. + n)
+ 83377.5 / (3. + n)
- 45750.0 / (4. + n)
+ (49150.0 * (6.803662258392675 + n) * S1) / (n.powu(2) * (1.0 + n))
+ (334400.0 * S2) / n;
#[rustfmt::skip]
let P3NSA1 = 160.0 / n.powu(6)
- 864.0 / n.powu(5)
+ 2583.1848 / n.powu(4)
- 5834.624 / n.powu(3)
+ 9239.374 / n.powu(2)
- 3079.76 * lm11(n, S1)
- (114047.0 / n)
- 465.0 / (1. + n).powu(4)
- 1230.0 / (1. + n).powu(3)
+ 7522.5 / (1. + n).powu(2)
+ 55669.3 / (1. + n)
- 43057.8 / (2. + n)
+ 13803.8 / (3. + n)
- 7896.0 / (4. + n)
- (120.0 * (-525.063 + n) * S1) / (n.powu(2) * (1.0 + n))
+ (63007.5 * S2) / n;

// Nonleading large-n_c, nf^0 and nf^1: two approximations
#[rustfmt::skip]
let P3NMA01 = 0.4964335 * (720. / n.powu(7) - 720.0 / n.powu(6))
- 13.5288 / n.powu(4)
+ 1618.07 / n.powu(2)
- 2118.8669999999997 * lm11(n, S1)
+ 31897.8 * lm11m1(n, S1)
+ 4653.76 * lm12m1(n, S1, S2)
+ 3902.3590000000004 / n
+ 5992.88 / (1. + n)
+ 19335.7 / (2. + n)
- 31321.4 / (3. + n);
#[rustfmt::skip]
let P3NMA02 = 0.4964335 * (720. / n.powu(7) - 2160.0 / n.powu(6))
- 189.6138 / n.powu(4)
+ 3065.92 / n.powu(3)
- 2118.8669999999997 * lm11(n, S1)
- 3997.39 * lm11m1(n, S1)
+ 511.567 * lm13m1(n, S1, S2, S3)
- (2099.268 / n)
+ 4043.59 / (1. + n)
- 19430.190000000002 / (2. + n)
+ 15386.6 / (3. + n);

#[rustfmt::skip]
let P3NMA11 = 64.7083 / n.powu(5)
- 254.024 / n.powu(3)
+ 337.931 * lm11(n, S1)
+ 1856.63 * lm11m1(n, S1)
+ 440.17 * lm12m1(n, S1, S2)
+ 419.53485 / n
+ 114.457 / (1. + n)
+ 2341.816 / (2. + n)
- 2570.73 / (3. + n);

#[rustfmt::skip]
let P3NMA12 = -17.0616 / n.powu(6)
- 19.53254 / n.powu(3)
+ 337.931 * lm11(n, S1)
- 1360.04 * lm11m1(n, S1)
+ 38.7337 * lm13m1(n, S1, S2, S3)
- (367.64646999999997 / n)
+ 335.995 / (1. + n)
- 1269.915 / (2. + n)
+ 1605.91 / (3. + n);

// nf^2 (parametrized) and nf^3 (exact)
#[rustfmt::skip]
let P3NSMA2 = -(
-193.84583328013258
- 23.7037032 / n.powu(5)
+ 117.5967 / n.powu(4)
- 256.5896 / n.powu(3)
+ 437.881 / n.powu(2)
+ 720.385709813466 / n
- 48.720000000000006 / (1. + n).powu(4)
+ 189.51000000000002 / (1. + n).powu(3)
+ 391.02500000000003 / (1. + n).powu(2)
+ 367.4750000000001 / (1. + n)
+ 404.47249999999997 / (2. + n)
- 2063.325 / ((1. + n).powu(2) * (2. + n))
- (1375.55 * n) / ((1. + n).powu(2) * (2. + n))
+ 687.775 / ((1. + n) * (2. + n))
- 81.71999999999998 / (3. + n)
+ 114.9225 / (4. + n)
+ 195.5772 * S1
- (817.725 * S1) / n.powu(2)
+ (714.46361 * S1) / n
- (687.775 * S1) / (1. + n)
- (817.725 * S2) / n
);
let eta = 1. / n * 1. / (n + 1.);
#[rustfmt::skip]
let P3NSA3 = -CF * (
-32. / 27. * ZETA3 * eta
- 16. / 9. * ZETA3
- 16. / 27. * eta.powu(4)
- 16. / 81. * eta.powu(3)
+ 80. / 27. * eta.powu(2)
- 320. / 81. * eta
+ 32. / 27. * 1. / (n + 1.).powu(4)
+ 128. / 27. * 1. / (n + 1.).powu(2)
+ 64. / 27. * S1 * ZETA3
- 32. / 81. * S1
- 32. / 81. * S2
- 160. / 81. * S3
+ 32. / 27. * S4
+ 131. / 81.
);

let mut result = cmplx!(0., 0.);

// Assembly regular piece.
let NF = nf as f64;
let P3NSMAI = P3NSA0 + NF * P3NSA1 + NF.pow(3) * P3NSA3 + NF.pow(2) * P3NSMA2;
result += Complex::from(match variation {
1 => P3NSMAI + P3NMA01 + NF * P3NMA11,
2 => P3NSMAI + P3NMA02 + NF * P3NMA12,
_ => P3NSMAI + 0.5 * ((P3NMA01 + P3NMA02) + NF * (P3NMA11 + P3NMA12)),
});

// The singular piece.
let A4qI = 2.120902 * f64::pow(10., 4) - 5.179372 * f64::pow(10., 3) * NF
// + 1.955772 * f64::pow(10.,2) * NF.pow(2)
// + 3.272344 * NF.pow(3)
;
let A4ap1 = -511.228 + 7.08645 * NF;
let A4ap2 = -502.481 + 7.82077 * NF;
let D1 = 1. / n - S1;
result += Complex::from(match variation {
1 => (A4qI + A4ap1) * D1,
2 => (A4qI + A4ap2) * D1,
_ => (A4qI + 0.5 * (A4ap1 + A4ap2)) * D1,
});

// ..The local piece.
let B4qI = 2.579609 * f64::pow(10., 4) + 0.08 - (5.818637 * f64::pow(10., 3) + 0.97) * NF
// + (1.938554 * f64::pow(10.,2) + 0.0037) * NF.pow(2)
// + 3.014982 * NF.pow(3)
;
let B4ap1 = -2426.05 + 266.674 * NF - 0.05 * NF;
let B4ap2 = -2380.255 + 270.518 * NF - 0.05 * NF;
result += Complex::from(match variation {
1 => B4qI + B4ap1,
2 => B4qI + B4ap2,
_ => B4qI + 0.5 * (B4ap1 + B4ap2),
});

-result
}

#[cfg(test)]
mod tests {

use super::*;
use crate::harmonics::cache::Cache;
use crate::{assert_approx_eq_cmplx, cmplx};
use num::complex::Complex;

#[test]
fn test_quark_number_conservation() {
let NF = 4;
let mut c = Cache::new(cmplx!(1., 0.));
// TODO: why these numbers are different from python,
// while the higher moments matches ?
let refs: [f64; 3] = [
-0.002068452870616966,
-0.006379286212450097,
0.002242380471443539,
];
for var in [0, 1, 2] {
let test_value = gamma_nsm(&mut c, NF, var);
assert_approx_eq_cmplx!(f64, test_value, cmplx!(refs[var as usize], 0.));
}
}

#[test]
fn test_non_singlet_reference_moments() {
let NF = 4;
let nsm_nf4_refs: [f64; 7] = [
4322.890485339998,
5491.581109692005,
6221.256799360004,
6774.606221595994,
7229.056043916002,
7618.358743427995,
7960.658678124,
];
for N in [3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0] {
let mut c = Cache::new(cmplx!(N, 0.));
let test_value = gamma_nsm(&mut c, NF, 0);
assert_approx_eq_cmplx!(
f64,
test_value,
cmplx!(nsm_nf4_refs[((N - 2.) / 2.) as usize], 0.),
rel = 8e-5
);
}
}
}
Loading
Loading