diff --git a/CHANGELOG.md b/CHANGELOG.md index c24e4a4b..e63a8ece 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added `PidBasis::charge_conjugate` and `PidBasis::guess` - added `Grid::set_pid_basis` method - added `Grid::subgrids` and `Grid::subgrids_mut` methods +- added new switch `conv_fun_uncert_from` to subcommand `plot` to allow + choosing with convolution function uncertainty should be plotted ### Changed @@ -39,6 +41,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed member `lumi_id_types` of `OperatorInfo` and `OperatorSliceInfo` to `pid_basis`, which is now of type `PidBasis` - renamed module `pineappl::lumi` to `pineappl::convolutions` +- renamed switch `--pdf` to `--conv-fun` in the subcommand `uncert`. This + switch now optionally accepts a list of indices, which determines the + corresponding convolution function (PDF/FF), for which the uncertainty should + calculated +- renamed `no_pdf_unc` to `no_conv_fun_unc` in subcommand `plot` ### Removed @@ -54,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - removed `TryFromGridError::MetadataMissing` - removed `Grid::subgrid` and `Grid::set_subgrid` methods; these functions have been replaced with `Grid::subgrids` and `Grid::subgrids_mut` +- removed the switch `--pdf-with-scale-cov` from `pineappl uncert` ## [0.7.4] - 23/05/2024 diff --git a/pineappl_cli/src/analyze.rs b/pineappl_cli/src/analyze.rs index 506767db..3c644c48 100644 --- a/pineappl_cli/src/analyze.rs +++ b/pineappl_cli/src/analyze.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::TypedValueParser; @@ -39,9 +39,8 @@ pub struct CkfOpts { /// Path to the input grid. #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, - /// LHAPDF id or name of the PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). + conv_funs: ConvFuns, /// Order defining the K factors. #[arg(value_parser = helpers::parse_order)] order: (u32, u32), @@ -65,7 +64,7 @@ pub struct CkfOpts { impl Subcommand for CkfOpts { fn run(&self, cfg: &GlobalConfiguration) -> Result { let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let orders_den = if self.orders_den.is_empty() { grid.orders() @@ -87,7 +86,7 @@ impl Subcommand for CkfOpts { lumi_mask[lumi] = true; helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &[self.order], &[], &lumi_mask, @@ -103,7 +102,7 @@ impl Subcommand for CkfOpts { lumi_mask[lumi] = true; helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &orders_den, &[], &lumi_mask, diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index d9841f66..53173a1e 100644 --- a/pineappl_cli/src/channels.rs +++ b/pineappl_cli/src/channels.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::TypedValueParser; @@ -14,9 +14,8 @@ pub struct Opts { /// Path to the input grid. #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, - /// LHAPDF id or name of the PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). + conv_funs: ConvFuns, /// Show absolute numbers of each contribution. #[arg(long, short)] absolute: bool, @@ -65,7 +64,7 @@ pub struct Opts { impl Subcommand for Opts { fn run(&self, cfg: &GlobalConfiguration) -> Result { let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let mut channels: Vec<_> = self.channels.iter().cloned().flatten().collect(); channels.sort_unstable(); @@ -93,7 +92,7 @@ impl Subcommand for Opts { channel_mask[channel] = true; helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &self.orders, &[], &channel_mask, diff --git a/pineappl_cli/src/convolve.rs b/pineappl_cli/src/convolve.rs index 71f0225e..5377abc5 100644 --- a/pineappl_cli/src/convolve.rs +++ b/pineappl_cli/src/convolve.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::{Parser, ValueHint}; @@ -15,8 +15,8 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF id(s) or name of the PDF set(s). - #[arg(required = true, value_parser = helpers::parse_pdfset)] - pdfsets: Vec, + #[arg(required = true)] + conv_funs: Vec, /// Selects a subset of bins. #[arg( long, @@ -49,12 +49,12 @@ pub struct Opts { impl Subcommand for Opts { fn run(&self, cfg: &GlobalConfiguration) -> Result { let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfsets[0])?; + let mut conv_funs_0 = helpers::create_conv_funs(&self.conv_funs[0])?; let bins: Vec<_> = self.bins.iter().cloned().flatten().collect(); let results = helpers::convolve( &grid, - &mut pdf, + &mut conv_funs_0, &self.orders, &bins, &[], @@ -77,13 +77,13 @@ impl Subcommand for Opts { ); let bin_count = limits.len(); - let other_results: Vec<_> = self.pdfsets[1..] + let other_results: Vec<_> = self.conv_funs[1..] .iter() - .flat_map(|pdfset| { - let mut pdf = helpers::create_pdf(pdfset).unwrap(); + .flat_map(|conv_funs| { + let mut conv_funs = helpers::create_conv_funs(conv_funs).unwrap(); helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &self.orders, &bins, &[], @@ -108,7 +108,7 @@ impl Subcommand for Opts { } title.add_cell(cell!(c->format!("{y_label}\n[{y_unit}]"))); - for other in self.pdfsets[1..].iter().map(|pdf| helpers::pdf_label(pdf)) { + for other in self.conv_funs[1..].iter().map(|conv_funs| &conv_funs.label) { let mut cell = cell!(c->format!("{other}\n[{y_unit}] [%]")); cell.set_hspan(2); title.add_cell(cell); diff --git a/pineappl_cli/src/diff.rs b/pineappl_cli/src/diff.rs index 8757c45d..4e6e4858 100644 --- a/pineappl_cli/src/diff.rs +++ b/pineappl_cli/src/diff.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{bail, Result}; use clap::{Parser, ValueHint}; @@ -16,9 +16,8 @@ pub struct Opts { /// Path to the second grid. #[arg(value_hint = ValueHint::FilePath)] input2: PathBuf, - /// LHAPDF id or name of the PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). + conv_funs: ConvFuns, /// Ignore differences in the orders and sum them. #[arg(long)] ignore_orders: bool, @@ -127,7 +126,7 @@ impl Subcommand for Opts { bail!("channels differ"); } - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let mut table = helpers::create_table(); let mut title = Row::empty(); @@ -149,7 +148,7 @@ impl Subcommand for Opts { let results1 = helpers::convolve( &grid1, - &mut pdf, + &mut conv_funs, &orders1, &[], &[], @@ -159,7 +158,7 @@ impl Subcommand for Opts { ); let results2 = helpers::convolve( &grid2, - &mut pdf, + &mut conv_funs, &orders2, &[], &[], @@ -205,7 +204,7 @@ impl Subcommand for Opts { .map(|&order| { helpers::convolve( &grid1, - &mut pdf, + &mut conv_funs, &[order], &[], &[], @@ -220,7 +219,7 @@ impl Subcommand for Opts { .map(|&order| { helpers::convolve( &grid2, - &mut pdf, + &mut conv_funs, &[order], &[], &[], diff --git a/pineappl_cli/src/evolve.rs b/pineappl_cli/src/evolve.rs index 07cd297f..b2fff58d 100644 --- a/pineappl_cli/src/evolve.rs +++ b/pineappl_cli/src/evolve.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::{Parser, ValueHint}; @@ -425,7 +425,7 @@ mod eko { fn evolve_grid( grid: &Grid, eko: &Path, - pdf: &Pdf, + use_alphas_from: &Pdf, orders: &[(u32, u32)], xir: f64, xif: f64, @@ -446,7 +446,7 @@ fn evolve_grid( .collect(); let mut eko_slices = EkoSlices::new(eko)?; - let alphas_table = AlphasTable::from_grid(grid, xir, &|q2| pdf.alphas_q2(q2)); + let alphas_table = AlphasTable::from_grid(grid, xir, &|q2| use_alphas_from.alphas_q2(q2)); if use_old_evolve { if let EkoSlices::V0 { @@ -506,9 +506,8 @@ pub struct Opts { /// Path to the converted grid. #[arg(value_hint = ValueHint::FilePath)] output: PathBuf, - /// LHAPDF id or name of the PDF set to check the converted grid with. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name of the PDF(s)/FF(s). + conv_funs: ConvFuns, /// Relative threshold between the table and the converted grid when comparison fails. #[arg(default_value = "1e-3", long)] accuracy: f64, @@ -542,10 +541,10 @@ impl Subcommand for Opts { use prettytable::row; let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let results = helpers::convolve_scales( &grid, - &mut pdf, + &mut conv_funs, &self.orders, &[], &[], @@ -557,7 +556,7 @@ impl Subcommand for Opts { let fk_table = evolve_grid( &grid, &self.eko, - &pdf, + &conv_funs[cfg.use_alphas_from], &self.orders, self.xir, self.xif, @@ -565,7 +564,7 @@ impl Subcommand for Opts { )?; let evolved_results = helpers::convolve_scales( fk_table.grid(), - &mut pdf, + &mut conv_funs, &[], &[], &[], diff --git a/pineappl_cli/src/export.rs b/pineappl_cli/src/export.rs index c2ece1d5..e4ee819d 100644 --- a/pineappl_cli/src/export.rs +++ b/pineappl_cli/src/export.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -16,7 +16,7 @@ mod applgrid; fn convert_into_applgrid( output: &Path, grid: &Grid, - pdf: &mut Pdf, + conv_funs: &mut [Pdf], _: usize, discard_non_matching_scales: bool, ) -> Result<(&'static str, Vec, usize, Vec)> { @@ -24,7 +24,7 @@ fn convert_into_applgrid( let (mut applgrid, order_mask) = applgrid::convert_into_applgrid(grid, output, discard_non_matching_scales)?; - let results = applgrid::convolve_applgrid(applgrid.pin_mut(), pdf); + let results = applgrid::convolve_applgrid(applgrid.pin_mut(), conv_funs); Ok(("APPLgrid", results, 1, order_mask)) } @@ -33,7 +33,7 @@ fn convert_into_applgrid( fn convert_into_applgrid( _: &Path, _: &Grid, - _: &mut Pdf, + _: &mut [Pdf], _: usize, _: bool, ) -> Result<(&'static str, Vec, usize, Vec)> { @@ -45,13 +45,19 @@ fn convert_into_applgrid( fn convert_into_grid( output: &Path, grid: &Grid, - pdf: &mut Pdf, + conv_funs: &mut [Pdf], scales: usize, discard_non_matching_scales: bool, ) -> Result<(&'static str, Vec, usize, Vec)> { if let Some(extension) = output.extension() { if extension == "appl" || extension == "root" { - return convert_into_applgrid(output, grid, pdf, scales, discard_non_matching_scales); + return convert_into_applgrid( + output, + grid, + conv_funs, + scales, + discard_non_matching_scales, + ); } } @@ -67,9 +73,8 @@ pub struct Opts { /// Path to the converted grid. #[arg(value_hint = ValueHint::FilePath)] output: PathBuf, - /// LHAPDF id or name of the PDF set to check the converted grid with. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with. + conv_funs: ConvFuns, /// Relative threshold between the table and the converted grid when comparison fails. #[arg(default_value = "1e-10", long)] accuracy: f64, @@ -97,13 +102,13 @@ impl Subcommand for Opts { use prettytable::{cell, row}; let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; // TODO: figure out `member` from `self.pdfset` let (grid_type, results, scale_variations, order_mask) = convert_into_grid( &self.output, &grid, - &mut pdf, + &mut conv_funs, self.scales, self.discard_non_matching_scales, )?; @@ -148,7 +153,7 @@ impl Subcommand for Opts { } else { let reference_results = helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &orders, &[], &[], diff --git a/pineappl_cli/src/export/applgrid.rs b/pineappl_cli/src/export/applgrid.rs index 28cef6f3..2f3ea6eb 100644 --- a/pineappl_cli/src/export/applgrid.rs +++ b/pineappl_cli/src/export/applgrid.rs @@ -303,8 +303,11 @@ pub fn convert_into_applgrid( } // TODO: deduplicate this function from import -pub fn convolve_applgrid(grid: Pin<&mut grid>, pdf: &mut Pdf) -> Vec { +pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &mut [Pdf]) -> Vec { let nloops = grid.nloops(); - pineappl_applgrid::grid_convolve_with_one(grid, pdf, nloops, 1.0, 1.0, 1.0) + // TODO: add support for convolving an APPLgrid with two functions + assert_eq!(conv_funs.len(), 1); + + pineappl_applgrid::grid_convolve_with_one(grid, &mut conv_funs[0], nloops, 1.0, 1.0, 1.0) } diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 7947da34..d1871f19 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -1,5 +1,5 @@ use super::GlobalConfiguration; -use anyhow::{ensure, Context, Result}; +use anyhow::{anyhow, ensure, Context, Error, Result}; use lhapdf::{Pdf, PdfSet}; use ndarray::Array3; use pineappl::convolutions::LumiCache; @@ -11,34 +11,90 @@ use std::iter; use std::ops::RangeInclusive; use std::path::Path; use std::process::ExitCode; +use std::str::FromStr; -pub fn create_pdf(pdf: &str) -> Result { - let pdf = pdf.split_once('=').map_or(pdf, |(name, _)| name); +#[derive(Clone, Debug, PartialEq)] +pub struct ConvFuns { + pub lhapdf_names: Vec, + pub members: Vec>, + pub label: String, +} - Ok(pdf - .parse() - .map_or_else(|_| Pdf::with_setname_and_nmem(pdf), Pdf::with_lhaid)?) +impl FromStr for ConvFuns { + type Err = Error; + + fn from_str(arg: &str) -> std::result::Result { + let (names, label) = arg.split_once('=').unwrap_or((arg, arg)); + let (lhapdf_names, members) = names + .split(',') + .map(|fun| { + Ok::<_, Error>(if let Some((name, mem)) = fun.split_once('/') { + (name.to_owned(), Some(mem.parse()?)) + } else { + (fun.to_owned(), None) + }) + }) + .collect::, _>>()? + .into_iter() + .unzip(); + + Ok(Self { + lhapdf_names, + members, + label: label.to_owned(), + }) + } } -pub fn create_pdfset(pdfset: &str) -> Result<(PdfSet, Option)> { - let pdfset = pdfset.split_once('=').map_or(pdfset, |(name, _)| name); - let (pdfset, member) = pdfset - .rsplit_once('/') - .map_or((pdfset, None), |(set, member)| { - (set, Some(member.parse::().unwrap())) - }); - - Ok(( - PdfSet::new(&pdfset.parse().map_or_else( - |_| pdfset.to_owned(), - |lhaid| lhapdf::lookup_pdf(lhaid).unwrap().0, - ))?, - member, - )) +pub fn create_conv_funs(funs: &ConvFuns) -> Result> { + Ok(funs + .lhapdf_names + .iter() + .zip(&funs.members) + .map(|(lhapdf_name, member)| { + lhapdf_name.parse().map_or_else( + |_| { + let member = member.unwrap_or(0); + // UNWRAP: we don't support sets with more members than `i32` + Pdf::with_setname_and_member(lhapdf_name, member.try_into().unwrap()) + }, + Pdf::with_lhaid, + ) + }) + .collect::>()?) } -pub fn pdf_label(pdf: &str) -> &str { - pdf.split_once('=').map_or(pdf, |(_, label)| label) +pub fn create_conv_funs_for_set( + funs: &ConvFuns, + index_of_set: usize, +) -> Result<(PdfSet, Vec>)> { + let setname = &funs.lhapdf_names[index_of_set]; + let set = setname.parse().map_or_else( + |_| Ok::<_, Error>(PdfSet::new(setname)?), + |lhaid| { + Ok(PdfSet::new( + &lhapdf::lookup_pdf(lhaid) + .map(|(set, _)| set) + .ok_or(anyhow!( + "no convolution function for LHAID = `{lhaid}` found" + ))?, + )?) + }, + )?; + + let conv_funs = set + .mk_pdfs()? + .into_iter() + .map(|conv_fun| { + // TODO: do not create objects that are getting overwritten in any case + let mut conv_funs = create_conv_funs(funs)?; + conv_funs[index_of_set] = conv_fun; + + Ok::<_, Error>(conv_funs) + }) + .collect::>()?; + + Ok((set, conv_funs)) } pub fn read_grid(input: &Path) -> Result { @@ -127,7 +183,7 @@ pub enum ConvoluteMode { pub fn convolve_scales( grid: &Grid, - lhapdf: &mut Pdf, + conv_funs: &mut [Pdf], orders: &[(u32, u32)], bins: &[usize], channels: &[bool], @@ -146,29 +202,88 @@ pub fn convolve_scales( }) .collect(); - // if the field 'Particle' is missing we assume it's a proton PDF - let pdf_pdg_id = lhapdf - .set() - .entry("Particle") - .map_or(Ok(2212), |string| string.parse::()) - .unwrap(); - if cfg.force_positive { - lhapdf.set_force_positive(1); + for fun in conv_funs.iter_mut() { + fun.set_force_positive(1); + } } - let x_max = lhapdf.x_max(); - let x_min = lhapdf.x_min(); - let mut pdf = |id, x, q2| { - if !cfg.allow_extrapolation && (x < x_min || x > x_max) { - 0.0 - } else { - lhapdf.xfx_q2(id, x, q2) + let mut results = match conv_funs { + [fun] => { + // there's only one convolution function from which we can use the strong coupling + assert_eq!(cfg.use_alphas_from, 0); + + // if the field 'Particle' is missing we assume it's a proton PDF + let pdg_id = fun + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + let x_max = fun.x_max(); + let x_min = fun.x_min(); + let mut alphas = |q2| fun.alphas_q2(q2); + let mut fun = |id, x, q2| { + if !cfg.allow_extrapolation && (x < x_min || x > x_max) { + 0.0 + } else { + fun.xfx_q2(id, x, q2) + } + }; + + let mut cache = LumiCache::with_one(pdg_id, &mut fun, &mut alphas); + + grid.convolve(&mut cache, &orders, bins, channels, scales) + } + [fun1, fun2] => { + let pdg_id1 = fun1 + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + let pdg_id2 = fun2 + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + let x_max1 = fun1.x_max(); + let x_min1 = fun1.x_min(); + let x_max2 = fun2.x_max(); + let x_min2 = fun2.x_min(); + + let mut alphas = |q2| match cfg.use_alphas_from { + 0 => fun1.alphas_q2(q2), + 1 => fun2.alphas_q2(q2), + _ => panic!( + "expected `use_alphas_from` to be `0` or `1`, is {}", + cfg.use_alphas_from + ), + }; + let mut fun1 = |id, x, q2| { + if !cfg.allow_extrapolation && (x < x_min1 || x > x_max1) { + 0.0 + } else { + fun1.xfx_q2(id, x, q2) + } + }; + + let mut fun2 = |id, x, q2| { + if !cfg.allow_extrapolation && (x < x_min2 || x > x_max2) { + 0.0 + } else { + fun2.xfx_q2(id, x, q2) + } + }; + + let mut cache = + LumiCache::with_two(pdg_id1, &mut fun1, pdg_id2, &mut fun2, &mut alphas); + + grid.convolve(&mut cache, &orders, bins, channels, scales) } + _ => unimplemented!(), }; - let mut alphas = |q2| lhapdf.alphas_q2(q2); - let mut cache = LumiCache::with_one(pdf_pdg_id, &mut pdf, &mut alphas); - let mut results = grid.convolve(&mut cache, &orders, bins, channels, scales); match mode { ConvoluteMode::Asymmetry => { @@ -212,7 +327,7 @@ pub fn convolve_scales( pub fn convolve( grid: &Grid, - lhapdf: &mut Pdf, + conv_funs: &mut [Pdf], orders: &[(u32, u32)], bins: &[usize], lumis: &[bool], @@ -222,7 +337,7 @@ pub fn convolve( ) -> Vec { convolve_scales( grid, - lhapdf, + conv_funs, orders, bins, lumis, @@ -249,41 +364,94 @@ pub fn convolve_limits(grid: &Grid, bins: &[usize], mode: ConvoluteMode) -> Vec< pub fn convolve_subgrid( grid: &Grid, - lhapdf: &mut Pdf, + conv_funs: &mut [Pdf], order: usize, bin: usize, lumi: usize, cfg: &GlobalConfiguration, ) -> Array3 { - // if the field 'Particle' is missing we assume it's a proton PDF - let pdf_pdg_id = lhapdf - .set() - .entry("Particle") - .map_or(Ok(2212), |string| string.parse::()) - .unwrap(); - if cfg.force_positive { - lhapdf.set_force_positive(1); + for fun in conv_funs.iter_mut() { + fun.set_force_positive(1); + } } - let x_max = lhapdf.x_max(); - let x_min = lhapdf.x_min(); - let mut pdf = |id, x, q2| { - if !cfg.allow_extrapolation && (x < x_min || x > x_max) { - 0.0 - } else { - lhapdf.xfx_q2(id, x, q2) + match conv_funs { + [fun] => { + // there's only one convolution function from which we can use the strong coupling + assert_eq!(cfg.use_alphas_from, 0); + + // if the field 'Particle' is missing we assume it's a proton PDF + let pdg_id = fun + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + let x_max = fun.x_max(); + let x_min = fun.x_min(); + let mut alphas = |q2| fun.alphas_q2(q2); + let mut fun = |id, x, q2| { + if !cfg.allow_extrapolation && (x < x_min || x > x_max) { + 0.0 + } else { + fun.xfx_q2(id, x, q2) + } + }; + + let mut cache = LumiCache::with_one(pdg_id, &mut fun, &mut alphas); + + grid.convolve_subgrid(&mut cache, order, bin, lumi, 1.0, 1.0) } - }; - let mut alphas = |q2| lhapdf.alphas_q2(q2); - let mut cache = LumiCache::with_one(pdf_pdg_id, &mut pdf, &mut alphas); - - grid.convolve_subgrid(&mut cache, order, bin, lumi, 1.0, 1.0) -} - -pub fn parse_pdfset(argument: &str) -> std::result::Result { - // TODO: figure out how to validate `argument` with `managed-lhapdf` - Ok(argument.to_owned()) + [fun1, fun2] => { + let pdg_id1 = fun1 + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + let pdg_id2 = fun2 + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + let x_max1 = fun1.x_max(); + let x_min1 = fun1.x_min(); + let x_max2 = fun2.x_max(); + let x_min2 = fun2.x_min(); + + let mut alphas = |q2| match cfg.use_alphas_from { + 0 => fun1.alphas_q2(q2), + 1 => fun2.alphas_q2(q2), + _ => panic!( + "expected `use_alphas_from` to be `0` or `1`, is {}", + cfg.use_alphas_from + ), + }; + let mut fun1 = |id, x, q2| { + if !cfg.allow_extrapolation && (x < x_min1 || x > x_max1) { + 0.0 + } else { + fun1.xfx_q2(id, x, q2) + } + }; + + let mut fun2 = |id, x, q2| { + if !cfg.allow_extrapolation && (x < x_min2 || x > x_max2) { + 0.0 + } else { + fun2.xfx_q2(id, x, q2) + } + }; + + let mut cache = + LumiCache::with_two(pdg_id1, &mut fun1, pdg_id2, &mut fun2, &mut alphas); + + grid.convolve_subgrid(&mut cache, order, bin, lumi, 1.0, 1.0) + } + _ => unimplemented!(), + } } pub fn parse_integer_range(range: &str) -> Result> { @@ -337,3 +505,25 @@ pub fn parse_order(order: &str) -> Result<(u32, u32)> { Ok((alphas, alpha)) } + +#[cfg(test)] +mod test { + use super::ConvFuns; + + #[test] + fn conv_fun_from_str() { + assert_eq!( + "A/2,B/1,C/0,D=X".parse::().unwrap(), + ConvFuns { + lhapdf_names: vec![ + "A".to_owned(), + "B".to_owned(), + "C".to_owned(), + "D".to_owned() + ], + members: vec![Some(2), Some(1), Some(0), None], + label: "X".to_owned() + } + ); + } +} diff --git a/pineappl_cli/src/import.rs b/pineappl_cli/src/import.rs index 858bc44a..e349640b 100644 --- a/pineappl_cli/src/import.rs +++ b/pineappl_cli/src/import.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -19,7 +19,7 @@ mod fktable; fn convert_applgrid( input: &Path, alpha: u32, - pdf: &mut Pdf, + conv_funs: &mut [Pdf], dis_pid: i32, _: usize, ) -> Result<(&'static str, Grid, Vec, usize)> { @@ -29,7 +29,7 @@ fn convert_applgrid( let mut grid = ffi::make_grid(input.to_str().unwrap())?; let pgrid = applgrid::convert_applgrid(grid.pin_mut(), alpha, dis_pid)?; - let results = applgrid::convolve_applgrid(grid.pin_mut(), pdf); + let results = applgrid::convolve_applgrid(grid.pin_mut(), conv_funs); Ok(("APPLgrid", pgrid, results, 1)) } @@ -38,7 +38,7 @@ fn convert_applgrid( fn convert_applgrid( _: &Path, _: u32, - _: &mut Pdf, + _: &mut [Pdf], _: i32, _: usize, ) -> Result<(&'static str, Grid, Vec, usize)> { @@ -51,7 +51,7 @@ fn convert_applgrid( fn convert_fastnlo( input: &Path, alpha: u32, - pdfset: &str, + conv_funs: &ConvFuns, member: usize, dis_pid: i32, scales: usize, @@ -61,9 +61,12 @@ fn convert_fastnlo( use pineappl_fastnlo::ffi; use std::ptr; + // TODO: convert this into an error? + assert_eq!(conv_funs.lhapdf_names.len(), 1); + let mut file = ffi::make_fastnlo_lhapdf_with_name_file_set( input.to_str().unwrap(), - pdfset, + &conv_funs.lhapdf_names[0], member.try_into().unwrap(), ); @@ -117,7 +120,7 @@ fn convert_fastnlo( fn convert_fastnlo( _: &Path, _: u32, - _: &str, + _: &ConvFuns, _: usize, _: i32, _: usize, @@ -146,8 +149,8 @@ fn convert_fktable(_: &Path, _: i32) -> Result<(&'static str, Grid, Vec, us fn convert_grid( input: &Path, alpha: u32, - pdf: &mut Pdf, - pdfset: &str, + conv_funs: &mut [Pdf], + fun_names: &ConvFuns, member: usize, dis_pid: i32, scales: usize, @@ -163,12 +166,12 @@ fn convert_grid( .map_or(false, |ext| ext == "tab")) { return convert_fastnlo( - input, alpha, pdfset, member, dis_pid, scales, fnlo_mur, fnlo_muf, + input, alpha, fun_names, member, dis_pid, scales, fnlo_mur, fnlo_muf, ); } else if extension == "dat" { return convert_fktable(input, dis_pid); } else if extension == "appl" || extension == "root" { - return convert_applgrid(input, alpha, pdf, dis_pid, scales); + return convert_applgrid(input, alpha, conv_funs, dis_pid, scales); } } @@ -210,9 +213,8 @@ pub struct Opts { /// Path to the converted grid. #[arg(value_hint = ValueHint::FilePath)] output: PathBuf, - /// LHAPDF id or name of the PDF set to check the converted grid with. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with. + conv_funs: ConvFuns, /// LO coupling power in alpha. #[arg(default_value_t = 0, long)] alpha: u32, @@ -253,14 +255,14 @@ impl Subcommand for Opts { fn run(&self, cfg: &GlobalConfiguration) -> Result { use prettytable::{cell, row}; - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; // TODO: figure out `member` from `self.pdfset` let (grid_type, mut grid, reference_results, scale_variations) = convert_grid( &self.input, self.alpha, - &mut pdf, - &self.pdfset, + &mut conv_funs, + &self.conv_funs, 0, self.dis_pid, self.scales, @@ -279,7 +281,7 @@ impl Subcommand for Opts { } else { let results = helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &[], &[], &[], diff --git a/pineappl_cli/src/import/applgrid.rs b/pineappl_cli/src/import/applgrid.rs index 34996f7c..94b17b70 100644 --- a/pineappl_cli/src/import/applgrid.rs +++ b/pineappl_cli/src/import/applgrid.rs @@ -246,8 +246,11 @@ pub fn convert_applgrid(grid: Pin<&mut grid>, alpha: u32, dis_pid: i32) -> Resul Ok(grid0) } -pub fn convolve_applgrid(grid: Pin<&mut grid>, pdf: &mut Pdf) -> Vec { +pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &mut [Pdf]) -> Vec { let nloops = grid.nloops(); - pineappl_applgrid::grid_convolve_with_one(grid, pdf, nloops, 1.0, 1.0, 1.0) + // TODO: add support for convolving an APPLgrid with two functions + assert_eq!(conv_funs.len(), 1); + + pineappl_applgrid::grid_convolve_with_one(grid, &mut conv_funs[0], nloops, 1.0, 1.0, 1.0) } diff --git a/pineappl_cli/src/lib.rs b/pineappl_cli/src/lib.rs index d02e045b..04ee204b 100644 --- a/pineappl_cli/src/lib.rs +++ b/pineappl_cli/src/lib.rs @@ -38,6 +38,9 @@ pub struct GlobalConfiguration { /// Allow extrapolation of PDFs outside their region of validity. #[arg(long)] pub allow_extrapolation: bool, + /// Choose the PDF/FF set for the strong coupling. + #[arg(default_value = "0", long, value_name = "IDX")] + pub use_alphas_from: usize, } #[enum_dispatch] diff --git a/pineappl_cli/src/orders.rs b/pineappl_cli/src/orders.rs index 77919d23..8a229251 100644 --- a/pineappl_cli/src/orders.rs +++ b/pineappl_cli/src/orders.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::{Parser, ValueHint}; @@ -12,9 +12,8 @@ pub struct Opts { /// Path to the input grid. #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, - /// LHAPDF id or name of the PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). + conv_funs: ConvFuns, /// Show absolute numbers of each perturbative order. #[arg(long, short)] absolute: bool, @@ -42,7 +41,7 @@ pub struct Opts { impl Subcommand for Opts { fn run(&self, cfg: &GlobalConfiguration) -> Result { let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let mut orders: Vec<_> = grid .orders() @@ -66,7 +65,7 @@ impl Subcommand for Opts { .map(|order| { helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &[(order.alphas, order.alpha)], &[], &[], diff --git a/pineappl_cli/src/plot.py b/pineappl_cli/src/plot.py index 09f4d67c..01eb8ed2 100644 --- a/pineappl_cli/src/plot.py +++ b/pineappl_cli/src/plot.py @@ -69,11 +69,11 @@ def main(): {inte}plot_int, {nint}plot_abs, {nint}plot_rel_ewonoff, - {pdfs}plot_abs_pdfs, - {pdfs}plot_ratio_pdf, - {pdfs}plot_double_ratio_pdf, - {pdfs}plot_rel_pdfunc, - {pdfs}plot_rel_pdfpull, + {nconvs}plot_abs_pdfs, + {nconvs}plot_ratio_pdf, + {nconvs}plot_double_ratio_pdf, + {nconvs}plot_rel_pdfunc, + {nconvs}plot_rel_pdfpull, ] mpl.rcParams.update(stylesheet) diff --git a/pineappl_cli/src/plot.rs b/pineappl_cli/src/plot.rs index 6e988ef2..87acbe1b 100644 --- a/pineappl_cli/src/plot.rs +++ b/pineappl_cli/src/plot.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -22,8 +22,11 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF id(s) or name of the PDF set(s). - #[arg(required = true, value_parser = helpers::parse_pdfset)] - pdfsets: Vec, + #[arg(required = true)] + conv_funs: Vec, + /// Choose for which convolution function the uncertainty should be calculated. + #[arg(default_value = "0", long, value_name = "IDX")] + conv_fun_uncert_from: usize, /// Set the number of scale variations. #[arg( default_value_t = 7, @@ -49,7 +52,7 @@ pub struct Opts { threads: usize, /// Disable the (time-consuming) calculation of PDF uncertainties. #[arg(long)] - no_pdf_unc: bool, + no_conv_fun_unc: bool, } fn map_format_join(slice: &[f64]) -> String { @@ -128,11 +131,11 @@ fn map_format_channels(channels: &[(String, Vec)]) -> String { .join(",\n") } -fn format_pdf_results(pdf_uncertainties: &[Vec>], pdfsets: &[String]) -> String { +fn format_pdf_results(pdf_uncertainties: &[Vec>], conv_funs: &[ConvFuns]) -> String { pdf_uncertainties .iter() - .zip(pdfsets.iter()) - .map(|(values, pdfset)| { + .zip(conv_funs.iter().map(|fun| &fun.label)) + .map(|(values, label)| { format!( " ( \"{}\", @@ -140,7 +143,7 @@ fn format_pdf_results(pdf_uncertainties: &[Vec>], pdfsets: &[String]) - np.array([{}]), np.array([{}]), ),", - helpers::pdf_label(pdfset).replace('_', r"\_"), + label.replace('_', r"\_"), map_format_e_join_repeat_last(&values[0]), map_format_e_join_repeat_last(&values[1]), map_format_e_join_repeat_last(&values[2]), @@ -191,7 +194,7 @@ impl Subcommand for Opts { }; let grid = helpers::read_grid(&self.input)?; - let mut pdf = helpers::create_pdf(&self.pdfsets[0])?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs[0])?; let slices = grid.bin_info().slices(); let mut data_string = String::new(); @@ -219,8 +222,16 @@ impl Subcommand for Opts { })) { let bins: Vec<_> = (slice.0..slice.1).collect(); - let results = - helpers::convolve(&grid, &mut pdf, &[], &bins, &[], self.scales, mode, cfg); + let results = helpers::convolve( + &grid, + &mut conv_funs, + &[], + &bins, + &[], + self.scales, + mode, + cfg, + ); let qcd_results = { let mut orders = grid.orders().to_vec(); @@ -239,7 +250,7 @@ impl Subcommand for Opts { helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &qcd_orders, &bins, &[], @@ -264,27 +275,37 @@ impl Subcommand for Opts { .map(|limits| 0.5 * (limits[0] + limits[1])) .collect(); - let pdf_uncertainties: Vec>> = self - .pdfsets + let conv_fun_uncertainties: Vec>> = self + .conv_funs .par_iter() - .map(|pdfset| { - if self.no_pdf_unc { - let mut pdf = helpers::create_pdf(pdfset).unwrap(); - - let results = - helpers::convolve(&grid, &mut pdf, &[], &bins, &[], 1, mode, cfg); + .map(|conv_funs| { + if self.no_conv_fun_unc { + let mut conv_funs = helpers::create_conv_funs(conv_funs)?; + + let results = helpers::convolve( + &grid, + &mut conv_funs, + &[], + &bins, + &[], + 1, + mode, + cfg, + ); Ok(vec![results; 3]) } else { - let (set, member) = helpers::create_pdfset(pdfset).unwrap(); + let (set, funs) = helpers::create_conv_funs_for_set( + conv_funs, + self.conv_fun_uncert_from, + )?; - let pdf_results: Vec<_> = set - .mk_pdfs()? + let pdf_results: Vec<_> = funs .into_par_iter() - .flat_map(|mut pdf| { + .flat_map(|mut funs| { helpers::convolve( &grid, - &mut pdf, + &mut funs, &[], &bins, &[], @@ -312,7 +333,8 @@ impl Subcommand for Opts { let uncertainty = set.uncertainty(&values, lhapdf::CL_1_SIGMA, false).unwrap(); central.push( - member.map_or(uncertainty.central, |member| values[member]), + conv_funs.members[self.conv_fun_uncert_from] + .map_or(uncertainty.central, |member| values[member]), ); min.push(uncertainty.central - uncertainty.errminus); max.push(uncertainty.central + uncertainty.errplus); @@ -383,7 +405,7 @@ impl Subcommand for Opts { ), helpers::convolve( &grid, - &mut pdf, + &mut conv_funs, &[], &bins, &channel_mask, @@ -425,7 +447,7 @@ impl Subcommand for Opts { }},", slice_label = label, mid = map_format_join(&mid), - pdf_results = format_pdf_results(&pdf_uncertainties, &self.pdfsets), + pdf_results = format_pdf_results(&conv_fun_uncertainties, &self.conv_funs), qcd_y = map_format_e_join_repeat_last(&qcd_central), qcd_min = map_format_e_join_repeat_last(&qcd_min), qcd_max = map_format_e_join_repeat_last(&qcd_max), @@ -489,13 +511,13 @@ impl Subcommand for Opts { let ylog = xlog; let title = key_values.get("description").map_or("", String::as_str); let bins = grid.bin_info().bins(); - let pdfs = self.pdfsets.len(); + let nconvs = self.conv_funs.len(); print!( include_str!("plot.py"), inte = if bins == 1 { "" } else { "# " }, nint = if bins == 1 { "# " } else { "" }, - pdfs = if pdfs == 1 || bins == 1 { "# " } else { "" }, + nconvs = if nconvs == 1 || bins == 1 { "# " } else { "" }, xlabel = xlabel, ylabel = ylabel, xlog = xlog, @@ -506,7 +528,13 @@ impl Subcommand for Opts { metadata = format_metadata(&vector), ); } else { - let (pdfset1, pdfset2) = self.pdfsets.iter().collect_tuple().unwrap(); + // TODO: enforce two arguments with clap + assert_eq!(self.conv_funs.len(), 2); + + let (set1, mut conv_funs1) = + helpers::create_conv_funs_for_set(&self.conv_funs[0], self.conv_fun_uncert_from)?; + let (set2, mut conv_funs2) = + helpers::create_conv_funs_for_set(&self.conv_funs[1], self.conv_fun_uncert_from)?; let (order, bin, channel) = self .subgrid_pull .iter() @@ -517,17 +545,15 @@ impl Subcommand for Opts { let cl = lhapdf::CL_1_SIGMA; let grid = helpers::read_grid(&self.input)?; - let (set1, member1) = helpers::create_pdfset(pdfset1)?; - let (set2, member2) = helpers::create_pdfset(pdfset2)?; - let mut pdfset1 = set1.mk_pdfs()?; - let mut pdfset2 = set2.mk_pdfs()?; + let member1 = self.conv_funs[0].members[self.conv_fun_uncert_from]; + let member2 = self.conv_funs[1].members[self.conv_fun_uncert_from]; - let values1: Vec<_> = pdfset1 + let values1: Vec<_> = conv_funs1 .par_iter_mut() - .map(|pdf| { + .map(|conv_funs| { let values = helpers::convolve( &grid, - pdf, + conv_funs, &[], &[bin], &[], @@ -539,12 +565,12 @@ impl Subcommand for Opts { values[0] }) .collect(); - let values2: Vec<_> = pdfset2 + let values2: Vec<_> = conv_funs2 .par_iter_mut() - .map(|pdf| { + .map(|conv_funs| { let values = helpers::convolve( &grid, - pdf, + conv_funs, &[], &[bin], &[], @@ -578,10 +604,26 @@ impl Subcommand for Opts { unc1.hypot(unc2) }; - let res1 = helpers::convolve_subgrid(&grid, &mut pdfset1[0], order, bin, channel, cfg) - .sum_axis(Axis(0)); - let res2 = helpers::convolve_subgrid(&grid, &mut pdfset2[0], order, bin, channel, cfg) - .sum_axis(Axis(0)); + // TODO: if no member is given, the zeroth is used, but we should show the averaged + // result of all members instead + let res1 = helpers::convolve_subgrid( + &grid, + &mut conv_funs1[member1.unwrap_or(0)], + order, + bin, + channel, + cfg, + ) + .sum_axis(Axis(0)); + let res2 = helpers::convolve_subgrid( + &grid, + &mut conv_funs2[member2.unwrap_or(0)], + order, + bin, + channel, + cfg, + ) + .sum_axis(Axis(0)); let subgrid = &grid.subgrids()[[order, bin, channel]]; //let q2 = subgrid.q2_grid(); diff --git a/pineappl_cli/src/pull.rs b/pineappl_cli/src/pull.rs index e12cc0ad..7669e846 100644 --- a/pineappl_cli/src/pull.rs +++ b/pineappl_cli/src/pull.rs @@ -1,6 +1,6 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; -use anyhow::Result; +use anyhow::{Error, Result}; use clap::{Parser, ValueHint}; use lhapdf::{Pdf, PdfSet}; use prettytable::{cell, Row}; @@ -18,12 +18,13 @@ pub struct Opts { /// Path to the input grid. #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, - /// LHAPDF id or name of the first PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset1: String, - /// LHAPDF id or name of the second PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset2: String, + /// LHAPDF ID(s) or name(s) of the first PDF(s)/FF(s). + conv_funs1: ConvFuns, + /// LHAPDF ID(s) or name(s) of the second PDF(s)/FF(s). + conv_funs2: ConvFuns, + /// Index of the convolution functions for which the pull should be calculated. + #[arg(default_value = "0", long, value_name = "IDX")] + pull_from: usize, /// Confidence level in per cent. #[arg(default_value_t = lhapdf::CL_1_SIGMA, long)] cl: f64, @@ -51,10 +52,10 @@ impl Subcommand for Opts { fn run(&self, cfg: &GlobalConfiguration) -> Result { let grid = helpers::read_grid(&self.input)?; - let (set1, member1) = helpers::create_pdfset(&self.pdfset1)?; - let (set2, member2) = helpers::create_pdfset(&self.pdfset2)?; - let mut pdfset1 = set1.mk_pdfs()?; - let mut pdfset2 = set2.mk_pdfs()?; + let (set1, mut conv_funs1) = + helpers::create_conv_funs_for_set(&self.conv_funs1, self.pull_from)?; + let (set2, mut conv_funs2) = + helpers::create_conv_funs_for_set(&self.conv_funs2, self.pull_from)?; ThreadPoolBuilder::new() .num_threads(self.threads) @@ -63,35 +64,41 @@ impl Subcommand for Opts { let limit = grid.channels().len().min(self.limit); let bin_limits = helpers::convolve_limits(&grid, &[], ConvoluteMode::Normal); - let results1: Vec<_> = pdfset1 + let results1: Vec<_> = conv_funs1 .par_iter_mut() - .flat_map(|pdf| { - helpers::convolve( + .map(|mut funs| { + Ok::<_, Error>(helpers::convolve( &grid, - pdf, + &mut funs, &self.orders, &[], &[], 1, ConvoluteMode::Normal, cfg, - ) + )) }) + .collect::>()?; + let results1: Vec> = (0..results1[0].len()) + .map(|bin| (0..results1.len()).map(|pdf| results1[pdf][bin]).collect()) .collect(); - let results2: Vec<_> = pdfset2 + let results2: Vec<_> = conv_funs2 .par_iter_mut() - .flat_map(|pdf| { - helpers::convolve( + .map(|mut funs| { + Ok::<_, Error>(helpers::convolve( &grid, - pdf, + &mut funs, &self.orders, &[], &[], 1, ConvoluteMode::Normal, cfg, - ) + )) }) + .collect::>()?; + let results2: Vec> = (0..results2[0].len()) + .map(|bin| (0..results2.len()).map(|pdf| results2[pdf][bin]).collect()) .collect(); let mut title = Row::empty(); @@ -112,24 +119,16 @@ impl Subcommand for Opts { for (bin, limits) in bin_limits.iter().enumerate() { let (total, unc1, unc2) = { - let values1: Vec<_> = results1 - .iter() - .skip(bin) - .step_by(bin_limits.len()) - .copied() - .collect(); - let values2: Vec<_> = results2 - .iter() - .skip(bin) - .step_by(bin_limits.len()) - .copied() - .collect(); - let uncertainty1 = set1.uncertainty(&values1, self.cl, false)?; - let uncertainty2 = set2.uncertainty(&values2, self.cl, false)?; + let values1 = &results1[bin]; + let values2 = &results2[bin]; + let uncertainty1 = set1.uncertainty(values1, self.cl, false)?; + let uncertainty2 = set2.uncertainty(values2, self.cl, false)?; // if requested use the given member instead of the central value - let diff = member2.map_or(uncertainty2.central, |member| values2[member]) - - member1.map_or(uncertainty1.central, |member| values1[member]); + let diff = self.conv_funs2.members[self.pull_from] + .map_or(uncertainty2.central, |member| values2[member]) + - self.conv_funs1.members[self.pull_from] + .map_or(uncertainty1.central, |member| values1[member]); // use the uncertainties in the direction in which they point to each other let (unc1, unc2) = if diff > 0.0 { @@ -141,7 +140,7 @@ impl Subcommand for Opts { }; let channel_results = - |member: Option, pdfset: &mut Vec, set: &PdfSet| -> Vec { + |member: Option, pdfset: &mut [Vec], set: &PdfSet| -> Vec { if let Some(member) = member { (0..grid.channels().len()) .map(|channel| { @@ -167,14 +166,14 @@ impl Subcommand for Opts { } else { let results: Vec<_> = pdfset .iter_mut() - .flat_map(|pdf| { + .flat_map(|mut pdf| { (0..grid.channels().len()) .map(|channel| { let mut channel_mask = vec![false; grid.channels().len()]; channel_mask[channel] = true; match helpers::convolve( &grid, - pdf, + &mut pdf, &self.orders, &[bin], &channel_mask, @@ -209,8 +208,16 @@ impl Subcommand for Opts { let mut pull_tuples = if self.limit == 0 { vec![] } else { - let channel_results1 = channel_results(member1, &mut pdfset1, &set1); - let channel_results2 = channel_results(member2, &mut pdfset2, &set2); + let channel_results1 = channel_results( + self.conv_funs1.members[self.pull_from], + &mut conv_funs1, + &set1, + ); + let channel_results2 = channel_results( + self.conv_funs2.members[self.pull_from], + &mut conv_funs2, + &set2, + ); let pull_tuples: Vec<_> = channel_results2 .iter() diff --git a/pineappl_cli/src/uncert.rs b/pineappl_cli/src/uncert.rs index aefe6f86..fe1e7971 100644 --- a/pineappl_cli/src/uncert.rs +++ b/pineappl_cli/src/uncert.rs @@ -1,6 +1,6 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; -use anyhow::Result; +use anyhow::{Error, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; use clap::{Args, Parser, ValueHint}; use prettytable::{cell, Row}; @@ -13,19 +13,16 @@ use std::thread; #[derive(Args)] #[group(multiple = true, required = true)] struct Group { - /// Calculate the PDF uncertainties. - #[arg(long)] - pdf: bool, - /// Calculate the combined PDF and scale uncertainty using the covariance method. + /// Calculate convolution function uncertainties. #[arg( - default_missing_value = "7", + default_missing_value = "0", num_args = 0..=1, long, require_equals = true, - value_name = "SCALES", - value_parser = PossibleValuesParser::new(["3", "7", "9"]).try_map(|s| s.parse::()) + value_delimiter = ',', + value_name = "IDX" )] - pdf_with_scale_cov: Option, + conv_fun: Vec, /// Show absolute numbers of the scale-varied results. #[arg( default_missing_value = "7", @@ -58,18 +55,17 @@ struct Group { scale_env: Option, } -/// Calculates scale and PDF uncertainties. +/// Calculate scale and convolution function uncertainties. #[derive(Parser)] pub struct Opts { /// Path to the input grid. #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, - /// LHAPDF id or name of the PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). + conv_funs: ConvFuns, #[command(flatten)] group: Group, - /// Confidence level in per cent, for PDF uncertainties. + /// Confidence level in per cent, for convolution function uncertainties. #[arg(default_value_t = lhapdf::CL_1_SIGMA, long)] cl: f64, /// Show integrated numbers (without bin widths) instead of differential ones. @@ -98,7 +94,7 @@ pub struct Opts { impl Subcommand for Opts { fn run(&self, cfg: &GlobalConfiguration) -> Result { let grid = helpers::read_grid(&self.input)?; - let (set, _) = helpers::create_pdfset(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let limits = helpers::convolve_limits( &grid, @@ -110,47 +106,60 @@ impl Subcommand for Opts { }, ); - let pdf_results = if self.group.pdf || self.group.pdf_with_scale_cov.is_some() { - ThreadPoolBuilder::new() - .num_threads(self.threads) - .build_global() - .unwrap(); + ThreadPoolBuilder::new() + .num_threads(self.threads) + .build_global() + .unwrap(); + + let conv_fun_results: Vec> = self + .group + .conv_fun + .iter() + .map(|&index| { + let (set, funs) = helpers::create_conv_funs_for_set(&self.conv_funs, index)?; + let results: Vec<_> = funs + .into_par_iter() + .map(|mut funs| { + Ok::<_, Error>(helpers::convolve( + &grid, + &mut funs, + &self.orders, + &[], + &[], + 1, + if self.integrated { + ConvoluteMode::Integrated + } else { + ConvoluteMode::Normal + }, + cfg, + )) + }) + .collect::>()?; + + // transpose results + let results: Vec> = (0..results[0].len()) + .map(|bin| (0..results.len()).map(|pdf| results[pdf][bin]).collect()) + .collect(); - set.mk_pdfs()? - .into_par_iter() - .flat_map(|mut pdf| { - helpers::convolve( - &grid, - &mut pdf, - &self.orders, - &[], - &[], - 1, - if self.integrated { - ConvoluteMode::Integrated - } else { - ConvoluteMode::Normal - }, - cfg, - ) - }) - .collect() - } else { - vec![] - }; + results + .into_iter() + .map(|values| Ok(set.uncertainty(&values, self.cl, false)?)) + .collect::>() + }) + .collect::>()?; let scales_max = self .group .scale_env .iter() .chain(self.group.scale_abs.iter()) .chain(self.group.scale_cov.iter()) - .chain(self.group.pdf_with_scale_cov.iter()) .map(|&x| usize::from(x)) .max() .unwrap_or(1); let scale_results = helpers::convolve( &grid, - &mut helpers::create_pdf(&self.pdfset)?, + &mut conv_funs, &self.orders, &[], &[], @@ -173,14 +182,12 @@ impl Subcommand for Opts { } title.add_cell(cell!(c->format!("{y_label}\n[{y_unit}]"))); - if self.group.pdf { - title.add_cell(cell!(c->"PDF central")); - title.add_cell(cell!(c->"PDF\n[%]").with_hspan(2)); - } - - if let Some(scales) = self.group.pdf_with_scale_cov { - title.add_cell(cell!(c->"PDF central")); - title.add_cell(cell!(c->format!("PDF w/ {}pt scale (cov)\n[%]", scales)).with_hspan(2)); + for &index in &self.group.conv_fun { + title.add_cell( + // TODO: fix alignment for second title row + cell!(c->format!("{}\n[{y_unit}] [%] [%]", self.conv_funs.lhapdf_names[index])) + .with_hspan(3), + ); } if let Some(scales) = self.group.scale_abs { @@ -205,25 +212,6 @@ impl Subcommand for Opts { .zip(scale_results.chunks_exact(scales_max)) .enumerate() { - let (pdf_cen, pdf_neg, pdf_pos) = - if self.group.pdf || self.group.pdf_with_scale_cov.is_some() { - let values: Vec<_> = pdf_results - .iter() - .skip(bin) - .step_by(limits.len()) - .copied() - .collect(); - let uncertainty = set.uncertainty(&values, self.cl, false)?; - - ( - uncertainty.central, - -100.0 * uncertainty.errminus / uncertainty.central, - 100.0 * uncertainty.errplus / uncertainty.central, - ) - } else { - (0.0, 0.0, 0.0) - }; - let row = table.add_empty_row(); row.add_cell(cell!(r->format!("{bin}"))); for (left, right) in left_right_limits { @@ -233,30 +221,10 @@ impl Subcommand for Opts { row.add_cell(cell!(r->format!("{:.*e}", self.digits_abs, scale_res[0]))); - if self.group.pdf { - row.add_cell(cell!(r->format!("{:.*e}", self.digits_abs, pdf_cen))); - row.add_cell(cell!(r->format!("{:.*}", self.digits_rel, pdf_neg))); - row.add_cell(cell!(r->format!("{:.*}", self.digits_rel, pdf_pos))); - } - - if let Some(scales) = self.group.pdf_with_scale_cov { - let ns = if scales == 3 { 1.0 } else { 2.0 } / f64::from(scales - 1); - let unc = (ns - * scale_res - .iter() - .take(scales.into()) - .skip(1) - .map(|x| (x - scale_res[0]).powi(2)) - .sum::()) - .sqrt(); - let rel_unc = 100.0 * unc / scale_res[0]; - - let total_neg = -(pdf_neg * pdf_neg + rel_unc * rel_unc).sqrt(); - let total_pos = (pdf_pos * pdf_pos + rel_unc * rel_unc).sqrt(); - - row.add_cell(cell!(r->format!("{:.*e}", self.digits_abs, pdf_cen))); - row.add_cell(cell!(r->format!("{:.*}", self.digits_rel, total_neg))); - row.add_cell(cell!(r->format!("{:.*}", self.digits_rel, total_pos))); + for uncertainty in conv_fun_results.iter().map(|results| &results[bin]) { + row.add_cell(cell!(r->format!("{:.*e}", self.digits_abs, uncertainty.central))); + row.add_cell(cell!(r->format!("{:.*}", self.digits_rel, -100.0 * uncertainty.errminus / uncertainty.central))); + row.add_cell(cell!(r->format!("{:.*}", self.digits_rel, 100.0 * uncertainty.errplus / uncertainty.central))); } if let Some(scales) = self.group.scale_abs { diff --git a/pineappl_cli/tests/analyze.rs b/pineappl_cli/tests/analyze.rs index a8471837..8c9454ff 100644 --- a/pineappl_cli/tests/analyze.rs +++ b/pineappl_cli/tests/analyze.rs @@ -13,11 +13,11 @@ Options: const CKF_HELP_STR: &str = "Compare K-factors with channel K factors (ckf) -Usage: pineappl analyze ckf [OPTIONS] [ORDERS_DEN]... +Usage: pineappl analyze ckf [OPTIONS] [ORDERS_DEN]... Arguments: Path to the input grid - LHAPDF id or name of the PDF set + LHAPDF ID(s) or name(s) of the PDF(s)/FF(s) Order defining the K factors [ORDERS_DEN]... Normalizing orders of the K factors diff --git a/pineappl_cli/tests/channels.rs b/pineappl_cli/tests/channels.rs index c6dcee11..84e9a25f 100644 --- a/pineappl_cli/tests/channels.rs +++ b/pineappl_cli/tests/channels.rs @@ -2,11 +2,11 @@ use assert_cmd::Command; const HELP_STR: &str = "Shows the contribution for each partonic channel -Usage: pineappl channels [OPTIONS] +Usage: pineappl channels [OPTIONS] Arguments: - Path to the input grid - LHAPDF id or name of the PDF set + Path to the input grid + LHAPDF ID(s) or name(s) of the PDF(s)/FF(s) Options: -a, --absolute Show absolute numbers of each contribution @@ -132,6 +132,14 @@ const DONT_SORT_STR: &str = "b etal c size c size c size c size c size 7 4 4.5 0 115.88 1 -7.29 2 0.01 3 -8.61 4 0.01 "; +const MISSING_CONV_FUN_STR: &str = "error: the following required arguments were not provided: + + +Usage: pineappl channels + +For more information, try '--help'. +"; + #[test] fn help() { Command::cargo_bin("pineappl") @@ -156,6 +164,17 @@ fn default() { .stdout(DEFAULT_STR); } +#[test] +fn missing_conv_fun() { + Command::cargo_bin("pineappl") + .unwrap() + .args(["channels", "../test-data/LHCB_WP_7TEV.pineappl.lz4"]) + .assert() + .failure() + .stderr(MISSING_CONV_FUN_STR) + .stdout(""); +} + #[test] fn absolute() { Command::cargo_bin("pineappl") diff --git a/pineappl_cli/tests/convolve.rs b/pineappl_cli/tests/convolve.rs index 9eb93292..36902e63 100644 --- a/pineappl_cli/tests/convolve.rs +++ b/pineappl_cli/tests/convolve.rs @@ -2,11 +2,11 @@ use assert_cmd::Command; const HELP_STR: &str = "Convolutes a PineAPPL grid with a PDF set -Usage: pineappl convolve [OPTIONS] ... +Usage: pineappl convolve [OPTIONS] ... Arguments: - Path of the input grid - ... LHAPDF id(s) or name of the PDF set(s) + Path of the input grid + ... LHAPDF id(s) or name of the PDF set(s) Options: -b, --bins Selects a subset of bins diff --git a/pineappl_cli/tests/diff.rs b/pineappl_cli/tests/diff.rs index cba20144..61e139d0 100644 --- a/pineappl_cli/tests/diff.rs +++ b/pineappl_cli/tests/diff.rs @@ -3,12 +3,12 @@ use assert_fs::NamedTempFile; const HELP_STR: &str = "Compares the numerical content of two grids with each other -Usage: pineappl diff [OPTIONS] +Usage: pineappl diff [OPTIONS] Arguments: - Path to the first grid - Path to the second grid - LHAPDF id or name of the PDF set + Path to the first grid + Path to the second grid + LHAPDF ID(s) or name(s) of the PDF(s)/FF(s) Options: --ignore-orders Ignore differences in the orders and sum them diff --git a/pineappl_cli/tests/evolve.rs b/pineappl_cli/tests/evolve.rs index 5173c15b..6b6193c8 100644 --- a/pineappl_cli/tests/evolve.rs +++ b/pineappl_cli/tests/evolve.rs @@ -5,13 +5,13 @@ use assert_fs::NamedTempFile; const HELP_STR: &str = "Evolve a grid with an evolution kernel operator to an FK table -Usage: pineappl evolve [OPTIONS] +Usage: pineappl evolve [OPTIONS] Arguments: - Path to the input grid - Path to the evolution kernel operator - Path to the converted grid - LHAPDF id or name of the PDF set to check the converted grid with + Path to the input grid + Path to the evolution kernel operator + Path to the converted grid + LHAPDF ID(s) or name of the PDF(s)/FF(s) Options: --accuracy Relative threshold between the table and the converted grid when comparison fails [default: 1e-3] diff --git a/pineappl_cli/tests/export.rs b/pineappl_cli/tests/export.rs index 392c3dc0..47fe293a 100644 --- a/pineappl_cli/tests/export.rs +++ b/pineappl_cli/tests/export.rs @@ -5,12 +5,12 @@ use assert_fs::NamedTempFile; const HELP_STR: &str = "Converts PineAPPL grids to APPLgrid files -Usage: pineappl export [OPTIONS] +Usage: pineappl export [OPTIONS] Arguments: - Path to the input grid - Path to the converted grid - LHAPDF id or name of the PDF set to check the converted grid with + Path to the input grid + Path to the converted grid + LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with Options: --accuracy Relative threshold between the table and the converted grid when comparison fails [default: 1e-10] diff --git a/pineappl_cli/tests/import.rs b/pineappl_cli/tests/import.rs index f5964780..c66f66c2 100644 --- a/pineappl_cli/tests/import.rs +++ b/pineappl_cli/tests/import.rs @@ -6,12 +6,12 @@ use assert_fs::NamedTempFile; #[cfg(feature = "fastnlo")] const HELP_STR: &str = "Converts APPLgrid/fastNLO/FastKernel files to PineAPPL grids -Usage: pineappl import [OPTIONS] +Usage: pineappl import [OPTIONS] Arguments: - Path to the input grid - Path to the converted grid - LHAPDF id or name of the PDF set to check the converted grid with + Path to the input grid + Path to the converted grid + LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with Options: --alpha LO coupling power in alpha [default: 0] @@ -29,12 +29,12 @@ Options: #[cfg(not(feature = "fastnlo"))] const HELP_STR: &str = "Converts APPLgrid/fastNLO/FastKernel files to PineAPPL grids -Usage: pineappl import [OPTIONS] +Usage: pineappl import [OPTIONS] Arguments: - Path to the input grid - Path to the converted grid - LHAPDF id or name of the PDF set to check the converted grid with + Path to the input grid + Path to the converted grid + LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with Options: --alpha LO coupling power in alpha [default: 0] diff --git a/pineappl_cli/tests/main.rs b/pineappl_cli/tests/main.rs index 00d42817..0ba04dce 100644 --- a/pineappl_cli/tests/main.rs +++ b/pineappl_cli/tests/main.rs @@ -19,15 +19,16 @@ Commands: pull Calculates the pull between two different PDF sets read Read out information of a grid subgrids Print information about the internal subgrid types - uncert Calculates scale and PDF uncertainties + uncert Calculate scale and convolution function uncertainties write Write a grid modified by various operations Options: - --lhapdf-banner Allow LHAPDF to print banners - --force-positive Forces negative PDF values to zero - --allow-extrapolation Allow extrapolation of PDFs outside their region of validity - -h, --help Print help - -V, --version Print version + --lhapdf-banner Allow LHAPDF to print banners + --force-positive Forces negative PDF values to zero + --allow-extrapolation Allow extrapolation of PDFs outside their region of validity + --use-alphas-from Choose the PDF/FF set for the strong coupling [default: 0] + -h, --help Print help + -V, --version Print version "; #[test] diff --git a/pineappl_cli/tests/orders.rs b/pineappl_cli/tests/orders.rs index a159c3c4..4c6c41bf 100644 --- a/pineappl_cli/tests/orders.rs +++ b/pineappl_cli/tests/orders.rs @@ -2,11 +2,11 @@ use assert_cmd::Command; const HELP_STR: &str = "Shows the predictions for all bin for each order separately -Usage: pineappl orders [OPTIONS] +Usage: pineappl orders [OPTIONS] Arguments: - Path to the input grid - LHAPDF id or name of the PDF set + Path to the input grid + LHAPDF ID(s) or name(s) of the PDF(s)/FF(s) Options: -a, --absolute Show absolute numbers of each perturbative order diff --git a/pineappl_cli/tests/plot.rs b/pineappl_cli/tests/plot.rs index 2f2d4355..a93ac23c 100644 --- a/pineappl_cli/tests/plot.rs +++ b/pineappl_cli/tests/plot.rs @@ -4,18 +4,19 @@ use std::thread; const HELP_STR: &str = "Creates a matplotlib script plotting the contents of the grid -Usage: pineappl plot [OPTIONS] ... +Usage: pineappl plot [OPTIONS] ... Arguments: - Path to the input grid - ... LHAPDF id(s) or name of the PDF set(s) + Path to the input grid + ... LHAPDF id(s) or name of the PDF set(s) Options: + --conv-fun-uncert-from Choose for which convolution function the uncertainty should be calculated [default: 0] -s, --scales Set the number of scale variations [default: 7] [possible values: 1, 3, 7, 9] --subgrid-pull Show the pull for a specific grid three-dimensionally --asymmetry Plot the asymmetry --threads Number of threads to utilize [default: {}] - --no-pdf-unc Disable the (time-consuming) calculation of PDF uncertainties + --no-conv-fun-unc Disable the (time-consuming) calculation of PDF uncertainties -h, --help Print help "; @@ -1471,7 +1472,7 @@ fn drell_yan_mass_slices() { .unwrap() .args([ "plot", - "--no-pdf-unc", + "--no-conv-fun-unc", "--threads=1", "../test-data/NNPDF_DY_14TEV_BSM_AFB.pineappl.lz4", "NNPDF40_nnlo_as_01180", diff --git a/pineappl_cli/tests/pull.rs b/pineappl_cli/tests/pull.rs index 4cc2f686..5668a8f0 100644 --- a/pineappl_cli/tests/pull.rs +++ b/pineappl_cli/tests/pull.rs @@ -4,14 +4,15 @@ use std::thread; const HELP_STR: &str = "Calculates the pull between two different PDF sets -Usage: pineappl pull [OPTIONS] +Usage: pineappl pull [OPTIONS] Arguments: - Path to the input grid - LHAPDF id or name of the first PDF set - LHAPDF id or name of the second PDF set + Path to the input grid + LHAPDF ID(s) or name(s) of the first PDF(s)/FF(s) + LHAPDF ID(s) or name(s) of the second PDF(s)/FF(s) Options: + --pull-from Index of the convolution functions for which the pull should be calculated [default: 0] --cl Confidence level in per cent [default: 68.26894921370858] -l, --limit The maximum number of channels displayed [default: 10] -o, --orders Select orders manually diff --git a/pineappl_cli/tests/uncert.rs b/pineappl_cli/tests/uncert.rs index 43b46538..c2e1da4d 100644 --- a/pineappl_cli/tests/uncert.rs +++ b/pineappl_cli/tests/uncert.rs @@ -2,79 +2,79 @@ use assert_cmd::Command; use std::num::NonZeroUsize; use std::thread; -const HELP_STR: &str = "Calculates scale and PDF uncertainties +const HELP_STR: &str = "Calculate scale and convolution function uncertainties -Usage: pineappl uncert [OPTIONS] <--pdf|--pdf-with-scale-cov[=]|--scale-abs[=]|--scale-cov[=]|--scale-env[=]> +Usage: pineappl uncert [OPTIONS] <--conv-fun[=]|--scale-abs[=]|--scale-cov[=]|--scale-env[=]> Arguments: - Path to the input grid - LHAPDF id or name of the PDF set + Path to the input grid + LHAPDF ID(s) or name(s) of the PDF(s)/FF(s) Options: - --pdf Calculate the PDF uncertainties - --pdf-with-scale-cov[=] Calculate the combined PDF and scale uncertainty using the covariance method [possible values: 3, 7, 9] - --scale-abs[=] Show absolute numbers of the scale-varied results [possible values: 3, 7, 9] - --scale-cov[=] Calculate scale uncertainties using the covariance method [possible values: 3, 7, 9] - --scale-env[=] Calculate the envelope of results where renormalization and factorization scales varied [possible values: 3, 7, 9] - --cl Confidence level in per cent, for PDF uncertainties [default: 68.26894921370858] - -i, --integrated Show integrated numbers (without bin widths) instead of differential ones - -o, --orders Select orders manually - --threads Number of threads to utilize [default: {}] - --digits-abs Set the number of fractional digits shown for absolute numbers [default: 7] - --digits-rel Set the number of fractional digits shown for relative numbers [default: 2] - -h, --help Print help + --conv-fun[=] Calculate convolution function uncertainties + --scale-abs[=] Show absolute numbers of the scale-varied results [possible values: 3, 7, 9] + --scale-cov[=] Calculate scale uncertainties using the covariance method [possible values: 3, 7, 9] + --scale-env[=] Calculate the envelope of results where renormalization and factorization scales varied [possible values: 3, 7, 9] + --cl Confidence level in per cent, for convolution function uncertainties [default: 68.26894921370858] + -i, --integrated Show integrated numbers (without bin widths) instead of differential ones + -o, --orders Select orders manually + --threads Number of threads to utilize [default: {}] + --digits-abs Set the number of fractional digits shown for absolute numbers [default: 7] + --digits-rel Set the number of fractional digits shown for relative numbers [default: 2] + -h, --help Print help "; -const DEFAULT_STR: &str = "b etal dsig/detal PDF central PDF - [] [pb] [%] --+----+----+-----------+-----------+-----+---- -0 2 2.25 7.5459110e2 7.5461655e2 -1.14 1.14 -1 2.25 2.5 6.9028342e2 6.9027941e2 -1.16 1.16 -2 2.5 2.75 6.0025198e2 6.0022595e2 -1.18 1.18 -3 2.75 3 4.8552235e2 4.8548211e2 -1.22 1.22 -4 3 3.25 3.6195456e2 3.6191001e2 -1.27 1.27 -5 3.25 3.5 2.4586691e2 2.4582640e2 -1.35 1.35 -6 3.5 4 1.1586851e2 1.1584074e2 -1.51 1.51 -7 4 4.5 2.7517266e1 2.7504644e1 -2.77 2.77 +const DEFAULT_STR: &str = + "b etal dsig/detal NNPDF31_nlo_as_0118_luxqed NNPDF40_nnlo_as_01180 + [] [pb] [pb] [%] [%] [pb] [%] [%] +-+----+----+-----------+-----------+---------+---------+-----------+--------+-------- +0 2 2.25 7.7302788e2 7.7302788e2 -0.67 0.67 7.7302788e2 -0.62 0.62 +1 2.25 2.5 7.0634852e2 7.0634851e2 -0.72 0.72 7.0634851e2 -0.62 0.62 +2 2.5 2.75 6.1354750e2 6.1354750e2 -0.78 0.78 6.1354750e2 -0.64 0.64 +3 2.75 3 4.9584391e2 4.9584391e2 -0.86 0.86 4.9584391e2 -0.68 0.68 +4 3 3.25 3.6957893e2 3.6957893e2 -0.97 0.97 3.6957893e2 -0.76 0.76 +5 3.25 3.5 2.5143057e2 2.5143057e2 -1.14 1.14 2.5143057e2 -0.89 0.89 +6 3.5 4 1.1962468e2 1.1962468e2 -1.55 1.55 1.1962468e2 -1.34 1.34 +7 4 4.5 2.9665790e1 2.9665790e1 -2.56 2.56 2.9665789e1 -3.51 3.51 "; -const CL_90_STR: &str = "b etal dsig/detal PDF central PDF - [] [pb] [%] --+----+----+-----------+-----------+-----+---- -0 2 2.25 7.5459110e2 7.5461655e2 -1.87 1.87 -1 2.25 2.5 6.9028342e2 6.9027941e2 -1.90 1.90 -2 2.5 2.75 6.0025198e2 6.0022595e2 -1.95 1.95 -3 2.75 3 4.8552235e2 4.8548211e2 -2.00 2.00 -4 3 3.25 3.6195456e2 3.6191001e2 -2.08 2.08 -5 3.25 3.5 2.4586691e2 2.4582640e2 -2.22 2.22 -6 3.5 4 1.1586851e2 1.1584074e2 -2.48 2.48 -7 4 4.5 2.7517266e1 2.7504644e1 -4.55 4.55 +const CL_90_STR: &str = "b etal dsig/detal NNPDF31_nlo_as_0118_luxqed + [] [pb] [pb] [%] [%] +-+----+----+-----------+-----------+---------+--------- +0 2 2.25 7.5459110e2 7.5461655e2 -1.87 1.87 +1 2.25 2.5 6.9028342e2 6.9027941e2 -1.90 1.90 +2 2.5 2.75 6.0025198e2 6.0022595e2 -1.95 1.95 +3 2.75 3 4.8552235e2 4.8548211e2 -2.00 2.00 +4 3 3.25 3.6195456e2 3.6191001e2 -2.08 2.08 +5 3.25 3.5 2.4586691e2 2.4582640e2 -2.22 2.22 +6 3.5 4 1.1586851e2 1.1584074e2 -2.48 2.48 +7 4 4.5 2.7517266e1 2.7504644e1 -4.55 4.55 "; -const INTEGRATED_STR: &str = "b etal integ PDF central PDF - [] [] [%] --+----+----+-----------+-----------+-----+---- -0 2 2.25 1.8864777e2 1.8865414e2 -1.14 1.14 -1 2.25 2.5 1.7257086e2 1.7256985e2 -1.16 1.16 -2 2.5 2.75 1.5006300e2 1.5005649e2 -1.18 1.18 -3 2.75 3 1.2138059e2 1.2137053e2 -1.22 1.22 -4 3 3.25 9.0488640e1 9.0477502e1 -1.27 1.27 -5 3.25 3.5 6.1466727e1 6.1456599e1 -1.35 1.35 -6 3.5 4 5.7934254e1 5.7920368e1 -1.51 1.51 -7 4 4.5 1.3758633e1 1.3752322e1 -2.77 2.77 +const INTEGRATED_STR: &str = "b etal integ NNPDF31_nlo_as_0118_luxqed + [] [] [] [%] [%] +-+----+----+-----------+-----------+---------+--------- +0 2 2.25 1.8864777e2 1.8865414e2 -1.14 1.14 +1 2.25 2.5 1.7257086e2 1.7256985e2 -1.16 1.16 +2 2.5 2.75 1.5006300e2 1.5005649e2 -1.18 1.18 +3 2.75 3 1.2138059e2 1.2137053e2 -1.22 1.22 +4 3 3.25 9.0488640e1 9.0477502e1 -1.27 1.27 +5 3.25 3.5 6.1466727e1 6.1456599e1 -1.35 1.35 +6 3.5 4 5.7934254e1 5.7920368e1 -1.51 1.51 +7 4 4.5 1.3758633e1 1.3752322e1 -2.77 2.77 "; -const ORDERS_A2_AS1A2_STR: &str = "b etal dsig/detal PDF central PDF - [] [pb] [%] --+----+----+-----------+-----------+-----+---- -0 2 2.25 7.6246034e2 7.6248591e2 -1.14 1.14 -1 2.25 2.5 6.9684577e2 6.9684166e2 -1.16 1.16 -2 2.5 2.75 6.0548681e2 6.0546059e2 -1.18 1.18 -3 2.75 3 4.8928139e2 4.8924093e2 -1.22 1.22 -4 3 3.25 3.6454175e2 3.6449702e2 -1.27 1.27 -5 3.25 3.5 2.4754316e2 2.4750254e2 -1.35 1.35 -6 3.5 4 1.1667878e2 1.1665095e2 -1.50 1.50 -7 4 4.5 2.7737493e1 2.7724826e1 -2.77 2.77 +const ORDERS_A2_AS1A2_STR: &str = "b etal dsig/detal NNPDF31_nlo_as_0118_luxqed + [] [pb] [pb] [%] [%] +-+----+----+-----------+-----------+---------+--------- +0 2 2.25 7.6246034e2 7.6248591e2 -1.14 1.14 +1 2.25 2.5 6.9684577e2 6.9684166e2 -1.16 1.16 +2 2.5 2.75 6.0548681e2 6.0546059e2 -1.18 1.18 +3 2.75 3 4.8928139e2 4.8924093e2 -1.22 1.22 +4 3 3.25 3.6454175e2 3.6449702e2 -1.27 1.27 +5 3.25 3.5 2.4754316e2 2.4750254e2 -1.35 1.35 +6 3.5 4 1.1667878e2 1.1665095e2 -1.50 1.50 +7 4 4.5 2.7737493e1 2.7724826e1 -2.77 2.77 "; const SCALE_ABS_STR: &str = @@ -143,19 +143,6 @@ const SCALE_ENV_9_STR: &str = "b etal dsig/detal 9pt-svar (env) 7 4 4.5 2.7517266e1 -5.36 5.22 "; -const PDF_WITH_SCALE_COV_STR: &str = "b etal dsig/detal PDF central PDF w/ 7pt scale (cov) - [] [pb] [%] --+----+----+-----------+-----------+-----------+----------- -0 2 2.25 7.5459110e2 7.5461655e2 -3.48 3.48 -1 2.25 2.5 6.9028342e2 6.9027941e2 -3.50 3.50 -2 2.5 2.75 6.0025198e2 6.0022595e2 -3.55 3.55 -3 2.75 3 4.8552235e2 4.8548211e2 -3.56 3.56 -4 3 3.25 3.6195456e2 3.6191001e2 -3.58 3.58 -5 3.25 3.5 2.4586691e2 2.4582640e2 -3.60 3.60 -6 3.5 4 1.1586851e2 1.1584074e2 -3.63 3.63 -7 4 4.5 2.7517266e1 2.7504644e1 -4.26 4.26 -"; - #[test] fn help() { Command::cargo_bin("pineappl") @@ -174,15 +161,15 @@ fn help() { } #[test] -fn pdf_default() { +fn conv_fun_default() { Command::cargo_bin("pineappl") .unwrap() .args([ "uncert", - "--pdf", + "--conv-fun=0,1", "--threads=1", "../test-data/LHCB_WP_7TEV.pineappl.lz4", - "NNPDF31_nlo_as_0118_luxqed", + "NNPDF31_nlo_as_0118_luxqed,NNPDF40_nnlo_as_01180=NNPDF3.1+NNPDF4.0", ]) .assert() .success() @@ -190,12 +177,12 @@ fn pdf_default() { } #[test] -fn pdf_cl_90() { +fn conv_fun_cl_90() { Command::cargo_bin("pineappl") .unwrap() .args([ "uncert", - "--pdf", + "--conv-fun", "--cl=90", "--threads=1", "../test-data/LHCB_WP_7TEV.pineappl.lz4", @@ -207,12 +194,12 @@ fn pdf_cl_90() { } #[test] -fn pdf_integrated() { +fn conv_fun_integrated() { Command::cargo_bin("pineappl") .unwrap() .args([ "uncert", - "--pdf", + "--conv-fun=0", "--integrated", "--threads=1", "../test-data/LHCB_WP_7TEV.pineappl.lz4", @@ -224,12 +211,12 @@ fn pdf_integrated() { } #[test] -fn pdf_orders_a2_as1a2() { +fn conv_fun_orders_a2_as1a2() { Command::cargo_bin("pineappl") .unwrap() .args([ "uncert", - "--pdf", + "--conv-fun=0", "--orders=a2,as1a2", "--threads=1", "../test-data/LHCB_WP_7TEV.pineappl.lz4", @@ -314,18 +301,3 @@ fn scale_env_9() { .success() .stdout(SCALE_ENV_9_STR); } - -#[test] -fn pdf_with_scale_cov() { - Command::cargo_bin("pineappl") - .unwrap() - .args([ - "uncert", - "--pdf-with-scale-cov", - "../test-data/LHCB_WP_7TEV.pineappl.lz4", - "NNPDF31_nlo_as_0118_luxqed", - ]) - .assert() - .success() - .stdout(PDF_WITH_SCALE_COV_STR); -}