Skip to content
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

Add Grid::evolve, a better version of Grid::convolute_eko #184

Merged
merged 73 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
58e1132
Add first candidate for `Grid::evolve`
cschwan Oct 6, 2022
1e824cf
Finish documentation of `Grid::evolve`
cschwan Oct 6, 2022
66d103a
Add more checks of `Grid::evolve`'s arguments
cschwan Oct 6, 2022
58e8321
Add temporary fix of x-grid ordering
cschwan Oct 6, 2022
bc48d90
Update unit test of `Grid::evolve`
cschwan Oct 6, 2022
75899fe
Replace `todo` macros with errors
cschwan Oct 6, 2022
435a49e
Fix warnings reported by clippy
cschwan Oct 6, 2022
9596e77
Make floating points assertions less strict
cschwan Oct 6, 2022
69f4428
Fix small but subtle bug
cschwan Oct 6, 2022
f5beb8b
Implement permutation of the EKO x1 entries
cschwan Oct 6, 2022
f5c2cfe
Fix assertion statement in `Grid::evolve`
cschwan Oct 6, 2022
2ea81cc
Fix another bug in `Grid::evolve`
cschwan Oct 7, 2022
f3aeba7
Add more checks of `Grid::evolve`'s arguments
cschwan Oct 7, 2022
197d732
Split off a generic part of `Grid::evolve`
cschwan Oct 7, 2022
60788ff
Use different pids and operators for each initial state
cschwan Oct 7, 2022
47a1f96
Remove commented lines
cschwan Oct 8, 2022
5b73e39
Improve error reporting in `Grid::evolve`
cschwan Oct 8, 2022
cbacfe1
Move parts of `Grid::evolve` to separate functions
cschwan Oct 8, 2022
5fb14a8
Make `Grid::evolve` more general
cschwan Oct 8, 2022
26d72ce
Reduce memory usage of `Grid::evolve`
cschwan Oct 8, 2022
3e47643
Fix two bugs in `Grid::evolve`
cschwan Oct 8, 2022
adc0047
Generalize `Grid::evolve` further
cschwan Oct 8, 2022
4cc7771
Increase tolerance in numerical comparisons
cschwan Oct 8, 2022
9e4591d
Update `Grid::evolve`'s unit test
cschwan Oct 9, 2022
e86ed0e
Remove outdated TODO comment
cschwan Oct 9, 2022
803b393
Improve readability of `Grid::operators`
cschwan Oct 9, 2022
6e841ae
Add `Grid::has_pdf{1,2}` and `Grid::initial_state_{1,2}`
cschwan Oct 10, 2022
f0e1701
Prepare for DIS evolutions
cschwan Oct 10, 2022
bf18aac
Move evolution code into separate module
cschwan Oct 10, 2022
d0f0a98
Fix warning
cschwan Oct 10, 2022
64fbc32
Rename `lumi0` to `lumi0_with_two`
cschwan Oct 13, 2022
69e1b00
Add first implementation of `Grid::evolve_with_one`
cschwan Oct 13, 2022
e7d162e
Fix wrong x-grid values
cschwan Oct 13, 2022
6df9bf1
Fix serious bug in `Lumi::setup`
cschwan Oct 13, 2022
a06554d
Fix unit test
cschwan Oct 13, 2022
c63aa4c
Update changelog
cschwan Oct 13, 2022
a15d4b4
Fix bug introduced in commit f0e1701
cschwan Oct 13, 2022
2eef5ce
Relax numerical assertions
cschwan Oct 13, 2022
efee28f
Cache operators in `Grid::evolve_with_one`
cschwan Oct 14, 2022
8d5fdca
Move `evolve_with_{one,two}` to module `evolution`
cschwan Oct 14, 2022
fec9c0c
Change the order of members of `OperatorInfo`
cschwan Oct 14, 2022
c7143c0
Add Python bindings to evolve
felixhekhorn Oct 14, 2022
7b1eac3
Adjust documentation
cschwan Oct 14, 2022
c7ac8a2
Add `NNPDF_POS_ANTI_UP_40` unit test
cschwan Oct 14, 2022
5fbd46b
Enable all tests
cschwan Oct 14, 2022
deb1622
Optimize factorization scale selection in `evolve_with_one`
cschwan Oct 14, 2022
540cdf2
Add CHORUS_CC_NB_PB_SIGMARED unit test
cschwan Oct 14, 2022
9d9d40a
Cache EKOs for double-hadronic evolutions
cschwan Oct 16, 2022
1c88c99
Print warnings if evolved grids differ too much
cschwan Oct 16, 2022
feb1e19
Do not use alphas if its power is zero
cschwan Oct 16, 2022
c56f38c
Add new subcommand `evolve`
cschwan Oct 16, 2022
55e3ccb
Fix tests
cschwan Oct 16, 2022
a98c53e
Remove ignored unit tests
cschwan Oct 17, 2022
de501f4
Comment out ignored unit test
cschwan Oct 17, 2022
f91e7ca
Test evolutions with `LHCB_WP_8TEV`
cschwan Oct 17, 2022
6511fe7
Reduce verbosity of wget in CI
cschwan Oct 17, 2022
5f485ff
Test DIS evolution
cschwan Oct 17, 2022
4e13e5f
Add real DIS test
cschwan Oct 17, 2022
8d58423
Cache test data in CI
cschwan Oct 17, 2022
5407d6d
Update Python doc
felixhekhorn Oct 18, 2022
7b6fdb2
Add gluon exception
cschwan Oct 18, 2022
8c4274e
Add missing to gluon exception
cschwan Oct 18, 2022
7884fa1
Fix clippy warnings
cschwan Oct 18, 2022
932e073
Add integration test for gluon exception
cschwan Oct 18, 2022
ea0f672
Add missing test data to CI
cschwan Oct 18, 2022
1d45b83
Add parameters `xir` and `xif` to `evolve` subcommand
cschwan Oct 18, 2022
2de87b3
Fix scale-variation in `Grid::evolve`
cschwan Oct 18, 2022
701a8d6
Replace `unwrap` calls with meaningful error messages
cschwan Oct 18, 2022
8de3a3e
Use strong coupling from LHAPDF
cschwan Oct 19, 2022
143a394
Remove TODO - evolution succeeds
cschwan Oct 19, 2022
f4b97c3
Disable tests unless `--features=fktable` is enabled
cschwan Oct 19, 2022
99e53ed
Use chinese food mind game construction
cschwan Oct 19, 2022
f841dff
Fix the right factorization scale choice
cschwan Oct 21, 2022
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
2 changes: 2 additions & 0 deletions pineappl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ anyhow = "1.0.48"
lhapdf = "0.2.0"
rand = { default-features = false, version = "0.8.4" }
rand_pcg = { default-features = false, version = "0.3.1" }
serde_yaml = "0.9.13"
ndarray-npy = "0.8.1"
235 changes: 235 additions & 0 deletions pineappl/src/evolution.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
//! Supporting classes and functions for [`Grid::evolve`].

use super::grid::{GridError, Order};
use super::subgrid::{Mu2, Subgrid, SubgridEnum};
use float_cmp::approx_eq;
use itertools::Itertools;
use ndarray::{s, Array3, Array5, ArrayView1, Axis};
use std::iter;

/// Information about the evolution kernel operator (EKO) passed to [`Grid::evolve`] as `operator`,
/// which is used to convert a [`Grid`] into an [`FkTable`]. The dimensions of the EKO must
/// correspond to the values given in [`fac1`], [`pids0`], [`x0`], [`pids1`] and [`x1`], exactly in
/// this order. Members with a `1` are defined at the squared factorization scales given in
/// [`fac1`] (often called process scales) and are found in the [`Grid`] that [`Grid::evolve`] is
/// called with. Members with a `0` are defined at the squared factorization scale [`fac0`] (often
/// called fitting scale or starting scale) and are found in the [`FkTable`] resulting from
/// [`Grid::evolve`].
///
/// The EKO may convert a `Grid` from a basis given by the particle identifiers [`pids1`] to a
/// possibly different basis given by [`pids0`]. This basis must also be identified using
/// [`lumi_id_types`], which tells [`FkTable::convolute`] how to perform a convolution. The members
/// [`ren1`] and [`alphas`] must be the strong couplings given at the respective renormalization
/// scales. Finally, [`xir`] and [`xif`] can be used to vary the renormalization and factorization
/// scales, respectively, around their central values.
pub struct OperatorInfo {
/// Squared factorization scales of the `Grid`.
pub fac1: Vec<f64>,
/// Particle identifiers of the `FkTable`.
pub pids0: Vec<i32>,
/// `x`-grid coordinates of the `FkTable`
pub x0: Vec<f64>,
/// Particle identifiers of the `Grid`. If the `Grid` contains more particle identifiers than
/// given here, the contributions of them are silently ignored.
pub pids1: Vec<i32>,
/// `x`-grid coordinates of the `Grid`.
pub x1: Vec<f64>,

/// Squared factorization scale of the `FkTable`.
pub fac0: f64,
/// Renormalization scales of the `Grid`.
pub ren1: Vec<f64>,
/// Strong couplings corresponding to the order given in [`ren1`].
pub alphas: Vec<f64>,
/// Multiplicative factor for the central renormalization scale.
pub xir: f64,
/// Multiplicative factor for the central factorization scale.
pub xif: f64,
/// Identifier of the particle basis for the `FkTable`.
pub lumi_id_types: String,
}

pub(crate) fn pids(
operator: &Array5<f64>,
info: &OperatorInfo,
pid1_nonzero: &dyn Fn(i32) -> bool,
) -> (Vec<(usize, usize)>, Vec<(i32, i32)>) {
// list of all non-zero PID indices
let pid_indices: Vec<_> = (0..operator.dim().3)
.cartesian_product(0..operator.dim().1)
.filter(|&(pid0_idx, pid1_idx)| {
// 1) at least one element of the operator must be non-zero, and 2) the pid must be
// contained in the lumi somewhere
operator
.slice(s![.., pid1_idx, .., pid0_idx, ..])
.iter()
.any(|&value| value != 0.0)
&& pid1_nonzero(info.pids1[pid1_idx])
})
.collect();

// list of all non-zero (pid0, pid1) combinations
let pids = pid_indices
.iter()
.map(|&(pid0_idx, pid1_idx)| (info.pids0[pid0_idx], info.pids1[pid1_idx]))
.collect();

(pid_indices, pids)
}

pub(crate) fn lumi0(pids_a: &[(i32, i32)], pids_b: &[(i32, i32)]) -> Vec<(i32, i32)> {
let mut pids0_a: Vec<_> = pids_a.iter().map(|&(pid0, _)| pid0).collect();
pids0_a.sort_unstable();
pids0_a.dedup();
let mut pids0_b: Vec<_> = pids_b.iter().map(|&(pid0, _)| pid0).collect();
pids0_b.sort_unstable();
pids0_b.dedup();

pids0_a
.iter()
.copied()
.cartesian_product(pids0_b.iter().copied())
.collect()
}

pub(crate) fn operators(
operator: &Array5<f64>,
info: &OperatorInfo,
pid_indices: &[(usize, usize)],
x1: &[f64],
) -> Result<Vec<Array3<f64>>, GridError> {
// permutation between the grid x values and the operator x1 values
let x1_indices: Vec<_> = if let Some(x1_indices) = x1
.iter()
.map(|&x1p| {
info.x1
.iter()
.position(|&x1| approx_eq!(f64, x1p, x1, ulps = 64))
})
.collect()
{
x1_indices
} else {
return Err(GridError::EvolutionFailure(
"operator information does not match grid's x-grid values".to_string(),
));
};

// create the corresponding operators accessible in the form [muf2, x0, x1]
let operators: Vec<_> = pid_indices
.iter()
.map(|&(pid0_idx, pid1_idx)| {
operator
.slice(s![.., pid1_idx, .., pid0_idx, ..])
.select(Axis(1), &x1_indices)
.permuted_axes([0, 2, 1])
.as_standard_layout()
.into_owned()
})
.collect();

Ok(operators)
}

pub(crate) fn ndarray_from_subgrid_orders(
info: &OperatorInfo,
subgrids: &ArrayView1<SubgridEnum>,
orders: &[Order],
order_mask: &[bool],
) -> Result<(Vec<f64>, Vec<f64>, Array3<f64>), GridError> {
let mut x1_a: Vec<_> = subgrids
.iter()
.flat_map(|subgrid| subgrid.x1_grid().into_owned())
.collect();
let mut x1_b: Vec<_> = subgrids
.iter()
.flat_map(|subgrid| subgrid.x2_grid().into_owned())
.collect();

x1_a.sort_by(|a, b| a.partial_cmp(b).unwrap());
x1_a.dedup_by(|a, b| approx_eq!(f64, *a, *b, ulps = 64));
x1_b.sort_by(|a, b| a.partial_cmp(b).unwrap());
x1_b.dedup_by(|a, b| approx_eq!(f64, *a, *b, ulps = 64));

let mut array = Array3::<f64>::zeros((info.fac1.len(), x1_a.len(), x1_b.len()));

// add subgrids for different orders, but the same bin and lumi, using the right
// couplings
for (subgrid, order) in subgrids
.iter()
.zip(orders.iter())
.zip(order_mask.iter().chain(iter::repeat(&true)))
.filter_map(|((subgrid, order), &enabled)| {
(enabled && !subgrid.is_empty()).then(|| (subgrid, order))
})
{
let mut logs = 1.0;

if order.logxir > 0 {
if approx_eq!(f64, info.xir, 1.0, ulps = 4) {
continue;
}

logs *= (info.xir * info.xir).ln();
}

if order.logxif > 0 {
if approx_eq!(f64, info.xif, 1.0, ulps = 4) {
continue;
}

logs *= (info.xif * info.xif).ln();
}

let xa_indices: Vec<_> = subgrid
.x1_grid()
.iter()
.map(|&xa| {
x1_a.iter()
.position(|&x1a| approx_eq!(f64, x1a, xa, ulps = 64))
.unwrap()
})
.collect();
let xb_indices: Vec<_> = subgrid
.x2_grid()
.iter()
.map(|&xb| {
x1_b.iter()
.position(|&x1b| approx_eq!(f64, x1b, xb, ulps = 64))
.unwrap()
})
.collect();

for ((imu2, ix1, ix2), value) in subgrid.iter() {
let Mu2 {
ren: mur2,
fac: muf2,
} = subgrid.mu2_grid()[imu2];

let als = if let Some(alphas) = info
.ren1
.iter()
.zip(info.alphas.iter())
.find_map(|(&ren1, &alphas)| approx_eq!(f64, ren1, mur2, ulps = 64).then(|| alphas))
{
alphas.powi(order.alphas.try_into().unwrap())
} else {
return Err(GridError::EvolutionFailure(format!(
"could not find alphas for mur2 = {}",
mur2
)));
};

// TODO: get rid of the `unwrap`
let mu2_index = info
.fac1
.iter()
.position(|&fac| approx_eq!(f64, fac, muf2, ulps = 64))
.unwrap();

array[[mu2_index, xa_indices[ix1], xb_indices[ix2]]] += als * logs * value;
}
}

Ok((x1_a, x1_b, array))
}
Loading