Skip to content

Commit

Permalink
Start generalizing C-interface with _lumi_add2, _grid_new2, and `…
Browse files Browse the repository at this point in the history
…_grid_fill2`
  • Loading branch information
Radonirinaunimi committed Oct 23, 2024
1 parent c0fe82a commit 9e30754
Showing 1 changed file with 251 additions and 3 deletions.
254 changes: 251 additions & 3 deletions pineappl_capi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs::File;
use std::mem;
use std::os::raw::{c_char, c_void};
use std::os::raw::{c_char, c_int, c_void};
use std::path::Path;
use std::slice;

Expand Down Expand Up @@ -691,8 +691,6 @@ pub unsafe extern "C" fn pineappl_grid_order_count(grid: *const Grid) -> usize {
grid.orders().len()
}

// TODO: add a function that supports fragmentation scale logs

/// Creates a new and empty grid. The creation requires four different sets of parameters:
/// - The luminosity function `lumi`: A pointer to the luminosity function that specifies how the
/// cross section should be reconstructed.
Expand Down Expand Up @@ -1357,3 +1355,253 @@ pub unsafe extern "C" fn pineappl_string_delete(string: *mut c_char) {
mem::drop(unsafe { CString::from_raw(string) });
}
}

// Here starts the generalized C-API interface.

/// Type for defining the interpolation object
#[repr(C)]
pub struct InterpTuples {
node_min: f64,
node_max: f64,
nb_nodes: usize,
interp_degree: usize,
reweighting_method: *const c_char,
mapping: *const c_char,
interpolation_method: *const c_char,
}

#[must_use]
fn construct_interpolation(interp: &InterpTuples) -> Interp {
// Interpolation specs for the reweighting
let reweight_mth = match unsafe {
CStr::from_ptr(interp.reweighting_method)
.to_str()
.expect("Failed to convert `reweighting_method` into a proper string.")
} {
"applgrid" => ReweightMeth::ApplGridX,
"noreweight" => ReweightMeth::NoReweight,
_ => todo!(),
};

// Interpolation specs for the mapping
let mapping = match unsafe {
CStr::from_ptr(interp.mapping)
.to_str()
.expect("Failed to convert `mapping` into a proper string.")
} {
"applgrid_f2" => Map::ApplGridF2,
"applgrid_h0" => Map::ApplGridH0,
_ => todo!(),
};

// Interpolation specs for the Interpolation Method
let interp_meth = match unsafe {
CStr::from_ptr(interp.interpolation_method)
.to_str()
.expect("Failed to convert `interpolation_method` into a proper string.")
} {
"lagrange" => InterpMeth::Lagrange,
_ => todo!(),
};

Interp::new(
interp.node_min,
interp.node_max,
interp.nb_nodes,
interp.interp_degree,
reweight_mth,
mapping,
interp_meth,
)
}

/// Adds a generalized linear combination of initial states to the Luminosity.
///
/// # Safety
///
/// The parameter `lumi` must point to a valid `Lumi` object created by `pineappl_lumi_new`.
/// `pdg_id_combinations` must be an array with length `n_combinations * combinations`, and
/// `factors` with length of `combinations`.
#[no_mangle]
pub unsafe extern "C" fn pineappl_lumi_add2(
lumi: *mut Lumi,
combinations: usize,
nb_combinations: usize,
pdg_id_combinations: *const i32,
factors: *const f64,
) {
let lumi = unsafe { &mut *lumi };
let pdg_id_pairs =
unsafe { slice::from_raw_parts(pdg_id_combinations, nb_combinations * combinations) };
let factors = if factors.is_null() {
vec![1.0; combinations]
} else {
unsafe { slice::from_raw_parts(factors, combinations) }.to_vec()
};

lumi.0.push(Channel::new(
pdg_id_pairs
.chunks(nb_combinations)
.zip(factors)
.map(|x| ((0..nb_combinations).map(|i| x.0[i]).collect(), x.1))
.collect(),
));
}

/// Creates a new and empty grid that can accept any number of convolutions. The creation requires
/// the following different sets of parameters:
/// - The PID basis `pid_basis`: The basis onto which the partons are mapped, can be `Evol` or `Pdg`.
/// - The channel function `channels`: A pointer to the luminosity function that specifies how the
/// cross section should be reconstructed.
/// - Order specification `orders` and `order_params`. Each `PineAPPL` grid contains a number of
/// different perturbative orders, specified by `orders`. The array `order_params` stores the
/// exponent of each perturbative order and must contain 4 integers denoting the exponent of the
/// string coupling, of the electromagnetic coupling, of the logarithm of the renormalization
/// scale, and finally of the logarithm of the factorization scale.
/// - The observable definition `bins` and `bin_limits`. Each `PineAPPL` grid can store observables
/// from a one-dimensional distribution. To this end `bins` specifies how many observables are
/// stored and `bin_limits` must contain `bins + 1` entries denoting the left and right limit for
/// each bin.
/// - The types of convolutions `convolution_types` and their numbers `nb_convolutions`: specify how
/// how many different convolutions are involved and their types - which are a cross product of the
/// the following combination: (unpolarized, polarized) ⊗ (PDF, Fragmentation Function).
/// - The PDG IDs of the involved initial- or final-state hadrons `pdg_ids`.
/// - The types of kinematics `kinematics`: specify the various kinematics required to construct the
/// Grid. These can be the energy and the various momentum fractions.
/// - The specifications of the interpolation methods `interpolations`: provide the specifications on
/// how each of the kinematics should be interpolated.
///
/// # Safety
///
/// # Panics
#[no_mangle]
#[must_use]
pub unsafe extern "C" fn pineappl_grid_new2(
pid_basis: *const c_char, // takes: `const char* pid_basis = "Evol";`
channels: *const Lumi,
orders: usize,
order_params: *const u32,
bins: usize,
bin_limits: *const f64,
nb_convolutions: usize,
convolution_types: *const *const c_char, // takes: `const char* convtype[] = { "UnpolPDF" };`
pdg_ids: *const c_int, // takes: `const char* pdg_dis[] = { 2212 }`
kinematics: *const *const c_char, // takes: `const char* kinematics[] = { "scale", "x1" }`
interpolations: *const InterpTuples, // takes: `struct InterpTuples interpdata[] = { {...} }`
) -> Box<Grid> {
// PID Basis
let pid_basis = match unsafe {
CStr::from_ptr(pid_basis)
.to_str()
.expect("Failed to convert `pid_basis` into a proper string.")
} {
"Evol" => PidBasis::Evol,
"Pdg" => PidBasis::Pdg,
_ => todo!(),
};

// Luminosity channels
let channels = unsafe { &*channels };

// Perturbative orders
let order_params = unsafe { slice::from_raw_parts(order_params, 4 * orders) };
let orders: Vec<_> = order_params
.chunks(4)
.map(|s| Order {
alphas: s[0].try_into().unwrap(),
alpha: s[1].try_into().unwrap(),
logxir: s[2].try_into().unwrap(),
logxif: s[3].try_into().unwrap(),
logxia: s[4].try_into().unwrap(),
})
.collect();

// Bin limits
let bin_limits = unsafe { slice::from_raw_parts(bin_limits, bins + 1).to_vec() };

// Types of convolutions
let mut convolutions = Vec::new();
for i in 0..nb_convolutions {
let c_conv = unsafe {
let str_ptr = *convolution_types.add(i);
CStr::from_ptr(str_ptr)
.to_str()
.expect("Failed to convert one of the `convolution_types` into a proper string.")
};

let pid_value = unsafe { *pdg_ids.add(i) };

let cvtype = match c_conv {
"UnpolPDF" => Conv::new(ConvType::UnpolPDF, pid_value),
"PolPDF" => Conv::new(ConvType::PolPDF, pid_value),
"UnpolFF" => Conv::new(ConvType::UnpolFF, pid_value),
"PolFF" => Conv::new(ConvType::PolFF, pid_value),
_ => todo!(),
};
convolutions.push(cvtype);
}

// Grid interpolations
let mut interp_vecs = Vec::new();
let interp_slices = unsafe { std::slice::from_raw_parts(interpolations, nb_convolutions + 1) };
for interp_ref in interp_slices {
interp_vecs.push(construct_interpolation(interp_ref));
}

// Kinematics
let mut kinematics_vec = Vec::new();
for k in 0..=nb_convolutions {
let kin = unsafe {
let kin_ptr = *kinematics.add(k);
CStr::from_ptr(kin_ptr)
.to_str()
.expect("Failed to convert one of the `kinematics` types into a proper string.")
};

let kin_type = match kin {
"scale" => Kinematics::Scale(0),
"x1" => Kinematics::X1,
"x2" => Kinematics::X2,
_ => todo!(),
};
kinematics_vec.push(kin_type);
}

Box::new(Grid::new(
pid_basis,
channels.0.clone(),
orders,
bin_limits,
convolutions,
interp_vecs,
kinematics_vec,
Scales {
ren: ScaleFuncForm::Scale(0),
fac: ScaleFuncForm::Scale(0),
frg: ScaleFuncForm::NoScale,
},
))
}

/// Fill `grid` for the given momentum fractions {`x1`, `x2`,..., `xn`}, at the scale `q2`
/// for the given value of the `order`, `observable`, and `lumi` with `weight`.
///
/// # Safety
///
/// If `grid` does not point to a valid `Grid` object, for example when `grid` is the null pointer,
/// this function is not safe to call.
#[no_mangle]
pub unsafe extern "C" fn pineappl_grid_fill2(
grid: *mut Grid,
order: usize,
observable: f64,
lumi: usize,
ntuple: *const f64,
weight: f64,
size_tuple: usize,
) {
let grid = unsafe { &mut *grid };
let ntuple = unsafe { slice::from_raw_parts(ntuple, size_tuple) };

grid.fill(order, observable, lumi, ntuple, weight);
}

0 comments on commit 9e30754

Please sign in to comment.