Skip to main content

neopdf/
lib.rs

1//! # NeoPDF Library
2//!
3//! NeoPDF is a modern, fast, and reliable Rust library for reading, managing, and interpolating
4//! non-perturbative functions, including but not limited to PDFs, TMDS, GPDs, and GTMDs.
5//!
6//! ## Main Features
7//!
8//! - **Unified PDF Set Interface:** Load, access, and interpolate PDF sets from both LHAPDF and
9//!   NeoPDF formats using a consistent API.
10//! - **High-Performance Interpolation:** Provides multi-dimensional interpolation (including
11//!   log-bicubic, log-tricubic, Chebyshev, and more) for PDF values, supporting advanced
12//!   use-cases in high-energy physics.
13//! - **Flexible Metadata Handling:** Rich metadata structures for describing PDF sets, including
14//!   support for an arbitrary type of hadrons.
15//! - **Conversion and Compression:** Tools to convert LHAPDF and TMDlib sets to NeoPDF format and
16//!   to combine multiple nuclear PDF sets into a single file with explicit A dependence.
17//! - **Efficient Storage:** Compressed storage and random access to large PDF sets using LZ4 and
18//!   bincode serialization.
19//!
20//! ## Module Overview
21//!
22//! - [`converter`]: Utilities for converting and combining PDF sets.
23//! - [`gridpdf`]: Core grid data structures and high-level PDF grid interface.
24//! - [`interleaved`]: Pre-compute the interpolation coefficients for caching.
25//! - [`interpolator`]: Dynamic interpolation traits and factories for PDF grids.
26//! - [`manage`]: Management utilities for PDF set installation, download, and path resolution.
27//! - [`metadata`]: Metadata structures and types for describing PDF sets.
28//! - [`parser`]: Parsing utilities for reading and interpreting PDF set data files.
29//! - [`pdf`]: High-level interface for working with PDF sets and interpolation.
30//! - [`strategy`]: Interpolation strategy implementations (bilinear, log-bicubic, etc.).
31//! - [`subgrid`]: Subgrid data structures and parameter range logic.
32//! - [`utils`]: Utility functions for interpolation and grid operations.
33//! - [`writer`]: Utilities for serializing, compressing, and accessing PDF grid data.
34//!
35//! ## Example 1: Single Point Interpolation
36//!
37//! Evaluate a single flavor at a single kinematic point *(x, Q²)*.
38//!
39//! ```rust
40//! use neopdf::pdf::PDF;
41//!
42//! // Load a PDF member from a set (LHAPDF or NeoPDF format)
43//! let pdf = PDF::load("NNPDF40_nnlo_as_01180", 0);
44//! let xf = pdf.xfxq2(21, &[0.01, 100.0]);
45//! println!("xf = {}", xf);
46//! ```
47//!
48//! ## Example 2: Multiple Flavors at a Single Kinematic Point
49//!
50//! [`PDF::xfxq2_allpids`] evaluates a set of flavors in a single pass, reusing the
51//! subgrid lookup and interpolation coefficients.
52//!
53//! ```rust
54//! use neopdf::pdf::PDF;
55//!
56//! let pdf = PDF::load("NNPDF40_nnlo_as_01180", 0);
57//!
58//! // PDG IDs to evaluate: gluon + light quarks and their anti-quarks.
59//! let pids = [21_i32, -3, -2, -1, 1, 2, 3];
60//!
61//! // Single kinematic point: x = 0.1, Q² = 10 000 GeV².
62//! let point = [0.1_f64, 10_000.0];
63//!
64//! let mut out = vec![0.0_f64; pids.len()];
65//! pdf.xfxq2_allpids(&pids, &point, &mut out);
66//!
67//! for (&pid, &xf) in pids.iter().zip(out.iter()) {
68//!     println!("pid = {:3}  xf = {:14.8e}", pid, xf);
69//! }
70//! ```
71//!
72//! ## Example 3: Batch Point Interpolation
73//!
74//! [`PDF::xfxq2s`] evaluates multiple flavors across a grid of *(x, Q²)* points,
75//! returning a 2-D array of shape `[flavors, N_knots]`. Use this when you need a
76//! dense grid evaluation rather than a single kinematic point.
77//!
78//! ```rust
79//! use ndarray::Array2;
80//! use neopdf::pdf::PDF;
81//!
82//! let pdf_name = "NNPDF40_nnlo_as_01180";
83//! let member = 0usize;
84//! let pdf = PDF::load(pdf_name, member);
85//!
86//! // Select a subset of flavors.
87//! let pids = vec![21, 1, 2, 3, 4, 5];
88//!
89//! // Build a list of knots (x, Q2). Each "knot" is a slice &[x, Q2].
90//! let xs = vec![1e-4, 1e-3, 1e-2, 1e-1];
91//! let q2s = vec![10.0, 100.0];
92//!
93//! let mut points: Vec<[f64; 2]> = Vec::new();
94//! for &x in &xs {
95//!     for &q2 in &q2s {
96//!         points.push([x, q2]);
97//!     }
98//! }
99//!
100//! // Slice-of-slices view required by xfxq2s.
101//! let slice_points: Vec<&[f64]> = points.iter().map(|p| &p[..]).collect();
102//!
103//! // Shape: [flavors, N_knots].
104//! let xf_grid: Array2<f64> = pdf.xfxq2s(pids.clone(), &slice_points);
105//!
106//! println!("{:-^80}", " xfxQ2 grid ");
107//! for (iflav, pid) in pids.iter().enumerate() {
108//!     println!("Flavor pid = {}", pid);
109//!     for (iknot, values) in slice_points.iter().enumerate() {
110//!         let (x, q2) = (values[0], values[1]);
111//!         let val = xf_grid[[iflav, iknot]];
112//!         println!("  x = {:10.3e}, Q2 = {:10.3e} -> xf = {:14.8e}", x, q2, val);
113//!     }
114//! }
115//! ```
116//!
117//! ## Example 4: Inspecting Metadata
118//!
119//! Access the set description, kinematic coverage, flavor content, and per-subgrid
120//! structure through the [`MetaData`](metadata::MetaData) object returned by
121//! [`PDF::metadata`](pdf::PDF::metadata).
122//!
123//! ```rust
124//! use neopdf::pdf::PDF;
125//!
126//! let pdf_name = "NNPDF40_nnlo_as_01180";
127//! let member = 0usize;
128//! let pdf = PDF::load(pdf_name, member);
129//!
130//! // --- Metadata inspection ---
131//! let meta = pdf.metadata();
132//! println!("Set description: {}", meta.set_desc);
133//! println!("Set index: {}", meta.set_index);
134//! println!("Number of members: {}", meta.num_members);
135//! println!("x range: [{}, {}]", meta.x_min, meta.x_max);
136//! println!("Q range: [{}, {}]", meta.q_min, meta.q_max);
137//! println!("Flavors (PIDs): {:?}", meta.flavors);
138//! println!("Format: {}", meta.format);
139//! println!("Set type: {:?}", meta.set_type);
140//! println!("Interpolator type: {:?}", meta.interpolator_type);
141//!
142//! // --- Subgrid information ---
143//! let num_subgrids = pdf.num_subgrids();
144//! println!("\nNumber of subgrids: {}", num_subgrids);
145//!
146//! for subgrid_idx in 0..num_subgrids {
147//!     let sg = pdf.subgrid(subgrid_idx);
148//!     println!("Subgrid {}:", subgrid_idx);
149//!     println!("  A values:   {:?}", sg.nucleons);
150//!     println!("  alphas:     {:?}", sg.alphas);
151//!     println!("  kT values:  {:?}", sg.kts);
152//!     println!("  x knots:    len = {}", sg.xs.len());
153//!     println!("  Q2 knots:   len = {}", sg.q2s.len());
154//! }
155//! ```
156//!
157//! ## Example 5: Controlling Positivity Clipping
158//!
159//! PDF replicas can produce negative values in sparsely-sampled regions. Use
160//! [`ForcePositive`](gridpdf::ForcePositive) to clip those values either for a
161//! single member or for an entire ensemble at once.
162//!
163//! ```rust
164//! use neopdf::gridpdf::ForcePositive;
165//! use neopdf::pdf::PDF;
166//!
167//! let pdf_name = "NNPDF40_nnlo_as_01180";
168//! let mut pdf = PDF::load(pdf_name, 0);
169//!
170//! // Set positivity clipping for a single member.
171//! pdf.set_force_positive(ForcePositive::ClipNegative);
172//! println!("Current clipping mode: {:?}", pdf.is_force_positive());
173//!
174//! // Set clipping for all members at once.
175//! let mut all_pdfs = PDF::load_pdfs(pdf_name);
176//! PDF::set_force_positive_members(&mut all_pdfs, ForcePositive::ClipSmall);
177//! println!(
178//!     "Clipping mode for member 4: {:?}",
179//!     all_pdfs[4].is_force_positive()
180//! );
181//! ```
182//!
183//! ## Example 6: Computing PDF Uncertainties
184//!
185//! Load all members of a replica set, evaluate the gluon PDF at a single kinematic point,
186//! and compute the 1-sigma uncertainty band using the LHAPDF-compatible
187//! [`uncertainty`](uncertainty::uncertainty) function.
188//!
189//! ```no_run
190//! use neopdf::pdf::PDF;
191//! use neopdf::uncertainty::{uncertainty, CL_1_SIGMA};
192//!
193//! let pdf_name = "NNPDF40_nnlo_as_01180";
194//! let pdfs = PDF::load_pdfs(pdf_name);
195//! let meta = pdfs[0].metadata();
196//!
197//! // Evaluate xf(g, x=0.1, Q²=10000) for every member.
198//! let values: Vec<f64> = pdfs
199//!     .iter()
200//!     .map(|p| p.xfxq2(21, &[0.1, 10_000.0]))
201//!     .collect();
202//!
203//! let unc = uncertainty(
204//!     &values,
205//!     &meta.error_type,
206//!     CL_1_SIGMA, // native CL of the set (1σ for NNPDF replicas)
207//!     CL_1_SIGMA, // desired output CL
208//!     false,
209//! )
210//! .expect("uncertainty computation failed");
211//!
212//! println!("central  = {:.6}", unc.central);
213//! println!("errminus = {:.6}", unc.errminus);
214//! println!("errplus  = {:.6}", unc.errplus);
215//! println!("errsymm  = {:.6}", (unc.errminus + unc.errplus) / 2.0);
216//! ```
217//!
218//! See module-level documentation for more details and advanced usage.
219
220pub mod alphas;
221pub mod converter;
222pub mod gridpdf;
223pub mod interleaved;
224pub mod interpolator;
225pub mod manage;
226pub mod metadata;
227pub mod parser;
228pub mod pdf;
229pub mod strategy;
230pub mod subgrid;
231pub mod uncertainty;
232pub mod utils;
233pub mod writer;