diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef25cd9..73bccfe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- added a `pineappl_grid_delete_bins` method to the C-API + +### Fixed + +- fixed bugs in stopping condition of the Newton iteration method +- fixed a bug in comparing `interpolation::Interp` objects when one of the + boundaries is `NaN` + ## [1.2.0] - 22/08/2025 ### Added diff --git a/pineappl/src/interpolation.rs b/pineappl/src/interpolation.rs index 02211279..e2154ed7 100644 --- a/pineappl/src/interpolation.rs +++ b/pineappl/src/interpolation.rs @@ -3,6 +3,7 @@ use super::convert; use super::packed_array::PackedArray; use arrayvec::ArrayVec; +use float_cmp::approx_eq; use serde::{Deserialize, Serialize}; use std::mem; use std::ops::Range; @@ -62,7 +63,7 @@ fn lagrange_weights(i: usize, n: usize, u: f64) -> f64 { /// TODO #[repr(C)] -#[derive(Clone, Copy, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum ReweightMeth { /// TODO ApplGridX, @@ -82,14 +83,14 @@ pub enum Map { /// TODO #[repr(C)] -#[derive(Clone, Copy, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum InterpMeth { /// TODO Lagrange, } /// TODO -#[derive(Clone, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Interp { min: f64, max: f64, @@ -100,6 +101,20 @@ pub struct Interp { interp_meth: InterpMeth, } +impl PartialEq for Interp { + fn eq(&self, other: &Self) -> bool { + self.nodes == other.nodes + && self.order == other.order + && self.reweight == other.reweight + && self.map == other.map + && self.interp_meth == other.interp_meth + && approx_eq!(f64, self.min, other.min, ulps = 1) + && approx_eq!(f64, self.max, other.max, ulps = 1) + } +} + +impl Eq for Interp {} + impl Interp { /// TODO /// @@ -641,6 +656,25 @@ mod tests { } } + #[test] + fn compare_fields_with_nan() { + let interp = Interp::new( + 1e-3, + 1e4, + 50, + 3, + ReweightMeth::NoReweight, + Map::ApplGridH0, + InterpMeth::Lagrange, + ); + + // Starting from below the valid domain of the map results in a NaN for `min`. + assert!(interp.min.is_nan()); + // We also need to check `.min()` which minimises between `min` and `max` is NaN. + assert!(!interp.min().is_nan()); + assert_eq!(interp, interp); + } + #[test] fn interpolate_zero_and_outside() { let interps = vec![