diff --git a/.github/actions/cache-data/action.yml b/.github/actions/cache-data/action.yml
index 2894856a..36f7b9ef 100644
--- a/.github/actions/cache-data/action.yml
+++ b/.github/actions/cache-data/action.yml
@@ -10,7 +10,7 @@ runs:
uses: actions/cache@v4
with:
path: neopdf-data
- key: data-v11
+ key: data-v12
- name: Download data if cache miss
if: steps.cache-data.outputs.cache-hit != 'true'
run: |
diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml
index 22120433..f22e33d9 100644
--- a/.github/workflows/benchmarks.yml
+++ b/.github/workflows/benchmarks.yml
@@ -34,7 +34,7 @@ jobs:
id: bench
run: |
export NEOPDF_DATA_PATH=${PWD}/neopdf-data
- # The awk command filters out the verbose test summary before the benchmark results.
+ # TODO: remove the version specification
cargo bench -p neopdf -- --nocapture | awk '/^test result: ok\./ {p=1; next} p' | tee benchmark_results.txt
- name: Post benchmark results as a PR comment
diff --git a/.github/workflows/run-python.yml b/.github/workflows/run-python.yml
index b1582aa6..da96c914 100644
--- a/.github/workflows/run-python.yml
+++ b/.github/workflows/run-python.yml
@@ -9,7 +9,7 @@ jobs:
strategy:
matrix:
- python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/run-rust.yml b/.github/workflows/run-rust.yml
index 73f6761d..ee25b5c9 100644
--- a/.github/workflows/run-rust.yml
+++ b/.github/workflows/run-rust.yml
@@ -12,8 +12,9 @@ env:
jobs:
build:
strategy:
+ fail-fast: false
matrix:
- os: [ubuntu-latest]
+ os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -37,9 +38,12 @@ jobs:
run: |
export NEOPDF_DATA_PATH=${PWD}/neopdf-data
cargo test --workspace --exclude neopdf_pyapi --exclude neopdf_tmdlib --exclude neopdf_wolfram --no-fail-fast 2> >(tee stderr 1>&2)
- sed -i 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' stderr
+ if [ "${{ matrix.os }}" != "macos-latest" ]; then
+ sed -i 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' stderr
+ fi
- name: Generate code coverage
+ if: matrix.os == 'ubuntu-latest'
run: |
find . -name '*.profraw' -exec $(rustc --print target-libdir)/../bin/llvm-profdata merge -sparse -o neopdf.profdata {} +
( sed -nE 's/[[:space:]]+Running( unittests|) [^[:space:]]+ \(([^)]+)\)/\2/p' stderr && echo target/debug/doctestbins/*/rust_out | tr ' ' "\n" ) | \
@@ -57,6 +61,7 @@ jobs:
grep SF lcov.info | sort -u | sed 's/SF://'
- name: Upload to codecov.io
+ if: matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc951f3b..a1ce76a6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Added
+
+- Added `LogFourCubic` and `LogFiveCubic` interpolation strategies.
+- Added new methods to the Fortran and C/C++ APIs to write and compress grids
+ with `xi` and `delta` dependence.
+
+### Changed
+
+- Breaking change to the Python API for the `PyMetaData` and `PySubgrid`.
+- Bump `PyO3` and `numpy` versions to `v0.27` to support Python `3.14`.
+- Extended the Grid layout to support GTMDs and GPDs (https://github.com/QCDLab/neopdf/pull/79).
+
## [0.2.0] - 06/10/2025
### Added
diff --git a/Cargo.lock b/Cargo.lock
index 8909c440..0a4a2623 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1361,6 +1361,30 @@ dependencies = [
"serde",
]
+[[package]]
+name = "neopdf"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61b0aaca320ec52a7b70f90e14b5046b194db82fcdf59d0692e539aff111e816"
+dependencies = [
+ "bincode",
+ "flate2",
+ "git-version",
+ "indicatif",
+ "itertools 0.13.0",
+ "lz4_flex",
+ "ndarray",
+ "ninterp",
+ "rayon",
+ "regex",
+ "reqwest",
+ "serde",
+ "serde_yaml",
+ "tar",
+ "tempfile",
+ "thiserror 1.0.69",
+]
+
[[package]]
name = "neopdf"
version = "0.2.1-alpha1"
@@ -1373,6 +1397,7 @@ dependencies = [
"itertools 0.13.0",
"lz4_flex",
"ndarray",
+ "neopdf 0.2.0",
"ninterp",
"rayon",
"regex",
@@ -1390,7 +1415,7 @@ version = "0.2.1-alpha1"
dependencies = [
"cbindgen",
"ndarray",
- "neopdf",
+ "neopdf 0.2.1-alpha1",
]
[[package]]
@@ -1401,7 +1426,7 @@ dependencies = [
"assert_fs",
"clap 4.5.41",
"ndarray",
- "neopdf",
+ "neopdf 0.2.1-alpha1",
"neopdf_tmdlib",
"predicates",
"serde",
@@ -1415,7 +1440,7 @@ name = "neopdf_pyapi"
version = "0.2.1-alpha1"
dependencies = [
"ndarray",
- "neopdf",
+ "neopdf 0.2.1-alpha1",
"numpy",
"pyo3",
"thiserror 1.0.69",
@@ -1436,7 +1461,7 @@ name = "neopdf_wolfram"
version = "0.2.1-alpha1"
dependencies = [
"lazy_static",
- "neopdf",
+ "neopdf 0.2.1-alpha1",
"parking_lot",
"wolfram-library-link",
]
@@ -1495,9 +1520,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "numpy"
-version = "0.25.0"
+version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29f1dee9aa8d3f6f8e8b9af3803006101bb3653866ef056d530d53ae68587191"
+checksum = "0fa24ffc88cf9d43f7269d6b6a0d0a00010924a8cc90604a21ef9c433b66998d"
dependencies = [
"libc",
"ndarray",
@@ -1710,9 +1735,9 @@ dependencies = [
[[package]]
name = "pyo3"
-version = "0.25.1"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a"
+checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf"
dependencies = [
"indoc",
"libc",
@@ -1727,19 +1752,18 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
-version = "0.25.1"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598"
+checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb"
dependencies = [
- "once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
-version = "0.25.1"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c"
+checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be"
dependencies = [
"libc",
"pyo3-build-config",
@@ -1747,9 +1771,9 @@ dependencies = [
[[package]]
name = "pyo3-macros"
-version = "0.25.1"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50"
+checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
@@ -1759,9 +1783,9 @@ dependencies = [
[[package]]
name = "pyo3-macros-backend"
-version = "0.25.1"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc"
+checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b"
dependencies = [
"heck 0.5.0",
"proc-macro2",
diff --git a/Cargo.toml b/Cargo.toml
index 6acf302d..7e972d33 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,8 +36,8 @@ clap = { version = "4.5", features = ["derive"] }
terminal_size = "0.3.0"
# Python bindings
-numpy = "0.25"
-pyo3 = { version = "0.25", features = ["extension-module"] }
+numpy = "0.27"
+pyo3 = { version = "0.27", features = ["extension-module"] }
# Build dependencies
cbindgen = "0.26.0"
diff --git a/README.md b/README.md
index 8f912848..ff621524 100644
--- a/README.md
+++ b/README.md
@@ -30,14 +30,13 @@
- NeoPDF is a fast, reliable, and scalable interpolation library for both collinear
- and transverse momentum dependent Parton Distribution Functions with modern features
- designed for both present and future hadron collider experiments:
+ NeoPDF is a fast, reliable, and scalable interpolation library for Non-Perturbative Distribution Functions
+ with modern features designed for both present and future hadron collider experiments:
-
- Beyond interpolations over the kinematic variables (x, kT, Q2), NeoPDF
+ Beyond interpolations over the kinematic variables (x, ξ, Δ, kT, Q²), NeoPDF
also supports interpolations along the nucleon numbers A (relevant for nuclear PDFs
and TMDs) and the strong coupling αs(MZ).
@@ -60,6 +59,30 @@
+## Supported distributions
+
+
+ NeoPDF supports generic classes of distributions that are functions of different combinations of the kinematic
+ variables. Examples of distribution functions are given in the diagram below with their simplified relationships.
+
+
+```mermaid
+graph TD
+
+A["**Generalized Tranverse Momentum Distribution**
GTMD(x, ξ, Δ, kT, Q²)"]
+
+A -->|∫ dkT| B["**Generalized Parton Distributions**
GPD(x, ξ, Δ, Q²)"]
+A -->|ξ → 0, Δ → 0| C["**Transverse Momentum Distributions**
TMD(x, kT, Q²)"]
+
+B -->|ξ → 0, Δ → 0| D["**Collinear Parton Distribution Functions**
PDF(x, Q²)"]
+C -->|∫ dkT| D
+
+style A fill:#ffd580,stroke:#b8860b,stroke-width:2px
+style B fill:#add8e6,stroke:#1e90ff,stroke-width:2px
+style C fill:#98fb98,stroke:#228b22,stroke-width:2px
+style D fill:#f08080,stroke:#8b0000,stroke-width:2px
+```
+
## Quick Links
- [Documentation](https://qcdlab.github.io/neopdf/) | [Rust Crate Documentation](https://docs.rs/neopdf/0.1.1/neopdf/) | [C++ API Reference](https://neopdf.readthedocs.io/en/latest/)
diff --git a/neopdf/Cargo.toml b/neopdf/Cargo.toml
index ab10c922..b54b9e26 100644
--- a/neopdf/Cargo.toml
+++ b/neopdf/Cargo.toml
@@ -30,6 +30,9 @@ regex.workspace = true
git-version.workspace = true
indicatif.workspace = true
+# For backward compatibility with v0.2.0 format
+neopdf_legacy = { package = "neopdf", version = "0.2.0" }
+
[dev-dependencies]
criterion.workspace = true
diff --git a/neopdf/src/alphas.rs b/neopdf/src/alphas.rs
index 180e6033..1be0151a 100644
--- a/neopdf/src/alphas.rs
+++ b/neopdf/src/alphas.rs
@@ -82,12 +82,14 @@ impl AlphaSAnalytic {
meta.alphas_order_qcd
};
+ let (_m_up, _m_down, _m_strange, m_charm, m_bottom, m_top) = meta.quark_masses();
+
Ok(Self {
qcd_order: alphas_order_qcd,
lambda_maps,
- mc_sq: meta.m_charm * meta.m_charm,
- mb_sq: meta.m_bottom * meta.m_bottom,
- mt_sq: meta.m_top * meta.m_top,
+ mc_sq: m_charm * m_charm,
+ mb_sq: m_bottom * m_bottom,
+ mt_sq: m_top * m_top,
num_fl: meta.number_flavors,
fl_scheme: meta.flavor_scheme.clone(),
})
@@ -162,7 +164,7 @@ impl AlphaSAnalytic {
let mut tmp = 1.0;
if self.qcd_order == 0 {
- return 0.118; // _alpha_mz reference value
+ return 0.118; // `_alpha_mz` reference value
}
if self.qcd_order > 1 {
@@ -202,12 +204,14 @@ pub struct AlphaSInterpol {
impl AlphaSInterpol {
pub fn from_metadata(meta: &MetaData) -> Result {
- let (q_values, alphas_vals): (Vec<_>, Vec<_>) = meta
- .alphas_q_values
+ let alphas_q_values = &meta.alphas_q_values;
+ let alphas_vals = &meta.alphas_vals;
+
+ let (q_values, alphas_vals_filtered): (Vec<_>, Vec<_>) = alphas_q_values
.iter()
- .zip(&meta.alphas_vals)
+ .zip(alphas_vals)
.enumerate()
- .filter(|(i, (&q, _))| *i == 0 || q != meta.alphas_q_values[i - 1])
+ .filter(|(i, (&q, _))| *i == 0 || q != alphas_q_values[i - 1])
.map(|(_, (&q, &alpha))| (q, alpha))
.unzip();
@@ -215,7 +219,7 @@ impl AlphaSInterpol {
let interpolator = Interp1D::new(
q2_values.into(),
- alphas_vals.into(),
+ alphas_vals_filtered.into(),
AlphaSCubicInterpolation,
Extrapolate::Error,
)
diff --git a/neopdf/src/converter.rs b/neopdf/src/converter.rs
index 824bc220..16b67348 100644
--- a/neopdf/src/converter.rs
+++ b/neopdf/src/converter.rs
@@ -11,7 +11,7 @@ use regex::Regex;
use super::gridpdf::GridArray;
use super::metadata::{InterpolatorType, MetaData};
use super::parser::LhapdfSet;
-use super::subgrid::{ParamRange, SubGrid};
+use super::subgrid::{GridData, ParamRange, SubGrid};
use super::writer::GridArrayCollection;
/// Converts an LHAPDF set to the NeoPDF format and writes it to disk.
@@ -155,11 +155,19 @@ pub fn combine_lhapdf_npdfs>(
xs: xs.clone(),
q2s: q2s.clone(),
kts: kts.clone(),
- grid: concatenated,
+ xis: subgrids[0].xis.clone(),
+ deltas: subgrids[0].deltas.clone(),
+ grid: GridData::Grid6D(
+ concatenated
+ .into_dimensionality()
+ .expect("Failed to convert to 6D"),
+ ),
nucleons,
alphas: alphas.clone(),
nucleons_range,
alphas_range: subgrids[0].alphas_range,
+ xi_range: subgrids[0].xi_range,
+ delta_range: subgrids[0].delta_range,
kt_range: subgrids[0].kt_range,
x_range: subgrids[0].x_range,
q2_range: subgrids[0].q2_range,
@@ -284,11 +292,19 @@ pub fn combine_lhapdf_alphas>(
xs: xs.clone(),
q2s: q2s.clone(),
kts: kts.clone(),
- grid: concatenated,
+ xis: subgrids[0].xis.clone(),
+ deltas: subgrids[0].deltas.clone(),
+ grid: GridData::Grid6D(
+ concatenated
+ .into_dimensionality()
+ .expect("Failed to convert to 6D"),
+ ),
nucleons: nucleons.clone(),
alphas,
nucleons_range: subgrids[0].nucleons_range,
alphas_range,
+ xi_range: subgrids[0].xi_range,
+ delta_range: subgrids[0].delta_range,
kt_range: subgrids[0].kt_range,
x_range: subgrids[0].x_range,
q2_range: subgrids[0].q2_range,
diff --git a/neopdf/src/gridpdf.rs b/neopdf/src/gridpdf.rs
index 501fe8e8..65dc917d 100644
--- a/neopdf/src/gridpdf.rs
+++ b/neopdf/src/gridpdf.rs
@@ -54,15 +54,29 @@ impl GridArray {
let subgrids = subgrid_data
.into_iter()
.map(|data| {
- SubGrid::new(
- data.nucleons,
- data.alphas,
- data.kts,
- data.xs,
- data.q2s,
- nflav,
- data.grid_data,
- )
+ if data.xis.len() > 1 || data.deltas.len() > 1 {
+ SubGrid::new_8d(
+ data.nucleons,
+ data.alphas,
+ data.xis,
+ data.deltas,
+ data.kts,
+ data.xs,
+ data.q2s,
+ nflav,
+ data.grid_data,
+ )
+ } else {
+ SubGrid::new(
+ data.nucleons,
+ data.alphas,
+ data.kts,
+ data.xs,
+ data.q2s,
+ nflav,
+ data.grid_data,
+ )
+ }
})
.collect();
@@ -103,7 +117,8 @@ impl GridArray {
subgrid_idx: usize,
) -> f64 {
let pid_idx = self.pid_index(flavor_id).expect("Invalid flavor ID");
- self.subgrids[subgrid_idx].grid[[nucleon_idx, alpha_idx, pid_idx, kt_idx, x_idx, q2_idx]]
+ let grid_view = self.subgrids[subgrid_idx].grid.view();
+ grid_view[[nucleon_idx, alpha_idx, pid_idx, kt_idx, x_idx, q2_idx]]
}
/// Finds the index of the subgrid that contains the given point.
@@ -169,6 +184,8 @@ impl GridArray {
RangeParameters::new(
global_range(&self.subgrids, |sg| &sg.nucleons_range),
global_range(&self.subgrids, |sg| &sg.alphas_range),
+ global_range(&self.subgrids, |sg| &sg.xi_range),
+ global_range(&self.subgrids, |sg| &sg.delta_range),
global_range(&self.subgrids, |sg| &sg.kt_range),
global_range(&self.subgrids, |sg| &sg.x_range),
global_range(&self.subgrids, |sg| &sg.q2_range),
@@ -261,7 +278,7 @@ impl GridPDF {
(0..knot_array.pids.len())
.map(|pid_idx| {
InterpolatorFactory::create(
- info.interpolator_type.to_owned(),
+ info.interpolator_type.clone(),
subgrid,
pid_idx,
)
@@ -297,6 +314,8 @@ impl GridPDF {
InterpolatorType::LogBilinear
| InterpolatorType::LogBicubic
| InterpolatorType::LogTricubic
+ | InterpolatorType::LogFourCubic
+ | InterpolatorType::LogFiveCubic
| InterpolatorType::LogChebyshev
);
@@ -462,6 +481,8 @@ mod tests {
nucleons: vec![1.0],
alphas: vec![0.118],
kts: vec![0.0],
+ xis: vec![0.0],
+ deltas: vec![0.0],
xs: vec![1.0, 2.0, 3.0],
q2s: vec![4.0, 5.0],
grid_data: vec![
@@ -471,7 +492,13 @@ mod tests {
let flavors = vec![21, 22];
let grid_array = GridArray::new(subgrid_data, flavors);
- assert_eq!(grid_array.subgrids[0].grid.shape(), &[1, 1, 2, 1, 3, 2]);
+ // Grid shape is 6D: [nucleons, alphas, pids, kT, x, Q²]
+ match &grid_array.subgrids[0].grid {
+ crate::subgrid::GridData::Grid6D(grid) => {
+ assert_eq!(grid.shape(), &[1, 1, 2, 1, 3, 2]);
+ }
+ _ => std::panic!("Expected 6D grid"),
+ }
assert!(grid_array.find_subgrid(&[1.5, 4.5]).is_some());
}
}
diff --git a/neopdf/src/interpolator.rs b/neopdf/src/interpolator.rs
index 43e886bc..3338c6f4 100644
--- a/neopdf/src/interpolator.rs
+++ b/neopdf/src/interpolator.rs
@@ -11,7 +11,7 @@
//! Interpolation strategies are defined in `strategy.rs`.
//! The [`SubGrid`] struct is defined in `subgrid.rs`.
-use ndarray::{s, OwnedRepr};
+use ndarray::{s, IxDyn, OwnedRepr};
use ninterp::data::{InterpData2D, InterpData3D};
use ninterp::error::InterpolateError;
use ninterp::interpolator::{
@@ -24,7 +24,8 @@ use ninterp::strategy::Linear;
use super::metadata::InterpolatorType;
use super::strategy::{
BilinearInterpolation, LogBicubicInterpolation, LogBilinearInterpolation,
- LogChebyshevBatchInterpolation, LogChebyshevInterpolation, LogTricubicInterpolation,
+ LogChebyshevBatchInterpolation, LogChebyshevInterpolation, LogFiveCubicInterpolation,
+ LogFourCubicInterpolation, LogTricubicInterpolation,
};
use super::subgrid::SubGrid;
@@ -34,43 +35,82 @@ use super::subgrid::SubGrid;
/// dimensions of the PDF grid data.
#[derive(Debug, Clone, Copy)]
pub enum InterpolationConfig {
- /// 2D interpolation, typically in `x` (momentum fraction) and `Q²` (energy scale).
+ /// 2D interpolation, typically in `x` (momentum fraction) and `Q2` (energy scale).
TwoD,
/// 3D interpolation, including a dimension for varying nucleon numbers `A`,
- /// in addition to `x` and `Q²`.
+ /// in addition to `x` and `Q2`.
ThreeDNucleons,
/// 3D interpolation, including a dimension for varying `alpha_s` values,
- /// in addition to `x` and `Q²`.
+ /// in addition to `x` and `Q2`.
ThreeDAlphas,
+ /// 3D interpolation, including a dimension for varying `xi` values,
+ /// in addition to `x` and `Q2`.
+ ThreeDXi,
+ /// 3D interpolation, including a dimension for varying `delta` values,
+ /// in addition to `x` and `Q2`.
+ ThreeDDelta,
/// 3D interpolation, including a dimension for varying `kT` values,
- /// in addition to `x` and `Q²`.
+ /// in addition to `x` and `Q2`.
ThreeDKt,
- /// 4D interpolation, covering nucleon numbers `A`, `alpha_s`, `x`, and `Q²`.
+ /// 4D interpolation, covering nucleon numbers `A`, `alpha_s`, `x`, and `Q2`.
FourDNucleonsAlphas,
- /// 4D interpolation, covering nucleon numbers `A`, kT, `x`, and `Q²`.
+ /// 4D interpolation, covering nucleon numbers `A`, kT, `x`, and `Q2`.
FourDNucleonsKt,
- /// 4D interpolation, covering `alpha_s`, kT, `x`, and `Q²`.
+ /// 4D interpolation, covering `alpha_s`, kT, `x`, and `Q2`.
FourDAlphasKt,
- /// 5D interpolation, covering nucleon numbers `A`, `alpha_s`, `kT`, `x`, and `Q²`.
+ /// 4D interpolation, covering `xi`, `delta`, `x`, and `Q2`.
+ FourDXiDelta,
+ /// 5D interpolation, covering `kT`, `xi`, `delta`, `x`, and `Q2`.
FiveD,
+ /// 6D interpolation, covering `A`, `kT`, `xi`, `delta`, `x`, and `Q2`.
+ SixD,
+ /// 7D interpolation, covering `A`, `alpha_s`, `xi`, `delta`, `kT`, `x`, and `Q2`.
+ SevenD,
}
impl InterpolationConfig {
- /// Determines the interpolation configuration from the number of nucleons and alpha_s values.
+ /// Determines the interpolation configuration from the dimension sizes.
///
- /// # Panics
+ /// # Arguments
///
- /// Panics if the combination of `n_nucleons` and `n_alphas` is not supported.
- pub fn from_dimensions(n_nucleons: usize, n_alphas: usize, n_kts: usize) -> Self {
- match (n_nucleons > 1, n_alphas > 1, n_kts > 1) {
- (false, false, false) => Self::TwoD,
- (true, false, false) => Self::ThreeDNucleons,
- (false, true, false) => Self::ThreeDAlphas,
- (false, false, true) => Self::ThreeDKt,
- (true, true, false) => Self::FourDNucleonsAlphas,
- (true, false, true) => Self::FourDNucleonsKt,
- (false, true, true) => Self::FourDAlphasKt,
- (true, true, true) => Self::FiveD,
+ /// * `n_nucleons` - Number of nucleon values
+ /// * `n_alphas` - Number of `alpha_s` values
+ /// * `n_xis` - Number of skeweness `xi` values
+ /// * `n_deltas` - Number of total momentum `delta` values
+ /// * `n_kts` - Number of transverse momentum `kT` values
+ pub fn from_dimensions(
+ n_nucleons: usize,
+ n_alphas: usize,
+ n_xis: usize,
+ n_deltas: usize,
+ n_kts: usize,
+ ) -> Self {
+ let dims = (
+ n_nucleons > 1,
+ n_alphas > 1,
+ n_xis > 1,
+ n_deltas > 1,
+ n_kts > 1,
+ );
+
+ match dims {
+ (false, false, false, false, false) => Self::TwoD,
+ (true, false, false, false, false) => Self::ThreeDNucleons,
+ (false, true, false, false, false) => Self::ThreeDAlphas,
+ (false, false, true, false, false) => Self::ThreeDXi,
+ (false, false, false, true, false) => Self::ThreeDDelta,
+ (false, false, false, false, true) => Self::ThreeDKt,
+ (true, true, false, false, false) => Self::FourDNucleonsAlphas,
+ (true, false, false, false, true) => Self::FourDNucleonsKt,
+ (false, true, false, false, true) => Self::FourDAlphasKt,
+ (false, false, true, true, false) => Self::FourDXiDelta,
+ (false, false, true, true, true) => Self::FiveD,
+ (true, false, true, true, true) => Self::SixD,
+ (true, true, true, true, true) => Self::SevenD,
+ _ => panic!(
+ "Unsupported dimension combination: nucleons={}, alphas={}, xis={}, deltas={}, kts={}",
+ n_nucleons, n_alphas, n_xis, n_deltas, n_kts
+ ),
}
}
}
@@ -167,6 +207,12 @@ impl InterpolatorFactory {
InterpolationConfig::ThreeDAlphas => {
Self::interpolator_xfxq2_alphas(interp_type, subgrid, pid_index)
}
+ InterpolationConfig::ThreeDXi => {
+ Self::interpolator_xfxq2_xi(interp_type, subgrid, pid_index)
+ }
+ InterpolationConfig::ThreeDDelta => {
+ Self::interpolator_xfxq2_delta(interp_type, subgrid, pid_index)
+ }
InterpolationConfig::ThreeDKt => {
Self::interpolator_xfxq2_kts(interp_type, subgrid, pid_index)
}
@@ -179,9 +225,18 @@ impl InterpolatorFactory {
InterpolationConfig::FourDAlphasKt => {
Self::interpolator_xfxq2_alphas_kts(interp_type, subgrid, pid_index)
}
+ InterpolationConfig::FourDXiDelta => {
+ Self::interpolator_xfxq2_xi_delta(interp_type, subgrid, pid_index)
+ }
InterpolationConfig::FiveD => {
Self::interpolator_xfxq2_5dim(interp_type, subgrid, pid_index)
}
+ InterpolationConfig::SixD => {
+ Self::interpolator_xfxq2_6dim(interp_type, subgrid, pid_index)
+ }
+ InterpolationConfig::SevenD => {
+ Self::interpolator_xfxq2_7dim(interp_type, subgrid, pid_index)
+ }
}
}
@@ -242,10 +297,8 @@ impl InterpolatorFactory {
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![.., 0, pid_index, 0, .., ..])
- .to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![.., 0, pid_index, 0, .., ..]).to_owned();
let reshaped_data = grid_data
.into_shape_with_order((subgrid.nucleons.len(), subgrid.xs.len(), subgrid.q2s.len()))
.expect("Failed to reshape 3D data");
@@ -282,10 +335,8 @@ impl InterpolatorFactory {
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![0, .., pid_index, 0, .., ..])
- .to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![0, .., pid_index, 0, .., ..]).to_owned();
let reshaped_data = grid_data
.into_shape_with_order((subgrid.alphas.len(), subgrid.xs.len(), subgrid.q2s.len()))
.expect("Failed to reshape 3D data");
@@ -322,10 +373,8 @@ impl InterpolatorFactory {
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![0, 0, pid_index, .., .., ..])
- .to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![0, 0, pid_index, .., .., ..]).to_owned();
let reshaped_data = grid_data
.into_shape_with_order((subgrid.kts.len(), subgrid.xs.len(), subgrid.q2s.len()))
.expect("Failed to reshape 3D data");
@@ -357,15 +406,93 @@ impl InterpolatorFactory {
}
}
- fn interpolator_xfxq2_nucleons_alphas(
+ fn interpolator_xfxq2_xi(
+ interp_type: InterpolatorType,
+ subgrid: &SubGrid,
+ pid_index: usize,
+ ) -> Box {
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view
+ .slice(s![0, 0, .., 0, 0, pid_index, .., ..])
+ .to_owned();
+ let reshaped_data = grid_data
+ .into_shape_with_order((subgrid.xis.len(), subgrid.xs.len(), subgrid.q2s.len()))
+ .expect("Failed to reshape 3D data");
+
+ match interp_type {
+ InterpolatorType::LogTricubic => Box::new(
+ Interp3D::new(
+ subgrid.xis.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ reshaped_data,
+ LogTricubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 3D interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ Interp3D::new(
+ subgrid.xis.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ reshaped_data,
+ LogChebyshevInterpolation::<3>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 3D interpolator"),
+ ),
+ _ => panic!("Unsupported 3D xi interpolator: {:?}", interp_type),
+ }
+ }
+
+ fn interpolator_xfxq2_delta(
interp_type: InterpolatorType,
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![.., .., pid_index, 0, .., ..])
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view
+ .slice(s![0, 0, 0, .., 0, pid_index, .., ..])
.to_owned();
+ let reshaped_data = grid_data
+ .into_shape_with_order((subgrid.deltas.len(), subgrid.xs.len(), subgrid.q2s.len()))
+ .expect("Failed to reshape 3D data");
+
+ match interp_type {
+ InterpolatorType::LogTricubic => Box::new(
+ Interp3D::new(
+ subgrid.deltas.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ reshaped_data,
+ LogTricubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 3D interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ Interp3D::new(
+ subgrid.deltas.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ reshaped_data,
+ LogChebyshevInterpolation::<3>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 3D interpolator"),
+ ),
+ _ => panic!("Unsupported 3D delta interpolator: {:?}", interp_type),
+ }
+ }
+
+ fn interpolator_xfxq2_nucleons_alphas(
+ interp_type: InterpolatorType,
+ subgrid: &SubGrid,
+ pid_index: usize,
+ ) -> Box {
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![.., .., pid_index, 0, .., ..]).to_owned();
let coords = vec![
subgrid.nucleons.to_owned(),
subgrid.alphas.to_owned(),
@@ -386,6 +513,24 @@ impl InterpolatorFactory {
InterpND::new(coords, reshaped_data.into_dyn(), Linear, Extrapolate::Clamp)
.expect("Failed to create 4D interpolator"),
),
+ InterpolatorType::LogFourCubic => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogFourCubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogFourCubic interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogChebyshevInterpolation::<4>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogChebyshev interpolator"),
+ ),
_ => panic!("Unsupported 4D interpolator: {:?}", interp_type),
}
}
@@ -395,10 +540,8 @@ impl InterpolatorFactory {
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![.., 0, pid_index, .., .., ..])
- .to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![.., 0, pid_index, .., .., ..]).to_owned();
let coords = vec![
subgrid.nucleons.mapv(f64::ln),
subgrid.kts.mapv(f64::ln),
@@ -419,6 +562,24 @@ impl InterpolatorFactory {
InterpND::new(coords, reshaped_data.into_dyn(), Linear, Extrapolate::Clamp)
.expect("Failed to create 4D interpolator"),
),
+ InterpolatorType::LogFourCubic => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogFourCubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogFourCubic interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogChebyshevInterpolation::<4>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogChebyshev interpolator"),
+ ),
_ => panic!("Unsupported 4D interpolator: {:?}", interp_type),
}
}
@@ -428,10 +589,8 @@ impl InterpolatorFactory {
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![0, .., pid_index, .., .., ..])
- .to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![0, .., pid_index, .., .., ..]).to_owned();
let coords = vec![
subgrid.alphas.mapv(f64::ln),
subgrid.kts.mapv(f64::ln),
@@ -452,42 +611,221 @@ impl InterpolatorFactory {
InterpND::new(coords, reshaped_data.into_dyn(), Linear, Extrapolate::Clamp)
.expect("Failed to create 4D interpolator"),
),
+ InterpolatorType::LogFourCubic => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogFourCubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogFourCubic interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogChebyshevInterpolation::<4>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogChebyshev interpolator"),
+ ),
_ => panic!("Unsupported 4D interpolator: {:?}", interp_type),
}
}
+ fn interpolator_xfxq2_xi_delta(
+ interp_type: InterpolatorType,
+ subgrid: &SubGrid,
+ pid_index: usize,
+ ) -> Box {
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view
+ .slice(s![0, 0, .., .., 0, pid_index, .., ..])
+ .to_owned();
+ let coords = vec![
+ subgrid.xis.mapv(f64::ln),
+ subgrid.deltas.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ ];
+ let reshaped_data = grid_data
+ .into_shape_with_order((
+ subgrid.xis.len(),
+ subgrid.deltas.len(),
+ subgrid.xs.len(),
+ subgrid.q2s.len(),
+ ))
+ .expect("Failed to reshape 4D data");
+
+ match interp_type {
+ InterpolatorType::InterpNDLinear => Box::new(
+ InterpND::new(coords, reshaped_data.into_dyn(), Linear, Extrapolate::Clamp)
+ .expect("Failed to create 4D interpolator"),
+ ),
+ InterpolatorType::LogFourCubic => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogFourCubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogFourCubic interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogChebyshevInterpolation::<4>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 4D LogChebyshev interpolator"),
+ ),
+ _ => panic!("Unsupported 4D xi/delta interpolator: {:?}", interp_type),
+ }
+ }
+
fn interpolator_xfxq2_5dim(
interp_type: InterpolatorType,
subgrid: &SubGrid,
pid_index: usize,
) -> Box {
- let grid_data = subgrid
- .grid
- .slice(s![.., .., pid_index, .., .., ..])
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view
+ .slice(s![0, 0, .., .., .., pid_index, .., ..])
+ .to_owned();
+ let coords = vec![
+ subgrid.kts.mapv(f64::ln),
+ subgrid.xis.mapv(f64::ln),
+ subgrid.deltas.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ ];
+ let reshaped_data = grid_data
+ .into_shape_with_order((
+ subgrid.kts.len(),
+ subgrid.xis.len(),
+ subgrid.deltas.len(),
+ subgrid.xs.len(),
+ subgrid.q2s.len(),
+ ))
+ .expect("Failed to reshape 5D data");
+
+ match interp_type {
+ InterpolatorType::InterpNDLinear => Box::new(
+ InterpND::new(
+ coords.clone(),
+ reshaped_data.clone().into_dyn(),
+ Linear,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 5D interpolator"),
+ ),
+ InterpolatorType::LogFiveCubic => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogFiveCubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 5D LogFiveCubic interpolator"),
+ ),
+ InterpolatorType::LogChebyshev => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data.into_dyn(),
+ LogChebyshevInterpolation::<5>::default(),
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 5D LogChebyshev interpolator"),
+ ),
+ _ => panic!("Unsupported 5D interpolator: {:?}", interp_type),
+ }
+ }
+
+ fn interpolator_xfxq2_6dim(
+ interp_type: InterpolatorType,
+ subgrid: &SubGrid,
+ pid_index: usize,
+ ) -> Box {
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view
+ .slice(s![.., 0, .., .., .., pid_index, .., ..])
.to_owned();
let coords = vec![
subgrid.nucleons.mapv(f64::ln),
- subgrid.alphas.mapv(f64::ln),
subgrid.kts.mapv(f64::ln),
+ subgrid.xis.mapv(f64::ln),
+ subgrid.deltas.mapv(f64::ln),
subgrid.xs.mapv(f64::ln),
subgrid.q2s.mapv(f64::ln),
];
let reshaped_data = grid_data
.into_shape_with_order((
subgrid.nucleons.len(),
- subgrid.alphas.len(),
subgrid.kts.len(),
+ subgrid.xis.len(),
+ subgrid.deltas.len(),
subgrid.xs.len(),
subgrid.q2s.len(),
))
- .expect("Failed to reshape 5D data");
+ .expect("Failed to reshape 6D data");
match interp_type {
InterpolatorType::InterpNDLinear => Box::new(
InterpND::new(coords, reshaped_data.into_dyn(), Linear, Extrapolate::Clamp)
- .expect("Failed to create 5D interpolator"),
+ .expect("Failed to create 6D interpolator"),
),
- _ => panic!("Unsupported 5D interpolator: {:?}", interp_type),
+ _ => panic!("Unsupported 6D interpolator: {:?}", interp_type),
+ }
+ }
+
+ fn interpolator_xfxq2_7dim(
+ interp_type: InterpolatorType,
+ subgrid: &SubGrid,
+ pid_index: usize,
+ ) -> Box {
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view
+ .slice(s![.., .., .., .., .., pid_index, .., ..])
+ .to_owned();
+ let coords = vec![
+ subgrid.nucleons.mapv(f64::ln),
+ subgrid.alphas.mapv(f64::ln),
+ subgrid.xis.mapv(f64::ln),
+ subgrid.deltas.mapv(f64::ln),
+ subgrid.kts.mapv(f64::ln),
+ subgrid.xs.mapv(f64::ln),
+ subgrid.q2s.mapv(f64::ln),
+ ];
+
+ let shape = IxDyn(&[
+ subgrid.nucleons.len(),
+ subgrid.alphas.len(),
+ subgrid.xis.len(),
+ subgrid.deltas.len(),
+ subgrid.kts.len(),
+ subgrid.xs.len(),
+ subgrid.q2s.len(),
+ ]);
+ let reshaped_data = grid_data
+ .into_shape_with_order(shape)
+ .expect("Failed to reshape 7D interpolation data");
+
+ match interp_type {
+ InterpolatorType::InterpNDLinear => Box::new(
+ InterpND::new(coords, reshaped_data.clone(), Linear, Extrapolate::Clamp)
+ .expect("Failed to create 7D interpolator"),
+ ),
+ InterpolatorType::LogFourCubic => Box::new(
+ InterpND::new(
+ coords,
+ reshaped_data,
+ LogFourCubicInterpolation,
+ Extrapolate::Clamp,
+ )
+ .expect("Failed to create 7D LogFourCubic interpolator"),
+ ),
+ _ => panic!("Unsupported 7D interpolator: {:?}", interp_type),
}
}
@@ -512,7 +850,8 @@ impl InterpolatorFactory {
}
InterpolationConfig::ThreeDNucleons => {
let mut strategy = LogChebyshevBatchInterpolation::<3>::default();
- let grid_data = subgrid.grid.slice(s![.., 0, pid_idx, 0, .., ..]).to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![.., 0, pid_idx, 0, .., ..]).to_owned();
let reshaped_data = grid_data
.into_shape_with_order((
@@ -535,7 +874,8 @@ impl InterpolatorFactory {
}
InterpolationConfig::ThreeDAlphas => {
let mut strategy = LogChebyshevBatchInterpolation::<3>::default();
- let grid_data = subgrid.grid.slice(s![0, .., pid_idx, 0, .., ..]).to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![0, .., pid_idx, 0, .., ..]).to_owned();
let reshaped_data = grid_data
.into_shape_with_order((
@@ -558,7 +898,8 @@ impl InterpolatorFactory {
}
InterpolationConfig::ThreeDKt => {
let mut strategy = LogChebyshevBatchInterpolation::<3>::default();
- let grid_data = subgrid.grid.slice(s![0, 0, pid_idx, .., .., ..]).to_owned();
+ let grid_view = subgrid.grid.view();
+ let grid_data = grid_view.slice(s![0, 0, pid_idx, .., .., ..]).to_owned();
let reshaped_data = grid_data
.into_shape_with_order((subgrid.kts.len(), subgrid.xs.len(), subgrid.q2s.len()))
@@ -632,35 +973,35 @@ mod tests {
#[test]
fn test_interpolation_config() {
assert!(matches!(
- InterpolationConfig::from_dimensions(1, 1, 1),
+ InterpolationConfig::from_dimensions(1, 1, 1, 1, 1),
InterpolationConfig::TwoD
));
assert!(matches!(
- InterpolationConfig::from_dimensions(2, 1, 1),
+ InterpolationConfig::from_dimensions(2, 1, 1, 1, 1),
InterpolationConfig::ThreeDNucleons
));
assert!(matches!(
- InterpolationConfig::from_dimensions(1, 2, 1),
+ InterpolationConfig::from_dimensions(1, 2, 1, 1, 1),
InterpolationConfig::ThreeDAlphas
));
assert!(matches!(
- InterpolationConfig::from_dimensions(1, 1, 2),
+ InterpolationConfig::from_dimensions(1, 1, 1, 1, 2),
InterpolationConfig::ThreeDKt
));
assert!(matches!(
- InterpolationConfig::from_dimensions(2, 2, 1),
+ InterpolationConfig::from_dimensions(2, 2, 1, 1, 1),
InterpolationConfig::FourDNucleonsAlphas
));
assert!(matches!(
- InterpolationConfig::from_dimensions(2, 1, 2),
+ InterpolationConfig::from_dimensions(2, 1, 1, 1, 2),
InterpolationConfig::FourDNucleonsKt
));
assert!(matches!(
- InterpolationConfig::from_dimensions(1, 2, 2),
+ InterpolationConfig::from_dimensions(1, 2, 1, 1, 2),
InterpolationConfig::FourDAlphasKt
));
assert!(matches!(
- InterpolationConfig::from_dimensions(2, 2, 2),
+ InterpolationConfig::from_dimensions(1, 1, 2, 2, 2),
InterpolationConfig::FiveD
));
}
diff --git a/neopdf/src/metadata.rs b/neopdf/src/metadata.rs
index 5b76da9d..190f6983 100644
--- a/neopdf/src/metadata.rs
+++ b/neopdf/src/metadata.rs
@@ -2,9 +2,7 @@
//!
//! It includes the `MetaData` struct (deserialized from .info files), PDF set
//! and interpolator type enums, and related utilities for handling PDF set information.
-use serde::{Deserialize, Deserializer, Serialize};
-use std::fmt;
-use std::ops::{Deref, DerefMut};
+use serde::{Deserialize, Serialize};
/// Represents the type of PDF set.
#[repr(C)]
@@ -17,7 +15,7 @@ pub enum SetType {
}
/// Represents the type of interpolator used for the PDF.
-/// WARNING: When adding elements, always append to the end!!!
+/// WARNING: When adding elements, always append at the end!!!
#[repr(C)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub enum InterpolatorType {
@@ -28,14 +26,16 @@ pub enum InterpolatorType {
LogTricubic,
InterpNDLinear,
LogChebyshev,
+ LogFourCubic,
+ LogFiveCubic,
}
-/// Represents the information block of a given set.
+/// Represents the information block of a given PDF set.
///
/// In order to support LHAPDF formats, the fields here are very much influenced by the
/// LHAPDF `.info` file. This struct is generally deserialized from a YAML-like format.
#[derive(Clone, Debug, Deserialize, Serialize)]
-pub struct MetaDataV1 {
+pub struct MetaDataV2 {
/// Description of the PDF set.
#[serde(rename = "SetDesc")]
pub set_desc: String,
@@ -129,65 +129,36 @@ pub struct MetaDataV1 {
/// Number of active PDF flavors.
#[serde(rename = "NumFlavors", default)]
pub number_flavors: u32,
+ /// Minimum xi-value for which the PDF is valid.
+ #[serde(rename = "XiMin", default)]
+ pub xi_min: f64,
+ /// Maximum xi-value for which the PDF is valid.
+ #[serde(rename = "XiMax", default)]
+ pub xi_max: f64,
+ /// Minimum delta-value for which the PDF is valid.
+ #[serde(rename = "DeltaMin", default)]
+ pub delta_min: f64,
+ /// Maximum delta-value for which the PDF is valid.
+ #[serde(rename = "DeltaMax", default)]
+ pub delta_max: f64,
}
-/// Version-aware metadata wrapper that handles serialization compatibility.
-#[derive(Clone, Debug, Serialize)]
-#[serde(untagged)]
-pub enum MetaData {
- V1(MetaDataV1),
-}
-
-impl MetaData {
- /// Creates a new instance of V1 `MetaData`.
- pub fn new_v1(data: MetaDataV1) -> Self {
- Self::V1(data)
- }
-
- /// Gets the current version as the latest available version.
- pub fn current_v1(data: MetaDataV1) -> Self {
- Self::V1(data)
- }
-
- /// Gets the underlying data as the latest version.
- pub fn as_latest(&self) -> MetaDataV1 {
- match self {
- MetaData::V1(data) => data.clone(),
- }
+impl MetaDataV2 {
+ /// Helper to get quark masses as a tuple
+ pub fn quark_masses(&self) -> (f64, f64, f64, f64, f64, f64) {
+ (
+ self.m_up,
+ self.m_down,
+ self.m_strange,
+ self.m_charm,
+ self.m_bottom,
+ self.m_top,
+ )
}
}
-impl Deref for MetaData {
- type Target = MetaDataV1;
-
- fn deref(&self) -> &Self::Target {
- match self {
- MetaData::V1(data) => data,
- }
- }
-}
-
-impl DerefMut for MetaData {
- fn deref_mut(&mut self) -> &mut Self::Target {
- match self {
- MetaData::V1(data) => data,
- }
- }
-}
-
-impl<'de> Deserialize<'de> for MetaData {
- fn deserialize(deserializer: D) -> Result
- where
- D: Deserializer<'de>,
- {
- let v1 = MetaDataV1::deserialize(deserializer)?;
-
- Ok(MetaData::V1(v1))
- }
-}
-
-impl fmt::Display for MetaData {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+impl std::fmt::Display for MetaDataV2 {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Set Description: {}", self.set_desc)?;
writeln!(f, "Set Index: {}", self.set_index)?;
writeln!(f, "Number of Members: {}", self.num_members)?;
@@ -216,6 +187,77 @@ impl fmt::Display for MetaData {
writeln!(f, "MBottom: {}", self.m_bottom)?;
writeln!(f, "MTop: {}", self.m_top)?;
writeln!(f, "AlphaS Type: {}", self.alphas_type)?;
- writeln!(f, "Number of PDF flavors: {}", self.number_flavors)
+ writeln!(f, "Number of PDF flavors: {}", self.number_flavors)?;
+ writeln!(f, "XiMin: {}", self.xi_min)?;
+ writeln!(f, "XiMax: {}", self.xi_max)?;
+ writeln!(f, "DeltaMin: {}", self.delta_min)?;
+ write!(f, "DeltaMax: {}", self.delta_max)
+ }
+}
+
+/// The following represent the main metadata type for v0.2.1+.
+pub type MetaData = MetaDataV2;
+
+/// Converts from legacy v0.2.0 MetaData to new v0.2.1 format
+impl From for MetaData {
+ fn from(legacy: neopdf_legacy::metadata::MetaData) -> Self {
+ Self {
+ set_desc: legacy.set_desc.clone(),
+ set_index: legacy.set_index,
+ num_members: legacy.num_members,
+ x_min: legacy.x_min,
+ x_max: legacy.x_max,
+ q_min: legacy.q_min,
+ q_max: legacy.q_max,
+ flavors: legacy.flavors.clone(),
+ format: legacy.format.clone(),
+ alphas_q_values: legacy.alphas_q_values.clone(),
+ alphas_vals: legacy.alphas_vals.clone(),
+ polarised: legacy.polarised,
+ set_type: match legacy.set_type {
+ neopdf_legacy::metadata::SetType::SpaceLike => SetType::SpaceLike,
+ neopdf_legacy::metadata::SetType::TimeLike => SetType::TimeLike,
+ },
+ interpolator_type: match legacy.interpolator_type {
+ neopdf_legacy::metadata::InterpolatorType::Bilinear => InterpolatorType::Bilinear,
+ neopdf_legacy::metadata::InterpolatorType::LogBilinear => {
+ InterpolatorType::LogBilinear
+ }
+ neopdf_legacy::metadata::InterpolatorType::LogBicubic => {
+ InterpolatorType::LogBicubic
+ }
+ neopdf_legacy::metadata::InterpolatorType::LogTricubic => {
+ InterpolatorType::LogTricubic
+ }
+ neopdf_legacy::metadata::InterpolatorType::InterpNDLinear => {
+ InterpolatorType::InterpNDLinear
+ }
+ neopdf_legacy::metadata::InterpolatorType::LogChebyshev => {
+ InterpolatorType::LogChebyshev
+ }
+ },
+ error_type: legacy.error_type.clone(),
+ hadron_pid: legacy.hadron_pid,
+ git_version: legacy.git_version.clone(),
+ code_version: legacy.code_version.clone(),
+ flavor_scheme: legacy.flavor_scheme.clone(),
+ order_qcd: legacy.order_qcd,
+ alphas_order_qcd: legacy.alphas_order_qcd,
+ m_w: legacy.m_w,
+ m_z: legacy.m_z,
+ m_up: legacy.m_up,
+ m_down: legacy.m_down,
+ m_strange: legacy.m_strange,
+ m_charm: legacy.m_charm,
+ m_bottom: legacy.m_bottom,
+ m_top: legacy.m_top,
+ alphas_type: legacy.alphas_type.clone(),
+ number_flavors: legacy.number_flavors,
+ // New V2 fields with defaults
+ xi_min: 0.0,
+ xi_max: 0.0,
+ delta_min: 0.0,
+ delta_max: 0.0,
+ }
}
}
diff --git a/neopdf/src/parser.rs b/neopdf/src/parser.rs
index 2d94f2be..165e5679 100644
--- a/neopdf/src/parser.rs
+++ b/neopdf/src/parser.rs
@@ -16,6 +16,8 @@ use super::writer::{GridArrayReader, LazyGridArrayIterator};
pub struct SubgridData {
pub nucleons: Vec,
pub alphas: Vec,
+ pub xis: Vec,
+ pub deltas: Vec,
pub kts: Vec,
pub xs: Vec,
pub q2s: Vec,
@@ -207,11 +209,15 @@ impl LhapdfSet {
// following values from LHAPDF, their defaults are set to zeros.
let nucleons: Vec = vec![0.0];
let alphas: Vec = vec![0.0];
+ let xis: Vec = vec![0.0];
+ let deltas: Vec = vec![0.0];
let kts: Vec = vec![0.0];
subgrid_data.push(SubgridData {
nucleons,
alphas,
+ xis,
+ deltas,
kts,
xs,
q2s,
@@ -240,7 +246,8 @@ impl NeopdfSet {
pub fn new(pdf_name: &str) -> Self {
let manager = ManageData::new(pdf_name, PdfSetFormat::Neopdf);
let neopdf_setpath = manager.set_path();
- let grid_readers = GridArrayReader::from_file(neopdf_setpath).unwrap();
+ let grid_readers = GridArrayReader::from_file(neopdf_setpath)
+ .unwrap_or_else(|e| panic!("Failed to load NeoPDF file: {}", e));
let metadata_info = grid_readers.metadata().as_ref().clone();
Self {
diff --git a/neopdf/src/strategy.rs b/neopdf/src/strategy.rs
index 8c517ac2..1d1cb0f8 100644
--- a/neopdf/src/strategy.rs
+++ b/neopdf/src/strategy.rs
@@ -14,10 +14,10 @@
//! All interpolation strategies are designed to work with `ninterp`'s data structures and traits,
//! ensuring compatibility and extensibility.
-use ndarray::{Array2, Axis, Data, RawDataClone};
-use ninterp::data::{InterpData1D, InterpData2D, InterpData3D};
+use ndarray::{Array2, Axis, Data, IxDyn, RawDataClone};
+use ninterp::data::{InterpData1D, InterpData2D, InterpData3D, InterpDataND};
use ninterp::error::{InterpolateError, ValidateError};
-use ninterp::strategy::traits::{Strategy1D, Strategy2D, Strategy3D};
+use ninterp::strategy::traits::{Strategy1D, Strategy2D, Strategy3D, StrategyND};
use serde::{Deserialize, Serialize};
use std::f64::consts::PI;
@@ -693,6 +693,665 @@ where
}
}
+/// Implements four-cubic (4D cubic) interpolation in log space.
+///
+/// This strategy extends the LogTricubic interpolation to 4 dimensions,
+/// providing cubic Hermite interpolation in log-log-log-log space.
+/// It is suitable for 4D PDF grids where all four dimensions benefit from
+/// logarithmic scaling and smooth cubic interpolation.
+#[derive(Debug, Clone, Default, Deserialize, Serialize)]
+pub struct LogFourCubicInterpolation;
+
+impl LogFourCubicInterpolation {
+ /// Returns the index i such that we can use points [i-1, i, i+1, i+2] for interpolation.
+ fn find_fourcubic_interval(coords: &[f64], x: f64) -> Result {
+ // Find the interval [i, i+1] such that coords[i] <= x < coords[i+1]
+ let i = utils::find_interval_index(coords, x)?;
+ Ok(i)
+ }
+
+ /// Calculates the derivative with respect to the first dimension at a given knot.
+ pub fn calculate_dd0(data: &InterpDataND, idx: &[usize]) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let n_knots = data.grid[0].len();
+ let coords = data.grid[0].as_slice().unwrap();
+ let values = &data.values;
+
+ let i0 = idx[0];
+ let del1 = match i0 {
+ 0 => 0.0,
+ i => coords[i] - coords[i - 1],
+ };
+
+ let del2 = match coords.get(i0 + 1) {
+ Some(&next) => next - coords[i0],
+ None => 0.0,
+ };
+
+ if i0 != 0 && i0 != n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[0] = i0 - 1;
+ let mut idx_next = idx.to_vec();
+ idx_next[0] = i0 + 1;
+
+ let ldd = (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1;
+ let rdd = (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2;
+ (ldd + rdd) / 2.0
+ } else if i0 == 0 {
+ let mut idx_next = idx.to_vec();
+ idx_next[0] = i0 + 1;
+ (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2
+ } else if i0 == n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[0] = i0 - 1;
+ (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1
+ } else {
+ panic!("Should not reach here: Invalid index for derivative calculation.");
+ }
+ }
+
+ /// Calculates the derivative with respect to the second dimension at a given knot.
+ pub fn calculate_dd1(data: &InterpDataND, idx: &[usize]) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let n_knots = data.grid[1].len();
+ let coords = data.grid[1].as_slice().unwrap();
+ let values = &data.values;
+
+ let i1 = idx[1];
+ let del1 = match i1 {
+ 0 => 0.0,
+ i => coords[i] - coords[i - 1],
+ };
+
+ let del2 = match coords.get(i1 + 1) {
+ Some(&next) => next - coords[i1],
+ None => 0.0,
+ };
+
+ if i1 != 0 && i1 != n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[1] = i1 - 1;
+ let mut idx_next = idx.to_vec();
+ idx_next[1] = i1 + 1;
+
+ let ldd = (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1;
+ let rdd = (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2;
+ (ldd + rdd) / 2.0
+ } else if i1 == 0 {
+ let mut idx_next = idx.to_vec();
+ idx_next[1] = i1 + 1;
+ (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2
+ } else if i1 == n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[1] = i1 - 1;
+ (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1
+ } else {
+ panic!("Should not reach here: Invalid index for derivative calculation.");
+ }
+ }
+
+ /// Calculates the derivative with respect to the third dimension at a given knot.
+ pub fn calculate_dd2(data: &InterpDataND, idx: &[usize]) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let n_knots = data.grid[2].len();
+ let coords = data.grid[2].as_slice().unwrap();
+ let values = &data.values;
+
+ let i2 = idx[2];
+ let del1 = match i2 {
+ 0 => 0.0,
+ i => coords[i] - coords[i - 1],
+ };
+
+ let del2 = match coords.get(i2 + 1) {
+ Some(&next) => next - coords[i2],
+ None => 0.0,
+ };
+
+ if i2 != 0 && i2 != n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[2] = i2 - 1;
+ let mut idx_next = idx.to_vec();
+ idx_next[2] = i2 + 1;
+
+ let ldd = (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1;
+ let rdd = (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2;
+ (ldd + rdd) / 2.0
+ } else if i2 == 0 {
+ let mut idx_next = idx.to_vec();
+ idx_next[2] = i2 + 1;
+ (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2
+ } else if i2 == n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[2] = i2 - 1;
+ (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1
+ } else {
+ panic!("Should not reach here: Invalid index for derivative calculation.");
+ }
+ }
+
+ /// Calculates the derivative with respect to the fourth dimension at a given knot.
+ pub fn calculate_dd3(data: &InterpDataND, idx: &[usize]) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let n_knots = data.grid[3].len();
+ let coords = data.grid[3].as_slice().unwrap();
+ let values = &data.values;
+
+ let i3 = idx[3];
+ let del1 = match i3 {
+ 0 => 0.0,
+ i => coords[i] - coords[i - 1],
+ };
+
+ let del2 = match coords.get(i3 + 1) {
+ Some(&next) => next - coords[i3],
+ None => 0.0,
+ };
+
+ if i3 != 0 && i3 != n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[3] = i3 - 1;
+ let mut idx_next = idx.to_vec();
+ idx_next[3] = i3 + 1;
+
+ let ldd = (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1;
+ let rdd = (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2;
+ (ldd + rdd) / 2.0
+ } else if i3 == 0 {
+ let mut idx_next = idx.to_vec();
+ idx_next[3] = i3 + 1;
+ (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2
+ } else if i3 == n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[3] = i3 - 1;
+ (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1
+ } else {
+ panic!("Should not reach here: Invalid index for derivative calculation.");
+ }
+ }
+
+ /// Hermite cubic interpolation with derivatives (same as LogTricubic)
+ fn cubic_interpolate(t: f64, f0: f64, f0_prime: f64, f1: f64, f1_prime: f64) -> f64 {
+ let t2 = t * t;
+ let t3 = t2 * t;
+
+ // Hermite basis functions
+ let h00 = 2.0 * t3 - 3.0 * t2 + 1.0;
+ let h10 = t3 - 2.0 * t2 + t;
+ let h01 = -2.0 * t3 + 3.0 * t2;
+ let h11 = t3 - t2;
+
+ h00 * f0 + h10 * f0_prime + h01 * f1 + h11 * f1_prime
+ }
+
+ /// Four-cubic Hermite interpolation in 4D
+ fn hermite_fourcubic_interpolate(
+ &self,
+ data: &InterpDataND,
+ indices: (usize, usize, usize, usize),
+ coords: (f64, f64, f64, f64),
+ deltas: (f64, f64, f64, f64),
+ ) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let (i0, i1, i2, i3) = indices;
+ let (u, v, w, t) = coords;
+ let (d0, d1, d2, d3) = deltas;
+
+ // Helper closures to access values and derivatives
+ let get = |o0: usize, o1: usize, o2: usize, o3: usize| {
+ data.values[IxDyn(&[i0 + o0, i1 + o1, i2 + o2, i3 + o3])]
+ };
+ let dd0 = |o0: usize, o1: usize, o2: usize, o3: usize| {
+ Self::calculate_dd0(data, &[i0 + o0, i1 + o1, i2 + o2, i3 + o3])
+ };
+ let dd1 = |o0: usize, o1: usize, o2: usize, o3: usize| {
+ Self::calculate_dd1(data, &[i0 + o0, i1 + o1, i2 + o2, i3 + o3])
+ };
+ let dd2 = |o0: usize, o1: usize, o2: usize, o3: usize| {
+ Self::calculate_dd2(data, &[i0 + o0, i1 + o1, i2 + o2, i3 + o3])
+ };
+ let dd3 = |o0: usize, o1: usize, o2: usize, o3: usize| {
+ Self::calculate_dd3(data, &[i0 + o0, i1 + o1, i2 + o2, i3 + o3])
+ };
+
+ // First, interpolate along dimension 0 for all combinations of (dim1, dim2, dim3)
+ // This creates a 2x2x2 cube of interpolated values and derivatives
+ let mut interp_dim0 = vec![];
+ for &o3 in &[0, 1] {
+ for &o2 in &[0, 1] {
+ for &o1 in &[0, 1] {
+ let (f0, f1) = (get(0, o1, o2, o3), get(1, o1, o2, o3));
+ let (deriv0, deriv1) = (dd0(0, o1, o2, o3) * d0, dd0(1, o1, o2, o3) * d0);
+ let interp_val = Self::cubic_interpolate(u, f0, deriv0, f1, deriv1);
+
+ // Interpolate derivatives for dimension 1
+ let (df0, df1) = (dd1(0, o1, o2, o3) * d1, dd1(1, o1, o2, o3) * d1);
+ let interp_deriv1 = (1.0 - u) * df0 + u * df1;
+
+ interp_dim0.push([interp_val, interp_deriv1]);
+ }
+ }
+ }
+
+ // Now interpolate along dimension 1, creating a 2x2 grid
+ let mut interp_dim1 = vec![];
+ for o3 in 0..2 {
+ for o2 in 0..2 {
+ let idx0 = o3 * 4 + o2 * 2;
+ let (f0, f1) = (interp_dim0[idx0][0], interp_dim0[idx0 + 1][0]);
+ let (deriv0, deriv1) = (interp_dim0[idx0][1], interp_dim0[idx0 + 1][1]);
+ let interp_val = Self::cubic_interpolate(v, f0, deriv0, f1, deriv1);
+
+ // Calculate derivative for dimension 2
+ let calc_d2_deriv = |o1_offset: usize| {
+ let (df0, df1) = (
+ dd2(0, o1_offset, o2, o3) * d2,
+ dd2(1, o1_offset, o2, o3) * d2,
+ );
+ (1.0 - u) * df0 + u * df1
+ };
+ let interp_deriv2 = (1.0 - v) * calc_d2_deriv(0) + v * calc_d2_deriv(1);
+
+ interp_dim1.push([interp_val, interp_deriv2]);
+ }
+ }
+
+ // Interpolate along dimension 2, creating a 1x2 vector
+ let mut interp_dim2 = vec![];
+ for o3 in 0..2 {
+ let idx0 = o3 * 2;
+ let (f0, f1) = (interp_dim1[idx0][0], interp_dim1[idx0 + 1][0]);
+ let (deriv0, deriv1) = (interp_dim1[idx0][1], interp_dim1[idx0 + 1][1]);
+ let interp_val = Self::cubic_interpolate(w, f0, deriv0, f1, deriv1);
+
+ // Calculate derivative for dimension 3
+ let calc_d3_deriv = |o2_offset: usize| {
+ let calc_d3_inner = |o1_offset: usize| {
+ let (df0, df1) = (
+ dd3(0, o1_offset, o2_offset, o3) * d3,
+ dd3(1, o1_offset, o2_offset, o3) * d3,
+ );
+ (1.0 - u) * df0 + u * df1
+ };
+ (1.0 - v) * calc_d3_inner(0) + v * calc_d3_inner(1)
+ };
+ let interp_deriv3 = (1.0 - w) * calc_d3_deriv(0) + w * calc_d3_deriv(1);
+
+ interp_dim2.push([interp_val, interp_deriv3]);
+ }
+
+ // Final interpolation along dimension 3
+ let (f0, f1) = (interp_dim2[0][0], interp_dim2[1][0]);
+ let (deriv0, deriv1) = (interp_dim2[0][1], interp_dim2[1][1]);
+ Self::cubic_interpolate(t, f0, deriv0, f1, deriv1)
+ }
+}
+
+impl StrategyND for LogFourCubicInterpolation
+where
+ D: Data + RawDataClone + Clone,
+{
+ fn init(&mut self, data: &InterpDataND) -> Result<(), ValidateError> {
+ if data.grid.len() != 4 {
+ return Err(ValidateError::Other(
+ "LogFourCubic requires exactly 4 dimensions".to_string(),
+ ));
+ }
+
+ for (i, grid) in data.grid.iter().enumerate() {
+ if grid.len() < 4 {
+ return Err(ValidateError::Other(format!(
+ "Need at least 4 grid points in dimension {}, got {}",
+ i,
+ grid.len()
+ )));
+ }
+ }
+
+ Ok(())
+ }
+
+ fn interpolate(&self, data: &InterpDataND, point: &[f64]) -> Result {
+ if point.len() != 4 {
+ return Err(InterpolateError::Other(
+ "LogFourCubic requires exactly 4-dimensional point".to_string(),
+ ));
+ }
+
+ let [x0, x1, x2, x3] = [point[0], point[1], point[2], point[3]];
+
+ let coords0 = data.grid[0].as_slice().unwrap();
+ let coords1 = data.grid[1].as_slice().unwrap();
+ let coords2 = data.grid[2].as_slice().unwrap();
+ let coords3 = data.grid[3].as_slice().unwrap();
+
+ let i0 = Self::find_fourcubic_interval(coords0, x0)?;
+ let i1 = Self::find_fourcubic_interval(coords1, x1)?;
+ let i2 = Self::find_fourcubic_interval(coords2, x2)?;
+ let i3 = Self::find_fourcubic_interval(coords3, x3)?;
+
+ let d0 = coords0[i0 + 1] - coords0[i0];
+ let d1 = coords1[i1 + 1] - coords1[i1];
+ let d2 = coords2[i2 + 1] - coords2[i2];
+ let d3 = coords3[i3 + 1] - coords3[i3];
+
+ if d0 == 0.0 || d1 == 0.0 || d2 == 0.0 || d3 == 0.0 {
+ return Err(InterpolateError::Other("Grid spacing is zero".to_string()));
+ }
+
+ let u = (x0 - coords0[i0]) / d0;
+ let v = (x1 - coords1[i1]) / d1;
+ let w = (x2 - coords2[i2]) / d2;
+ let t = (x3 - coords3[i3]) / d3;
+
+ let result = self.hermite_fourcubic_interpolate(
+ data,
+ (i0, i1, i2, i3),
+ (u, v, w, t),
+ (d0, d1, d2, d3),
+ );
+
+ Ok(result)
+ }
+
+ fn allow_extrapolate(&self) -> bool {
+ true
+ }
+}
+
+/// Implements five-cubic (5D cubic) interpolation in log space.
+///
+/// This strategy extends the LogFourCubic interpolation to 5 dimensions,
+/// providing cubic Hermite interpolation in log-log-log-log-log space.
+/// It is suitable for 5D PDF grids where all five dimensions benefit from
+/// logarithmic scaling and smooth cubic interpolation.
+#[derive(Debug, Clone, Default, Deserialize, Serialize)]
+pub struct LogFiveCubicInterpolation;
+
+impl LogFiveCubicInterpolation {
+ /// Returns the index i such that we can use points [i-1, i, i+1, i+2] for interpolation.
+ fn find_fivecubic_interval(coords: &[f64], x: f64) -> Result {
+ // Find the interval [i, i+1] such that coords[i] <= x < coords[i+1]
+ let i = utils::find_interval_index(coords, x)?;
+ Ok(i)
+ }
+
+ /// Calculates the derivative with respect to dimension k at a given knot.
+ fn calculate_ddk(data: &InterpDataND, idx: &[usize], dim: usize) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let n_knots = data.grid[dim].len();
+ let coords = data.grid[dim].as_slice().unwrap();
+ let values = &data.values;
+
+ let ik = idx[dim];
+ let del1 = match ik {
+ 0 => 0.0,
+ i => coords[i] - coords[i - 1],
+ };
+
+ let del2 = match coords.get(ik + 1) {
+ Some(&next) => next - coords[ik],
+ None => 0.0,
+ };
+
+ if ik != 0 && ik != n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[dim] = ik - 1;
+ let mut idx_next = idx.to_vec();
+ idx_next[dim] = ik + 1;
+
+ let ldd = (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1;
+ let rdd = (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2;
+ (ldd + rdd) / 2.0
+ } else if ik == 0 {
+ let mut idx_next = idx.to_vec();
+ idx_next[dim] = ik + 1;
+ (values[IxDyn(&idx_next)] - values[IxDyn(idx)]) / del2
+ } else if ik == n_knots - 1 {
+ let mut idx_prev = idx.to_vec();
+ idx_prev[dim] = ik - 1;
+ (values[IxDyn(idx)] - values[IxDyn(&idx_prev)]) / del1
+ } else {
+ panic!("Should not reach here: Invalid index for derivative calculation.");
+ }
+ }
+
+ /// Hermite cubic interpolation with derivatives (same as LogTricubic/LogFourCubic)
+ fn cubic_interpolate(t: f64, f0: f64, f0_prime: f64, f1: f64, f1_prime: f64) -> f64 {
+ let t2 = t * t;
+ let t3 = t2 * t;
+
+ // Hermite basis functions
+ let h00 = 2.0 * t3 - 3.0 * t2 + 1.0;
+ let h10 = t3 - 2.0 * t2 + t;
+ let h01 = -2.0 * t3 + 3.0 * t2;
+ let h11 = t3 - t2;
+
+ h00 * f0 + h10 * f0_prime + h01 * f1 + h11 * f1_prime
+ }
+
+ /// Five-cubic Hermite interpolation in 5D
+ fn hermite_fivecubic_interpolate(
+ &self,
+ data: &InterpDataND,
+ indices: (usize, usize, usize, usize, usize),
+ coords: (f64, f64, f64, f64, f64),
+ deltas: (f64, f64, f64, f64, f64),
+ ) -> f64
+ where
+ D: Data + RawDataClone + Clone,
+ {
+ let (i0, i1, i2, i3, i4) = indices;
+ let (u, v, w, t, s) = coords;
+ let (d0, d1, d2, d3, d4) = deltas;
+
+ // Helper closures to access values and derivatives
+ let get = |o0: usize, o1: usize, o2: usize, o3: usize, o4: usize| {
+ data.values[IxDyn(&[i0 + o0, i1 + o1, i2 + o2, i3 + o3, i4 + o4])]
+ };
+ let ddk = |o0: usize, o1: usize, o2: usize, o3: usize, o4: usize, dim: usize| {
+ Self::calculate_ddk(data, &[i0 + o0, i1 + o1, i2 + o2, i3 + o3, i4 + o4], dim)
+ };
+
+ // Interpolate along dimension 0 for all 2^4 = 16 combinations
+ let mut interp_dim0 = vec![];
+ for &o4 in &[0, 1] {
+ for &o3 in &[0, 1] {
+ for &o2 in &[0, 1] {
+ for &o1 in &[0, 1] {
+ let (f0, f1) = (get(0, o1, o2, o3, o4), get(1, o1, o2, o3, o4));
+ let (deriv0, deriv1) = (
+ ddk(0, o1, o2, o3, o4, 0) * d0,
+ ddk(1, o1, o2, o3, o4, 0) * d0,
+ );
+ let interp_val = Self::cubic_interpolate(u, f0, deriv0, f1, deriv1);
+
+ // Interpolate derivatives for dimension 1
+ let (df0, df1) = (
+ ddk(0, o1, o2, o3, o4, 1) * d1,
+ ddk(1, o1, o2, o3, o4, 1) * d1,
+ );
+ let interp_deriv1 = (1.0 - u) * df0 + u * df1;
+
+ interp_dim0.push([interp_val, interp_deriv1]);
+ }
+ }
+ }
+ }
+
+ // Interpolate along dimension 1, creating a 2^3 = 8 element array
+ let mut interp_dim1 = vec![];
+ for o4 in 0..2 {
+ for o3 in 0..2 {
+ for o2 in 0..2 {
+ let idx0 = o4 * 8 + o3 * 4 + o2 * 2;
+ let (f0, f1) = (interp_dim0[idx0][0], interp_dim0[idx0 + 1][0]);
+ let (deriv0, deriv1) = (interp_dim0[idx0][1], interp_dim0[idx0 + 1][1]);
+ let interp_val = Self::cubic_interpolate(v, f0, deriv0, f1, deriv1);
+
+ // Calculate derivative for dimension 2
+ let calc_d2_deriv = |o1_offset: usize| {
+ let (df0, df1) = (
+ ddk(0, o1_offset, o2, o3, o4, 2) * d2,
+ ddk(1, o1_offset, o2, o3, o4, 2) * d2,
+ );
+ (1.0 - u) * df0 + u * df1
+ };
+ let interp_deriv2 = (1.0 - v) * calc_d2_deriv(0) + v * calc_d2_deriv(1);
+
+ interp_dim1.push([interp_val, interp_deriv2]);
+ }
+ }
+ }
+
+ // Interpolate along dimension 2, creating a 2^2 = 4 element array
+ let mut interp_dim2 = vec![];
+ for o4 in 0..2 {
+ for o3 in 0..2 {
+ let idx0 = o4 * 4 + o3 * 2;
+ let (f0, f1) = (interp_dim1[idx0][0], interp_dim1[idx0 + 1][0]);
+ let (deriv0, deriv1) = (interp_dim1[idx0][1], interp_dim1[idx0 + 1][1]);
+ let interp_val = Self::cubic_interpolate(w, f0, deriv0, f1, deriv1);
+
+ // Calculate derivative for dimension 3
+ let calc_d3_deriv = |o2_offset: usize| {
+ let calc_d3_inner = |o1_offset: usize| {
+ let (df0, df1) = (
+ ddk(0, o1_offset, o2_offset, o3, o4, 3) * d3,
+ ddk(1, o1_offset, o2_offset, o3, o4, 3) * d3,
+ );
+ (1.0 - u) * df0 + u * df1
+ };
+ (1.0 - v) * calc_d3_inner(0) + v * calc_d3_inner(1)
+ };
+ let interp_deriv3 = (1.0 - w) * calc_d3_deriv(0) + w * calc_d3_deriv(1);
+
+ interp_dim2.push([interp_val, interp_deriv3]);
+ }
+ }
+
+ // Interpolate along dimension 3, creating a 2 element array
+ let mut interp_dim3 = vec![];
+ for o4 in 0..2 {
+ let idx0 = o4 * 2;
+ let (f0, f1) = (interp_dim2[idx0][0], interp_dim2[idx0 + 1][0]);
+ let (deriv0, deriv1) = (interp_dim2[idx0][1], interp_dim2[idx0 + 1][1]);
+ let interp_val = Self::cubic_interpolate(t, f0, deriv0, f1, deriv1);
+
+ // Calculate derivative for dimension 4
+ let calc_d4_deriv = |o3_offset: usize| {
+ let calc_d4_mid = |o2_offset: usize| {
+ let calc_d4_inner = |o1_offset: usize| {
+ let (df0, df1) = (
+ ddk(0, o1_offset, o2_offset, o3_offset, o4, 4) * d4,
+ ddk(1, o1_offset, o2_offset, o3_offset, o4, 4) * d4,
+ );
+ (1.0 - u) * df0 + u * df1
+ };
+ (1.0 - v) * calc_d4_inner(0) + v * calc_d4_inner(1)
+ };
+ (1.0 - w) * calc_d4_mid(0) + w * calc_d4_mid(1)
+ };
+ let interp_deriv4 = (1.0 - t) * calc_d4_deriv(0) + t * calc_d4_deriv(1);
+
+ interp_dim3.push([interp_val, interp_deriv4]);
+ }
+
+ // Final interpolation along dimension 4
+ let (f0, f1) = (interp_dim3[0][0], interp_dim3[1][0]);
+ let (deriv0, deriv1) = (interp_dim3[0][1], interp_dim3[1][1]);
+ Self::cubic_interpolate(s, f0, deriv0, f1, deriv1)
+ }
+}
+
+impl StrategyND for LogFiveCubicInterpolation
+where
+ D: Data + RawDataClone + Clone,
+{
+ fn init(&mut self, data: &InterpDataND) -> Result<(), ValidateError> {
+ if data.grid.len() != 5 {
+ return Err(ValidateError::Other(
+ "LogFiveCubic requires exactly 5 dimensions".to_string(),
+ ));
+ }
+
+ for (i, grid) in data.grid.iter().enumerate() {
+ if grid.len() < 4 {
+ return Err(ValidateError::Other(format!(
+ "Need at least 4 grid points in dimension {}, got {}",
+ i,
+ grid.len()
+ )));
+ }
+ }
+
+ Ok(())
+ }
+
+ fn interpolate(&self, data: &InterpDataND, point: &[f64]) -> Result {
+ if point.len() != 5 {
+ return Err(InterpolateError::Other(
+ "LogFiveCubic requires exactly 5-dimensional point".to_string(),
+ ));
+ }
+
+ let [x0, x1, x2, x3, x4] = [point[0], point[1], point[2], point[3], point[4]];
+
+ let coords0 = data.grid[0].as_slice().unwrap();
+ let coords1 = data.grid[1].as_slice().unwrap();
+ let coords2 = data.grid[2].as_slice().unwrap();
+ let coords3 = data.grid[3].as_slice().unwrap();
+ let coords4 = data.grid[4].as_slice().unwrap();
+
+ let i0 = Self::find_fivecubic_interval(coords0, x0)?;
+ let i1 = Self::find_fivecubic_interval(coords1, x1)?;
+ let i2 = Self::find_fivecubic_interval(coords2, x2)?;
+ let i3 = Self::find_fivecubic_interval(coords3, x3)?;
+ let i4 = Self::find_fivecubic_interval(coords4, x4)?;
+
+ let d0 = coords0[i0 + 1] - coords0[i0];
+ let d1 = coords1[i1 + 1] - coords1[i1];
+ let d2 = coords2[i2 + 1] - coords2[i2];
+ let d3 = coords3[i3 + 1] - coords3[i3];
+ let d4 = coords4[i4 + 1] - coords4[i4];
+
+ if d0 == 0.0 || d1 == 0.0 || d2 == 0.0 || d3 == 0.0 || d4 == 0.0 {
+ return Err(InterpolateError::Other("Grid spacing is zero".to_string()));
+ }
+
+ let u = (x0 - coords0[i0]) / d0;
+ let v = (x1 - coords1[i1]) / d1;
+ let w = (x2 - coords2[i2]) / d2;
+ let t = (x3 - coords3[i3]) / d3;
+ let s = (x4 - coords4[i4]) / d4;
+
+ let result = self.hermite_fivecubic_interpolate(
+ data,
+ (i0, i1, i2, i3, i4),
+ (u, v, w, t, s),
+ (d0, d1, d2, d3, d4),
+ );
+
+ Ok(result)
+ }
+
+ fn allow_extrapolate(&self) -> bool {
+ true
+ }
+}
+
/// Implements cubic interpolation for alpha_s values in log-Q2 space.
///
/// This strategy handles the specific extrapolation and interpolation rules
@@ -1131,6 +1790,174 @@ where
}
}
+impl StrategyND for LogChebyshevInterpolation<4>
+where
+ D: Data + RawDataClone + Clone,
+{
+ fn init(&mut self, data: &InterpDataND) -> Result<(), ValidateError> {
+ if data.grid.len() != 4 {
+ return Err(ValidateError::Other(
+ "LogChebyshevInterpolation<4> requires exactly 4 dimensions".to_string(),
+ ));
+ }
+ for dim in 0..4 {
+ let x_coords = data.grid[dim].as_slice().unwrap();
+ let n = x_coords.len();
+ if n < 2 {
+ return Err(ValidateError::Other(
+ "LogChebyshevInterpolation requires at least 2 grid points per dimension."
+ .to_string(),
+ ));
+ }
+ self.t_coords[dim] = (0..n)
+ .map(|j| (PI * (n - 1 - j) as f64 / (n - 1) as f64).cos())
+ .collect();
+ self.weights[dim] = Self::compute_barycentric_weights(n);
+ }
+ Ok(())
+ }
+
+ fn interpolate(&self, data: &InterpDataND, point: &[f64]) -> Result {
+ if point.len() != 4 {
+ return Err(InterpolateError::Other(
+ "LogChebyshevInterpolation<4> requires a 4D point".to_string(),
+ ));
+ }
+ let [x, y, z, w] = [point[0], point[1], point[2], point[3]];
+
+ let x_coords = data.grid[0].as_slice().unwrap();
+ let y_coords = data.grid[1].as_slice().unwrap();
+ let z_coords = data.grid[2].as_slice().unwrap();
+ let w_coords = data.grid[3].as_slice().unwrap();
+
+ let x_min = *x_coords.first().unwrap();
+ let x_max = *x_coords.last().unwrap();
+ let y_min = *y_coords.first().unwrap();
+ let y_max = *y_coords.last().unwrap();
+ let z_min = *z_coords.first().unwrap();
+ let z_max = *z_coords.last().unwrap();
+ let w_min = *w_coords.first().unwrap();
+ let w_max = *w_coords.last().unwrap();
+
+ let t_x = 2.0 * (x - x_min) / (x_max - x_min) - 1.0;
+ let t_y = 2.0 * (y - y_min) / (y_max - y_min) - 1.0;
+ let t_z = 2.0 * (z - z_min) / (z_max - z_min) - 1.0;
+ let t_w = 2.0 * (w - w_min) / (w_max - w_min) - 1.0;
+
+ let x_coeffs = Self::barycentric_coefficients(t_x, &self.t_coords[0], &self.weights[0]);
+ let y_coeffs = Self::barycentric_coefficients(t_y, &self.t_coords[1], &self.weights[1]);
+ let z_coeffs = Self::barycentric_coefficients(t_z, &self.t_coords[2], &self.weights[2]);
+ let w_coeffs = Self::barycentric_coefficients(t_w, &self.t_coords[3], &self.weights[3]);
+
+ let mut result = 0.0;
+ for (i, &x_coeff) in x_coeffs.iter().enumerate() {
+ for (j, &y_coeff) in y_coeffs.iter().enumerate() {
+ for (k, &z_coeff) in z_coeffs.iter().enumerate() {
+ for (l, &w_coeff) in w_coeffs.iter().enumerate() {
+ result += x_coeff * y_coeff * z_coeff * w_coeff * data.values[[i, j, k, l]];
+ }
+ }
+ }
+ }
+
+ Ok(result)
+ }
+
+ fn allow_extrapolate(&self) -> bool {
+ true
+ }
+}
+
+impl StrategyND for LogChebyshevInterpolation<5>
+where
+ D: Data + RawDataClone + Clone,
+{
+ fn init(&mut self, data: &InterpDataND) -> Result<(), ValidateError> {
+ if data.grid.len() != 5 {
+ return Err(ValidateError::Other(
+ "LogChebyshevInterpolation<5> requires exactly 5 dimensions".to_string(),
+ ));
+ }
+ for dim in 0..5 {
+ let x_coords = data.grid[dim].as_slice().unwrap();
+ let n = x_coords.len();
+ if n < 2 {
+ return Err(ValidateError::Other(
+ "LogChebyshevInterpolation requires at least 2 grid points per dimension."
+ .to_string(),
+ ));
+ }
+ self.t_coords[dim] = (0..n)
+ .map(|j| (PI * (n - 1 - j) as f64 / (n - 1) as f64).cos())
+ .collect();
+ self.weights[dim] = Self::compute_barycentric_weights(n);
+ }
+ Ok(())
+ }
+
+ fn interpolate(&self, data: &InterpDataND, point: &[f64]) -> Result {
+ if point.len() != 5 {
+ return Err(InterpolateError::Other(
+ "LogChebyshevInterpolation<5> requires a 5D point".to_string(),
+ ));
+ }
+ let [x, y, z, w, v_] = [point[0], point[1], point[2], point[3], point[4]];
+
+ let x_coords = data.grid[0].as_slice().unwrap();
+ let y_coords = data.grid[1].as_slice().unwrap();
+ let z_coords = data.grid[2].as_slice().unwrap();
+ let w_coords = data.grid[3].as_slice().unwrap();
+ let v_coords = data.grid[4].as_slice().unwrap();
+
+ let x_min = *x_coords.first().unwrap();
+ let x_max = *x_coords.last().unwrap();
+ let y_min = *y_coords.first().unwrap();
+ let y_max = *y_coords.last().unwrap();
+ let z_min = *z_coords.first().unwrap();
+ let z_max = *z_coords.last().unwrap();
+ let w_min = *w_coords.first().unwrap();
+ let w_max = *w_coords.last().unwrap();
+ let v_min = *v_coords.first().unwrap();
+ let v_max = *v_coords.last().unwrap();
+
+ let t_x = 2.0 * (x - x_min) / (x_max - x_min) - 1.0;
+ let t_y = 2.0 * (y - y_min) / (y_max - y_min) - 1.0;
+ let t_z = 2.0 * (z - z_min) / (z_max - z_min) - 1.0;
+ let t_w = 2.0 * (w - w_min) / (w_max - w_min) - 1.0;
+ let t_v = 2.0 * (v_ - v_min) / (v_max - v_min) - 1.0;
+
+ let x_coeffs = Self::barycentric_coefficients(t_x, &self.t_coords[0], &self.weights[0]);
+ let y_coeffs = Self::barycentric_coefficients(t_y, &self.t_coords[1], &self.weights[1]);
+ let z_coeffs = Self::barycentric_coefficients(t_z, &self.t_coords[2], &self.weights[2]);
+ let w_coeffs = Self::barycentric_coefficients(t_w, &self.t_coords[3], &self.weights[3]);
+ let v_coeffs = Self::barycentric_coefficients(t_v, &self.t_coords[4], &self.weights[4]);
+
+ let mut result = 0.0;
+ for (i, &x_coeff) in x_coeffs.iter().enumerate() {
+ for (j, &y_coeff) in y_coeffs.iter().enumerate() {
+ for (k, &z_coeff) in z_coeffs.iter().enumerate() {
+ for (l, &w_coeff) in w_coeffs.iter().enumerate() {
+ for (m, &v_coeff) in v_coeffs.iter().enumerate() {
+ result += x_coeff
+ * y_coeff
+ * z_coeff
+ * w_coeff
+ * v_coeff
+ * data.values[[i, j, k, l, m]];
+ }
+ }
+ }
+ }
+ }
+
+ Ok(result)
+ }
+
+ fn allow_extrapolate(&self) -> bool {
+ true
+ }
+}
+
/// Implements a global N-dimensional batch interpolation using Chebyshev polynomials
/// with logarithmic coordinate scaling.
///
@@ -1435,12 +2262,14 @@ impl LogChebyshevBatchInterpolation<3> {
mod tests {
use super::*;
use itertools::Itertools;
- use ndarray::{Array1, Array2, Array3, OwnedRepr};
- use ninterp::data::{InterpData1D, InterpData2D};
+ use ndarray::{Array, Array1, Array2, Array3, OwnedRepr};
+ use std::f64::consts::PI;
+
+ use ninterp::data::{InterpData1D, InterpData2D, InterpDataND};
use ninterp::interpolator::{Extrapolate, InterpND};
+ use ninterp::num_traits::Float;
use ninterp::prelude::Interpolator;
use ninterp::strategy::Linear;
- use std::f64::consts::PI;
const EPSILON: f64 = 1e-9;
@@ -1974,4 +2803,412 @@ mod tests {
assert_close(*res, *exp, EPSILON);
}
}
+
+ #[test]
+ fn test_log_fourcubic_interpolation() {
+ use ndarray::Array4;
+ use ninterp::data::InterpDataND;
+
+ // Create 4D test grid
+ let x0_coords = create_logspaced(1e-5, 1e-3, 6);
+ let x1_coords = create_logspaced(1e2, 1e4, 6);
+ let x2_coords = [1.0, 5.0, 25.0, 100.0, 150.0, 200.0];
+ let x3_coords = [0.5, 1.0, 2.0, 5.0, 10.0, 20.0];
+
+ // Generate test values: f(x0, x1, x2, x3) = x0 * x1 * x2 * x3
+ let values: Vec = x0_coords
+ .iter()
+ .cartesian_product(x1_coords.iter())
+ .cartesian_product(x2_coords.iter())
+ .cartesian_product(x3_coords.iter())
+ .map(|(((&a, &b), &c), &d)| a * b * c * d)
+ .collect();
+
+ // Transform to log space
+ let values_ln: Vec = values.iter().map(|val| val.ln()).collect();
+
+ // Create 4D array
+ let shape = (
+ x0_coords.len(),
+ x1_coords.len(),
+ x2_coords.len(),
+ x3_coords.len(),
+ );
+ let values_array = Array4::from_shape_vec(shape, values_ln.clone())
+ .unwrap()
+ .into_dyn();
+
+ // Create InterpDataND
+ let grids = vec![
+ x0_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x1_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x2_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x3_coords.iter().map(|v| v.ln()).collect::>().into(),
+ ];
+ let interp_data_ln = InterpDataND::new(grids, values_array).unwrap();
+
+ // Initialize strategy
+ let mut strategy = LogFourCubicInterpolation;
+ strategy.init(&interp_data_ln).unwrap();
+
+ // Test interpolation at a point
+ let point: [f64; 4] = [1e-4, 2e3, 25.0, 5.0];
+ let log_point = [point[0].ln(), point[1].ln(), point[2].ln(), point[3].ln()];
+ let expected: f64 = point.iter().product();
+ let result = strategy
+ .interpolate(&interp_data_ln, &log_point)
+ .unwrap()
+ .exp();
+
+ // Allow for some numerical error in 4D interpolation
+ let tolerance = 1e-6 * expected.abs();
+ assert_close(result, expected, tolerance);
+ }
+
+ #[test]
+ fn test_log_fourcubic_grid_point() {
+ use ndarray::Array4;
+ use ninterp::data::InterpDataND;
+
+ // Test that interpolation at grid points returns exact values
+ let x0_coords = [0.1, 0.2, 0.3, 0.4];
+ let x1_coords = [1.0, 2.0, 3.0, 4.0];
+ let x2_coords = [10.0, 20.0, 30.0, 40.0];
+ let x3_coords = [100.0, 200.0, 300.0, 400.0];
+
+ let values: Vec = x0_coords
+ .iter()
+ .cartesian_product(x1_coords.iter())
+ .cartesian_product(x2_coords.iter())
+ .cartesian_product(x3_coords.iter())
+ .map(|(((&a, &b), &c), &d)| a + b + c + d)
+ .collect();
+
+ let values_ln: Vec = values.iter().map(|val| val.ln()).collect();
+
+ let shape = (
+ x0_coords.len(),
+ x1_coords.len(),
+ x2_coords.len(),
+ x3_coords.len(),
+ );
+ let values_array = Array4::from_shape_vec(shape, values_ln).unwrap().into_dyn();
+
+ let grids = vec![
+ x0_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x1_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x2_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x3_coords.iter().map(|v| v.ln()).collect::>().into(),
+ ];
+ let interp_data = InterpDataND::new(grids, values_array).unwrap();
+
+ let mut strategy = LogFourCubicInterpolation;
+ strategy.init(&interp_data).unwrap();
+
+ // Test at a grid point (should be exact)
+ let test_point = [0.2f64.ln(), 2.0f64.ln(), 20.0f64.ln(), 200.0f64.ln()];
+ let expected = (0.2f64 + 2.0 + 20.0 + 200.0).ln();
+ let result = strategy.interpolate(&interp_data, &test_point).unwrap();
+
+ assert_close(result, expected, EPSILON);
+ }
+
+ #[test]
+ fn test_log_fourcubic_init_validation() {
+ use ndarray::Array4;
+ use ninterp::data::InterpDataND;
+
+ // Test that init fails with too few grid points
+ let x0_coords = vec![0.1, 0.2, 0.3]; // Only 3 points
+ let x1_coords = vec![1.0, 2.0, 3.0, 4.0];
+ let x2_coords = vec![10.0, 20.0, 30.0, 40.0];
+ let x3_coords = vec![100.0, 200.0, 300.0, 400.0];
+
+ let n_total = x0_coords.len() * x1_coords.len() * x2_coords.len() * x3_coords.len();
+ let values = vec![1.0; n_total];
+
+ let shape = (
+ x0_coords.len(),
+ x1_coords.len(),
+ x2_coords.len(),
+ x3_coords.len(),
+ );
+ let values_array = Array4::from_shape_vec(shape, values).unwrap().into_dyn();
+
+ let grids = vec![
+ x0_coords.into(),
+ x1_coords.into(),
+ x2_coords.into(),
+ x3_coords.into(),
+ ];
+ let interp_data = InterpDataND::new(grids, values_array).unwrap();
+
+ let mut strategy = LogFourCubicInterpolation;
+ let result = strategy.init(&interp_data);
+
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn test_log_fivecubic_interpolation() {
+ use ndarray::Array5;
+ use ninterp::data::InterpDataND;
+
+ // Create 5D test grid
+ let x0_coords = create_logspaced(1e-5, 1e-3, 5);
+ let x1_coords = create_logspaced(1e2, 1e4, 5);
+ let x2_coords = [1.0, 5.0, 25.0, 100.0, 200.0];
+ let x3_coords = [0.5, 1.0, 2.0, 5.0, 10.0];
+ let x4_coords = [10.0, 20.0, 50.0, 100.0, 200.0];
+
+ // Generate test values: f(x0, x1, x2, x3, x4) = x0 * x1 * x2 * x3 * x4
+ let values: Vec = x0_coords
+ .iter()
+ .cartesian_product(x1_coords.iter())
+ .cartesian_product(x2_coords.iter())
+ .cartesian_product(x3_coords.iter())
+ .cartesian_product(x4_coords.iter())
+ .map(|((((&a, &b), &c), &d), &e)| a * b * c * d * e)
+ .collect();
+
+ // Transform to log space
+ let values_ln: Vec = values.iter().map(|val| val.ln()).collect();
+
+ // Create 5D array
+ let shape = (
+ x0_coords.len(),
+ x1_coords.len(),
+ x2_coords.len(),
+ x3_coords.len(),
+ x4_coords.len(),
+ );
+ let values_array = Array5::from_shape_vec(shape, values_ln.clone())
+ .unwrap()
+ .into_dyn();
+
+ // Create InterpDataND
+ let grids = vec![
+ x0_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x1_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x2_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x3_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x4_coords.iter().map(|v| v.ln()).collect::>().into(),
+ ];
+ let interp_data_ln = InterpDataND::new(grids, values_array).unwrap();
+
+ // Initialize strategy
+ let mut strategy = LogFiveCubicInterpolation;
+ strategy.init(&interp_data_ln).unwrap();
+
+ // Test interpolation at a point
+ let point: [f64; 5] = [1e-4, 2e3, 25.0, 5.0, 100.0];
+ let log_point = [
+ point[0].ln(),
+ point[1].ln(),
+ point[2].ln(),
+ point[3].ln(),
+ point[4].ln(),
+ ];
+ let expected: f64 = point.iter().product();
+ let result = strategy
+ .interpolate(&interp_data_ln, &log_point)
+ .unwrap()
+ .exp();
+
+ // Allow for some numerical error in 5D interpolation
+ let tolerance = 1e-5 * expected.abs();
+ assert_close(result, expected, tolerance);
+ }
+
+ #[test]
+ fn test_log_fivecubic_grid_point() {
+ use ndarray::Array5;
+ use ninterp::data::InterpDataND;
+
+ // Test that interpolation at grid points returns exact values
+ let x0_coords = [0.1, 0.2, 0.3, 0.4];
+ let x1_coords = [1.0, 2.0, 3.0, 4.0];
+ let x2_coords = [10.0, 20.0, 30.0, 40.0];
+ let x3_coords = [100.0, 200.0, 300.0, 400.0];
+ let x4_coords = [1000.0, 2000.0, 3000.0, 4000.0];
+
+ let values: Vec = x0_coords
+ .iter()
+ .cartesian_product(x1_coords.iter())
+ .cartesian_product(x2_coords.iter())
+ .cartesian_product(x3_coords.iter())
+ .cartesian_product(x4_coords.iter())
+ .map(|((((&a, &b), &c), &d), &e)| a + b + c + d + e)
+ .collect();
+
+ let values_ln: Vec = values.iter().map(|val| val.ln()).collect();
+
+ let shape = (
+ x0_coords.len(),
+ x1_coords.len(),
+ x2_coords.len(),
+ x3_coords.len(),
+ x4_coords.len(),
+ );
+ let values_array = Array5::from_shape_vec(shape, values_ln).unwrap().into_dyn();
+
+ let grids = vec![
+ x0_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x1_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x2_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x3_coords.iter().map(|v| v.ln()).collect::>().into(),
+ x4_coords.iter().map(|v| v.ln()).collect::>().into(),
+ ];
+ let interp_data = InterpDataND::new(grids, values_array).unwrap();
+
+ let mut strategy = LogFiveCubicInterpolation;
+ strategy.init(&interp_data).unwrap();
+
+ // Test at a grid point (should be exact)
+ let test_point = [
+ 0.2f64.ln(),
+ 2.0f64.ln(),
+ 20.0f64.ln(),
+ 200.0f64.ln(),
+ 2000.0f64.ln(),
+ ];
+ let expected = (0.2f64 + 2.0 + 20.0 + 200.0 + 2000.0).ln();
+ let result = strategy.interpolate(&interp_data, &test_point).unwrap();
+
+ assert_close(result, expected, EPSILON);
+ }
+
+ #[test]
+ fn test_log_fivecubic_init_validation() {
+ use ndarray::Array5;
+ use ninterp::data::InterpDataND;
+
+ // Test that init fails with too few grid points
+ let x0_coords = vec![0.1, 0.2, 0.3]; // Only 3 points
+ let x1_coords = vec![1.0, 2.0, 3.0, 4.0];
+ let x2_coords = vec![10.0, 20.0, 30.0, 40.0];
+ let x3_coords = vec![100.0, 200.0, 300.0, 400.0];
+ let x4_coords = vec![1000.0, 2000.0, 3000.0, 4000.0];
+
+ let n_total =
+ x0_coords.len() * x1_coords.len() * x2_coords.len() * x3_coords.len() * x4_coords.len();
+ let values = vec![1.0; n_total];
+
+ let shape = (
+ x0_coords.len(),
+ x1_coords.len(),
+ x2_coords.len(),
+ x3_coords.len(),
+ x4_coords.len(),
+ );
+ let values_array = Array5::from_shape_vec(shape, values).unwrap().into_dyn();
+
+ let grids = vec![
+ x0_coords.into(),
+ x1_coords.into(),
+ x2_coords.into(),
+ x3_coords.into(),
+ x4_coords.into(),
+ ];
+ let interp_data = InterpDataND::new(grids, values_array).unwrap();
+
+ let mut strategy = LogFiveCubicInterpolation;
+ let result = strategy.init(&interp_data);
+
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn test_log_chebyshev_4d() {
+ let n = 4;
+ let x_coords = create_cheby_grid(n, 0.1, 10.0);
+ let y_coords = create_cheby_grid(n, 0.1, 10.0);
+ let z_coords = create_cheby_grid(n, 0.1, 10.0);
+ let w_coords = create_cheby_grid(n, 0.1, 10.0);
+
+ let f_values: Vec = x_coords
+ .iter()
+ .cartesian_product(y_coords.iter())
+ .cartesian_product(z_coords.iter())
+ .cartesian_product(w_coords.iter())
+ .map(|(((&x, &y), &z), &w)| x.ln() + y.ln() + z.ln() + w.ln())
+ .collect();
+
+ let shape = (
+ x_coords.len(),
+ y_coords.len(),
+ z_coords.len(),
+ w_coords.len(),
+ );
+ let values_array = Array::from_shape_vec(shape, f_values).unwrap().into_dyn();
+
+ let data = InterpDataND {
+ grid: vec![
+ x_coords.iter().map(|v| v.ln()).collect::>().into(),
+ y_coords.iter().map(|v| v.ln()).collect::>().into(),
+ z_coords.iter().map(|v| v.ln()).collect::>().into(),
+ w_coords.iter().map(|v| v.ln()).collect::>().into(),
+ ],
+ values: values_array,
+ };
+
+ let mut strategy = LogChebyshevInterpolation::<4>::default();
+ strategy.init(&data).unwrap();
+
+ let point = [2.5, 3.5, 4.5, 5.5];
+ let log_point: Vec = point.iter().map(|v| v.ln()).collect();
+ let expected = log_point.iter().sum();
+ let result = strategy.interpolate(&data, &log_point).unwrap();
+
+ assert_close(result, expected, EPSILON);
+ }
+
+ #[test]
+ fn test_log_chebyshev_5d() {
+ let n = 4;
+ let x_coords = create_cheby_grid(n, 0.1, 10.0);
+ let y_coords = create_cheby_grid(n, 0.1, 10.0);
+ let z_coords = create_cheby_grid(n, 0.1, 10.0);
+ let w_coords = create_cheby_grid(n, 0.1, 10.0);
+ let v_coords = create_cheby_grid(n, 0.1, 10.0);
+
+ let f_values: Vec = x_coords
+ .iter()
+ .cartesian_product(y_coords.iter())
+ .cartesian_product(z_coords.iter())
+ .cartesian_product(w_coords.iter())
+ .cartesian_product(v_coords.iter())
+ .map(|((((&x, &y), &z), &w), &v)| x.ln() + y.ln() + z.ln() + w.ln() + v.ln())
+ .collect();
+
+ let shape = (
+ x_coords.len(),
+ y_coords.len(),
+ z_coords.len(),
+ w_coords.len(),
+ v_coords.len(),
+ );
+ let values_array = Array::from_shape_vec(shape, f_values).unwrap().into_dyn();
+
+ let data = InterpDataND {
+ grid: vec![
+ x_coords.iter().map(|v| v.ln()).collect::>().into(),
+ y_coords.iter().map(|v| v.ln()).collect::>().into(),
+ z_coords.iter().map(|v| v.ln()).collect::>().into(),
+ w_coords.iter().map(|v| v.ln()).collect::>().into(),
+ v_coords.iter().map(|v| v.ln()).collect::>().into(),
+ ],
+ values: values_array,
+ };
+
+ let mut strategy = LogChebyshevInterpolation::<5>::default();
+ strategy.init(&data).unwrap();
+
+ let point = [2.5, 3.5, 4.5, 5.5, 6.5];
+ let log_point: Vec = point.iter().map(|v| v.ln()).collect();
+ let expected = log_point.iter().sum();
+ let result = strategy.interpolate(&data, &log_point).unwrap();
+
+ assert_close(result, expected, EPSILON);
+ }
}
diff --git a/neopdf/src/subgrid.rs b/neopdf/src/subgrid.rs
index 7de78bf6..fd83d09b 100644
--- a/neopdf/src/subgrid.rs
+++ b/neopdf/src/subgrid.rs
@@ -6,7 +6,7 @@
//! - [`SubGrid`]: Represents a region of phase space with a consistent grid and provides
//! methods for subgrid logic.
-use ndarray::{s, Array1, Array6, ArrayView2};
+use ndarray::{s, Array1, Array6, ArrayD, ArrayView2, IxDyn};
use serde::{Deserialize, Serialize};
use super::interpolator::InterpolationConfig;
@@ -45,12 +45,16 @@ impl ParamRange {
}
}
-/// Represents the parameter ranges for `x` and `q2`.
+/// Represents the parameter ranges for all dimensions.
pub struct RangeParameters {
/// The range for the nucleon numbers `A`.
pub nucleons: ParamRange,
/// The range for the AlphaS values `as`.
pub alphas: ParamRange,
+ /// The range for the xi values.
+ pub xi: ParamRange,
+ /// The range for the delta values.
+ pub delta: ParamRange,
/// The range for the transverse momentum `kT`.
pub kt: ParamRange,
/// The range for the momentum fraction `x`.
@@ -66,12 +70,16 @@ impl RangeParameters {
///
/// * `nucleons` - The `ParamRange` for the nuleon numbers `A`.
/// * `alphas` - The `ParamRange` for the strong coupling `as`.
+ /// * `xi` - The `ParamRange` for the xi values.
+ /// * `delta` - The `ParamRange` for the delta values.
/// * `kt` - The `ParamRange` for the transverse momentum `kT`.
/// * `x` - The `ParamRange` for the momentum fraction `x`.
/// * `q2` - The `ParamRange` for the energy scale `q2`.
pub fn new(
nucleons: ParamRange,
alphas: ParamRange,
+ xi: ParamRange,
+ delta: ParamRange,
kt: ParamRange,
x: ParamRange,
q2: ParamRange,
@@ -79,6 +87,8 @@ impl RangeParameters {
Self {
nucleons,
alphas,
+ xi,
+ delta,
kt,
x,
q2,
@@ -86,10 +96,45 @@ impl RangeParameters {
}
}
+/// Enum to hold either 6D or 8D grid data for backward compatibility.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum GridData {
+ /// 6-dimensional grid data: [nucleons, alphas, pids, kT, x, Q2].
+ Grid6D(Array6),
+ /// 8-dimensional grid data: [nucleons, alphas, xi, delta, kT, pids, x, Q2].
+ Grid8D(ArrayD),
+}
+
+impl GridData {
+ /// Returns a view of the grid data for slicing operations.
+ pub fn view(&self) -> ndarray::ArrayViewD<'_, f64> {
+ match self {
+ GridData::Grid6D(arr) => arr.view().into_dyn(),
+ GridData::Grid8D(arr) => arr.view(),
+ }
+ }
+
+ /// Returns a reference to the 6D grid, panicking if it's 8D.
+ pub fn as_6d(&self) -> &Array6 {
+ match self {
+ GridData::Grid6D(arr) => arr,
+ GridData::Grid8D(_) => panic!("Cannot convert 8D grid to 6D"),
+ }
+ }
+
+ /// Returns a reference to the 8D grid, panicking if it's 6D.
+ pub fn as_8d(&self) -> &ArrayD {
+ match self {
+ GridData::Grid6D(_) => panic!("Cannot convert 6D grid to 8D"),
+ GridData::Grid8D(arr) => arr,
+ }
+ }
+}
+
/// Stores the PDF grid data for a single subgrid.
///
/// A subgrid represents a region of the phase space with a consistent
-/// grid of `x` and `Q²` values.
+/// grid of `x` and `Q2` values.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubGrid {
/// Array of `x` values (momentum fraction).
@@ -98,8 +143,12 @@ pub struct SubGrid {
pub q2s: Array1,
/// Array of `kT` values (transverse momentum).
pub kts: Array1,
- /// 6-dimensional grid data: [nucleons, alphas, pids, kT, x, Q²].
- pub grid: Array6,
+ /// Array of `xi` values.
+ pub xis: Array1,
+ /// Array of `delta` values.
+ pub deltas: Array1,
+ /// Grid data (either 6D or 7D for backward compatibility).
+ pub grid: GridData,
/// Array of nucleon number values.
pub nucleons: Array1,
/// Array of alpha_s values.
@@ -108,6 +157,10 @@ pub struct SubGrid {
pub nucleons_range: ParamRange,
/// The valid range for the `AlphaS` parameter in this subgrid.
pub alphas_range: ParamRange,
+ /// The valid range for the `xi` parameter in this subgrid.
+ pub xi_range: ParamRange,
+ /// The valid range for the `delta` parameter in this subgrid.
+ pub delta_range: ParamRange,
/// The valid range for the `kT` parameter in this subgrid.
pub kt_range: ParamRange,
/// The valid range for the `x` parameter in this subgrid.
@@ -117,15 +170,15 @@ pub struct SubGrid {
}
impl SubGrid {
- /// Creates a new `SubGrid` from raw data.
+ /// Creates a new 6D `SubGrid` from raw data (for backward compatibility).
///
/// # Arguments
///
/// * `nucleon_numbers` - A vector of nucleon numbers.
/// * `alphas_values` - A vector of alpha_s values.
/// * `kt_subgrid` - A vector of `kT` values.
- /// * `xs` - A vector of `x` values.
- /// * `q2s` - A vector of `q2` values.
+ /// * `x_subgrid` - A vector of `x` values.
+ /// * `q2_subgrid` - A vector of `q2` values.
/// * `nflav` - The number of quark flavors.
/// * `grid_data` - A flat vector of grid data points.
///
@@ -173,11 +226,93 @@ impl SubGrid {
xs: Array1::from_vec(x_subgrid),
q2s: Array1::from_vec(q2_subgrid),
kts: Array1::from_vec(kt_subgrid),
- grid: subgrid,
+ xis: Array1::from_vec(vec![0.0]),
+ deltas: Array1::from_vec(vec![0.0]),
+ grid: GridData::Grid6D(subgrid),
+ nucleons: Array1::from_vec(nucleon_numbers),
+ alphas: Array1::from_vec(alphas_values),
+ nucleons_range: ncs_range,
+ alphas_range: as_range,
+ xi_range: ParamRange::new(0.0, 0.0),
+ delta_range: ParamRange::new(0.0, 0.0),
+ kt_range: kts_range,
+ x_range: xs_range,
+ q2_range: q2s_range,
+ }
+ }
+
+ /// Creates a new 8D `SubGrid` from raw data.
+ ///
+ /// # Arguments
+ ///
+ /// * `nucleon_numbers` - A vector of nucleon numbers.
+ /// * `alphas_values` - A vector of alpha_s values.
+ /// * `xi_values` - A vector of xi values.
+ /// * `delta_values` - A vector of delta values.
+ /// * `kt_subgrid` - A vector of `kT` values.
+ /// * `x_subgrid` - A vector of `x` values.
+ /// * `q2_subgrid` - A vector of `q2` values.
+ /// * `nflav` - The number of quark flavors.
+ /// * `grid_data` - A flat vector of grid data points.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the grid data cannot be reshaped to the expected dimensions.
+ #[allow(clippy::too_many_arguments)]
+ pub fn new_8d(
+ nucleon_numbers: Vec,
+ alphas_values: Vec,
+ xi_values: Vec,
+ delta_values: Vec,
+ kt_subgrid: Vec,
+ x_subgrid: Vec,
+ q2_subgrid: Vec,
+ nflav: usize,
+ grid_data: Vec,
+ ) -> Self {
+ let xs_range = ParamRange::new(*x_subgrid.first().unwrap(), *x_subgrid.last().unwrap());
+ let q2s_range = ParamRange::new(*q2_subgrid.first().unwrap(), *q2_subgrid.last().unwrap());
+ let kts_range = ParamRange::new(*kt_subgrid.first().unwrap(), *kt_subgrid.last().unwrap());
+ let xis_range = ParamRange::new(*xi_values.first().unwrap(), *xi_values.last().unwrap());
+ let deltas_range = ParamRange::new(
+ *delta_values.first().unwrap(),
+ *delta_values.last().unwrap(),
+ );
+ let ncs_range = ParamRange::new(
+ *nucleon_numbers.first().unwrap(),
+ *nucleon_numbers.last().unwrap(),
+ );
+ let as_range = ParamRange::new(
+ *alphas_values.first().unwrap(),
+ *alphas_values.last().unwrap(),
+ );
+
+ let shape = IxDyn(&[
+ nucleon_numbers.len(),
+ alphas_values.len(),
+ xi_values.len(),
+ delta_values.len(),
+ kt_subgrid.len(),
+ nflav,
+ x_subgrid.len(),
+ q2_subgrid.len(),
+ ]);
+
+ let subgrid = ArrayD::from_shape_vec(shape, grid_data).expect("Failed to create 8D grid");
+
+ Self {
+ xs: Array1::from_vec(x_subgrid),
+ q2s: Array1::from_vec(q2_subgrid),
+ kts: Array1::from_vec(kt_subgrid),
+ xis: Array1::from_vec(xi_values),
+ deltas: Array1::from_vec(delta_values),
+ grid: GridData::Grid8D(subgrid),
nucleons: Array1::from_vec(nucleon_numbers),
alphas: Array1::from_vec(alphas_values),
nucleons_range: ncs_range,
alphas_range: as_range,
+ xi_range: xis_range,
+ delta_range: deltas_range,
kt_range: kts_range,
x_range: xs_range,
q2_range: q2s_range,
@@ -200,15 +335,36 @@ impl SubGrid {
InterpolationConfig::TwoD => (2, vec![]),
InterpolationConfig::ThreeDNucleons => (3, vec![&self.nucleons_range]),
InterpolationConfig::ThreeDAlphas => (3, vec![&self.alphas_range]),
+ InterpolationConfig::ThreeDXi => (3, vec![&self.xi_range]),
+ InterpolationConfig::ThreeDDelta => (3, vec![&self.delta_range]),
InterpolationConfig::ThreeDKt => (3, vec![&self.kt_range]),
InterpolationConfig::FourDNucleonsAlphas => {
(4, vec![&self.nucleons_range, &self.alphas_range])
}
InterpolationConfig::FourDNucleonsKt => (4, vec![&self.nucleons_range, &self.kt_range]),
InterpolationConfig::FourDAlphasKt => (4, vec![&self.alphas_range, &self.kt_range]),
- InterpolationConfig::FiveD => (
- 5,
- vec![&self.nucleons_range, &self.alphas_range, &self.kt_range],
+ InterpolationConfig::FourDXiDelta => (4, vec![&self.xi_range, &self.delta_range]),
+ InterpolationConfig::FiveD => {
+ (5, vec![&self.kt_range, &self.xi_range, &self.delta_range])
+ }
+ InterpolationConfig::SixD => (
+ 6,
+ vec![
+ &self.nucleons_range,
+ &self.kt_range,
+ &self.xi_range,
+ &self.delta_range,
+ ],
+ ),
+ InterpolationConfig::SevenD => (
+ 7,
+ vec![
+ &self.nucleons_range,
+ &self.alphas_range,
+ &self.xi_range,
+ &self.delta_range,
+ &self.kt_range,
+ ],
),
};
@@ -236,27 +392,39 @@ impl SubGrid {
/// Gathers the parameter ranges for the subgrid based on its configuration.
fn parameter_ranges(&self) -> Vec {
- let mut ranges = match self.interpolation_config() {
- InterpolationConfig::TwoD => vec![],
- InterpolationConfig::ThreeDNucleons => vec![self.nucleons_range],
- InterpolationConfig::ThreeDAlphas => vec![self.alphas_range],
- InterpolationConfig::ThreeDKt => vec![self.kt_range],
- InterpolationConfig::FourDNucleonsAlphas => {
- vec![self.nucleons_range, self.alphas_range]
- }
- InterpolationConfig::FourDNucleonsKt => vec![self.nucleons_range, self.kt_range],
- InterpolationConfig::FourDAlphasKt => vec![self.alphas_range, self.kt_range],
- InterpolationConfig::FiveD => {
- vec![self.nucleons_range, self.alphas_range, self.kt_range]
- }
- };
+ let mut ranges = Vec::new();
+
+ // Add ranges based on which dimensions are active
+ if self.nucleons.len() > 1 {
+ ranges.push(self.nucleons_range);
+ }
+ if self.alphas.len() > 1 {
+ ranges.push(self.alphas_range);
+ }
+ if self.xis.len() > 1 {
+ ranges.push(self.xi_range);
+ }
+ if self.deltas.len() > 1 {
+ ranges.push(self.delta_range);
+ }
+ if self.kts.len() > 1 {
+ ranges.push(self.kt_range);
+ }
+
+ // Always include x and q2
ranges.extend([self.x_range, self.q2_range]);
ranges
}
/// Gets the interpolation configuration for this subgrid.
pub fn interpolation_config(&self) -> InterpolationConfig {
- InterpolationConfig::from_dimensions(self.nucleons.len(), self.alphas.len(), self.kts.len())
+ InterpolationConfig::from_dimensions(
+ self.nucleons.len(),
+ self.alphas.len(),
+ self.xis.len(),
+ self.deltas.len(),
+ self.kts.len(),
+ )
}
/// Gets the parameter ranges for this subgrid.
@@ -264,6 +432,8 @@ impl SubGrid {
RangeParameters::new(
self.nucleons_range,
self.alphas_range,
+ self.xi_range,
+ self.delta_range,
self.kt_range,
self.x_range,
self.q2_range,
@@ -283,10 +453,42 @@ impl SubGrid {
/// Panics if called on a subgrid that is not 2D.
pub fn grid_slice(&self, pid_index: usize) -> ArrayView2<'_, f64> {
match self.interpolation_config() {
- InterpolationConfig::TwoD => self.grid.slice(s![0, 0, pid_index, 0, .., ..]),
+ InterpolationConfig::TwoD => match &self.grid {
+ GridData::Grid6D(grid) => grid.slice(s![0, 0, pid_index, 0, .., ..]),
+ GridData::Grid8D(grid) => grid.slice(s![0, 0, 0, 0, 0, pid_index, .., ..]),
+ },
_ => panic!("grid_slice only valid for 2D interpolation"),
}
}
+
+ /// Returns a reference to the underlying grid (6D).
+ ///
+ /// # Panics
+ ///
+ /// Panics if the grid is 8D.
+ pub fn grid_6d(&self) -> &Array6 {
+ match &self.grid {
+ GridData::Grid6D(grid) => grid,
+ GridData::Grid8D(_) => panic!("Cannot access 8D grid as 6D"),
+ }
+ }
+
+ /// Returns a reference to the underlying grid (8D).
+ ///
+ /// # Panics
+ ///
+ /// Panics if the grid is 6D.
+ pub fn grid_8d(&self) -> &ArrayD {
+ match &self.grid {
+ GridData::Grid6D(_) => panic!("Cannot access 6D grid as 8D"),
+ GridData::Grid8D(grid) => grid,
+ }
+ }
+
+ /// Returns true if this is an 8D grid.
+ pub fn is_8d(&self) -> bool {
+ matches!(self.grid, GridData::Grid8D(_))
+ }
}
#[cfg(test)]
diff --git a/neopdf/src/writer.rs b/neopdf/src/writer.rs
index 06101fa4..0544184a 100644
--- a/neopdf/src/writer.rs
+++ b/neopdf/src/writer.rs
@@ -29,6 +29,7 @@ use std::sync::Arc;
use git_version::git_version;
use lz4_flex::frame::{FrameDecoder, FrameEncoder};
+use tempfile::NamedTempFile;
use super::gridpdf::GridArray;
use super::metadata::MetaData;
@@ -76,12 +77,14 @@ impl GridArrayCollection {
let buf_writer = BufWriter::new(file);
let mut encoder = FrameEncoder::new(buf_writer);
- let mut metadata_mut = metadata.as_latest();
- metadata_mut.git_version = GIT_VERSION.to_string();
- metadata_mut.code_version = CODE_VERSION.to_string();
-
- let updated_metadata = MetaData::new_v1(metadata_mut);
- let metadata_serialized = bincode::serialize(&updated_metadata)?;
+ let mut metadata_mut = metadata.clone();
+ if metadata_mut.git_version.is_empty() || metadata_mut.git_version == "unknown" {
+ metadata_mut.git_version = GIT_VERSION.to_string();
+ }
+ if metadata_mut.code_version.is_empty() {
+ metadata_mut.code_version = CODE_VERSION.to_string();
+ }
+ let metadata_serialized = bincode::serialize(&metadata_mut)?;
let metadata_size = metadata_serialized.len() as u64;
let metadata_size_bytes = bincode::serialize(&metadata_size)?;
@@ -129,7 +132,12 @@ impl GridArrayCollection {
encoder.write_all(serialized)?;
}
- encoder.finish()?;
+ let mut writer = encoder.finish()?;
+ writer.flush()?;
+
+ // Sync to disk to ensure data is written before returning
+ writer.get_mut().sync_all()?;
+
Ok(())
}
@@ -235,6 +243,10 @@ pub struct GridArrayReader {
impl GridArrayReader {
/// Creates a new reader from a file, enabling random access to grid members.
///
+ /// This method automatically handles backward compatibility with v0.2.0 files.
+ /// If reading with the current format fails, it falls back to using the legacy
+ /// loader.
+ ///
/// # Arguments
///
/// * `path` - Input file path.
@@ -243,6 +255,32 @@ impl GridArrayReader {
///
/// A [`GridArrayReader`] instance on success, or an error if reading fails.
pub fn from_file>(path: P) -> Result> {
+ match Self::from_file_v2(path.as_ref()) {
+ Ok(reader) => Ok(reader),
+ Err(err) => {
+ let error_string = format!("{:?}", err);
+
+ if error_string.contains("UnexpectedEof")
+ || error_string.contains("Eof")
+ || error_string.contains("Grid is not v2")
+ {
+ match Self::from_file_legacy(path.as_ref()) {
+ Ok(reader) => Ok(reader),
+ Err(legacy_err) => Err(format!(
+ "Failed to load PDF with both v0.2.1+ ({}) and v0.2.0 ({}) loaders",
+ err, legacy_err
+ )
+ .into()),
+ }
+ } else {
+ Err(err)
+ }
+ }
+ }
+ }
+
+ /// Loads a file using the v0.2.1+ format.
+ fn from_file_v2(path: &Path) -> Result> {
let file = File::open(path)?;
let buf_reader = BufReader::new(file);
let mut decoder = FrameDecoder::new(buf_reader);
@@ -252,7 +290,6 @@ impl GridArrayReader {
let mut cursor = std::io::Cursor::new(&data);
- // Read metadata
let metadata_size: u64 = bincode::deserialize_from(&mut cursor)?;
let mut metadata_bytes = vec![0u8; metadata_size as usize];
cursor.read_exact(&mut metadata_bytes)?;
@@ -260,10 +297,8 @@ impl GridArrayReader {
let shared_metadata = Arc::new(metadata);
let count: u64 = bincode::deserialize_from(&mut cursor)?;
- // Read offset table size (but don't skip it!)
let _offset_table_size: u64 = bincode::deserialize_from(&mut cursor)?;
- // Read the actual offsets
let mut offsets = Vec::with_capacity(count as usize);
for _ in 0..count {
let offset: u64 = bincode::deserialize_from(&mut cursor)?;
@@ -281,6 +316,78 @@ impl GridArrayReader {
})
}
+ /// Loads a file using the legacy v0.2.0 format and converts it to v0.2.1+ format.
+ fn from_file_legacy(path: &Path) -> Result> {
+ let legacy_reader = neopdf_legacy::writer::GridArrayReader::from_file(path)?;
+
+ let legacy_metadata = legacy_reader.metadata();
+ let metadata = MetaData::from((**legacy_metadata).clone());
+
+ let mut new_grids = Vec::new();
+ for i in 0..legacy_reader.len() {
+ let legacy_grid_with_meta = legacy_reader.load_grid(i)?;
+ let converted_grid = Self::convert_legacy_grid(legacy_grid_with_meta.grid);
+ new_grids.push(converted_grid);
+ }
+
+ let temp_file = NamedTempFile::new()?;
+ let temp_path = temp_file.path();
+
+ let grid_refs: Vec<&GridArray> = new_grids.iter().collect();
+ GridArrayCollection::compress(&grid_refs, &metadata, temp_path)?;
+ let result = Self::from_file_v2(temp_path)?;
+
+ Ok(result)
+ }
+
+ /// Converts a legacy GridArray to the new format.
+ fn convert_legacy_grid(legacy_grid: neopdf_legacy::gridpdf::GridArray) -> GridArray {
+ use crate::subgrid::{GridData, ParamRange, SubGrid};
+ use ndarray::Array1;
+
+ let subgrids: Vec = legacy_grid
+ .subgrids
+ .into_iter()
+ .map(|legacy_subgrid| SubGrid {
+ xs: legacy_subgrid.xs,
+ q2s: legacy_subgrid.q2s,
+ kts: legacy_subgrid.kts,
+ xis: Array1::from_vec(vec![0.0]),
+ deltas: Array1::from_vec(vec![0.0]),
+ grid: GridData::Grid6D(legacy_subgrid.grid),
+ nucleons: legacy_subgrid.nucleons,
+ alphas: legacy_subgrid.alphas,
+ nucleons_range: ParamRange {
+ min: legacy_subgrid.nucleons_range.min,
+ max: legacy_subgrid.nucleons_range.max,
+ },
+ alphas_range: ParamRange {
+ min: legacy_subgrid.alphas_range.min,
+ max: legacy_subgrid.alphas_range.max,
+ },
+ xi_range: ParamRange::new(0.0, 0.0),
+ delta_range: ParamRange::new(0.0, 0.0),
+ kt_range: ParamRange {
+ min: legacy_subgrid.kt_range.min,
+ max: legacy_subgrid.kt_range.max,
+ },
+ x_range: ParamRange {
+ min: legacy_subgrid.x_range.min,
+ max: legacy_subgrid.x_range.max,
+ },
+ q2_range: ParamRange {
+ min: legacy_subgrid.q2_range.min,
+ max: legacy_subgrid.q2_range.max,
+ },
+ })
+ .collect();
+
+ GridArray {
+ pids: legacy_grid.pids,
+ subgrids,
+ }
+ }
+
/// Returns the number of grid arrays in the collection.
pub fn len(&self) -> usize {
self.count as usize
@@ -304,8 +411,8 @@ impl GridArrayReader {
///
/// # Returns
///
- /// The requested [`GridArrayWithMetadata`] on success, or an error if the index is out
- /// of bounds or reading fails.
+ /// The requested [`GridArrayWithMetadata`] on success, or an error if the
+ /// index is out of bounds or reading fails.
pub fn load_grid(
&self,
index: usize,
@@ -385,6 +492,9 @@ impl LazyGridArrayIterator {
/// Creates a new lazy iterator from a file path.
///
+ /// This method automatically handles backward compatibility with v0.2.0 files.
+ /// If reading with the current format fails, it falls back to using the legacy loader.
+ ///
/// # Arguments
///
/// * `path` - Input file path.
@@ -393,11 +503,61 @@ impl LazyGridArrayIterator {
///
/// A [`LazyGridArrayIterator`] instance on success, or an error if reading fails.
pub fn from_file>(path: P) -> Result> {
+ match Self::from_file_v2(path.as_ref()) {
+ Ok(iter) => Ok(iter),
+ Err(e) => {
+ let error_string = format!("{:?}", e);
+
+ if error_string.contains("UnexpectedEof")
+ || error_string.contains("Eof")
+ || error_string.contains("unexpected end of file")
+ {
+ match Self::from_file_legacy(path.as_ref()) {
+ Ok(iter) => Ok(iter),
+ Err(legacy_err) => Err(format!(
+ "Failed to load PDF with both v0.2.1+ ({}) and v0.2.0 ({}) loaders",
+ e, legacy_err
+ )
+ .into()),
+ }
+ } else {
+ Err(e)
+ }
+ }
+ }
+ }
+
+ /// Loads a file using the v0.2.1+ format for lazy iteration.
+ fn from_file_v2(path: &Path) -> Result> {
let file = File::open(path)?;
let buf_reader = BufReader::new(file);
Self::new(buf_reader)
}
+ /// Loads a file using the legacy v0.2.0 format and converts it to v0.2.1+ format for lazy iteration.
+ fn from_file_legacy(path: &Path) -> Result> {
+ let legacy_reader = neopdf_legacy::writer::GridArrayReader::from_file(path)?;
+
+ let legacy_metadata = legacy_reader.metadata();
+ let metadata = MetaData::from((**legacy_metadata).clone());
+
+ let mut new_grids = Vec::new();
+ for i in 0..legacy_reader.len() {
+ let legacy_grid_with_meta = legacy_reader.load_grid(i)?;
+ let converted_grid = GridArrayReader::convert_legacy_grid(legacy_grid_with_meta.grid);
+ new_grids.push(converted_grid);
+ }
+
+ let temp_file = NamedTempFile::new()?;
+ let temp_path = temp_file.path();
+
+ let grid_refs: Vec<&GridArray> = new_grids.iter().collect();
+ GridArrayCollection::compress(&grid_refs, &metadata, temp_path)?;
+ let result = Self::from_file_v2(temp_path)?;
+
+ Ok(result)
+ }
+
/// Returns a reference to the shared metadata.
pub fn metadata(&self) -> &Arc {
&self.metadata
@@ -413,10 +573,7 @@ impl Iterator for LazyGridArrayIterator {
}
let result = (|| -> Result> {
- // Read size
let size: u64 = bincode::deserialize_from(&mut self.cursor)?;
-
- // Read grid data
self.buffer.resize(size as usize, 0);
self.cursor.read_exact(&mut self.buffer)?;
@@ -446,11 +603,11 @@ mod tests {
use ndarray::Array1;
use tempfile::NamedTempFile;
- use crate::metadata::{InterpolatorType, MetaDataV1, SetType};
+ use crate::metadata::{InterpolatorType, MetaDataV2, SetType};
#[test]
fn test_collection_with_metadata() {
- let metadata_v1 = MetaDataV1 {
+ let metadata = MetaDataV2 {
set_desc: "Test PDF".into(),
set_index: 1,
num_members: 2,
@@ -482,8 +639,12 @@ mod tests {
m_top: 0.0,
alphas_type: String::new(),
number_flavors: 0,
+ // V2 fields
+ xi_min: 0.0,
+ xi_max: 0.0,
+ delta_min: 0.0,
+ delta_max: 0.0,
};
- let metadata = MetaData::new_v1(metadata_v1);
let test_grid = test_grid();
let grids = vec![&test_grid, &test_grid];
diff --git a/neopdf/tests/pdf.rs b/neopdf/tests/pdf.rs
index 6f71ea2b..35c0899a 100644
--- a/neopdf/tests/pdf.rs
+++ b/neopdf/tests/pdf.rs
@@ -270,7 +270,7 @@ pub fn test_multi_members_loader() {
pub fn test_multi_members_lazy_loader() {
let pdfs = PDF::load_pdfs_lazy("NNPDF40_nnlo_as_01180.neopdf.lz4");
- let _ = pdfs.map(|pdf| {
+ pdfs.for_each(|pdf| {
let result = match pdf {
Ok(t) => t,
Err(err) => unreachable!("{err}"),
diff --git a/neopdf_capi/docs/source/examples.rst b/neopdf_capi/docs/source/examples.rst
index 92efa438..6c28dc91 100644
--- a/neopdf_capi/docs/source/examples.rst
+++ b/neopdf_capi/docs/source/examples.rst
@@ -327,7 +327,7 @@ below in the case the grid should explicitly depend on more parameters.
.. code-block:: cpp
- :linenos:
+ :linenos:
#include
#include
@@ -506,7 +506,7 @@ a dependence on the transverse momentum :math:`k_T`. The following example makes
the `TMDlib `_ library to provide the TMD distributions.
.. code-block:: cpp
- :linenos:
+ :linenos:
#include "neopdf_capi.h"
#include "tmdlib/TMDlib.h"
diff --git a/neopdf_capi/src/include/NeoPDF.hpp b/neopdf_capi/src/include/NeoPDF.hpp
index c3ab2699..f1361382 100644
--- a/neopdf_capi/src/include/NeoPDF.hpp
+++ b/neopdf_capi/src/include/NeoPDF.hpp
@@ -95,6 +95,44 @@ struct MetaData {
}
};
+/** @brief C++ representation of NeoPDFMetaDataV2. */
+struct MetaDataV2 : public MetaData {
+ double xi_min = 1.0;
+ double xi_max = 1.0;
+ double delta_min = 0.0;
+ double delta_max = 0.0;
+
+ // Conversion to C struct
+ NeoPDFMetaDataV2 to_c_v2() const {
+ NeoPDFMetaDataV2 c_meta;
+ c_meta.set_desc = set_desc.c_str();
+ c_meta.set_index = set_index;
+ c_meta.num_members = num_members;
+ c_meta.x_min = x_min;
+ c_meta.x_max = x_max;
+ c_meta.q_min = q_min;
+ c_meta.q_max = q_max;
+ c_meta.flavors = flavors.data();
+ c_meta.num_flavors = flavors.size();
+ c_meta.format = format.c_str();
+ c_meta.alphas_q_values = alphas_q_values.data();
+ c_meta.num_alphas_q = alphas_q_values.size();
+ c_meta.alphas_vals = alphas_vals.data();
+ c_meta.num_alphas_vals = alphas_vals.size();
+ c_meta.polarised = polarised;
+ c_meta.set_type = set_type;
+ c_meta.interpolator_type = interpolator_type;
+ c_meta.error_type = error_type.c_str();
+ c_meta.hadron_pid = hadron_pid;
+ c_meta.phys_params = phys_params.to_c();
+ c_meta.xi_min = xi_min;
+ c_meta.xi_max = xi_max;
+ c_meta.delta_min = delta_min;
+ c_meta.delta_max = delta_max;
+ return c_meta;
+ }
+};
+
class NeoPDFs; // Forward declaration
/** @brief Base PDF class that instantiates the PDF object. */
@@ -420,6 +458,47 @@ class GridWriter {
}
}
+ /**
+ * @brief Adds a subgrid to the current grid (v2 for 8D).
+ *
+ * @param nucleons Vector of nucleon numbers.
+ * @param alphas Vector of alpha_s values.
+ * @param xis Vector of xi values.
+ * @param deltas Vector of delta values.
+ * @param kts Vector of kt values.
+ * @param xs Vector of x values.
+ * @param q2s Vector of Q2 values.
+ * @param grid_data Vector of grid data.
+ */
+ void add_subgrid_v2(
+ const std::vector& nucleons,
+ const std::vector& alphas,
+ const std::vector& xis,
+ const std::vector& deltas,
+ const std::vector& kts,
+ const std::vector& xs,
+ const std::vector& q2s,
+ const std::vector& grid_data
+ ) {
+ if (!current_grid) {
+ throw std::runtime_error("No grid started. Call new_grid() first.");
+ }
+ NeopdfResult result = neopdf_grid_add_subgridv2(
+ current_grid,
+ nucleons.data(), nucleons.size(),
+ alphas.data(), alphas.size(),
+ xis.data(), xis.size(),
+ deltas.data(), deltas.size(),
+ kts.data(), kts.size(),
+ xs.data(), xs.size(),
+ q2s.data(), q2s.size(),
+ grid_data.data(), grid_data.size()
+ );
+ if (result != NeopdfResult::NEOPDF_RESULT_SUCCESS) {
+ throw std::runtime_error("Failed to add subgrid (v2)");
+ }
+ }
+
/**
* @brief Finalizes the current grid, sets its flavors, and adds it to the collection.
*
@@ -468,6 +547,27 @@ class GridWriter {
throw std::runtime_error("Failed to compress grid data");
}
}
+
+ /**
+ * @brief Compresses the added grids and writes them to a file using V2 metadata.
+ *
+ * @param metadata The V2 metadata for the PDF set.
+ * @param output_path The path to the output file.
+ */
+ void compress_v2(const MetaDataV2& metadata, const std::string& output_path) {
+ if (current_grid) {
+ neopdf_grid_free(current_grid);
+ current_grid = nullptr;
+ throw std::runtime_error("A grid was being built but was not committed before compress().");
+ }
+
+ NeoPDFMetaDataV2 c_meta = metadata.to_c_v2();
+ NeopdfResult result = neopdf_grid_compress_v2(collection_raw, &c_meta, output_path.c_str());
+
+ if (result != NeopdfResult::NEOPDF_RESULT_SUCCESS) {
+ throw std::runtime_error("Failed to compress grid data (v2)");
+ }
+ }
};
} // namespace neopdf
diff --git a/neopdf_capi/src/lib.rs b/neopdf_capi/src/lib.rs
index 8768ed7d..f0a296b0 100644
--- a/neopdf_capi/src/lib.rs
+++ b/neopdf_capi/src/lib.rs
@@ -5,7 +5,7 @@ use std::os::raw::{c_char, c_double, c_int};
use std::slice;
use neopdf::gridpdf::{ForcePositive, GridArray};
-use neopdf::metadata::{InterpolatorType, MetaData, MetaDataV1, SetType};
+use neopdf::metadata::{InterpolatorType, MetaData, SetType};
use neopdf::parser::SubgridData;
use neopdf::pdf::PDF;
use neopdf::writer::GridArrayCollection;
@@ -478,6 +478,10 @@ pub enum NeopdfSubgridParams {
Nucleons,
/// The strong coupling constant (`alpha_s`) parameter.
Alphas,
+ /// The xi parameter.
+ Xi,
+ /// The delta parameter.
+ Delta,
/// The transverse momentum `kT` parameter.
Kt,
/// The momentum fraction (x) parameter.
@@ -531,6 +535,11 @@ pub unsafe extern "C" fn neopdf_pdf_param_range(
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]
@@ -570,6 +579,8 @@ pub unsafe extern "C" fn neopdf_pdf_subgrids_shape_for_param(
.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(),
@@ -606,6 +617,8 @@ pub unsafe extern "C" fn neopdf_pdf_subgrids_for_param(
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,
@@ -662,6 +675,8 @@ impl NeoPDFGrid {
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(),
@@ -682,6 +697,57 @@ impl NeoPDFGrid {
NeopdfResult::Success
}
+
+ /// Adds a subgrid to the grid (v2 for 8D)
+ #[allow(clippy::too_many_arguments)]
+ 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 {
+ // Check for null pointers
+ 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
+ }
}
/// Creates a new, empty `NeoPDFGrid`.
@@ -736,6 +802,58 @@ pub unsafe extern "C" fn neopdf_grid_add_subgrid(
}
}
+/// Adds a subgrid to an existing `NeoPDFGrid` (v2 for 8D).
+///
+/// This function takes ownership of the provided data arrays and resizes them as needed.
+///
+/// # Safety
+/// - `grid` must be a valid pointer to a `NeoPDFGrid` created by `neopdf_grid_new`.
+/// - The data pointers must be valid for the specified lengths.
+#[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,
+ )
+ })
+ }
+}
+
/// Sets the flavor IDs for a `NeoPDFGrid`.
///
/// # Safety
@@ -822,6 +940,35 @@ pub struct NeoPDFMetaData {
phys_params: NeoPDFPhysicsParameters,
}
+/// Metadata for PDF grids (V2 with extended fields)
+#[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,
+}
+
/// Safely converts C string to Rust string
unsafe fn cstr_to_string(ptr: *const c_char) -> Option {
if ptr.is_null() {
@@ -857,7 +1004,68 @@ fn process_metadata(meta: *const NeoPDFMetaData) -> Option {
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_v1 = MetaDataV1 {
+ // Create MetaData (now MetaDataV2) directly
+ 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(), // placeholder to be overwritten
+ code_version: String::new(), // placeholder to be overwritten
+ 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,
+ // New V2 fields with defaults
+ xi_min: 1.0,
+ xi_max: 1.0,
+ delta_min: 0.0,
+ delta_max: 0.0,
+ };
+
+ Some(metadata)
+}
+
+/// Processes metadata from C struct to Rust struct (V2)
+fn process_metadata_v2(meta: *const NeoPDFMetaDataV2) -> Option {
+ 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) }?;
+
+ // Create MetaData directly from V2 struct
+ let metadata = MetaData {
set_desc,
set_index: meta.set_index,
num_members: meta.num_members,
@@ -889,8 +1097,12 @@ fn process_metadata(meta: *const NeoPDFMetaData) -> Option {
m_top: meta.phys_params.m_top,
alphas_type,
number_flavors: meta.phys_params.number_flavors,
+ // New V2 fields
+ xi_min: meta.xi_min,
+ xi_max: meta.xi_max,
+ delta_min: meta.delta_min,
+ delta_max: meta.delta_max,
};
- let metadata = MetaData::new_v1(metadata_v1);
Some(metadata)
}
@@ -1116,6 +1328,54 @@ pub unsafe extern "C" fn neopdf_grid_compress(
}
}
+/// Compresses a collection of `NeoPDFGrid` objects and writes them to a file (V2).
+///
+/// This function iterates through the grids in the collection, converts them to `GridArray`s,
+/// and then uses the `neopdf::writer::GridArrayCollection::compress` function to write them.
+///
+/// # Safety
+/// - `collection` must be a valid, non-null pointer to a `NeoPDFGridArrayCollection`.
+/// - `metadata` must be a valid, non-null pointer to a `NeoPDFMetaDataV2` struct.
+/// - `output_path` must be a valid, null-terminated C string representing the output file path.
+#[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,
+ }
+}
+
// LHAPDF C-API drop-in compatibility layer.
///
/// This global state stores the loaded PDF set and the currently selected
diff --git a/neopdf_capi/tests/Makefile b/neopdf_capi/tests/Makefile
index 46eb724f..11087df9 100644
--- a/neopdf_capi/tests/Makefile
+++ b/neopdf_capi/tests/Makefile
@@ -5,7 +5,7 @@ NEOPDF_DEPS != pkg-config --cflags --libs neopdf_capi
LHAPDF_DEPS != pkg-config --cflags --libs lhapdf
MATH_LIBS = -lm
-PROGRAMS = check-capi check-oop check-writer check-writer-oop check-xapi check-xwriter check-lhapdf-compatibility
+PROGRAMS = check-capi check-oop check-writer check-writer-8d check-writer-oop check-xapi check-xwriter check-lhapdf-compatibility
all: $(PROGRAMS)
@@ -18,6 +18,9 @@ check-capi: check-capi.cpp
check-writer: check-writer.cpp
$(CXX) $(CXXFLAGS) $< $(LHAPDF_DEPS) $(NEOPDF_DEPS) -o $@
+check-writer-8d: check-writer-8d.cpp
+ $(CXX) $(CXXFLAGS) $< $(LHAPDF_DEPS) $(NEOPDF_DEPS) -o $@
+
check-oop: check-oop.cpp
$(CXX) $(CXXFLAGS) $< $(LHAPDF_DEPS) $(NEOPDF_DEPS) -o $@
diff --git a/neopdf_capi/tests/check-writer-8d.cpp b/neopdf_capi/tests/check-writer-8d.cpp
new file mode 100644
index 00000000..a65c35d9
--- /dev/null
+++ b/neopdf_capi/tests/check-writer-8d.cpp
@@ -0,0 +1,264 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+const double TOLERANCE = 1e-10; // Increased tolerance for synthetic data
+
+template
+std::vector geomspace(T start, T stop, int num, bool endpoint = false) {
+ std::vector result(num);
+
+ if (num == 1) {
+ result[0] = start;
+ return result;
+ }
+
+ T log_start = std::log(start);
+ T log_stop = std::log(stop);
+ T step = (log_stop - log_start) / (endpoint ? (num - 1) : num);
+
+ for (int i = 0; i < num; ++i) {
+ result[i] = std::exp(log_start + i * step);
+ }
+
+ return result;
+}
+
+// Helper function to extract subgrid parameters
+std::vector extract_subgrid_params(
+ NeoPDFWrapper* pdf,
+ NeopdfSubgridParams param_type,
+ std::size_t subgrid_idx,
+ std::size_t num_subgrids
+) {
+ std::vector shape(num_subgrids);
+ neopdf_pdf_subgrids_shape_for_param(
+ pdf,
+ shape.data(),
+ num_subgrids,
+ param_type
+ );
+
+ std::vector values(shape[subgrid_idx]);
+ neopdf_pdf_subgrids_for_param(
+ pdf,
+ values.data(),
+ param_type,
+ num_subgrids,
+ shape.data(),
+ subgrid_idx
+ );
+
+ return values;
+}
+
+int main() {
+ const char* pdfname = "NNPDF40_nnlo_as_01180";
+ // Load all PDF members
+ NeoPDFMembers neo_pdfs = neopdf_pdf_load_all(pdfname);
+ if (neo_pdfs.size == 0) {
+ std::cerr << "Failed to load any PDF members!\n";
+ return 1;
+ }
+ std::cout << "Loaded " << neo_pdfs.size << " PDF members\n";
+
+ // Extract the PID values of the PDF set
+ std::size_t num_pids = neopdf_pdf_num_pids(neo_pdfs.pdfs[0]);
+ std::vector pids(num_pids);
+ neopdf_pdf_pids(neo_pdfs.pdfs[0], pids.data(), num_pids);
+
+ // Extract the number of subgrids
+ std::size_t num_subgrids = neopdf_pdf_num_subgrids(neo_pdfs.pdfs[0]);
+
+ // Define synthetic xi and delta values
+ std::vector xis = {0.0};
+ std::vector deltas = {0.0};
+
+ // Create a collection
+ NeoPDFGridArrayCollection* collection = neopdf_gridarray_collection_new();
+ if (!collection) {
+ std::cerr << "Failed to create grid array collection!\n";
+ neopdf_pdf_array_free(neo_pdfs);
+ return 1;
+ }
+
+ // For each member, build a grid
+ for (size_t m = 0; m < neo_pdfs.size; ++m) {
+ NeoPDFWrapper* pdf = neo_pdfs.pdfs[m];
+ NeoPDFGrid* grid = neopdf_grid_new();
+
+ if (!grid) {
+ std::cerr << "Failed to create grid for member: " << m << "!\n";
+ continue;
+ }
+
+ // Loop over the Subgrids
+ bool member_failed = false;
+ for (std::size_t subgrid_idx = 0; subgrid_idx < num_subgrids; ++subgrid_idx) {
+ // Extract base parameters from the original PDF (x, q2, nucleons, alphas, kts)
+ auto xs = extract_subgrid_params(pdf, NEOPDF_SUBGRID_PARAMS_MOMENTUM, subgrid_idx, num_subgrids);
+ auto q2s = extract_subgrid_params(pdf, NEOPDF_SUBGRID_PARAMS_SCALE, subgrid_idx, num_subgrids);
+ auto alphas = extract_subgrid_params(pdf, NEOPDF_SUBGRID_PARAMS_ALPHAS, subgrid_idx, num_subgrids);
+ auto nucleons = extract_subgrid_params(pdf, NEOPDF_SUBGRID_PARAMS_NUCLEONS, subgrid_idx, num_subgrids);
+ auto kts = extract_subgrid_params(pdf, NEOPDF_SUBGRID_PARAMS_KT, subgrid_idx, num_subgrids);
+
+ // Compute grid_data: [q2s][xs][flavors], instead of [nucleons][alphas][xis][deltas][q2s][xs][flavors]
+ // NOTE: This assumes that there is no 'A', `alphas`, `xis`, and `deltas` dependence.
+ assert(alphas.size() == 1);
+ assert(kts.size() == 1);
+ assert(xis.size() == 1);
+ assert(deltas.size() == 1);
+ assert(nucleons.size() == 1);
+ std::vector grid_data;
+ for (size_t xi = 0; xi < xs.size(); ++xi) {
+ for (size_t qi = 0; qi < q2s.size(); ++qi) {
+ for (size_t f = 0; f < pids.size(); ++f) {
+ int pid = pids[f];
+ double val = neopdf_pdf_xfxq2(pdf, pid, xs[xi], q2s[qi]);
+ grid_data.push_back(val);
+ }
+ }
+ }
+
+ // Add subgrid using the v2 function
+ NeopdfResult add_subgrid_res = neopdf_grid_add_subgridv2(
+ grid,
+ nucleons.data(), nucleons.size(),
+ alphas.data(), alphas.size(),
+ xis.data(), xis.size(),
+ deltas.data(), deltas.size(),
+ kts.data(), kts.size(),
+ xs.data(), xs.size(),
+ q2s.data(), q2s.size(),
+ grid_data.data(), grid_data.size()
+ );
+ if (add_subgrid_res != NEOPDF_RESULT_SUCCESS) {
+ std::cerr << "Failed to add subgrid (v2) for member: " << m << "!\n";
+ neopdf_grid_free(grid);
+ member_failed = true;
+ break;
+ }
+ }
+
+ if (member_failed) {
+ continue;
+ }
+
+ // Set flavor PIDs
+ int add_flavors = neopdf_grid_set_flavors(grid, pids.data(), pids.size());
+ if (add_flavors != 0) {
+ std::cerr << "Failed to set flavors for member: " << m << "!\n";
+ neopdf_grid_free(grid);
+ continue;
+ }
+
+ // Add grid to collection
+ int add_grid = neopdf_gridarray_collection_add_grid(collection, grid);
+ if (add_grid != 0) {
+ std::cerr << "Failed to add grid to collection for member: " << m << "!\n";
+ neopdf_grid_free(grid);
+ continue;
+ }
+ std::cout << "Added grid for member " << m << "\n";
+ }
+
+ // Fill the running of alphas with some random values
+ double alphas_qs[] = {2.0};
+ double alphas_vals[] = {0.118};
+
+ // Extract the ranges for the momentum x and scale Q2
+ std::vector x_range(2);
+ std::vector q2_range(2);
+ neopdf_pdf_param_range(neo_pdfs.pdfs[0], NEOPDF_SUBGRID_PARAMS_MOMENTUM, x_range.data());
+ neopdf_pdf_param_range(neo_pdfs.pdfs[0], NEOPDF_SUBGRID_PARAMS_SCALE, q2_range.data());
+
+ NeoPDFPhysicsParameters phys_params = {
+ .flavor_scheme = "variable",
+ .order_qcd = 2,
+ .alphas_order_qcd = 2,
+ .m_w = 80.352,
+ .m_z = 91.1876,
+ .m_up = 0.0,
+ .m_down = 0.0,
+ .m_strange = 0.0,
+ .m_charm = 1.51,
+ .m_bottom = 4.92,
+ .m_top = 172.5,
+ .alphas_type = "ipol",
+ .number_flavors = 4,
+ };
+
+ NeoPDFMetaDataV2 meta = {
+ .set_desc = "NNPDF40_nnlo_as_01180 8D collection",
+ .set_index = 0,
+ .num_members = (uint32_t)neo_pdfs.size,
+ .x_min = x_range[0],
+ .x_max = x_range[1],
+ .q_min = sqrt(q2_range[0]),
+ .q_max = sqrt(q2_range[1]),
+ .flavors = pids.data(),
+ .num_flavors = (size_t)pids.size(),
+ .format = "neopdf",
+ .alphas_q_values = alphas_qs,
+ .num_alphas_q = 1,
+ .alphas_vals = alphas_vals,
+ .num_alphas_vals = 1,
+ .polarised = false,
+ .set_type = NEOPDF_SET_TYPE_SPACE_LIKE,
+ .interpolator_type = NEOPDF_INTERPOLATOR_TYPE_LOG_BICUBIC,
+ .error_type = "replicas",
+ .hadron_pid = 2212,
+ .phys_params = phys_params,
+ .xi_min = xis[0],
+ .xi_max = xis.back(),
+ .delta_min = deltas[0],
+ .delta_max = deltas.back(),
+ };
+
+ // Check if `NEOPDF_DATA_PATH` is defined and store the Grid there.
+ const char* filename = "check-writer-8d.neopdf.lz4";
+ const char* neopdf_path = std::getenv("NEOPDF_DATA_PATH");
+ std::string output_path = neopdf_path
+ ? std::string(neopdf_path) + (std::string(neopdf_path).back() == '/' ? "" : "/") + filename
+ : filename;
+
+ // Write the PDF Grid into disk
+ int result = neopdf_grid_compress_v2(collection, &meta, output_path.c_str());
+ if (result != 0) {
+ std::cerr << "Compression failed with code " << result << "\n";
+ } else {
+ std::cout << "Compression succeeded!\n";
+ }
+
+ // If `NEOPDF_DATA_PATH` is defined, reload the grid and check the results.
+ if (neopdf_path) {
+ int pid_test = 21;
+ double x_test = 1e-3;
+ double q2_test = 1e2;
+
+ double ref = neopdf_pdf_xfxq2(neo_pdfs.pdfs[0], pid_test, x_test, q2_test);
+
+ // For the newly written 8D PDF
+ NeoPDFWrapper* wpdf = neopdf_pdf_load(output_path.c_str(), 0);
+ std::vector params = {x_test, q2_test};
+ double res = neopdf_pdf_xfxq2_nd(wpdf, pid_test, params.data(), params.size());
+
+ assert(std::abs(res - ref) < TOLERANCE);
+
+ // Delete PDF object from memory
+ neopdf_pdf_free(wpdf);
+ }
+
+ // Cleanup
+ neopdf_gridarray_collection_free(collection);
+ neopdf_pdf_array_free(neo_pdfs);
+
+ return result == 0 ? 0 : 1;
+}
diff --git a/neopdf_capi/tests/check-writer-8d.output b/neopdf_capi/tests/check-writer-8d.output
new file mode 100644
index 00000000..ac273bda
--- /dev/null
+++ b/neopdf_capi/tests/check-writer-8d.output
@@ -0,0 +1,103 @@
+Loaded 101 PDF members
+Added grid for member 0
+Added grid for member 1
+Added grid for member 2
+Added grid for member 3
+Added grid for member 4
+Added grid for member 5
+Added grid for member 6
+Added grid for member 7
+Added grid for member 8
+Added grid for member 9
+Added grid for member 10
+Added grid for member 11
+Added grid for member 12
+Added grid for member 13
+Added grid for member 14
+Added grid for member 15
+Added grid for member 16
+Added grid for member 17
+Added grid for member 18
+Added grid for member 19
+Added grid for member 20
+Added grid for member 21
+Added grid for member 22
+Added grid for member 23
+Added grid for member 24
+Added grid for member 25
+Added grid for member 26
+Added grid for member 27
+Added grid for member 28
+Added grid for member 29
+Added grid for member 30
+Added grid for member 31
+Added grid for member 32
+Added grid for member 33
+Added grid for member 34
+Added grid for member 35
+Added grid for member 36
+Added grid for member 37
+Added grid for member 38
+Added grid for member 39
+Added grid for member 40
+Added grid for member 41
+Added grid for member 42
+Added grid for member 43
+Added grid for member 44
+Added grid for member 45
+Added grid for member 46
+Added grid for member 47
+Added grid for member 48
+Added grid for member 49
+Added grid for member 50
+Added grid for member 51
+Added grid for member 52
+Added grid for member 53
+Added grid for member 54
+Added grid for member 55
+Added grid for member 56
+Added grid for member 57
+Added grid for member 58
+Added grid for member 59
+Added grid for member 60
+Added grid for member 61
+Added grid for member 62
+Added grid for member 63
+Added grid for member 64
+Added grid for member 65
+Added grid for member 66
+Added grid for member 67
+Added grid for member 68
+Added grid for member 69
+Added grid for member 70
+Added grid for member 71
+Added grid for member 72
+Added grid for member 73
+Added grid for member 74
+Added grid for member 75
+Added grid for member 76
+Added grid for member 77
+Added grid for member 78
+Added grid for member 79
+Added grid for member 80
+Added grid for member 81
+Added grid for member 82
+Added grid for member 83
+Added grid for member 84
+Added grid for member 85
+Added grid for member 86
+Added grid for member 87
+Added grid for member 88
+Added grid for member 89
+Added grid for member 90
+Added grid for member 91
+Added grid for member 92
+Added grid for member 93
+Added grid for member 94
+Added grid for member 95
+Added grid for member 96
+Added grid for member 97
+Added grid for member 98
+Added grid for member 99
+Added grid for member 100
+Compression succeeded!
diff --git a/neopdf_cli/src/converter.rs b/neopdf_cli/src/converter.rs
index 16274b43..a0eca83d 100644
--- a/neopdf_cli/src/converter.rs
+++ b/neopdf_cli/src/converter.rs
@@ -168,6 +168,7 @@ fn load_pdf_names(
/// # Errors
///
/// TODO
+#[allow(clippy::implicit_clone)]
#[allow(clippy::needless_pass_by_value)]
pub fn run_cli(cli: Cli) -> Result<(), Box> {
match &cli.command {
diff --git a/neopdf_cli/src/read.rs b/neopdf_cli/src/read.rs
index a01c79b7..120f67ae 100644
--- a/neopdf_cli/src/read.rs
+++ b/neopdf_cli/src/read.rs
@@ -30,6 +30,9 @@ pub enum ReadCommands {
/// Print the git version of the code that generated the PDF.
#[command(name = "git-version")]
GitVersion(PdfNameArgs),
+ /// Print the code version of the code that generated the PDF.
+ #[command(name = "code-version")]
+ CodeVersion(PdfNameArgs),
}
/// Arguments for the metadata subcommand.
@@ -89,6 +92,7 @@ pub struct SubgridArgs {
/// # Panics
///
/// This function panics when a PID not present in the Grid is requested.
+#[allow(clippy::too_many_lines)]
#[allow(clippy::needless_pass_by_value)]
pub fn main(cli: ReadCli) {
match &cli.command {
@@ -136,14 +140,28 @@ pub fn main(cli: ReadCli) {
}
println!();
- let grid_slice = subgrid.grid.slice(s![
- args.nucleon_index,
- args.alphas_index,
- pid_idx,
- args.kt_index,
- ..,
- ..
- ]);
+ let grid_slice = match &subgrid.grid {
+ neopdf::subgrid::GridData::Grid6D(grid) => grid.slice(s![
+ args.nucleon_index,
+ args.alphas_index,
+ pid_idx,
+ args.kt_index,
+ ..,
+ ..
+ ]),
+ neopdf::subgrid::GridData::Grid8D(grid) => {
+ grid.slice(s![
+ args.nucleon_index,
+ args.alphas_index,
+ 0, // xi_index - default to first
+ 0, // delta_index - default to first
+ args.kt_index,
+ pid_idx,
+ ..,
+ ..
+ ])
+ }
+ };
let width = if let Some((Width(w), _)) = terminal_size() {
w as usize
@@ -184,5 +202,9 @@ pub fn main(cli: ReadCli) {
let pdf = neopdf::pdf::PDF::load(&args.pdf_name, 0);
println!("{}", pdf.metadata().git_version);
}
+ ReadCommands::CodeVersion(args) => {
+ let pdf = neopdf::pdf::PDF::load(&args.pdf_name, 0);
+ println!("{}", pdf.metadata().code_version);
+ }
}
}
diff --git a/neopdf_cli/src/tmd_converter.rs b/neopdf_cli/src/tmd_converter.rs
index b03c9b5e..216d6df7 100644
--- a/neopdf_cli/src/tmd_converter.rs
+++ b/neopdf_cli/src/tmd_converter.rs
@@ -6,7 +6,7 @@ use std::f64::consts::PI;
use std::fs;
use neopdf::gridpdf::GridArray;
-use neopdf::metadata::{InterpolatorType, MetaData, MetaDataV1, SetType};
+use neopdf::metadata::{InterpolatorType, MetaDataV2, SetType};
use neopdf::subgrid::SubGrid;
use neopdf::writer::GridArrayCollection;
use neopdf_tmdlib::Tmd;
@@ -246,7 +246,7 @@ pub fn convert_tmd(input_path: &str, output_path: &str) -> Result<(), Box = member_grids.iter().collect();
- let meta = MetaData::new_v1(MetaDataV1 {
+ let meta = MetaDataV2 {
set_desc: config.set_desc,
set_index: config.set_index,
num_members: n_members as u32,
@@ -278,7 +278,11 @@ pub fn convert_tmd(input_path: &str, output_path: &str) -> Result<(), Box) -> PyResult<()> {
Ok(())
}
-/// Converts an LHAPDF set to the NeoPDF format and writes it to disk.
+/// Converts an LHAPDF set to the `NeoPDF` format and writes it to disk.
///
-/// Converts the specified LHAPDF set into the NeoPDF format and saves the result to the given
+/// Converts the specified LHAPDF set into the `NeoPDF` format and saves the result to the given
/// output path.
///
/// # Parameters
///
-/// - `pdf_name`: The name of the LHAPDF set (e.g., "NNPDF40_nnlo_as_01180").
-/// - `output_path`: The path to the output NeoPDF file.
+/// - `pdf_name`: The name of the LHAPDF set (e.g., "`NNPDF40_nnlo_as_01180`").
+/// - `output_path`: The path to the output `NeoPDF` file.
///
/// # Returns
///
@@ -42,15 +42,15 @@ pub fn py_convert_lhapdf(pdf_name: &str, output_path: &str) -> PyResult<()> {
.map_err(|e| PyRuntimeError::new_err(format!("Conversion failed: {e}")))
}
-/// Combines a list of nuclear PDF sets into a single NeoPDF file with explicit A dependence.
+/// Combines a list of nuclear PDF sets into a single `NeoPDF` file with explicit A dependence.
///
-/// Combines multiple LHAPDF nuclear PDF sets into a single NeoPDF file, allowing for explicit
+/// Combines multiple LHAPDF nuclear PDF sets into a single `NeoPDF` file, allowing for explicit
/// nuclear dependence.
///
/// # Parameters
///
/// - `pdf_names`: List of PDF set names (each with a different A).
-/// - `output_path`: Output NeoPDF file path.
+/// - `output_path`: Output `NeoPDF` file path.
///
/// # Returns
///
diff --git a/neopdf_pyapi/src/gridpdf.rs b/neopdf_pyapi/src/gridpdf.rs
index 841fbfdb..681d6d06 100644
--- a/neopdf_pyapi/src/gridpdf.rs
+++ b/neopdf_pyapi/src/gridpdf.rs
@@ -1,9 +1,9 @@
-use ndarray::Array1;
-use numpy::{PyArrayMethods, PyReadonlyArray6};
+use ndarray::{Array1, Dimension};
+use numpy::{PyArrayMethods, PyReadonlyArrayDyn};
use pyo3::prelude::*;
use neopdf::gridpdf::GridArray;
-use neopdf::subgrid::{ParamRange, SubGrid};
+use neopdf::subgrid::{GridData, ParamRange, SubGrid};
/// Python wrapper for the `SubGrid` struct.
#[pyclass(name = "SubGrid")]
@@ -20,9 +20,11 @@ impl PySubGrid {
/// - `xs`: The x-axis values.
/// - `q2s`: The Q^2-axis values.
/// - `kts`: The kT-axis values.
+ /// - `xsis`: The Skeweness `\xi`.
+ /// - `deltas`: The total momentum fraction `\Delta`.
/// - `nucleons`: The nucleon number axis values.
- /// - `alphas`: The alpha_s axis values.
- /// - `grid`: The 6D grid data as a NumPy array.
+ /// - `alphas`: The `alpha_s` axis values.
+ /// - `grid`: The 6D grid data as a `NumPy` array.
///
/// # Returns
///
@@ -36,18 +38,23 @@ impl PySubGrid {
///
/// Returns a `PyErr` if the grid cannot be constructed from the input data.
#[new]
+ #[allow(clippy::too_many_arguments)]
#[allow(clippy::needless_pass_by_value)]
pub fn new(
xs: Vec,
q2s: Vec,
kts: Vec,
+ xsis: Vec,
+ deltas: Vec,
nucleons: Vec,
alphas: Vec,
- grid: PyReadonlyArray6,
+ grid: PyReadonlyArrayDyn,
) -> PyResult {
let alphas_range = ParamRange::new(*alphas.first().unwrap(), *alphas.last().unwrap());
let x_range = ParamRange::new(*xs.first().unwrap(), *xs.last().unwrap());
let q2_range = ParamRange::new(*q2s.first().unwrap(), *q2s.last().unwrap());
+ let xsi_range = ParamRange::new(*xsis.first().unwrap(), *xsis.last().unwrap());
+ let delta_range = ParamRange::new(*deltas.first().unwrap(), *deltas.last().unwrap());
let kt_range = ParamRange::new(*kts.first().unwrap(), *kts.last().unwrap());
let nucleons_range = ParamRange::new(*nucleons.first().unwrap(), *nucleons.last().unwrap());
@@ -55,11 +62,15 @@ impl PySubGrid {
xs: Array1::from(xs),
q2s: Array1::from(q2s),
kts: Array1::from(kts),
- grid: grid.to_owned_array(),
+ xis: Array1::from(xsis),
+ deltas: Array1::from(deltas),
+ grid: GridData::Grid8D(grid.to_owned_array()),
nucleons: Array1::from(nucleons),
alphas: Array1::from(alphas),
nucleons_range,
alphas_range,
+ xi_range: xsi_range,
+ delta_range,
kt_range,
x_range,
q2_range,
@@ -68,7 +79,7 @@ impl PySubGrid {
Ok(Self { subgrid })
}
- /// Returns the minimum and maximum values of the alpha_s axis.
+ /// Returns the minimum and maximum values of the `alpha_s` axis.
#[must_use]
pub const fn alphas_range(&self) -> (f64, f64) {
(self.subgrid.alphas_range.min, self.subgrid.alphas_range.max)
@@ -86,6 +97,18 @@ impl PySubGrid {
(self.subgrid.q2_range.min, self.subgrid.q2_range.max)
}
+ /// Returns the minimum and maximum values of the skeweness `xi`.
+ #[must_use]
+ pub const fn xi_range(&self) -> (f64, f64) {
+ (self.subgrid.xi_range.min, self.subgrid.xi_range.max)
+ }
+
+ /// Returns the minimum and maximum values of the total momentum fraction `delta`.
+ #[must_use]
+ pub const fn delta_range(&self) -> (f64, f64) {
+ (self.subgrid.delta_range.min, self.subgrid.delta_range.max)
+ }
+
/// Returns the minimum and maximum values of the Nucleon number `A`.
#[must_use]
pub const fn nucleons_range(&self) -> (f64, f64) {
@@ -102,9 +125,19 @@ impl PySubGrid {
}
/// Returns the shape of the subgrid
+ ///
+ /// # Panics
+ ///
+ /// TODO
#[must_use]
- pub fn grid_shape(&self) -> (usize, usize, usize, usize, usize, usize) {
- self.subgrid.grid.dim()
+ pub fn grid_shape(&self) -> Vec {
+ match &self.subgrid.grid {
+ GridData::Grid6D(grid) => {
+ let (d0, d1, d2, d3, d4, d5) = grid.dim();
+ vec![d0, d1, d2, d3, d4, d5]
+ }
+ GridData::Grid8D(grid) => grid.dim().as_array_view().to_vec(),
+ }
}
}
diff --git a/neopdf_pyapi/src/lib.rs b/neopdf_pyapi/src/lib.rs
index cf817f77..ca714d4e 100644
--- a/neopdf_pyapi/src/lib.rs
+++ b/neopdf_pyapi/src/lib.rs
@@ -19,7 +19,7 @@ pub mod pdf;
/// Python bindings for the `writer` module.
pub mod writer;
-/// PyO3 Python module that contains all exposed classes from Rust.
+/// `PyO3` Python module that contains all exposed classes from Rust.
#[pymodule]
fn neopdf(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add("version", env!("CARGO_PKG_VERSION"))?;
diff --git a/neopdf_pyapi/src/manage.rs b/neopdf_pyapi/src/manage.rs
index 8384d4db..f5fd557f 100644
--- a/neopdf_pyapi/src/manage.rs
+++ b/neopdf_pyapi/src/manage.rs
@@ -8,7 +8,7 @@ use pyo3::prelude::*;
pub enum PyPdfSetFormat {
/// LHAPDF format (standard PDF set format used by LHAPDF).
Lhapdf,
- /// NeoPDF format (native format for this library).
+ /// `NeoPDF` format (native format for this library).
Neopdf,
}
@@ -29,7 +29,7 @@ pub struct PyManageData {
#[pymethods]
impl PyManageData {
- /// Create a new ManageData instance.
+ /// Create a new `ManageData` instance.
#[new]
#[must_use]
pub fn new(set_name: &str, format: PyPdfSetFormat) -> Self {
diff --git a/neopdf_pyapi/src/metadata.rs b/neopdf_pyapi/src/metadata.rs
index d05d59d5..8ca7f5d8 100644
--- a/neopdf_pyapi/src/metadata.rs
+++ b/neopdf_pyapi/src/metadata.rs
@@ -1,6 +1,6 @@
use pyo3::prelude::*;
-use neopdf::metadata::{InterpolatorType, MetaData, MetaDataV1, SetType};
+use neopdf::metadata::{InterpolatorType, MetaData, SetType};
/// The type of the set.
#[pyclass(eq, eq_int, name = "SetType")]
@@ -46,6 +46,10 @@ pub enum PyInterpolatorType {
NDLinear,
/// Chebyshev logarithmic interpolation strategy.
LogChebyshev,
+ /// Four-dimensional cubic logarithmic interpolation strategy.
+ LogFourCubic,
+ /// Five-dimensional cubic logarithmic interpolation strategy.
+ LogFiveCubic,
}
impl From<&InterpolatorType> for PyInterpolatorType {
@@ -57,6 +61,8 @@ impl From<&InterpolatorType> for PyInterpolatorType {
InterpolatorType::LogTricubic => Self::LogTricubic,
InterpolatorType::InterpNDLinear => Self::NDLinear,
InterpolatorType::LogChebyshev => Self::LogChebyshev,
+ InterpolatorType::LogFourCubic => Self::LogFourCubic,
+ InterpolatorType::LogFiveCubic => Self::LogFiveCubic,
}
}
}
@@ -70,6 +76,8 @@ impl From<&PyInterpolatorType> for InterpolatorType {
PyInterpolatorType::LogTricubic => Self::LogTricubic,
PyInterpolatorType::NDLinear => Self::InterpNDLinear,
PyInterpolatorType::LogChebyshev => Self::LogChebyshev,
+ PyInterpolatorType::LogFourCubic => Self::LogFourCubic,
+ PyInterpolatorType::LogFiveCubic => Self::LogFiveCubic,
}
}
}
@@ -95,7 +103,7 @@ pub struct PyPhysicsParameters {
#[pymethods]
impl PyPhysicsParameters {
- /// Constructor for PyPhysicsParameters.
+ /// Constructor for `PyPhysicsParameters`.
#[new]
#[must_use]
#[allow(clippy::too_many_arguments)]
@@ -151,7 +159,7 @@ impl PyPhysicsParameters {
/// # Errors
///
/// Raises an error if the values are not Python compatible.
- pub fn to_dict(&self, py: Python) -> PyResult {
+ pub fn to_dict(&self, py: Python) -> PyResult> {
let dict = pyo3::types::PyDict::new(py);
dict.set_item("flavor_scheme", &self.flavor_scheme)?;
dict.set_item("order_qcd", self.order_qcd)?;
@@ -199,11 +207,11 @@ pub struct PyMetaData {
#[pymethods]
impl PyMetaData {
- /// Constructor for PyMetaData.
+ /// Constructor for `PyMetaData`.
#[new]
#[must_use]
- #[allow(clippy::needless_pass_by_value)]
#[allow(clippy::too_many_arguments)]
+ #[allow(clippy::needless_pass_by_value)]
#[pyo3(signature = (
set_desc,
set_index,
@@ -212,6 +220,10 @@ impl PyMetaData {
x_max,
q_min,
q_max,
+ xsi_min,
+ xsi_max,
+ delta_min,
+ delta_max,
flavors,
format,
alphas_q_values = vec![],
@@ -231,6 +243,10 @@ impl PyMetaData {
x_max: f64,
q_min: f64,
q_max: f64,
+ xsi_min: f64,
+ xsi_max: f64,
+ delta_min: f64,
+ delta_max: f64,
flavors: Vec,
format: String,
alphas_q_values: Vec,
@@ -242,45 +258,45 @@ impl PyMetaData {
hadron_pid: i32,
phys_params: PyPhysicsParameters,
) -> Self {
- let git_version = String::new();
- let code_version = String::new();
-
- let meta_v1 = MetaDataV1 {
- set_desc,
- set_index,
- num_members,
- x_min,
- x_max,
- q_min,
- q_max,
- flavors,
- format,
- alphas_q_values,
- alphas_vals,
- polarised,
- set_type: SetType::from(&set_type),
- interpolator_type: InterpolatorType::from(&interpolator_type),
- error_type,
- hadron_pid,
- git_version, // placeholder to be overwritten
- code_version, // placeholder to be overwritten
- flavor_scheme: phys_params.flavor_scheme,
- order_qcd: phys_params.order_qcd,
- alphas_order_qcd: phys_params.alphas_order_qcd,
- m_w: phys_params.m_w,
- m_z: phys_params.m_z,
- m_up: phys_params.m_up,
- m_down: phys_params.m_down,
- m_strange: phys_params.m_strange,
- m_charm: phys_params.m_charm,
- m_bottom: phys_params.m_bottom,
- m_top: phys_params.m_top,
- alphas_type: phys_params.alphas_type,
- number_flavors: phys_params.number_flavors,
- };
-
Self {
- meta: MetaData::new_v1(meta_v1),
+ meta: MetaData {
+ set_desc,
+ set_index,
+ num_members,
+ x_min,
+ x_max,
+ q_min,
+ q_max,
+ flavors,
+ format,
+ alphas_q_values,
+ alphas_vals,
+ polarised,
+ set_type: SetType::from(&set_type),
+ interpolator_type: InterpolatorType::from(&interpolator_type),
+ error_type,
+ hadron_pid,
+ git_version: String::new(), // placeholder to be overwritten
+ code_version: String::new(), // placeholder to be overwritten
+ flavor_scheme: phys_params.flavor_scheme,
+ order_qcd: phys_params.order_qcd,
+ alphas_order_qcd: phys_params.alphas_order_qcd,
+ m_w: phys_params.m_w,
+ m_z: phys_params.m_z,
+ m_up: phys_params.m_up,
+ m_down: phys_params.m_down,
+ m_strange: phys_params.m_strange,
+ m_charm: phys_params.m_charm,
+ m_bottom: phys_params.m_bottom,
+ m_top: phys_params.m_top,
+ alphas_type: phys_params.alphas_type,
+ number_flavors: phys_params.number_flavors,
+ // New V2 fields with defaults
+ xi_min: xsi_min,
+ xi_max: xsi_max,
+ delta_min,
+ delta_max,
+ },
}
}
@@ -289,7 +305,7 @@ impl PyMetaData {
/// # Errors
///
/// Raises an erro if the values are not Python compatible.
- pub fn to_dict(&self, py: Python) -> PyResult {
+ pub fn to_dict(&self, py: Python) -> PyResult> {
let dict = pyo3::types::PyDict::new(py);
let set_type = match &self.meta.set_type {
@@ -304,6 +320,8 @@ impl PyMetaData {
InterpolatorType::LogTricubic => "LogTricubic",
InterpolatorType::InterpNDLinear => "NDLinear",
InterpolatorType::LogChebyshev => "LogChebyshev",
+ InterpolatorType::LogFourCubic => "LogFourCubic",
+ InterpolatorType::LogFiveCubic => "LogFiveCubic",
};
dict.set_item("set_desc", &self.meta.set_desc)?;
@@ -341,73 +359,97 @@ impl PyMetaData {
/// The description of the set.
#[must_use]
- pub fn set_desc(&self) -> &String {
+ pub const fn set_desc(&self) -> &String {
&self.meta.set_desc
}
/// The index of the grid.
#[must_use]
- pub fn set_index(&self) -> u32 {
+ pub const fn set_index(&self) -> u32 {
self.meta.set_index
}
/// The number of sets in the grid.
#[must_use]
- pub fn number_sets(&self) -> u32 {
+ pub const fn number_sets(&self) -> u32 {
self.meta.num_members
}
/// The minimum value of `x` in the grid.
#[must_use]
- pub fn x_min(&self) -> f64 {
+ pub const fn x_min(&self) -> f64 {
self.meta.x_min
}
/// The maximum value of `x` in the grid.
#[must_use]
- pub fn x_max(&self) -> f64 {
+ pub const fn x_max(&self) -> f64 {
self.meta.x_max
}
/// The minimum value of `q` in the grid.
#[must_use]
- pub fn q_min(&self) -> f64 {
+ pub const fn q_min(&self) -> f64 {
self.meta.q_min
}
/// The maximum value of `q` in the grid.
#[must_use]
- pub fn q_max(&self) -> f64 {
+ pub const fn q_max(&self) -> f64 {
self.meta.q_max
}
+ /// The minimum value of `xi` in the grid.
+ #[must_use]
+ pub const fn xi_min(&self) -> f64 {
+ self.meta.xi_min
+ }
+
+ /// The maximum value of `xi` in the grid.
+ #[must_use]
+ pub const fn xi_max(&self) -> f64 {
+ self.meta.xi_max
+ }
+
+ /// The minimum value of `delta` in the grid.
+ #[must_use]
+ pub const fn delta_min(&self) -> f64 {
+ self.meta.delta_min
+ }
+
+ /// The maximum value of `delta` in the grid.
+ #[must_use]
+ pub const fn delta_max(&self) -> f64 {
+ self.meta.delta_max
+ }
+
/// The particle IDs of the grid.
#[must_use]
- pub fn pids(&self) -> &Vec {
+ pub const fn pids(&self) -> &Vec {
&self.meta.flavors
}
/// The format of the grid.
#[must_use]
- pub fn format(&self) -> &String {
+ pub const fn format(&self) -> &String {
&self.meta.format
}
/// The values of `q` for the running of the strong coupling constant.
#[must_use]
- pub fn alphas_q(&self) -> &Vec {
+ pub const fn alphas_q(&self) -> &Vec {
&self.meta.alphas_q_values
}
/// The values of the running of the strong coupling constant.
#[must_use]
- pub fn alphas_values(&self) -> &Vec {
+ pub const fn alphas_values(&self) -> &Vec {
&self.meta.alphas_vals
}
/// Whether the grid is polarised.
#[must_use]
- pub fn is_polarised(&self) -> bool {
+ pub const fn is_polarised(&self) -> bool {
self.meta.polarised
}
@@ -425,13 +467,13 @@ impl PyMetaData {
/// The type of error.
#[must_use]
- pub fn error_type(&self) -> &String {
+ pub const fn error_type(&self) -> &String {
&self.meta.error_type
}
/// The hadron PID.
#[must_use]
- pub fn hadron_pid(&self) -> i32 {
+ pub const fn hadron_pid(&self) -> i32 {
self.meta.hadron_pid
}
}
diff --git a/neopdf_pyapi/src/parser.rs b/neopdf_pyapi/src/parser.rs
index 28b54e27..a7248798 100644
--- a/neopdf_pyapi/src/parser.rs
+++ b/neopdf_pyapi/src/parser.rs
@@ -12,7 +12,7 @@ pub struct PyLhapdfSet {
#[pymethods]
impl PyLhapdfSet {
- /// Create a new LhapdfSet instance for a given PDF set name.
+ /// Create a new `LhapdfSet` instance for a given PDF set name.
#[new]
#[must_use]
pub fn new(pdf_name: &str) -> Self {
@@ -56,7 +56,7 @@ pub struct PyNeopdfSet {
#[pymethods]
impl PyNeopdfSet {
- /// Create a new NeopdfSet instance for a given PDF set name.
+ /// Create a new `NeopdfSet` instance for a given PDF set name.
#[new]
#[must_use]
pub fn new(pdf_name: &str) -> Self {
diff --git a/neopdf_pyapi/src/pdf.rs b/neopdf_pyapi/src/pdf.rs
index 7ad5b5c5..4dba4fc9 100644
--- a/neopdf_pyapi/src/pdf.rs
+++ b/neopdf_pyapi/src/pdf.rs
@@ -121,6 +121,7 @@ pub struct PyPDF {
}
#[pymethods]
+#[allow(clippy::doc_markdown)]
impl PyPDF {
/// Creates a new `PDF` instance for a given PDF set and member.
///
diff --git a/neopdf_pyapi/src/writer.rs b/neopdf_pyapi/src/writer.rs
index b4416e5e..df633c8d 100644
--- a/neopdf_pyapi/src/writer.rs
+++ b/neopdf_pyapi/src/writer.rs
@@ -6,7 +6,7 @@ use pyo3::prelude::*;
use super::gridpdf::PyGridArray;
use super::metadata::PyMetaData;
-/// Python interface for GridArrayCollection utilities.
+/// Python interface for `GridArrayCollection` utilities.
///
/// This module provides functions to compress, decompress, and extract metadata from
/// collections of PDF grids.
@@ -23,7 +23,7 @@ pub fn writer(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
Ok(())
}
-/// Compresses and writes a collection of GridArrays and shared metadata to a file.
+/// Compresses and writes a collection of `GridArrays` and shared metadata to a file.
///
/// Compresses the provided grids and metadata and writes them to the specified file path.
///
@@ -52,7 +52,7 @@ pub fn py_compress(
.map_err(|e| PyRuntimeError::new_err(format!("Compress failed: {e}")))
}
-/// Decompresses and loads all GridArrays and shared metadata from a file.
+/// Decompresses and loads all `GridArrays` and shared metadata from a file.
///
/// Loads and decompresses all grid arrays and their associated metadata from the specified file.
///
diff --git a/neopdf_pyapi/tests/test_gridpdf.py b/neopdf_pyapi/tests/test_gridpdf.py
index 1080b3e8..7f3089f2 100644
--- a/neopdf_pyapi/tests/test_gridpdf.py
+++ b/neopdf_pyapi/tests/test_gridpdf.py
@@ -8,38 +8,58 @@ def test_subgrid(self, xq2_points):
xmin, xmax, q2min, q2max = (1e-5, 1.0, 1.65, 1.0e8)
xs, q2s = xq2_points(xmin, xmax, q2min, q2max)
kts = [0.5, 1.0]
+ xis = [0.0] # dummy values
+ deltas = [0.0] # dummy values
nucleons = [1.0, 2.0]
alphas = [0.118, 0.120]
grid = np.random.rand(
- len(nucleons), len(alphas), len(kts), len(xs), len(q2s), 1
+ len(nucleons),
+ len(alphas),
+ len(xis),
+ len(deltas),
+ len(kts),
+ len(xs),
+ len(q2s),
+ 1,
)
- subgrid = SubGrid(xs, q2s, kts, nucleons, alphas, grid)
+ subgrid = SubGrid(xs, q2s, kts, xis, deltas, nucleons, alphas, grid)
assert subgrid.alphas_range() == (0.118, 0.120)
assert subgrid.x_range() == (xs[0], xs[-1])
assert subgrid.q2_range() == (q2s[0], q2s[-1])
- assert subgrid.grid_shape() == (
+ assert subgrid.grid_shape() == [
len(nucleons),
len(alphas),
+ len(xis),
+ len(deltas),
len(kts),
len(xs),
len(q2s),
1,
- )
+ ]
def test_gridarray(self, xq2_points):
xmin, xmax, q2min, q2max = (1e-5, 1.0, 1.65, 1.0e8)
xs, q2s = xq2_points(xmin, xmax, q2min, q2max)
kts = [0.5, 1.0]
+ xis = [0.0] # dummy values
+ deltas = [0.0] # dummy values
nucleons = [1.0, 2.0]
alphas = [0.118, 0.120]
grid = np.random.rand(
- len(nucleons), len(alphas), len(kts), len(xs), len(q2s), 1
+ len(nucleons),
+ len(alphas),
+ len(xis),
+ len(deltas),
+ len(kts),
+ len(xs),
+ len(q2s),
+ 1,
)
- subgrid1 = SubGrid(xs, q2s, kts, nucleons, alphas, grid)
- subgrid2 = SubGrid(xs, q2s, kts, nucleons, alphas, grid)
+ subgrid1 = SubGrid(xs, q2s, kts, xis, deltas, nucleons, alphas, grid)
+ subgrid2 = SubGrid(xs, q2s, kts, xis, deltas, nucleons, alphas, grid)
pids = [21, -2, -1, 1, 2]
grid_array = GridArray(pids, [subgrid1, subgrid2])
diff --git a/neopdf_pyapi/tests/test_metadata.py b/neopdf_pyapi/tests/test_metadata.py
index e27240f6..34b46fcd 100644
--- a/neopdf_pyapi/tests/test_metadata.py
+++ b/neopdf_pyapi/tests/test_metadata.py
@@ -40,6 +40,10 @@ def test_metadata_creation(self):
x_max=1.0,
q_min=1.65,
q_max=1.0e4,
+ xsi_min=0.0,
+ xsi_max=0.0,
+ delta_min=0.0,
+ delta_max=0.0,
flavors=[21, 1, 2, 3, 4, -1, -2, -3, -4],
format="test_format",
alphas_q_values=[1.0, 2.0],
@@ -59,6 +63,10 @@ def test_metadata_creation(self):
assert meta.x_max() == 1.0
assert meta.q_min() == 1.65
assert meta.q_max() == 1.0e4
+ assert meta.xi_min() == 0.0
+ assert meta.xi_max() == 0.0
+ assert meta.delta_min() == 0.0
+ assert meta.delta_max() == 0.0
assert meta.pids() == [21, 1, 2, 3, 4, -1, -2, -3, -4]
assert meta.format() == "test_format"
assert meta.alphas_q() == [1.0, 2.0]
diff --git a/pixi.lock b/pixi.lock
index 3d288202..d353de35 100644
--- a/pixi.lock
+++ b/pixi.lock
@@ -14,19 +14,19 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.44-h4852527_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.44-h4bf12b8_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.44-h4852527_1.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hfdbb021_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py314ha160325_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.5-hb9d3cd8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-hbd8a1cb_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/cargo-c-0.10.14-hc3c1012_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.7.14-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py311hf29c0ef_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.2-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh707e725_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_4.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.10.1-py311h3778330_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.11.0-py314h67df5f8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h76bdaa0_4.conda
@@ -49,14 +49,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/lhapdf-6.5.5-py311hd49b95e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lhapdf-6.5.5-py314h3a4f467_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-32_h59b9bed_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-32_he106b2a_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.14.1-h332b0f4_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h9ec8514_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_4.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-h85bb3a7_104.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_4.conda
@@ -66,8 +66,8 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-32_h7ac8fdf_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-hd08acf3_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda
@@ -75,11 +75,10 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_4.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h85bb3a7_104.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_4.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.2-he9a06e4_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/maturin-1.9.2-py39h3314b2b_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mergedeep-1.3.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-1.6.1-pyhd8ed1ab_1.conda
@@ -87,13 +86,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-9.6.16-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-extensions-1.3.1-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py311h2e04523_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.1-h7b32b05_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.4-py314h2b28147_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.4-h26f9b46_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/paginate-0.5.7-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.45-hc749103_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda
@@ -103,17 +102,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.13-h9e4cc4f_0_cpython.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.0-h32b2ec7_102_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py311h2dc5d0c_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-env-tag-1.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/rust-1.88.0-h1a8d7c4_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.88.0-h2c6d0dc_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_8.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda
@@ -122,17 +120,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/watchdog-6.0.0-py311h38be061_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/watchdog-6.0.0-py314hdafbbf9_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py311h9ecbd09_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py314h31f8a6b_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda
- pypi: https://files.pythonhosted.org/packages/1f/d4/6fe9c62bec56212b96607bdc26ee1072518213414d77c4ff878c17c7889c/mkdocs_roamlinks_plugin-0.3.2-py3-none-any.whl
osx-64:
- conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.17.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/backrefs-5.8-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py311hc356e98_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py314hb6723d8_4.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.5-hf13058a_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda
@@ -141,7 +138,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1021.4-h67a6458_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1021.4-haa85c18_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.7.14-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.17.1-py311h137bacd_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py314h8ca4d5a_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.2-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19-19.1.7-default_h3571c67_3.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-19.1.7-default_h576c50e_3.conda
@@ -154,7 +151,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-19.1.7-h52031e2_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-19.1.7-hc6f8467_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.10.1-py311hfbe4617_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.11.0-py314hb9c7d66_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/gfortran-15.1.0-hcc3c99d_0.conda
@@ -174,7 +171,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.3-h37d8d59_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-954.16-hc3792c1_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-954.16-hf1c22e8_1.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/lhapdf-6.5.5-py311hc3782e1_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/lhapdf-6.5.5-py314haba150f_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-32_h7f60823_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-32_hff6cab4_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_h3571c67_3.conda
@@ -184,7 +181,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.1-h21dd04a_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.6-h281671d_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-h750e83c_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.1.0-h5f6db21_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-15.1.0-h5f6db21_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.1.0-hfa3c126_0.conda
@@ -193,6 +190,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-32_h236ab99_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm19-19.1.7-hc29ff6c_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.1-hd471939_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-h6e16a3a_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.64.0-hc7306c3_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.30-openmp_h83c2472_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.50.4-h39a8b3b_0.conda
@@ -203,7 +201,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19-19.1.7-he90a8e3_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-19.1.7-h3fe3016_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/markupsafe-3.0.2-py311ha3cf9ac_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/maturin-1.9.2-py39h58e7067_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mergedeep-1.3.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-1.6.1-pyhd8ed1ab_1.conda
@@ -213,13 +211,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.3.2-py311h09fcace_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.1-hc426f3f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.3.4-py314hf08249b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.4-h230baf5_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/paginate-0.5.7-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/pcre2-10.45-hf733adb_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/pkg-config-0.29.2-hf7e621a_1009.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda
@@ -229,17 +227,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.13-h9ccd52b_0_cpython.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.0-hf88997e_102_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.2-py311ha3cf9ac_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-env-tag-1.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/rust-1.88.0-h34a2095_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.88.0-h38e4360_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1300.6.5-h390ca13_0.conda
@@ -249,18 +246,17 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/watchdog-6.0.0-py311h4d7f069_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/watchdog-6.0.0-py314h03d016b_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/zlib-1.3.1-hd23fc13_2.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.23.0-py311h4d7f069_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py314h12c88b1_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda
- pypi: https://files.pythonhosted.org/packages/1f/d4/6fe9c62bec56212b96607bdc26ee1072518213414d77c4ff878c17c7889c/mkdocs_roamlinks_plugin-0.3.2-py3-none-any.whl
osx-arm64:
- conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.17.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/backrefs-5.8-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311h155a34a_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py314he8615de_4.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda
@@ -269,7 +265,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-1021.4-hd01ab73_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-1021.4-haeb51d2_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.7.14-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.1-py311h3a79f62_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.2-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-19-19.1.7-default_hf90f093_3.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-19.1.7-default_h474c9e2_3.conda
@@ -282,7 +278,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-19.1.7-hd2aecb6_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-h7969c41_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.10.1-py311h2fe624c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.11.0-py314hb7e19f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/gfortran-15.1.0-h3ef1dbf_0.conda
@@ -302,7 +298,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64-954.16-he86490a_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-954.16-hc42d924_1.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lhapdf-6.5.5-py311h6dccdbe_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lhapdf-6.5.5-py314h999937e_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-32_h10e41b3_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-32_hb3479ef_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp19.1-19.1.7-default_hf90f093_3.conda
@@ -312,17 +308,18 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-he5f378a_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.1.0-hfdf1602_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-arm64-15.1.0-hfdf1602_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgit2-1.9.1-h41192e5_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.84.2-hbec27ea_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgit2-1.9.1-h3653167_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.86.0-he69a767_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-hfe07756_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-32_hc9a63f6_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm19-19.1.7-hc4b4ae8_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h5505292_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.64.0-h6d7220d_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_h60d53f8_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda
@@ -333,7 +330,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19-19.1.7-h87a4c7e_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-19.1.7-hd2aecb6_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/maturin-1.9.2-py39he71e08c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mergedeep-1.3.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-1.6.1-pyhd8ed1ab_1.conda
@@ -343,13 +340,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/mpc-1.3.1-h8f1351a_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/mpfr-4.2.1-hb693164_3.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.2-py311h0856f98_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.1-h81ee809_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.4-py314h5b5928d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.4-h5503f6c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/paginate-0.5.7-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.45-ha881caa_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pkg-config-0.29.2-hde07d2e_1009.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda
@@ -359,17 +356,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.13-hc22306f_0_cpython.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.0-h40d2674_102_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.2-py311h4921393_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-env-tag-1.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.88.0-h4ff7c5d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.88.0-hf6ec828_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/sigtool-0.1.3-h44b9a77_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tapi-1300.6.5-h03f4b80_0.conda
@@ -379,12 +375,11 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/watchdog-6.0.0-py311h917b07b_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/watchdog-6.0.0-py314hb84d1df_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py311h917b07b_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py314h163e31d_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda
- pypi: https://files.pythonhosted.org/packages/1f/d4/6fe9c62bec56212b96607bdc26ee1072518213414d77c4ff878c17c7889c/mkdocs_roamlinks_plugin-0.3.2-py3-none-any.whl
win-64:
@@ -392,18 +387,18 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.17.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/backrefs-5.8-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/binutils_impl_win-64-2.44-h095e170_1.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.1.0-py311hda3d55a_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.1.0-py314h13fbf68_4.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/c-compiler-1.11.0-h528c1b4_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.7.14-h4c7d964_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/cargo-c-0.10.14-h4834f17_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.7.14-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/cffi-1.17.1-py311he736701_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py314h5a2d7ad_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.2-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh7428d3b_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/conda-gcc-specs-15.1.0-h69eaf6f_4.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/coverage-7.10.1-py311h3f79411_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/coverage-7.11.0-py314h2359020_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/gcc-15.1.0-he7be042_4.conda
@@ -423,7 +418,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-32_h641d27c_mkl.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libcblas-3.9.0-32_h5e41251_mkl.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.1-hac47afa_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.6-h537db12_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h52bdfb6_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgcc-15.1.0-h1383e82_4.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_win-64-15.1.0-hec057c1_104.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgfortran5-15.1.0-h997fb6f_4.conda
@@ -433,6 +428,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-h135ad9c_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-32_h1aa476e_mkl.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-h2466b09_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.50.4-hf5d6505_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libstdcxx-15.1.0-h904f734_4.conda
@@ -441,7 +437,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/m2w64-sysroot_win-64-12.0.0.r4.gg4f2fc60ca-h7428d3b_9.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/markupsafe-3.0.2-py311h5082efb_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/maturin-1.9.2-py39h9f238f0_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mergedeep-1.3.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mingw-w64-ucrt-x86_64-crt-git-12.0.0.r4.gg4f2fc60ca-h7428d3b_9.conda
@@ -453,12 +449,12 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-9.6.16-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-extensions-1.3.1-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2024.2.2-h66d3029_15.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.2-py311h80b3fa1_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.1-h725018a_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.4-py314h06c3c77_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.4-h725018a_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/paginate-0.5.7-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda
@@ -467,16 +463,15 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.11.13-h3f84c4b_0_cpython.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.0-h4b44e0e_102_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.2-py311h5082efb_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-env-tag-1.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/rust-1.88.0-hf8d6059_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.88.0-h17fc481_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2021.13.0-h62715c5_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h2c6b04d_2.conda
@@ -491,12 +486,12 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_31.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_31.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/watchdog-6.0.0-py311h1ea47a8_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/watchdog-6.0.0-py314h86ab7b2_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.23.0-py311he736701_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py314h4667ab5_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-hbeecb71_2.conda
- pypi: https://files.pythonhosted.org/packages/1f/d4/6fe9c62bec56212b96607bdc26ee1072518213414d77c4ff878c17c7889c/mkdocs_roamlinks_plugin-0.3.2-py3-none-any.whl
packages:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
@@ -600,73 +595,73 @@ packages:
purls: []
size: 36046
timestamp: 1752032788780
-- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hfdbb021_3.conda
- sha256: 4fab04fcc599853efb2904ea3f935942108613c7515f7dd57e7f034650738c52
- md5: 8565f7297b28af62e5de2d968ca32e31
+- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py314ha160325_4.conda
+ sha256: c3580d093d1662fd4f5370dd07492d161c3d8e09c524c56d28ff57da78f2824b
+ md5: a5529cb388bf7c6c9ae3d9d1ae54be56
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=13
- - libstdcxx >=13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - libgcc >=14
+ - libstdcxx >=14
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
constrains:
- - libbrotlicommon 1.1.0 hb9d3cd8_3
+ - libbrotlicommon 1.1.0 hb03c661_4
license: MIT
license_family: MIT
purls:
- pkg:pypi/brotli?source=hash-mapping
- size: 350166
- timestamp: 1749230304421
-- conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py311hc356e98_3.conda
- sha256: 63f3771e23a1f3f9866ece0252586b5b57eefba8d83a2871a72c82716944cc7b
- md5: 7259b2f4870cab602f1512562e5cbb30
+ size: 354296
+ timestamp: 1756599490120
+- conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py314hb6723d8_4.conda
+ sha256: abf4d71502aa7e72191d3b7e293705bdb2a0218ddff736d166c58d85909c9082
+ md5: 7478ccd9121628f21a5db0a5f4bf2c49
depends:
- __osx >=10.13
- - libcxx >=18
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - libcxx >=19
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
constrains:
- - libbrotlicommon 1.1.0 h6e16a3a_3
+ - libbrotlicommon 1.1.0 h1c43f85_4
license: MIT
license_family: MIT
purls:
- pkg:pypi/brotli?source=hash-mapping
- size: 367210
- timestamp: 1749230581348
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311h155a34a_3.conda
- sha256: 7414997b02a5f07d0b089fb24f1e755347fd827fa5fd158681766fce9583dd9b
- md5: ba41239b4753557a20cf2ac2cd4250c5
+ size: 369206
+ timestamp: 1756600353583
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py314he8615de_4.conda
+ sha256: a98896c84230c17250e1a4cd2f23bc0fda78ba5e36daba2592dffa9c8595b24e
+ md5: ba3469ba447f703495855c75827ae68f
depends:
- __osx >=11.0
- - libcxx >=18
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
+ - libcxx >=19
+ - python >=3.14.0rc2,<3.15.0a0
+ - python >=3.14.0rc2,<3.15.0a0 *_cp314
+ - python_abi 3.14.* *_cp314
constrains:
- - libbrotlicommon 1.1.0 h5505292_3
+ - libbrotlicommon 1.1.0 h6caf38d_4
license: MIT
license_family: MIT
purls:
- pkg:pypi/brotli?source=hash-mapping
- size: 338502
- timestamp: 1749230799184
-- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.1.0-py311hda3d55a_3.conda
- sha256: a602b15fe1b3a6b40aab7d99099a410b69ccad9bb273779531cef00fc52d762e
- md5: 2d99144abeb3b6b65608fdd7810dbcbd
- depends:
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ size: 341292
+ timestamp: 1756599838917
+- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.1.0-py314h13fbf68_4.conda
+ sha256: b8ee84b8fe3418373fb3a79ca5976d427117c499a0311451acf598d64912df07
+ md5: 4a0473238e95bddd97b32f68983fc0fe
+ depends:
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
constrains:
- - libbrotlicommon 1.1.0 h2466b09_3
+ - libbrotlicommon 1.1.0 hfd05255_4
license: MIT
license_family: MIT
purls:
- pkg:pypi/brotli?source=hash-mapping
- size: 321757
- timestamp: 1749231264056
+ size: 323005
+ timestamp: 1756599884143
- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda
sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d
md5: 62ee74e96c5ebb0af99386de58cf9553
@@ -946,69 +941,69 @@ packages:
- pkg:pypi/certifi?source=hash-mapping
size: 159755
timestamp: 1752493370797
-- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py311hf29c0ef_0.conda
- sha256: bc47aa39c8254e9e487b8bcd74cfa3b4a3de3648869eb1a0b89905986b668e35
- md5: 55553ecd5328336368db611f350b7039
+- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda
+ sha256: c6339858a0aaf5d939e00d345c98b99e4558f285942b27232ac098ad17ac7f8e
+ md5: cf45f4278afd6f4e6d03eda0f435d527
depends:
- __glibc >=2.17,<3.0.a0
- - libffi >=3.4,<4.0a0
- - libgcc >=13
+ - libffi >=3.5.2,<3.6.0a0
+ - libgcc >=14
- pycparser
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python_abi 3.14.* *_cp314
license: MIT
license_family: MIT
purls:
- pkg:pypi/cffi?source=hash-mapping
- size: 302115
- timestamp: 1725560701719
-- conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.17.1-py311h137bacd_0.conda
- sha256: 012ee7b1ed4f9b0490d6e90c72decf148d7575173c7eaf851cd87fd434d2cacc
- md5: a4b0f531064fa3dd5e3afbb782ea2cd5
+ size: 300271
+ timestamp: 1761203085220
+- conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py314h8ca4d5a_1.conda
+ sha256: e2c58cc2451cc96db2a3c8ec34e18889878db1e95cc3e32c85e737e02a7916fb
+ md5: 71c2caaa13f50fe0ebad0f961aee8073
depends:
- __osx >=10.13
- - libffi >=3.4,<4.0a0
+ - libffi >=3.5.2,<3.6.0a0
- pycparser
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python_abi 3.14.* *_cp314
license: MIT
license_family: MIT
purls:
- pkg:pypi/cffi?source=hash-mapping
- size: 288762
- timestamp: 1725560945833
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.1-py311h3a79f62_0.conda
- sha256: 253605b305cc4548b8f97eb7c2e146697e0c7672b099c4862ec5ca7e8e995307
- md5: a42272c5dbb6ffbc1a5af70f24c7b448
+ size: 293633
+ timestamp: 1761203106369
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda
+ sha256: 5b5ee5de01eb4e4fd2576add5ec9edfc654fbaf9293e7b7ad2f893a67780aa98
+ md5: 10dd19e4c797b8f8bdb1ec1fbb6821d7
depends:
- __osx >=11.0
- - libffi >=3.4,<4.0a0
+ - libffi >=3.5.2,<3.6.0a0
- pycparser
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python >=3.14,<3.15.0a0 *_cp314
+ - python_abi 3.14.* *_cp314
license: MIT
license_family: MIT
purls:
- pkg:pypi/cffi?source=hash-mapping
- size: 288211
- timestamp: 1725560745212
-- conda: https://conda.anaconda.org/conda-forge/win-64/cffi-1.17.1-py311he736701_0.conda
- sha256: 9689fbd8a31fdf273f826601e90146006f6631619767a67955048c7ad7798a1d
- md5: e1c69be23bd05471a6c623e91680ad59
+ size: 292983
+ timestamp: 1761203354051
+- conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py314h5a2d7ad_1.conda
+ sha256: 924f2f01fa7a62401145ef35ab6fc95f323b7418b2644a87fea0ea68048880ed
+ md5: c360170be1c9183654a240aadbedad94
depends:
- pycparser
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
license: MIT
license_family: MIT
purls:
- pkg:pypi/cffi?source=hash-mapping
- size: 297627
- timestamp: 1725561079708
+ size: 294731
+ timestamp: 1761203441365
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.2-pyhd8ed1ab_0.conda
sha256: 535ae5dcda8022e31c6dc063eb344c80804c537a5a04afba43a845fa6fa130f5
md5: 40fe4284b8b5835a9073a645139f35af
@@ -1290,56 +1285,56 @@ packages:
purls: []
size: 56517
timestamp: 1753904326451
-- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.10.1-py311h3778330_0.conda
- sha256: b29c8d2217d45bbde6e3096fcded2317d624de4daf4b32015483aea8fbfc0492
- md5: ad5c4453544b1bbbb9cc29e4ab9a97cd
+- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.11.0-py314h67df5f8_0.conda
+ sha256: d928f6d0567807c8a09786e18966445b011ec2eb85c7e18382c0b4870cf12f17
+ md5: 6ff84b39468623308dee97e5dfbafca0
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=14
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- tomli
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/coverage?source=hash-mapping
- size: 388308
- timestamp: 1753652308151
-- conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.10.1-py311hfbe4617_0.conda
- sha256: 8a43d954f0685a3e36a90c895a771cacd7774b1f2d477afbd1a8557bc721c66d
- md5: 8a7f0fecd1a61504e54b0f5a396c2de8
+ size: 402708
+ timestamp: 1760545023449
+- conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.11.0-py314hb9c7d66_0.conda
+ sha256: e5d099e7daa1c71c53b420fbc5b211e941a3820ca7514b5235f7720c09da2448
+ md5: a8ce02c59aa971f762a8983a01f5749d
depends:
- __osx >=10.13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- tomli
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/coverage?source=hash-mapping
- size: 385986
- timestamp: 1753652453774
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.10.1-py311h2fe624c_0.conda
- sha256: 6a199ce363c3030905726e28ffe593b18e1da70e3d1b41fbfc74befa7c971db4
- md5: fa7911d8486c7d9983d1c60f0078c436
+ size: 401937
+ timestamp: 1760545293564
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.11.0-py314hb7e19f3_0.conda
+ sha256: c977b9e080860cf64d247aa07528f65d8d01c1ad51a23ac1c6ad7a3f5f2a34bc
+ md5: a9d2395b30c275eb59b35292ec104233
depends:
- __osx >=11.0
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
+ - python >=3.14,<3.15.0a0
+ - python >=3.14,<3.15.0a0 *_cp314
+ - python_abi 3.14.* *_cp314
- tomli
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/coverage?source=hash-mapping
- size: 385989
- timestamp: 1753652480016
-- conda: https://conda.anaconda.org/conda-forge/win-64/coverage-7.10.1-py311h3f79411_0.conda
- sha256: 62e2b5ab514072d5c4f86b7def9debfe629deedd81e73565cfbf10dfa62222a0
- md5: 60f4e897f4f16069855ff5d30c04b11c
- depends:
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ size: 402944
+ timestamp: 1760545272491
+- conda: https://conda.anaconda.org/conda-forge/win-64/coverage-7.11.0-py314h2359020_0.conda
+ sha256: 9042f962d7c644c7e6e14afcd3549c97e05c41d4d51b50ff2159088584ede6de
+ md5: ca8c9e9f8aa2b715b88b595420769e58
+ depends:
+ - python >=3.14,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- tomli
- ucrt >=10.0.20348.0
- vc >=14.3,<15
@@ -1348,8 +1343,8 @@ packages:
license_family: APACHE
purls:
- pkg:pypi/coverage?source=hash-mapping
- size: 413579
- timestamp: 1753652687642
+ size: 429894
+ timestamp: 1760545168798
- conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda
sha256: 3fcc97ae3e89c150401a50a4de58794ffc67b1ed0e1851468fcc376980201e25
md5: 5da8c935dca9186673987f79cef0b2a5
@@ -1973,47 +1968,47 @@ packages:
purls: []
size: 776789
timestamp: 1752032889203
-- conda: https://conda.anaconda.org/conda-forge/linux-64/lhapdf-6.5.5-py311hd49b95e_0.conda
- sha256: e08dccb394ed0ab6da50b15a35818d87adb3133a01c6f043b93368dfe57404d7
- md5: 8494b9aa28229722e46ee9d1b7ec4cc1
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lhapdf-6.5.5-py314h3a4f467_1.conda
+ sha256: 572dfb2a12101c5ccfc726cf5c95fde5a1f17636ff17c076596431e3629ccebf
+ md5: addcbc713a59383c8c7433f7217e5095
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=13
- - libstdcxx >=13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - libgcc >=14
+ - libstdcxx >=14
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
license: GPL-3.0-only
license_family: GPL
purls: []
- size: 919155
- timestamp: 1737702964993
-- conda: https://conda.anaconda.org/conda-forge/osx-64/lhapdf-6.5.5-py311hc3782e1_0.conda
- sha256: f5b1934a6d5403ce85b19b4ed29662d768491ef39be0681346846b883e980369
- md5: 991820ec74d2d89ace4fea10eee9ae2b
+ size: 918168
+ timestamp: 1756661811989
+- conda: https://conda.anaconda.org/conda-forge/osx-64/lhapdf-6.5.5-py314haba150f_1.conda
+ sha256: 11424e103f51e2dfa60c8e2fd38677be52310376cc381ce4b3f5c0a76c6984c6
+ md5: 3b447f848127f5a3df93205cc932d854
depends:
- __osx >=10.13
- - libcxx >=18
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - libcxx >=19
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
license: GPL-3.0-only
license_family: GPL
purls: []
- size: 820385
- timestamp: 1737703124758
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lhapdf-6.5.5-py311h6dccdbe_0.conda
- sha256: 7b680f89ce17e81ce2e8e52f5f51dd7c7e86434d2cafa6e1fe98834b89342405
- md5: 517d2de2cc123ae1a8b7aeed0507228b
+ size: 804384
+ timestamp: 1756662066473
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lhapdf-6.5.5-py314h999937e_1.conda
+ sha256: 52328898334b6a00c39943b120f034b2bb8a892f2ddb1abd6e6997021e3b0572
+ md5: d595b1769d6840e77ae8697f9c50fc66
depends:
- __osx >=11.0
- - libcxx >=18
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
+ - libcxx >=19
+ - python >=3.14.0rc2,<3.15.0a0
+ - python >=3.14.0rc2,<3.15.0a0 *_cp314
+ - python_abi 3.14.* *_cp314
license: GPL-3.0-only
license_family: GPL
purls: []
- size: 836481
- timestamp: 1737703209161
+ size: 814845
+ timestamp: 1756662103383
- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-32_h59b9bed_openblas.conda
build_number: 32
sha256: 1540bf739feb446ff71163923e7f044e867d163c50b605c8b421c55ff39aa338
@@ -2371,49 +2366,49 @@ packages:
purls: []
size: 141322
timestamp: 1752719767870
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda
- sha256: 764432d32db45466e87f10621db5b74363a9f847d2b8b1f9743746cd160f06ab
- md5: ede4673863426c0883c0063d853bbd85
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h9ec8514_0.conda
+ sha256: 25cbdfa65580cfab1b8d15ee90b4c9f1e0d72128f1661449c9a999d341377d54
+ md5: 35f29eec58405aaf55e01cb470d8c26a
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=13
+ - libgcc >=14
license: MIT
license_family: MIT
purls: []
- size: 57433
- timestamp: 1743434498161
-- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.6-h281671d_1.conda
- sha256: 6394b1bc67c64a21a5cc73d1736d1d4193a64515152e861785c44d2cfc49edf3
- md5: 4ca9ea59839a9ca8df84170fab4ceb41
+ size: 57821
+ timestamp: 1760295480630
+- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-h750e83c_0.conda
+ sha256: 277dc89950f5d97f1683f26e362d6dca3c2efa16cb2f6fdb73d109effa1cd3d0
+ md5: d214916b24c625bcc459b245d509f22e
depends:
- __osx >=10.13
license: MIT
license_family: MIT
purls: []
- size: 51216
- timestamp: 1743434595269
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda
- sha256: c6a530924a9b14e193ea9adfe92843de2a806d1b7dbfd341546ece9653129e60
- md5: c215a60c2935b517dcda8cad4705734d
+ size: 52573
+ timestamp: 1760295626449
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-he5f378a_0.conda
+ sha256: 9b8acdf42df61b7bfe8bdc545c016c29e61985e79748c64ad66df47dbc2e295f
+ md5: 411ff7cd5d1472bba0f55c0faf04453b
depends:
- __osx >=11.0
license: MIT
license_family: MIT
purls: []
- size: 39839
- timestamp: 1743434670405
-- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.6-h537db12_1.conda
- sha256: d3b0b8812eab553d3464bbd68204f007f1ebadf96ce30eb0cbc5159f72e353f5
- md5: 85d8fa5e55ed8f93f874b3b23ed54ec6
+ size: 40251
+ timestamp: 1760295839166
+- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h52bdfb6_0.conda
+ sha256: ddff25aaa4f0aa535413f5d831b04073789522890a4d8626366e43ecde1534a3
+ md5: ba4ad812d2afc22b9a34ce8327a0930f
depends:
- ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
license: MIT
license_family: MIT
purls: []
- size: 44978
- timestamp: 1743435053850
+ size: 44866
+ timestamp: 1760295760649
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_4.conda
sha256: 144e35c1c2840f2dc202f6915fc41879c19eddbb8fa524e3ca4aa0d14018b26f
md5: f406dcbb2e7bef90d793e50e79a2882b
@@ -2603,22 +2598,22 @@ packages:
purls: []
size: 886237
timestamp: 1749251348265
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgit2-1.9.1-h41192e5_0.conda
- sha256: 05594297662f86188f9c2d94b051785b8dd76c63d8ff0e37cba5d3e0cdeeae3a
- md5: d61f6e69a3d4eaeba9ae72d33bc2be81
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgit2-1.9.1-h3653167_1.conda
+ sha256: 25443863cb8258699fb54a56b710500e485119c8579934fa23e5b1702edd5a0c
+ md5: 60405477889cfb1ce078e02082ee3c6c
depends:
- - libcxx >=18
- __osx >=11.0
- - openssl >=3.5.0,<4.0a0
- - pcre2 >=10.45,<10.46.0a0
- - libiconv >=1.18,<2.0a0
+ - libcxx >=19
+ - openssl >=3.5.3,<4.0a0
- libssh2 >=1.11.1,<2.0a0
- libzlib >=1.3.1,<2.0a0
+ - libiconv >=1.18,<2.0a0
+ - pcre2 >=10.46,<10.47.0a0
license: GPL-2.0-only WITH GCC-exception-2.0
license_family: GPL
purls: []
- size: 840704
- timestamp: 1749251385909
+ size: 840795
+ timestamp: 1758613963815
- conda: https://conda.anaconda.org/conda-forge/win-64/libgit2-1.9.1-hc9b8bfc_0.conda
sha256: bfcc750d2b07ac176eaca7ff6fb0b6e76d5508999f498b7267e77296c374bd2b
md5: 9287db16b7f545abd2c0a63b9ec2822c
@@ -2636,22 +2631,22 @@ packages:
purls: []
size: 1197428
timestamp: 1749251415886
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.84.2-hbec27ea_0.conda
- sha256: 5fcc5e948706cc64e45e2454267f664ed5a1e84f15345aae04a41d852a879c0e
- md5: 7bbb8961dca1b4b9f2b01b6e722111a7
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.86.0-he69a767_1.conda
+ sha256: 58b0ccce58b6503cd9448d332c46de9b0757bee6251eb14ac5dd95f7ad3e83fe
+ md5: 16edb7fa702df38c414e1638de3596de
depends:
- __osx >=11.0
- - libffi >=3.4.6,<3.5.0a0
+ - libffi >=3.5.2,<3.6.0a0
- libiconv >=1.18,<2.0a0
- - libintl >=0.24.1,<1.0a0
+ - libintl >=0.25.1,<1.0a0
- libzlib >=1.3.1,<2.0a0
- - pcre2 >=10.45,<10.46.0a0
+ - pcre2 >=10.46,<10.47.0a0
constrains:
- - glib 2.84.2 *_0
+ - glib 2.86.0 *_1
license: LGPL-2.1-or-later
purls: []
- size: 3666180
- timestamp: 1747837044507
+ size: 3656888
+ timestamp: 1761246684692
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_4.conda
sha256: e0487a8fec78802ac04da0ac1139c3510992bc58a58cde66619dde3b363c2933
md5: 3baf8976c96134738bba224e9ef6b1e5
@@ -2862,6 +2857,49 @@ packages:
purls: []
size: 104935
timestamp: 1749230611612
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda
+ sha256: 3aa92d4074d4063f2a162cd8ecb45dccac93e543e565c01a787e16a43501f7ee
+ md5: c7e925f37e3b40d893459e625f6a53f1
+ depends:
+ - __glibc >=2.17,<3.0.a0
+ - libgcc >=13
+ license: BSD-2-Clause
+ license_family: BSD
+ purls: []
+ size: 91183
+ timestamp: 1748393666725
+- conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-h6e16a3a_0.conda
+ sha256: 98299c73c7a93cd4f5ff8bb7f43cd80389f08b5a27a296d806bdef7841cc9b9e
+ md5: 18b81186a6adb43f000ad19ed7b70381
+ depends:
+ - __osx >=10.13
+ license: BSD-2-Clause
+ license_family: BSD
+ purls: []
+ size: 77667
+ timestamp: 1748393757154
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h5505292_0.conda
+ sha256: 0a1875fc1642324ebd6c4ac864604f3f18f57fbcf558a8264f6ced028a3c75b2
+ md5: 85ccccb47823dd9f7a99d2c7f530342f
+ depends:
+ - __osx >=11.0
+ license: BSD-2-Clause
+ license_family: BSD
+ purls: []
+ size: 71829
+ timestamp: 1748393749336
+- conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-h2466b09_0.conda
+ sha256: fc529fc82c7caf51202cc5cec5bb1c2e8d90edbac6d0a4602c966366efe3c7bf
+ md5: 74860100b2029e2523cf480804c76b9b
+ depends:
+ - ucrt >=10.0.20348.0
+ - vc >=14.2,<15
+ - vc14_runtime >=14.29.30139
+ license: BSD-2-Clause
+ license_family: BSD
+ purls: []
+ size: 88657
+ timestamp: 1723861474602
- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda
sha256: b0f2b3695b13a989f75d8fd7f4778e1c7aabe3b36db83f0fe80b2cd812c0e975
md5: 19e57602824042dfd0446292ef90488b
@@ -2911,17 +2949,6 @@ packages:
purls: []
size: 566719
timestamp: 1729572385640
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda
- sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5
- md5: d864d34357c3b65a4b731f78c0801dc4
- depends:
- - __glibc >=2.17,<3.0.a0
- - libgcc >=13
- license: LGPL-2.1-only
- license_family: GPL
- purls: []
- size: 33731
- timestamp: 1750274110928
- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_1.conda
sha256: 3f3fc30fe340bc7f8f46fea6a896da52663b4d95caed1f144e8ea114b4bb6b61
md5: 7e2ba4ca7e6ffebb7f7fc2da2744df61
@@ -3114,16 +3141,17 @@ packages:
purls: []
size: 29317
timestamp: 1753903924491
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda
- sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18
- md5: 40b61aab5c7ba9ff276c41cfffe6b80b
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.2-he9a06e4_0.conda
+ sha256: e5ec6d2ad7eef538ddcb9ea62ad4346fde70a4736342c4ad87bd713641eb9808
+ md5: 80c07c68d2f6870250959dcc95b209d1
depends:
- - libgcc-ng >=12
+ - __glibc >=2.17,<3.0.a0
+ - libgcc >=14
license: BSD-3-Clause
license_family: BSD
purls: []
- size: 33601
- timestamp: 1680112270483
+ size: 37135
+ timestamp: 1758626800002
- conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_9.conda
sha256: 373f2973b8a358528b22be5e8d84322c165b4c5577d24d94fd67ad1bb0a0f261
md5: 08bfa5da6e242025304b206d152479ef
@@ -3136,15 +3164,6 @@ packages:
purls: []
size: 35794
timestamp: 1737099561703
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
- sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c
- md5: 5aa797f8787fe7a17d1b0821485b5adc
- depends:
- - libgcc-ng >=12
- license: LGPL-2.1-or-later
- purls: []
- size: 100393
- timestamp: 1702724383534
- conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.13.8-h93c44a6_0.conda
sha256: 4b29663164d7beb9a9066ddcb8578fc67fe0e9b40f7553ea6255cd6619d24205
md5: e42a93a31cbc6826620144343d42f472
@@ -3351,70 +3370,21 @@ packages:
- pkg:pypi/markdown?source=hash-mapping
size: 80353
timestamp: 1750360406187
-- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda
- sha256: 0291d90706ac6d3eea73e66cd290ef6d805da3fad388d1d476b8536ec92ca9a8
- md5: 6565a715337ae279e351d0abd8ffe88a
- depends:
- - __glibc >=2.17,<3.0.a0
- - libgcc >=13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
- constrains:
- - jinja2 >=3.0.0
- license: BSD-3-Clause
- license_family: BSD
- purls:
- - pkg:pypi/markupsafe?source=hash-mapping
- size: 25354
- timestamp: 1733219879408
-- conda: https://conda.anaconda.org/conda-forge/osx-64/markupsafe-3.0.2-py311ha3cf9ac_1.conda
- sha256: e9965b5d4c29b17b1512035b24a7c126ed7bdb6b39103b52cae099d5bb4194a9
- md5: 1d6596ca7c7b66215c5c0d58b3cb0dd3
+- conda: https://conda.anaconda.org/conda-forge/noarch/markupsafe-3.0.3-pyh7db6752_0.conda
+ sha256: e0cbfea51a19b3055ca19428bd9233a25adca956c208abb9d00b21e7259c7e03
+ md5: fab1be106a50e20f10fe5228fd1d1651
depends:
- - __osx >=10.13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
- constrains:
- - jinja2 >=3.0.0
- license: BSD-3-Clause
- license_family: BSD
- purls:
- - pkg:pypi/markupsafe?source=hash-mapping
- size: 24688
- timestamp: 1733219887972
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda
- sha256: 4f738a7c80e34e5e5d558e946b06d08e7c40e3cc4bdf08140bf782c359845501
- md5: 249e2f6f5393bb6b36b3d3a3eebdcdf9
- depends:
- - __osx >=11.0
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
- constrains:
- - jinja2 >=3.0.0
- license: BSD-3-Clause
- license_family: BSD
- purls:
- - pkg:pypi/markupsafe?source=hash-mapping
- size: 24976
- timestamp: 1733219849253
-- conda: https://conda.anaconda.org/conda-forge/win-64/markupsafe-3.0.2-py311h5082efb_1.conda
- sha256: 6f756e13ccf1a521d3960bd3cadddf564e013e210eaeced411c5259f070da08e
- md5: c1f2ddad665323278952a453912dc3bd
- depends:
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
- - ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
+ - python >=3.10
constrains:
- jinja2 >=3.0.0
+ track_features:
+ - markupsafe_no_compile
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/markupsafe?source=hash-mapping
- size: 28238
- timestamp: 1733220208800
+ size: 15499
+ timestamp: 1759055275624
- conda: https://conda.anaconda.org/conda-forge/linux-64/maturin-1.9.2-py39h3314b2b_0.conda
noarch: python
sha256: 0f0e38651b9524c7f5ff5ad50436704e69236a256e24537f3f5e8760641d8ade
@@ -3714,69 +3684,69 @@ packages:
purls: []
size: 797030
timestamp: 1738196177597
-- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py311h2e04523_0.conda
- sha256: 16f2c3c3f912e55ee133cb5c2ddc719152e418335ffadb9130e2ee1e269b6ea3
- md5: 61e1b42eb1d9f0ebaf038522ce9ca2fe
+- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.4-py314h2b28147_0.conda
+ sha256: c440f429b2e217cb3afbda92eb65a8a768aaf1be90657a133cf02871caa89fc4
+ md5: 1a829816158b0129acfe809f2971c14e
depends:
- python
- libgcc >=14
+ - __glibc >=2.17,<3.0.a0
- libstdcxx >=14
- libgcc >=14
- - __glibc >=2.17,<3.0.a0
- - python_abi 3.11.* *_cp311
+ - libblas >=3.9.0,<4.0a0
- liblapack >=3.9.0,<4.0a0
+ - python_abi 3.14.* *_cp314
- libcblas >=3.9.0,<4.0a0
- - libblas >=3.9.0,<4.0a0
constrains:
- numpy-base <0a0
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/numpy?source=hash-mapping
- size: 9415425
- timestamp: 1753401560940
-- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.3.2-py311h09fcace_0.conda
- sha256: d72790ba7a79548b7c9d8c509d0a8f6093e0fd7bbe97e9d1bd175ffd60f426a8
- md5: 37f9922b287fd0f76a743f8e38cbea8d
+ size: 8952104
+ timestamp: 1761162099395
+- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.3.4-py314hf08249b_0.conda
+ sha256: 6b9c236e59a4494b290807c17f0f631d8836cb7c1a8c5ddda9c924cd8d13e9e7
+ md5: 997a0a22d754b95696dfdb055e1075ba
depends:
- python
- - __osx >=10.13
- libcxx >=19
- - libblas >=3.9.0,<4.0a0
+ - __osx >=10.13
- liblapack >=3.9.0,<4.0a0
- - python_abi 3.11.* *_cp311
- libcblas >=3.9.0,<4.0a0
+ - libblas >=3.9.0,<4.0a0
+ - python_abi 3.14.* *_cp314
constrains:
- numpy-base <0a0
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/numpy?source=hash-mapping
- size: 8551212
- timestamp: 1753401547206
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.2-py311h0856f98_0.conda
- sha256: ffe161b3ee67c55ad994fb7dfab2411f99c9baa801ef9538de756cab53bbe92d
- md5: d399436ee3e7a06af9941cdf624d99c9
+ size: 8098251
+ timestamp: 1761161570315
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.4-py314h5b5928d_0.conda
+ sha256: 9e28281e67a94e4efb25617247cfcc171b30277a3407cd75c8f64a18275eed60
+ md5: b61ad142f0d5978e98a4bb67cd5a4e22
depends:
- python
- - python 3.11.* *_cpython
+ - python 3.14.* *_cp314
- libcxx >=19
- __osx >=11.0
+ - liblapack >=3.9.0,<4.0a0
- libcblas >=3.9.0,<4.0a0
+ - python_abi 3.14.* *_cp314
- libblas >=3.9.0,<4.0a0
- - python_abi 3.11.* *_cp311
- - liblapack >=3.9.0,<4.0a0
constrains:
- numpy-base <0a0
license: BSD-3-Clause
license_family: BSD
purls:
- - pkg:pypi/numpy?source=hash-mapping
- size: 7273975
- timestamp: 1753401541542
-- conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.2-py311h80b3fa1_0.conda
- sha256: d4a3832f3c79f0142b613bcf1670b90d1646c636f46ccc1d69d0d3b60af8d44c
- md5: ecbc2648b2d6f542a45176ee67c63764
+ - pkg:pypi/numpy?source=compressed-mapping
+ size: 6818770
+ timestamp: 1761161593428
+- conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.4-py314h06c3c77_0.conda
+ sha256: 4aa2ad078817c1bf8e97d4fa534550efa4ff55c83a27582d6007f87323a8fb62
+ md5: 7c802e1e0b259eca63442c17f7e01132
depends:
- python
- vc >=14.3,<15
@@ -3785,55 +3755,55 @@ packages:
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
- ucrt >=10.0.20348.0
- - python_abi 3.11.* *_cp311
+ - libblas >=3.9.0,<4.0a0
- liblapack >=3.9.0,<4.0a0
- libcblas >=3.9.0,<4.0a0
- - libblas >=3.9.0,<4.0a0
+ - python_abi 3.14.* *_cp314
constrains:
- numpy-base <0a0
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/numpy?source=compressed-mapping
- size: 8017357
- timestamp: 1753401560734
-- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.1-h7b32b05_0.conda
- sha256: 942347492164190559e995930adcdf84e2fea05307ec8012c02a505f5be87462
- md5: c87df2ab1448ba69169652ab9547082d
+ size: 7526912
+ timestamp: 1761161584209
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.4-h26f9b46_0.conda
+ sha256: e807f3bad09bdf4075dbb4168619e14b0c0360bacb2e12ef18641a834c8c5549
+ md5: 14edad12b59ccbfa3910d42c72adc2a0
depends:
- __glibc >=2.17,<3.0.a0
- ca-certificates
- - libgcc >=13
+ - libgcc >=14
license: Apache-2.0
license_family: Apache
purls: []
- size: 3131002
- timestamp: 1751390382076
-- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.1-hc426f3f_0.conda
- sha256: d5dc7da2ef7502a14f88443675c4894db336592ac7b9ae0517e1339ebb94f38a
- md5: f1ac2dbc36ce2017bd8f471960b1261d
+ size: 3119624
+ timestamp: 1759324353651
+- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.4-h230baf5_0.conda
+ sha256: 3ce8467773b2472b2919412fd936413f05a9b10c42e52c27bbddc923ef5da78a
+ md5: 075eaad78f96bbf5835952afbe44466e
depends:
- __osx >=10.13
- ca-certificates
license: Apache-2.0
license_family: Apache
purls: []
- size: 2744123
- timestamp: 1751391059798
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.1-h81ee809_0.conda
- sha256: f94fde0f096fa79794c8aa0a2665630bbf9026cc6438e8253f6555fc7281e5a8
- md5: a8ac77e7c7e58d43fa34d60bd4361062
+ size: 2747108
+ timestamp: 1759326402264
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.4-h5503f6c_0.conda
+ sha256: f0512629f9589392c2fb9733d11e753d0eab8fc7602f96e4d7f3bd95c783eb07
+ md5: 71118318f37f717eefe55841adb172fd
depends:
- __osx >=11.0
- ca-certificates
license: Apache-2.0
license_family: Apache
purls: []
- size: 3071649
- timestamp: 1751390309393
-- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.1-h725018a_0.conda
- sha256: 2b2eb73b0661ff1aed55576a3d38614852b5d857c2fa9205ac115820c523306c
- md5: d124fc2fd7070177b5e2450627f8fc1a
+ size: 3067808
+ timestamp: 1759324763146
+- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.4-h725018a_0.conda
+ sha256: 5ddc1e39e2a8b72db2431620ad1124016f3df135f87ebde450d235c212a61994
+ md5: f28ffa510fe055ab518cbd9d6ddfea23
depends:
- ca-certificates
- ucrt >=10.0.20348.0
@@ -3842,8 +3812,8 @@ packages:
license: Apache-2.0
license_family: Apache
purls: []
- size: 9327033
- timestamp: 1751392489008
+ size: 9218823
+ timestamp: 1759326176247
- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda
sha256: 289861ed0c13a15d7bbb408796af4de72c2fe67e2bcb0de98f4c3fce259d7991
md5: 58335b26c38bf4a20f399384c33cbcf9
@@ -3903,9 +3873,9 @@ packages:
purls: []
size: 1086588
timestamp: 1745955211398
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.45-ha881caa_0.conda
- sha256: e9ecb706b58b5a2047c077b3a1470e8554f3aad02e9c3c00cfa35d537420fea3
- md5: a52385b93558d8e6bbaeec5d61a21cd7
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda
+ sha256: 5bf2eeaa57aab6e8e95bea6bd6bb2a739f52eb10572d8ed259d25864d3528240
+ md5: 0e6e82c3cc3835f4692022e9b9cd5df8
depends:
- __osx >=11.0
- bzip2 >=1.0.8,<2.0a0
@@ -3913,21 +3883,19 @@ packages:
license: BSD-3-Clause
license_family: BSD
purls: []
- size: 837826
- timestamp: 1745955207242
-- conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda
- sha256: ec9ed3cef137679f3e3a68e286c6efd52144684e1be0b05004d9699882dadcdd
- md5: dfce4b2af4bfe90cdcaf56ca0b28ddf5
+ size: 835080
+ timestamp: 1756743041908
+- conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda
+ sha256: 20fe420bb29c7e655988fd0b654888e6d7755c1d380f82ca2f1bd2493b95d650
+ md5: e7ab34d5a93e0819b62563c78635d937
depends:
- - python >=3.9,<3.13.0a0
- - setuptools
- - wheel
+ - python >=3.13.0a0
license: MIT
license_family: MIT
purls:
- - pkg:pypi/pip?source=compressed-mapping
- size: 1177168
- timestamp: 1753924973872
+ - pkg:pypi/pip?source=hash-mapping
+ size: 1179951
+ timestamp: 1753925011027
- conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda
sha256: c9601efb1af5391317e04eca77c6fe4d716bf1ca1ad8da2a05d15cb7c28d7d4e
md5: 1bee70681f504ea424fb07cdb090c001
@@ -4080,99 +4048,109 @@ packages:
- pkg:pypi/pytest-cov?source=hash-mapping
size: 28216
timestamp: 1749778064293
-- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.13-h9e4cc4f_0_cpython.conda
- sha256: 9979a7d4621049388892489267139f1aa629b10c26601ba5dce96afc2b1551d4
- md5: 8c399445b6dc73eab839659e6c7b5ad1
+- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.0-h32b2ec7_102_cp314.conda
+ build_number: 102
+ sha256: 76d750045b94fded676323bfd01975a26a474023635735773d0e4d80aaa72518
+ md5: 0a19d2cc6eb15881889b0c6fa7d6a78d
depends:
- __glibc >=2.17,<3.0.a0
- bzip2 >=1.0.8,<2.0a0
- ld_impl_linux-64 >=2.36.1
- - libexpat >=2.7.0,<3.0a0
- - libffi >=3.4.6,<3.5.0a0
- - libgcc >=13
+ - libexpat >=2.7.1,<3.0a0
+ - libffi >=3.5.2,<3.6.0a0
+ - libgcc >=14
- liblzma >=5.8.1,<6.0a0
- - libnsl >=2.0.1,<2.1.0a0
- - libsqlite >=3.50.0,<4.0a0
- - libuuid >=2.38.1,<3.0a0
- - libxcrypt >=4.4.36
+ - libmpdec >=4.0.0,<5.0a0
+ - libsqlite >=3.50.4,<4.0a0
+ - libuuid >=2.41.2,<3.0a0
- libzlib >=1.3.1,<2.0a0
- ncurses >=6.5,<7.0a0
- - openssl >=3.5.0,<4.0a0
+ - openssl >=3.5.4,<4.0a0
+ - python_abi 3.14.* *_cp314
- readline >=8.2,<9.0a0
- tk >=8.6.13,<8.7.0a0
- tzdata
- constrains:
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.6.0a0
license: Python-2.0
purls: []
- size: 30629559
- timestamp: 1749050021812
-- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.13-h9ccd52b_0_cpython.conda
- sha256: d8e15db837c10242658979bc475298059bd6615524f2f71365ab8e54fbfea43c
- md5: 6e28c31688c6f1fdea3dc3d48d33e1c0
+ size: 36681389
+ timestamp: 1761176838143
+ python_site_packages_path: lib/python3.14/site-packages
+- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.0-hf88997e_102_cp314.conda
+ build_number: 102
+ sha256: 2470866eee70e75d6be667aa537424b63f97c397a0a90f05f2bab347b9ed5a51
+ md5: 7917d1205eed3e72366a3397dca8a2af
depends:
- __osx >=10.13
- bzip2 >=1.0.8,<2.0a0
- - libexpat >=2.7.0,<3.0a0
- - libffi >=3.4.6,<3.5.0a0
+ - libexpat >=2.7.1,<3.0a0
+ - libffi >=3.5.2,<3.6.0a0
- liblzma >=5.8.1,<6.0a0
- - libsqlite >=3.50.0,<4.0a0
+ - libmpdec >=4.0.0,<5.0a0
+ - libsqlite >=3.50.4,<4.0a0
- libzlib >=1.3.1,<2.0a0
- ncurses >=6.5,<7.0a0
- - openssl >=3.5.0,<4.0a0
+ - openssl >=3.5.4,<4.0a0
+ - python_abi 3.14.* *_cp314
- readline >=8.2,<9.0a0
- tk >=8.6.13,<8.7.0a0
- tzdata
- constrains:
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.6.0a0
license: Python-2.0
purls: []
- size: 15423460
- timestamp: 1749049420299
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.13-hc22306f_0_cpython.conda
- sha256: 2c966293ef9e97e66b55747c7a97bc95ba0311ac1cf0d04be4a51aafac60dcb1
- md5: 95facc4683b7b3b9cf8ae0ed10f30dce
+ size: 14427639
+ timestamp: 1761177864469
+ python_site_packages_path: lib/python3.14/site-packages
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.0-h40d2674_102_cp314.conda
+ build_number: 102
+ sha256: 3ca1da026fe5df8a479d60e1d3ed02d9bc50fcbafd5f125d86abe70d21a34cc7
+ md5: a9ff09231c555da7e30777747318321b
depends:
- __osx >=11.0
- bzip2 >=1.0.8,<2.0a0
- - libexpat >=2.7.0,<3.0a0
- - libffi >=3.4.6,<3.5.0a0
+ - libexpat >=2.7.1,<3.0a0
+ - libffi >=3.5.2,<3.6.0a0
- liblzma >=5.8.1,<6.0a0
- - libsqlite >=3.50.0,<4.0a0
+ - libmpdec >=4.0.0,<5.0a0
+ - libsqlite >=3.50.4,<4.0a0
- libzlib >=1.3.1,<2.0a0
- ncurses >=6.5,<7.0a0
- - openssl >=3.5.0,<4.0a0
+ - openssl >=3.5.4,<4.0a0
+ - python_abi 3.14.* *_cp314
- readline >=8.2,<9.0a0
- tk >=8.6.13,<8.7.0a0
- tzdata
- constrains:
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.6.0a0
license: Python-2.0
purls: []
- size: 14573820
- timestamp: 1749048947732
-- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.11.13-h3f84c4b_0_cpython.conda
- sha256: 723dbca1384f30bd2070f77dd83eefd0e8d7e4dda96ac3332fbf8fe5573a8abb
- md5: bedbb6f7bb654839719cd528f9b298ad
+ size: 13590581
+ timestamp: 1761177195716
+ python_site_packages_path: lib/python3.14/site-packages
+- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.0-h4b44e0e_102_cp314.conda
+ build_number: 102
+ sha256: 2b8c8fcafcc30690b4c5991ee28eb80c962e50e06ce7da03b2b302e2d39d6a81
+ md5: 3e1ce2fb0f277cebcae01a3c418eb5e2
depends:
- bzip2 >=1.0.8,<2.0a0
- - libexpat >=2.7.0,<3.0a0
- - libffi >=3.4.6,<3.5.0a0
+ - libexpat >=2.7.1,<3.0a0
+ - libffi >=3.5.2,<3.6.0a0
- liblzma >=5.8.1,<6.0a0
- - libsqlite >=3.50.0,<4.0a0
+ - libmpdec >=4.0.0,<5.0a0
+ - libsqlite >=3.50.4,<4.0a0
- libzlib >=1.3.1,<2.0a0
- - openssl >=3.5.0,<4.0a0
+ - openssl >=3.5.4,<4.0a0
+ - python_abi 3.14.* *_cp314
- tk >=8.6.13,<8.7.0a0
- tzdata
- ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
- constrains:
- - python_abi 3.11.* *_cp311
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
+ - zstd >=1.5.7,<1.6.0a0
license: Python-2.0
purls: []
- size: 18242669
- timestamp: 1749048351218
+ size: 16706286
+ timestamp: 1761175439068
+ python_site_packages_path: Lib/site-packages
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664
md5: 5b8d21249ff20967101ffa321cab24e8
@@ -4186,17 +4164,17 @@ packages:
- pkg:pypi/python-dateutil?source=hash-mapping
size: 233310
timestamp: 1751104122689
-- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
build_number: 8
- sha256: fddf123692aa4b1fc48f0471e346400d9852d96eeed77dbfdd746fa50a8ff894
- md5: 8fcb6b0e2161850556231336dae58358
+ sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5
+ md5: 0539938c55b6b1a59b560e843ad864a4
constrains:
- - python 3.11.* *_cpython
+ - python 3.14.* *_cp314
license: BSD-3-Clause
license_family: BSD
purls: []
- size: 7003
- timestamp: 1752805919375
+ size: 6989
+ timestamp: 1752805904792
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda
sha256: 8d2a8bf110cc1fc3df6904091dead158ba3e614d8402a83e51ed3a8aa93cdeb0
md5: bc8e3267d44011051f2eb14d22fb0960
@@ -4208,66 +4186,20 @@ packages:
- pkg:pypi/pytz?source=hash-mapping
size: 189015
timestamp: 1742920947249
-- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py311h2dc5d0c_2.conda
- sha256: d107ad62ed5c62764fba9400f2c423d89adf917d687c7f2e56c3bfed605fb5b3
- md5: 014417753f948da1f70d132b2de573be
- depends:
- - __glibc >=2.17,<3.0.a0
- - libgcc >=13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
- - yaml >=0.2.5,<0.3.0a0
- license: MIT
- license_family: MIT
- purls:
- - pkg:pypi/pyyaml?source=hash-mapping
- size: 213136
- timestamp: 1737454846598
-- conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.2-py311ha3cf9ac_2.conda
- sha256: 4855c51eedcde05f3d9666a0766050c7cbdff29b150d63c1adc4071637ba61d7
- md5: f49b0da3b1e172263f4f1e2f261a490d
- depends:
- - __osx >=10.13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
- - yaml >=0.2.5,<0.3.0a0
- license: MIT
- license_family: MIT
- purls:
- - pkg:pypi/pyyaml?source=hash-mapping
- size: 197287
- timestamp: 1737454852180
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.2-py311h4921393_2.conda
- sha256: 2af6006c9f692742181f4aa2e0656eb112981ccb0b420b899d3dd42c881bd72f
- md5: 250b2ee8777221153fd2de9c279a7efa
+- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda
+ sha256: 828af2fd7bb66afc9ab1c564c2046be391aaf66c0215f05afaf6d7a9a270fe2a
+ md5: b12f41c0d7fb5ab81709fcc86579688f
depends:
- - __osx >=11.0
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
- - yaml >=0.2.5,<0.3.0a0
- license: MIT
- license_family: MIT
- purls:
- - pkg:pypi/pyyaml?source=hash-mapping
- size: 196951
- timestamp: 1737454935552
-- conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.2-py311h5082efb_2.conda
- sha256: 6095e1d58c666f6a06c55338df09485eac34c76e43d92121d5786794e195aa4d
- md5: e474ba674d780f0fa3b979ae9e81ba91
- depends:
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
- - ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
- - yaml >=0.2.5,<0.3.0a0
+ - python >=3.10.*
+ - yaml
+ track_features:
+ - pyyaml_no_compile
license: MIT
license_family: MIT
purls:
- pkg:pypi/pyyaml?source=hash-mapping
- size: 187430
- timestamp: 1737454904007
+ size: 45223
+ timestamp: 1758891992558
- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-env-tag-1.1-pyhd8ed1ab_0.conda
sha256: 69ab63bd45587406ae911811fc4d4c1bf972d643fa57a009de7c01ac978c4edd
md5: e8e53c4150a1bba3b160eacf9d53a51b
@@ -4421,17 +4353,6 @@ packages:
purls: []
size: 37041309
timestamp: 1751057508252
-- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda
- sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863
- md5: 4de79c071274a53dcaf2a8c749d1499e
- depends:
- - python >=3.9
- license: MIT
- license_family: MIT
- purls:
- - pkg:pypi/setuptools?source=hash-mapping
- size: 748788
- timestamp: 1748804951958
- conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2
sha256: 46fdeadf8f8d725819c4306838cdfd1099cd8fe3e17bd78862a5dfdcd6de61cf
md5: fbfb84b9de9a6939cb165c02c69b1865
@@ -4686,72 +4607,61 @@ packages:
purls: []
size: 238764
timestamp: 1745560912727
-- conda: https://conda.anaconda.org/conda-forge/linux-64/watchdog-6.0.0-py311h38be061_0.conda
- sha256: 3b22d78a338b6b237566175dbd5f37a79cbeb13ed271a36ddc6ec8c812afb3bd
- md5: 7904988363c292e8ca9d3161f5fcd16a
+- conda: https://conda.anaconda.org/conda-forge/linux-64/watchdog-6.0.0-py314hdafbbf9_1.conda
+ sha256: 0fee43f08e1f7d407588e8bffb0916c63d1ab907b1a18003666ed3467674f1dc
+ md5: 099125fcb130e9fe134c6b610f33b0e1
depends:
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- pyyaml >=3.10
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/watchdog?source=hash-mapping
- size: 144958
- timestamp: 1730493000568
-- conda: https://conda.anaconda.org/conda-forge/osx-64/watchdog-6.0.0-py311h4d7f069_0.conda
- sha256: 7fd445533ad206a22b30f66798e408113e70abb1ad0a6ba4fc179fddf3c23a06
- md5: 97ad1750d3e143044fbece36644fc900
+ size: 151503
+ timestamp: 1756135453073
+- conda: https://conda.anaconda.org/conda-forge/osx-64/watchdog-6.0.0-py314h03d016b_1.conda
+ sha256: d449cd438bcbd5dc98dae6053d1cf3d1dedbe918b2f495f519eee073786db700
+ md5: 6b0e1a579b0c407480b006a834b00e0c
depends:
- __osx >=10.13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- pyyaml >=3.10
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/watchdog?source=hash-mapping
- size: 152566
- timestamp: 1730493137565
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/watchdog-6.0.0-py311h917b07b_0.conda
- sha256: 8058fec3cafb5d8fec494d7494ee65ad774ff5e777d05b80c675a40b54703758
- md5: 48b8db03ce8aa36248c5039d10aed423
+ size: 159539
+ timestamp: 1756135474975
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/watchdog-6.0.0-py314hb84d1df_1.conda
+ sha256: ffe72a3248f537c3a8da00150057d43b138df0baad4e228dd89a0bb2d399bb26
+ md5: d1bbcc127fdc918a64267dc2bf9b5106
depends:
- __osx >=11.0
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
+ - python >=3.14.0rc2,<3.15.0a0
+ - python >=3.14.0rc2,<3.15.0a0 *_cp314
+ - python_abi 3.14.* *_cp314
- pyyaml >=3.10
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/watchdog?source=hash-mapping
- size: 153434
- timestamp: 1730493114888
-- conda: https://conda.anaconda.org/conda-forge/win-64/watchdog-6.0.0-py311h1ea47a8_0.conda
- sha256: 1613a3e7c9357a7c35184b6441577f3d69047008b5b0651ed86c31bdfb6d77df
- md5: e351573c323c28d25de8af994bd04cec
- depends:
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ size: 160938
+ timestamp: 1756135543209
+- conda: https://conda.anaconda.org/conda-forge/win-64/watchdog-6.0.0-py314h86ab7b2_1.conda
+ sha256: 9de00692237b746e273c8855002a5c0285924f9f9a183563871e37216cfbc7a2
+ md5: 2159a850d04a7b77f95a8d494eec5096
+ depends:
+ - python >=3.14.0rc2,<3.15.0a0
+ - python_abi 3.14.* *_cp314
- pyyaml >=3.10
license: Apache-2.0
license_family: APACHE
purls:
- pkg:pypi/watchdog?source=hash-mapping
- size: 170407
- timestamp: 1730493371386
-- conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda
- sha256: 1b34021e815ff89a4d902d879c3bd2040bc1bd6169b32e9427497fa05c55f1ce
- md5: 75cb7132eb58d97896e173ef12ac9986
- depends:
- - python >=3.9
- license: MIT
- license_family: MIT
- purls:
- - pkg:pypi/wheel?source=hash-mapping
- size: 62931
- timestamp: 1733130309598
+ size: 176905
+ timestamp: 1756135615605
- conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda
sha256: 93807369ab91f230cf9e6e2a237eaa812492fe00face5b38068735858fba954f
md5: 46e441ba871f524e2b067929da3051c2
@@ -4842,66 +4752,77 @@ packages:
purls: []
size: 77606
timestamp: 1727963209370
-- conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py311h9ecbd09_2.conda
- sha256: 76d28240cc9fa0c3cb2cde750ecaf98716ce397afaf1ce90f8d18f5f43a122f1
- md5: ca02de88df1cc3cfc8f24766ff50cb3c
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py314h31f8a6b_0.conda
+ sha256: ec4e66b4e042ea9554b9db92b509358f75390f7dcbafb8eead940a2880486a63
+ md5: 68bd13651618354987763f746ee1fadc
depends:
- - __glibc >=2.17,<3.0.a0
+ - python
- cffi >=1.11
- - libgcc >=13
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.5.8.0a0
+ - libgcc >=14
+ - __glibc >=2.17,<3.0.a0
+ - zstd >=1.5.7,<1.6.0a0
+ - python_abi 3.14.* *_cp314
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/zstandard?source=hash-mapping
- size: 731883
- timestamp: 1745869796301
-- conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.23.0-py311h4d7f069_2.conda
- sha256: 72ab78bbde3396ffb2b81a2513f48a27c128ddc4e06a8d3dbcfa790479deab40
- md5: 2712198232a6fcc673f9eef62fce85d5
+ size: 127864
+ timestamp: 1757930108791
+- conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py314h12c88b1_0.conda
+ sha256: e66dbbac3e2b999336620d6d2f6ea21f234989e5672c1ba708b22f3483e91a5b
+ md5: 60b35d160b3095b1c754ee6567c43f6d
depends:
- - __osx >=10.13
+ - python
- cffi >=1.11
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.5.8.0a0
+ - __osx >=10.13
+ - zstd >=1.5.7,<1.6.0a0
+ - python_abi 3.14.* *_cp314
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/zstandard?source=hash-mapping
- size: 691672
- timestamp: 1745869990327
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py311h917b07b_2.conda
- sha256: 7c7f7e24ff49dc6ecb804373bedca663d3c24d57cac55524be8c83da90313928
- md5: 9fd87c9aae7db68b4a3427886b5f3eea
+ size: 123692
+ timestamp: 1757930114277
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py314h163e31d_0.conda
+ sha256: 5b707d7b80d9b410fce776a439273213745ffc3fa4553ec31f264bbaf63a6ec6
+ md5: c824d8cd887ce1d7af8963ca4087a764
depends:
- - __osx >=11.0
+ - python
- cffi >=1.11
- - python >=3.11,<3.12.0a0
- - python >=3.11,<3.12.0a0 *_cpython
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.5.8.0a0
+ - __osx >=11.0
+ - python 3.14.* *_cp314
+ - zstd >=1.5.7,<1.6.0a0
+ - python_abi 3.14.* *_cp314
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/zstandard?source=hash-mapping
- size: 532851
- timestamp: 1745869893672
-- conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.23.0-py311he736701_2.conda
- sha256: aaae40057eac5b5996db4e6b3d8eb00d38455e67571e796135d29702a19736bd
- md5: 8355ec073f73581e29adf77c49096aed
+ size: 125883
+ timestamp: 1757930173407
+- conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py314h4667ab5_0.conda
+ sha256: 285890e987cb14b2ac27f74a4ae844eb80e73654ab3321f085e13538c6ac7d23
+ md5: 765406da1e9f31231a56ea4d2e191d7c
depends:
+ - python
- cffi >=1.11
- - python >=3.11,<3.12.0a0
- - python_abi 3.11.* *_cp311
+ - zstd >=1.5.7,<1.5.8.0a0
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
- ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
+ - ucrt >=10.0.20348.0
+ - zstd >=1.5.7,<1.6.0a0
+ - python_abi 3.14.* *_cp314
license: BSD-3-Clause
license_family: BSD
purls:
- pkg:pypi/zstandard?source=hash-mapping
- size: 445673
- timestamp: 1745870127079
+ size: 285971
+ timestamp: 1757930137171
- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda
sha256: a4166e3d8ff4e35932510aaff7aa90772f84b4d07e9f6f83c614cba7ceefe0eb
md5: 6432cb5d4ac0046c3ac0a8a0f95842f9
@@ -4937,3 +4858,16 @@ packages:
purls: []
size: 399979
timestamp: 1742433432699
+- conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-hbeecb71_2.conda
+ sha256: bc64864377d809b904e877a98d0584f43836c9f2ef27d3d2a1421fa6eae7ca04
+ md5: 21f56217d6125fb30c3c3f10c786d751
+ depends:
+ - libzlib >=1.3.1,<2.0a0
+ - ucrt >=10.0.20348.0
+ - vc >=14.2,<15
+ - vc14_runtime >=14.29.30139
+ license: BSD-3-Clause
+ license_family: BSD
+ purls: []
+ size: 354697
+ timestamp: 1742433568506
diff --git a/pixi.toml b/pixi.toml
index 131f7d87..9a543215 100644
--- a/pixi.toml
+++ b/pixi.toml
@@ -6,7 +6,7 @@ channels = ["conda-forge"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]
[dependencies]
-python = ">=3.10,<3.12"
+python = "3.14.*"
pip = "*"
rust = "*"