use std::ffi::CStr;
use std::os::raw::{c_char, c_double, c_int};
use std::slice;
use neopdf::gridpdf::{ForcePositive, GridArray};
use neopdf::metadata::{InterpolatorType, MetaData, SetType};
use neopdf::parser::SubgridData;
use neopdf::pdf::PDF;
use neopdf::writer::GridArrayCollection;
const DEFAULT_PIDS: [i32; 14] = [21, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 22];
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NeopdfResult {
Success = 0,
ErrorNullPointer = -1,
ErrorInvalidData = -2,
ErrorMemoryError = -3,
ErrorInvalidLength = -4,
}
impl From<NeopdfResult> for c_int {
fn from(result: NeopdfResult) -> Self {
result as Self
}
}
pub struct NeoPDFWrapper(PDF);
#[repr(C)]
pub struct NeoPDFMembers {
pub pdfs: *mut *mut NeoPDFWrapper,
pub size: usize,
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_load(
pdf_name: *const c_char,
member: usize,
) -> *mut NeoPDFWrapper {
let c_str = unsafe { CStr::from_ptr(pdf_name) };
let pdf_name = c_str.to_str().expect("Invalid UTF-8 string");
let pdf = PDF::load(pdf_name, member);
Box::into_raw(Box::new(NeoPDFWrapper(pdf)))
}
#[no_mangle]
pub extern "C" fn neopdf_pdf_load_by_lhaid(lhaid: u32) -> *mut NeoPDFWrapper {
let pdf = PDF::load_by_lhaid(lhaid);
Box::into_raw(Box::new(NeoPDFWrapper(pdf)))
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_load_lhapdf_by_file(path: *const c_char) -> *mut NeoPDFWrapper {
let c_str = unsafe { CStr::from_ptr(path) };
let path_str = c_str.to_str().expect("Invalid UTF-8 string for path");
let pdf = PDF::load_lhapdf_by_file(path_str);
Box::into_raw(Box::new(NeoPDFWrapper(pdf)))
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_load_all(pdf_name: *const c_char) -> NeoPDFMembers {
let c_str = unsafe { CStr::from_ptr(pdf_name) };
let pdf_name = c_str.to_str().expect("Invalid UTF-8 string");
let pdfs = PDF::load_pdfs(pdf_name);
let length = pdfs.len();
let mut pdf_pointers: Vec<*mut NeoPDFWrapper> = pdfs
.into_iter()
.map(|pdf| Box::into_raw(Box::new(NeoPDFWrapper(pdf))))
.collect();
let pdfs_ptr = pdf_pointers.as_mut_ptr();
std::mem::forget(pdf_pointers);
NeoPDFMembers {
pdfs: pdfs_ptr,
size: length,
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_free(pdf: *mut NeoPDFWrapper) {
if pdf.is_null() {
return;
}
unsafe { drop(Box::from_raw(pdf)) };
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_array_free(pdfs: NeoPDFMembers) {
if pdfs.pdfs.is_null() {
return;
}
let pdf_pointers = unsafe { Vec::from_raw_parts(pdfs.pdfs, pdfs.size, pdfs.size) };
for pdf_ptr in pdf_pointers {
if !pdf_ptr.is_null() {
unsafe { drop(Box::from_raw(pdf_ptr)) };
}
}
}
pub struct NeoPDFLazyIterator(Box<dyn Iterator<Item = Result<PDF, Box<dyn std::error::Error>>>>);
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_load_lazy(pdf_name: *const c_char) -> *mut NeoPDFLazyIterator {
let c_str = unsafe { CStr::from_ptr(pdf_name) };
let pdf_name = c_str.to_str().expect("Invalid UTF-8 string");
if !pdf_name.ends_with(".neopdf.lz4") {
return std::ptr::null_mut();
}
let lazy_iter = PDF::load_pdfs_lazy(pdf_name);
let boxed_iter: Box<dyn Iterator<Item = Result<PDF, Box<dyn std::error::Error>>>> =
Box::new(lazy_iter);
Box::into_raw(Box::new(NeoPDFLazyIterator(boxed_iter)))
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_lazy_iterator_next(
iter: *mut NeoPDFLazyIterator,
) -> *mut NeoPDFWrapper {
if iter.is_null() {
return std::ptr::null_mut();
}
let iter_wrapper = unsafe { &mut (*iter).0 };
match iter_wrapper.next() {
Some(Ok(pdf)) => Box::into_raw(Box::new(NeoPDFWrapper(pdf))),
Some(Err(_)) | None => std::ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_lazy_iterator_free(iter: *mut NeoPDFLazyIterator) {
if !iter.is_null() {
unsafe { drop(Box::from_raw(iter)) };
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_x_min(pdf: *mut NeoPDFWrapper) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.param_ranges().x.min
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_x_max(pdf: *mut NeoPDFWrapper) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.param_ranges().x.max
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_q2_min(pdf: *mut NeoPDFWrapper) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.param_ranges().q2.min
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_q2_max(pdf: *mut NeoPDFWrapper) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.param_ranges().q2.max
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_xfxq2(
pdf: *mut NeoPDFWrapper,
id: i32,
x: f64,
q2: f64,
) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.xfxq2(id, &[x, q2])
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_xfxq2_nd(
pdf: *mut NeoPDFWrapper,
id: i32,
params: *mut f64,
num_params: usize,
) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let params = unsafe { slice::from_raw_parts(params, num_params) };
pdf_obj.xfxq2(id, params)
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_xfxq2_cheby_batch(
pdf: *mut NeoPDFWrapper,
pid: i32,
points: *const *const c_double,
lengths: *const usize,
num_points: usize,
results: *mut c_double,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let points_slices: &[*const c_double] = unsafe { slice::from_raw_parts(points, num_points) };
let lengths_slice: &[usize] = unsafe { slice::from_raw_parts(lengths, num_points) };
let rust_points: Vec<&[f64]> = points_slices
.iter()
.zip(lengths_slice)
.map(|(&p, &l)| unsafe { slice::from_raw_parts(p, l) })
.collect();
let res_vec = pdf_obj.xfxq2_cheby_batch(pid, &rust_points);
let results_slice = unsafe { slice::from_raw_parts_mut(results, res_vec.len()) };
results_slice.copy_from_slice(&res_vec);
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_xfxq2_pids(
pdf: *mut NeoPDFWrapper,
pids: *const c_int,
num_pids: usize,
points: *const c_double,
num_points: usize,
results: *mut c_double,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let pids_slice = unsafe { slice::from_raw_parts(pids, num_pids) };
let points_slice = unsafe { slice::from_raw_parts(points, num_points) };
let results_slice = unsafe { slice::from_raw_parts_mut(results, num_pids) };
pdf_obj.xfxq2_allpids(pids_slice, points_slice, results_slice);
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_xfxq2s(
pdf: *mut NeoPDFWrapper,
pids: *const c_int,
num_pids: usize,
points: *const *const c_double,
lengths: *const usize,
num_points: usize,
results: *mut c_double,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let pids_slice = unsafe { slice::from_raw_parts(pids, num_pids) };
let points_slices = unsafe { slice::from_raw_parts(points, num_points) };
let lengths_slice = unsafe { slice::from_raw_parts(lengths, num_points) };
let rust_points: Vec<&[f64]> = points_slices
.iter()
.zip(lengths_slice)
.map(|(&p, &l)| unsafe { slice::from_raw_parts(p, l) })
.collect();
let result_array = pdf_obj.xfxq2s(pids_slice.to_vec(), &rust_points);
let results_slice = unsafe { slice::from_raw_parts_mut(results, num_pids * num_points) };
results_slice.copy_from_slice(result_array.as_slice().unwrap());
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_set_force_positive(
pdf: *mut NeoPDFWrapper,
option: ForcePositive,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &mut (*pdf).0 };
pdf_obj.set_force_positive(option);
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_set_force_positive_members(
pdfs: *mut NeoPDFMembers,
option: ForcePositive,
) {
assert!(!pdfs.is_null());
let members = unsafe { &mut *pdfs };
let pdf_slice = unsafe { slice::from_raw_parts_mut(members.pdfs, members.size) };
for pdf_ptr in pdf_slice {
let pdf_obj = unsafe { &mut (**pdf_ptr).0 };
pdf_obj.set_force_positive(option.clone());
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_is_force_positive(pdf: *mut NeoPDFWrapper) -> ForcePositive {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &mut (*pdf).0 };
pdf_obj.is_force_positive().clone()
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_alphas_q2(pdf: *mut NeoPDFWrapper, q2: f64) -> f64 {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.alphas_q2(q2)
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_num_pids(pdf: *mut NeoPDFWrapper) -> usize {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.pids().len()
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_pids(pdf: *mut NeoPDFWrapper, pids: *mut i32, num_pids: usize) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let pids = unsafe { slice::from_raw_parts_mut(pids, num_pids) };
let pid_values = pdf_obj.pids();
pids.copy_from_slice(pid_values.as_slice().unwrap());
}
#[repr(C)]
pub enum NeopdfSubgridParams {
Nucleons,
Alphas,
Xi,
Delta,
Kt,
Momentum,
Scale,
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_num_subgrids(pdf: *mut NeoPDFWrapper) -> usize {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
pdf_obj.num_subgrids()
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_param_range(
pdf: *mut NeoPDFWrapper,
param: NeopdfSubgridParams,
param_range: *mut f64,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let param_range = unsafe { slice::from_raw_parts_mut(param_range, 2) };
let range_params = match param {
NeopdfSubgridParams::Nucleons => &[
pdf_obj.param_ranges().nucleons.min,
pdf_obj.param_ranges().nucleons.max,
],
NeopdfSubgridParams::Alphas => &[
pdf_obj.param_ranges().alphas.min,
pdf_obj.param_ranges().alphas.max,
],
NeopdfSubgridParams::Xi => &[pdf_obj.param_ranges().xi.min, pdf_obj.param_ranges().xi.max],
NeopdfSubgridParams::Delta => &[
pdf_obj.param_ranges().delta.min,
pdf_obj.param_ranges().delta.max,
],
NeopdfSubgridParams::Kt => &[pdf_obj.param_ranges().kt.min, pdf_obj.param_ranges().kt.max],
NeopdfSubgridParams::Momentum => {
&[pdf_obj.param_ranges().x.min, pdf_obj.param_ranges().x.max]
}
NeopdfSubgridParams::Scale => {
&[pdf_obj.param_ranges().q2.min, pdf_obj.param_ranges().q2.max]
}
};
param_range.copy_from_slice(range_params);
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_subgrids_shape_for_param(
pdf: *mut NeoPDFWrapper,
subgrid_shape: *mut usize,
num_subgrid: usize,
subgrid_param: NeopdfSubgridParams,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let subgrid_shape = unsafe { slice::from_raw_parts_mut(subgrid_shape, num_subgrid) };
let shape_subgrids: Vec<usize> = pdf_obj
.subgrids()
.iter()
.map(|sub| match subgrid_param {
NeopdfSubgridParams::Nucleons => sub.nucleons.len(),
NeopdfSubgridParams::Alphas => sub.alphas.len(),
NeopdfSubgridParams::Xi => sub.xis.len(),
NeopdfSubgridParams::Delta => sub.deltas.len(),
NeopdfSubgridParams::Kt => sub.kts.len(),
NeopdfSubgridParams::Momentum => sub.xs.len(),
NeopdfSubgridParams::Scale => sub.q2s.len(),
})
.collect();
subgrid_shape.copy_from_slice(&shape_subgrids);
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_pdf_subgrids_for_param(
pdf: *mut NeoPDFWrapper,
subgrid: *mut f64,
subgrid_param: NeopdfSubgridParams,
num_subgrid: usize,
subgrid_shape: *mut usize,
subgrid_index: usize,
) {
assert!(!pdf.is_null());
let pdf_obj = unsafe { &(*pdf).0 };
let subgrid_shape = unsafe { slice::from_raw_parts(subgrid_shape, num_subgrid) };
let subgrid = unsafe { slice::from_raw_parts_mut(subgrid, subgrid_shape[subgrid_index]) };
let subgrid_knots = match subgrid_param {
NeopdfSubgridParams::Nucleons => &pdf_obj.subgrids()[subgrid_index].nucleons,
NeopdfSubgridParams::Alphas => &pdf_obj.subgrids()[subgrid_index].alphas,
NeopdfSubgridParams::Xi => &pdf_obj.subgrids()[subgrid_index].xis,
NeopdfSubgridParams::Delta => &pdf_obj.subgrids()[subgrid_index].deltas,
NeopdfSubgridParams::Kt => &pdf_obj.subgrids()[subgrid_index].kts,
NeopdfSubgridParams::Momentum => &pdf_obj.subgrids()[subgrid_index].xs,
NeopdfSubgridParams::Scale => &pdf_obj.subgrids()[subgrid_index].q2s,
};
subgrid.copy_from_slice(subgrid_knots.as_slice().unwrap());
}
pub struct NeoPDFGrid {
subgrids: Vec<SubgridData>,
flavors: Vec<i32>,
}
impl NeoPDFGrid {
const fn new() -> Self {
Self {
subgrids: Vec::new(),
flavors: Vec::new(),
}
}
#[allow(clippy::too_many_arguments)]
unsafe fn add_subgrid(
&mut self,
nucleons: *const c_double,
num_nucleons: usize,
alphas: *const c_double,
num_alphas: usize,
kts: *const c_double,
num_kts: usize,
xs: *const c_double,
num_xs: usize,
q2s: *const c_double,
num_q2s: usize,
grid_data: *const c_double,
grid_data_len: usize,
) -> NeopdfResult {
if nucleons.is_null()
|| alphas.is_null()
|| kts.is_null()
|| xs.is_null()
|| q2s.is_null()
|| grid_data.is_null()
{
return NeopdfResult::ErrorNullPointer;
}
let subgrid = unsafe {
SubgridData {
nucleons: slice::from_raw_parts(nucleons, num_nucleons).to_vec(),
alphas: slice::from_raw_parts(alphas, num_alphas).to_vec(),
xis: vec![0.0],
deltas: vec![0.0],
kts: slice::from_raw_parts(kts, num_kts).to_vec(),
xs: slice::from_raw_parts(xs, num_xs).to_vec(),
q2s: slice::from_raw_parts(q2s, num_q2s).to_vec(),
grid_data: slice::from_raw_parts(grid_data, grid_data_len).to_vec(),
}
};
self.subgrids.push(subgrid);
NeopdfResult::Success
}
unsafe fn set_flavors(&mut self, flavors: *const c_int, num_flavors: usize) -> NeopdfResult {
if flavors.is_null() {
return NeopdfResult::ErrorNullPointer;
}
self.flavors = unsafe { slice::from_raw_parts(flavors, num_flavors).to_vec() };
NeopdfResult::Success
}
#[allow(clippy::too_many_arguments, clippy::similar_names)]
unsafe fn add_subgrid_v2(
&mut self,
nucleons: *const c_double,
num_nucleons: usize,
alphas: *const c_double,
num_alphas: usize,
xis: *const c_double,
num_xis: usize,
deltas: *const c_double,
num_deltas: usize,
kts: *const c_double,
num_kts: usize,
xs: *const c_double,
num_xs: usize,
q2s: *const c_double,
num_q2s: usize,
grid_data: *const c_double,
grid_data_len: usize,
) -> NeopdfResult {
if nucleons.is_null()
|| alphas.is_null()
|| xis.is_null()
|| deltas.is_null()
|| kts.is_null()
|| xs.is_null()
|| q2s.is_null()
|| grid_data.is_null()
{
return NeopdfResult::ErrorNullPointer;
}
let subgrid = unsafe {
SubgridData {
nucleons: slice::from_raw_parts(nucleons, num_nucleons).to_vec(),
alphas: slice::from_raw_parts(alphas, num_alphas).to_vec(),
xis: slice::from_raw_parts(xis, num_xis).to_vec(),
deltas: slice::from_raw_parts(deltas, num_deltas).to_vec(),
kts: slice::from_raw_parts(kts, num_kts).to_vec(),
xs: slice::from_raw_parts(xs, num_xs).to_vec(),
q2s: slice::from_raw_parts(q2s, num_q2s).to_vec(),
grid_data: slice::from_raw_parts(grid_data, grid_data_len).to_vec(),
}
};
self.subgrids.push(subgrid);
NeopdfResult::Success
}
}
#[no_mangle]
pub extern "C" fn neopdf_grid_new() -> *mut NeoPDFGrid {
Box::into_raw(Box::new(NeoPDFGrid::new()))
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_grid_add_subgrid(
grid: *mut NeoPDFGrid,
nucleons: *const c_double,
num_nucleons: usize,
alphas: *const c_double,
num_alphas: usize,
kts: *const c_double,
num_kts: usize,
xs: *const c_double,
num_xs: usize,
q2s: *const c_double,
num_q2s: usize,
grid_data: *const c_double,
grid_data_len: usize,
) -> NeopdfResult {
unsafe {
grid.as_mut()
.map_or(NeopdfResult::ErrorNullPointer, |grid| {
grid.add_subgrid(
nucleons,
num_nucleons,
alphas,
num_alphas,
kts,
num_kts,
xs,
num_xs,
q2s,
num_q2s,
grid_data,
grid_data_len,
)
})
}
}
#[allow(clippy::similar_names)]
#[no_mangle]
pub unsafe extern "C" fn neopdf_grid_add_subgridv2(
grid: *mut NeoPDFGrid,
nucleons: *const c_double,
num_nucleons: usize,
alphas: *const c_double,
num_alphas: usize,
xis: *const c_double,
num_xis: usize,
deltas: *const c_double,
num_deltas: usize,
kts: *const c_double,
num_kts: usize,
xs: *const c_double,
num_xs: usize,
q2s: *const c_double,
num_q2s: usize,
grid_data: *const c_double,
grid_data_len: usize,
) -> NeopdfResult {
unsafe {
grid.as_mut()
.map_or(NeopdfResult::ErrorNullPointer, |grid| {
grid.add_subgrid_v2(
nucleons,
num_nucleons,
alphas,
num_alphas,
xis,
num_xis,
deltas,
num_deltas,
kts,
num_kts,
xs,
num_xs,
q2s,
num_q2s,
grid_data,
grid_data_len,
)
})
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_grid_set_flavors(
grid: *mut NeoPDFGrid,
flavors: *const c_int,
num_flavors: usize,
) -> NeopdfResult {
unsafe {
grid.as_mut()
.map_or(NeopdfResult::ErrorNullPointer, |grid| {
grid.set_flavors(flavors, num_flavors)
})
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_grid_free(grid: *mut NeoPDFGrid) {
if !grid.is_null() {
unsafe { drop(Box::from_raw(grid)) };
}
}
#[repr(C)]
pub struct NeoPDFPhysicsParameters {
pub flavor_scheme: *const c_char,
pub order_qcd: u32,
pub alphas_order_qcd: u32,
pub m_w: f64,
pub m_z: f64,
pub m_up: f64,
pub m_down: f64,
pub m_strange: f64,
pub m_charm: f64,
pub m_bottom: f64,
pub m_top: f64,
pub alphas_type: *const c_char,
pub number_flavors: u32,
}
#[repr(C)]
pub struct NeoPDFMetaData {
set_desc: *const c_char,
set_index: u32,
num_members: u32,
x_min: c_double,
x_max: c_double,
q_min: c_double,
q_max: c_double,
flavors: *const c_int,
num_flavors: usize,
format: *const c_char,
alphas_q_values: *const c_double,
num_alphas_q: usize,
alphas_vals: *const c_double,
num_alphas_vals: usize,
polarised: bool,
set_type: SetType,
interpolator_type: InterpolatorType,
error_type: *const c_char,
hadron_pid: c_int,
phys_params: NeoPDFPhysicsParameters,
}
#[repr(C)]
pub struct NeoPDFMetaDataV2 {
set_desc: *const c_char,
set_index: u32,
num_members: u32,
x_min: c_double,
x_max: c_double,
q_min: c_double,
q_max: c_double,
flavors: *const c_int,
num_flavors: usize,
format: *const c_char,
alphas_q_values: *const c_double,
num_alphas_q: usize,
alphas_vals: *const c_double,
num_alphas_vals: usize,
polarised: bool,
set_type: SetType,
interpolator_type: InterpolatorType,
error_type: *const c_char,
hadron_pid: c_int,
phys_params: NeoPDFPhysicsParameters,
xi_min: c_double,
xi_max: c_double,
delta_min: c_double,
delta_max: c_double,
}
unsafe fn cstr_to_string(ptr: *const c_char) -> Option<String> {
if ptr.is_null() {
None
} else {
unsafe { Some(CStr::from_ptr(ptr).to_string_lossy().into_owned()) }
}
}
unsafe fn carray_to_vec<T: Copy>(ptr: *const T, len: usize) -> Option<Vec<T>> {
if ptr.is_null() {
None
} else {
unsafe { Some(slice::from_raw_parts(ptr, len).to_vec()) }
}
}
fn process_metadata(meta: *const NeoPDFMetaData) -> Option<MetaData> {
if meta.is_null() {
return None;
}
let meta = unsafe { &*meta };
let set_desc = unsafe { cstr_to_string(meta.set_desc) }?;
let format = unsafe { cstr_to_string(meta.format) }?;
let flavors = unsafe { carray_to_vec(meta.flavors, meta.num_flavors) }?;
let alphas_q_values = unsafe { carray_to_vec(meta.alphas_q_values, meta.num_alphas_q) }?;
let alphas_vals = unsafe { carray_to_vec(meta.alphas_vals, meta.num_alphas_vals) }?;
let error_type = unsafe { cstr_to_string(meta.error_type) }?;
let flavor_scheme = unsafe { cstr_to_string(meta.phys_params.flavor_scheme) }?;
let alphas_type = unsafe { cstr_to_string(meta.phys_params.alphas_type) }?;
let metadata = MetaData {
set_desc,
set_index: meta.set_index,
num_members: meta.num_members,
x_min: meta.x_min,
x_max: meta.x_max,
q_min: meta.q_min,
q_max: meta.q_max,
flavors,
format,
alphas_q_values,
alphas_vals,
polarised: meta.polarised,
set_type: meta.set_type.clone(),
interpolator_type: meta.interpolator_type.clone(),
error_type,
hadron_pid: meta.hadron_pid,
git_version: String::new(), code_version: String::new(), flavor_scheme,
order_qcd: meta.phys_params.order_qcd,
alphas_order_qcd: meta.phys_params.alphas_order_qcd,
m_w: meta.phys_params.m_w,
m_z: meta.phys_params.m_z,
m_up: meta.phys_params.m_up,
m_down: meta.phys_params.m_down,
m_strange: meta.phys_params.m_strange,
m_charm: meta.phys_params.m_charm,
m_bottom: meta.phys_params.m_bottom,
m_top: meta.phys_params.m_top,
alphas_type,
number_flavors: meta.phys_params.number_flavors,
xi_min: 1.0,
xi_max: 1.0,
delta_min: 0.0,
delta_max: 0.0,
error_conf_level: None,
};
Some(metadata)
}
fn process_metadata_v2(meta: *const NeoPDFMetaDataV2) -> Option<MetaData> {
if meta.is_null() {
return None;
}
let meta = unsafe { &*meta };
let set_desc = unsafe { cstr_to_string(meta.set_desc) }?;
let format = unsafe { cstr_to_string(meta.format) }?;
let flavors = unsafe { carray_to_vec(meta.flavors, meta.num_flavors) }?;
let alphas_q_values = unsafe { carray_to_vec(meta.alphas_q_values, meta.num_alphas_q) }?;
let alphas_vals = unsafe { carray_to_vec(meta.alphas_vals, meta.num_alphas_vals) }?;
let error_type = unsafe { cstr_to_string(meta.error_type) }?;
let flavor_scheme = unsafe { cstr_to_string(meta.phys_params.flavor_scheme) }?;
let alphas_type = unsafe { cstr_to_string(meta.phys_params.alphas_type) }?;
let metadata = MetaData {
set_desc,
set_index: meta.set_index,
num_members: meta.num_members,
x_min: meta.x_min,
x_max: meta.x_max,
q_min: meta.q_min,
q_max: meta.q_max,
flavors,
format,
alphas_q_values,
alphas_vals,
polarised: meta.polarised,
set_type: meta.set_type.clone(),
interpolator_type: meta.interpolator_type.clone(),
error_type,
hadron_pid: meta.hadron_pid,
git_version: String::new(), code_version: String::new(), flavor_scheme,
order_qcd: meta.phys_params.order_qcd,
alphas_order_qcd: meta.phys_params.alphas_order_qcd,
m_w: meta.phys_params.m_w,
m_z: meta.phys_params.m_z,
m_up: meta.phys_params.m_up,
m_down: meta.phys_params.m_down,
m_strange: meta.phys_params.m_strange,
m_charm: meta.phys_params.m_charm,
m_bottom: meta.phys_params.m_bottom,
m_top: meta.phys_params.m_top,
alphas_type,
number_flavors: meta.phys_params.number_flavors,
xi_min: meta.xi_min,
xi_max: meta.xi_max,
delta_min: meta.delta_min,
delta_max: meta.delta_max,
error_conf_level: None,
};
Some(metadata)
}
#[repr(C)]
pub struct NeoPDFGridArrayCollection {
grids: *mut *mut NeoPDFGrid,
num_grids: usize,
capacity: usize,
}
impl NeoPDFGridArrayCollection {
const fn new() -> Self {
Self {
grids: std::ptr::null_mut(),
num_grids: 0,
capacity: 0,
}
}
fn add_grid(&mut self, grid: *mut NeoPDFGrid) -> NeopdfResult {
if grid.is_null() {
return NeopdfResult::ErrorNullPointer;
}
if self.num_grids == self.capacity {
let new_capacity = if self.capacity == 0 {
4
} else {
self.capacity * 2
};
let new_ptr = if self.grids.is_null() {
unsafe {
std::alloc::alloc(
std::alloc::Layout::array::<*mut NeoPDFGrid>(new_capacity).unwrap(),
)
.cast::<()>()
.cast::<*mut NeoPDFGrid>()
}
} else {
unsafe {
std::alloc::realloc(
self.grids.cast::<u8>(),
std::alloc::Layout::array::<*mut NeoPDFGrid>(self.capacity).unwrap(),
new_capacity * std::mem::size_of::<*mut NeoPDFGrid>(),
)
.cast::<()>()
.cast::<*mut NeoPDFGrid>()
}
};
if new_ptr.is_null() {
return NeopdfResult::ErrorMemoryError;
}
self.grids = new_ptr;
self.capacity = new_capacity;
}
unsafe {
*self.grids.add(self.num_grids) = grid;
}
self.num_grids += 1;
NeopdfResult::Success
}
const fn len(&self) -> usize {
self.num_grids
}
fn get(&self, index: usize) -> Option<&NeoPDFGrid> {
if index >= self.num_grids {
return None;
}
unsafe { (*self.grids.add(index)).as_ref() }
}
}
impl Drop for NeoPDFGridArrayCollection {
fn drop(&mut self) {
if self.grids.is_null() {
return;
}
let grids_slice = unsafe { slice::from_raw_parts(self.grids, self.num_grids) };
for &grid_ptr in grids_slice {
if !grid_ptr.is_null() {
unsafe { drop(Box::from_raw(grid_ptr)) };
}
}
unsafe {
std::alloc::dealloc(
self.grids.cast::<u8>(),
std::alloc::Layout::array::<*mut NeoPDFGrid>(self.capacity).unwrap(),
);
}
}
}
#[no_mangle]
pub extern "C" fn neopdf_gridarray_collection_new() -> *mut NeoPDFGridArrayCollection {
Box::into_raw(Box::new(NeoPDFGridArrayCollection::new()))
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_gridarray_collection_add_grid(
collection: *mut NeoPDFGridArrayCollection,
grid: *mut NeoPDFGrid,
) -> NeopdfResult {
unsafe {
collection
.as_mut()
.map_or(NeopdfResult::ErrorNullPointer, |collection| {
collection.add_grid(grid)
})
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_gridarray_collection_free(
collection: *mut NeoPDFGridArrayCollection,
) {
if !collection.is_null() {
unsafe { drop(Box::from_raw(collection)) };
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_grid_compress(
collection: *const NeoPDFGridArrayCollection,
metadata: *const NeoPDFMetaData,
output_path: *const c_char,
) -> NeopdfResult {
if collection.is_null() || metadata.is_null() || output_path.is_null() {
return NeopdfResult::ErrorNullPointer;
}
let collection = unsafe { &*collection };
let Some(meta) = process_metadata(metadata) else {
return NeopdfResult::ErrorInvalidData;
};
let out_path = unsafe { CStr::from_ptr(output_path).to_str() };
let Ok(out_path) = out_path else {
return NeopdfResult::ErrorInvalidData;
};
let mut grid_arrays = Vec::with_capacity(collection.len());
for i in 0..collection.len() {
let Some(grid) = collection.get(i) else {
return NeopdfResult::ErrorInvalidData;
};
let grid_array = GridArray::new(grid.subgrids.clone(), grid.flavors.clone());
grid_arrays.push(grid_array);
}
let grid_refs: Vec<&GridArray> = grid_arrays.iter().collect();
match GridArrayCollection::compress(&grid_refs, &meta, out_path) {
Ok(()) => NeopdfResult::Success,
Err(_) => NeopdfResult::ErrorMemoryError,
}
}
#[no_mangle]
pub unsafe extern "C" fn neopdf_grid_compress_v2(
collection: *const NeoPDFGridArrayCollection,
metadata: *const NeoPDFMetaDataV2,
output_path: *const c_char,
) -> NeopdfResult {
if collection.is_null() || metadata.is_null() || output_path.is_null() {
return NeopdfResult::ErrorNullPointer;
}
let collection = unsafe { &*collection };
let Some(meta) = process_metadata_v2(metadata) else {
return NeopdfResult::ErrorInvalidData;
};
let out_path = unsafe { CStr::from_ptr(output_path).to_str() };
let Ok(out_path) = out_path else {
return NeopdfResult::ErrorInvalidData;
};
let mut grid_arrays = Vec::with_capacity(collection.len());
for i in 0..collection.len() {
let Some(grid) = collection.get(i) else {
return NeopdfResult::ErrorInvalidData;
};
let grid_array = GridArray::new(grid.subgrids.clone(), grid.flavors.clone());
grid_arrays.push(grid_array);
}
let grid_refs: Vec<&GridArray> = grid_arrays.iter().collect();
match GridArrayCollection::compress(&grid_refs, &meta, out_path) {
Ok(()) => NeopdfResult::Success,
Err(_) => NeopdfResult::ErrorMemoryError,
}
}
struct LhapdfState {
pdf_set: Option<Vec<PDF>>,
member: usize,
}
static mut LHAPDF_STATE: LhapdfState = LhapdfState {
pdf_set: None,
member: 0,
};
#[no_mangle]
pub const unsafe extern "C" fn setlhaparm(_line: *const c_char) {}
#[no_mangle]
pub const unsafe extern "C" fn setlhaparm_(_line: *const c_char, _len: isize) {}
#[no_mangle]
pub unsafe extern "C" fn initpdfsetbyname(name: *const c_char) {
unsafe {
let c_str = CStr::from_ptr(name);
let pdf_name = c_str.to_str().expect("Invalid UTF-8 string");
let pdfs = PDF::load_pdfs(pdf_name);
LHAPDF_STATE.pdf_set = Some(pdfs);
LHAPDF_STATE.member = 0;
}
}
#[no_mangle]
#[allow(clippy::cast_sign_loss)]
pub unsafe extern "C" fn initpdfsetbyname_(name: *const c_char, len: c_int) {
unsafe {
let name_slice = slice::from_raw_parts(name.cast::<u8>(), len as usize);
let pdf_name = std::str::from_utf8(name_slice).unwrap().trim_end();
let pdfs = PDF::load_pdfs(pdf_name);
LHAPDF_STATE.pdf_set = Some(pdfs);
LHAPDF_STATE.member = 0;
}
}
#[no_mangle]
#[allow(clippy::cast_sign_loss)]
pub unsafe extern "C" fn initpdf(member: c_int) {
unsafe { LHAPDF_STATE.member = member as usize };
}
#[no_mangle]
#[allow(clippy::cast_sign_loss)]
pub unsafe extern "C" fn initpdf_(member: *const c_int) {
unsafe { LHAPDF_STATE.member = *member as usize };
}
#[no_mangle]
pub unsafe extern "C" fn evolvepdf(x: c_double, q: c_double, f: *mut c_double) {
unsafe {
let state_ptr = &raw const LHAPDF_STATE;
let pdf_set_ptr = &raw const (*state_ptr).pdf_set;
if let Some(pdfs) = &*pdf_set_ptr {
let member = (*state_ptr).member;
if member >= pdfs.len() {
return;
}
let pdf = &pdfs[member];
let q2 = q * q;
let out_slice = slice::from_raw_parts_mut(f, 14);
pdf.xfxq2_allpids(&DEFAULT_PIDS, &[x, q2], out_slice);
}
}
}
#[no_mangle]
pub unsafe extern "C" fn evolvepdf_(x: *const c_double, q: *const c_double, f: *mut c_double) {
unsafe {
let pdf_set_ptr = &raw const LHAPDF_STATE.pdf_set;
if let Some(pdfs) = &*pdf_set_ptr {
let member = (&raw const LHAPDF_STATE.member).read();
if member >= pdfs.len() {
return;
}
let pdf = &pdfs[member];
let q2 = (*q) * (*q);
let out_slice = slice::from_raw_parts_mut(f, 14);
pdf.xfxq2_allpids(&DEFAULT_PIDS, &[*x, q2], out_slice);
}
}
}
#[no_mangle]
pub unsafe extern "C" fn alphaspdf(q: c_double) -> c_double {
unsafe {
let state_ptr = &raw const LHAPDF_STATE;
let pdf_set_ptr = &raw const (*state_ptr).pdf_set;
if let Some(pdfs) = &*pdf_set_ptr {
let member = (*state_ptr).member;
if member >= pdfs.len() {
return 0.0;
}
let pdf = &pdfs[member];
let q2 = q * q;
pdf.alphas_q2(q2)
} else {
0.0
}
}
}
#[no_mangle]
pub unsafe extern "C" fn alphaspdf_(q: *const c_double) -> c_double {
unsafe {
let state_ptr = &raw const LHAPDF_STATE;
let pdf_set_ptr = &raw const (*state_ptr).pdf_set;
if let Some(pdfs) = &*pdf_set_ptr {
let member = (*state_ptr).member;
if member >= pdfs.len() {
return 0.0;
}
let pdf = &pdfs[member];
let q2 = (*q) * (*q);
pdf.alphas_q2(q2)
} else {
0.0
}
}
}