From 31cc7799dccb5887d54ed9cc45e35a8eb57b4d9d Mon Sep 17 00:00:00 2001 From: t7phy Date: Sun, 9 Jun 2024 12:10:00 +0200 Subject: [PATCH 01/27] pdf input to a Vec of strings --- pineappl_cli/src/channels.rs | 4 ++-- pineappl_cli/src/convolve.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index d9841f66..341be9df 100644 --- a/pineappl_cli/src/channels.rs +++ b/pineappl_cli/src/channels.rs @@ -15,8 +15,8 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF id or name of the PDF set. - #[arg(value_parser = helpers::parse_pdfset)] - pdfset: String, + #[arg(num_args = 1, value_delimiter = ',', value_parser = helpers::parse_pdfset)] + pdfset: Vec, /// Show absolute numbers of each contribution. #[arg(long, short)] absolute: bool, diff --git a/pineappl_cli/src/convolve.rs b/pineappl_cli/src/convolve.rs index 71f0225e..ef37ca6a 100644 --- a/pineappl_cli/src/convolve.rs +++ b/pineappl_cli/src/convolve.rs @@ -16,7 +16,7 @@ pub struct Opts { input: PathBuf, /// LHAPDF id(s) or name of the PDF set(s). #[arg(required = true, value_parser = helpers::parse_pdfset)] - pdfsets: Vec, + pdfsets: Vec>, /// Selects a subset of bins. #[arg( long, From 5efc0f1df6166a70c7ac99f33100a2740d51ab8c Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 10 Jun 2024 10:30:48 +0200 Subject: [PATCH 02/27] Undo changes from commit 31cc779 --- pineappl_cli/src/channels.rs | 4 ++-- pineappl_cli/src/convolve.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index 341be9df..d9841f66 100644 --- a/pineappl_cli/src/channels.rs +++ b/pineappl_cli/src/channels.rs @@ -15,8 +15,8 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF id or name of the PDF set. - #[arg(num_args = 1, value_delimiter = ',', value_parser = helpers::parse_pdfset)] - pdfset: Vec, + #[arg(value_parser = helpers::parse_pdfset)] + pdfset: String, /// Show absolute numbers of each contribution. #[arg(long, short)] absolute: bool, diff --git a/pineappl_cli/src/convolve.rs b/pineappl_cli/src/convolve.rs index ef37ca6a..71f0225e 100644 --- a/pineappl_cli/src/convolve.rs +++ b/pineappl_cli/src/convolve.rs @@ -16,7 +16,7 @@ pub struct Opts { input: PathBuf, /// LHAPDF id(s) or name of the PDF set(s). #[arg(required = true, value_parser = helpers::parse_pdfset)] - pdfsets: Vec>, + pdfsets: Vec, /// Selects a subset of bins. #[arg( long, From 0ec739360bc292af8b5bdfe8e617a3514a58cab4 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 10 Jun 2024 10:25:07 +0200 Subject: [PATCH 03/27] Prepare CLI for multiple convolution functions --- pineappl_cli/src/analyze.rs | 5 ++-- pineappl_cli/src/channels.rs | 3 +- pineappl_cli/src/convolve.rs | 5 ++-- pineappl_cli/src/diff.rs | 9 +++--- pineappl_cli/src/evolve.rs | 5 ++-- pineappl_cli/src/export.rs | 3 +- pineappl_cli/src/helpers.rs | 56 ++++++++++++++++++++---------------- pineappl_cli/src/import.rs | 3 +- pineappl_cli/src/orders.rs | 3 +- pineappl_cli/src/plot.rs | 35 ++++++++++++++++------ pineappl_cli/src/pull.rs | 9 +++--- pineappl_cli/src/uncert.rs | 5 ++-- 12 files changed, 88 insertions(+), 53 deletions(-) diff --git a/pineappl_cli/src/analyze.rs b/pineappl_cli/src/analyze.rs index 506767db..134556b1 100644 --- a/pineappl_cli/src/analyze.rs +++ b/pineappl_cli/src/analyze.rs @@ -6,6 +6,7 @@ use clap::{value_parser, Parser, ValueHint}; use prettytable::{cell, Row}; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; /// Perform various analyses with grids. #[derive(Parser)] @@ -87,7 +88,7 @@ impl Subcommand for CkfOpts { lumi_mask[lumi] = true; helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &[self.order], &[], &lumi_mask, @@ -103,7 +104,7 @@ impl Subcommand for CkfOpts { lumi_mask[lumi] = true; helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &orders_den, &[], &lumi_mask, diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index d9841f66..4278eb5b 100644 --- a/pineappl_cli/src/channels.rs +++ b/pineappl_cli/src/channels.rs @@ -7,6 +7,7 @@ use prettytable::{cell, Row}; use std::ops::RangeInclusive; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; /// Shows the contribution for each partonic channel. #[derive(Parser)] @@ -93,7 +94,7 @@ impl Subcommand for Opts { channel_mask[channel] = true; helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &self.orders, &[], &channel_mask, diff --git a/pineappl_cli/src/convolve.rs b/pineappl_cli/src/convolve.rs index 71f0225e..91ee8bfe 100644 --- a/pineappl_cli/src/convolve.rs +++ b/pineappl_cli/src/convolve.rs @@ -6,6 +6,7 @@ use prettytable::{cell, Row}; use std::ops::RangeInclusive; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; /// Convolutes a PineAPPL grid with a PDF set. #[derive(Parser)] @@ -54,7 +55,7 @@ impl Subcommand for Opts { let results = helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &self.orders, &bins, &[], @@ -83,7 +84,7 @@ impl Subcommand for Opts { let mut pdf = helpers::create_pdf(pdfset).unwrap(); helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &self.orders, &bins, &[], diff --git a/pineappl_cli/src/diff.rs b/pineappl_cli/src/diff.rs index 8757c45d..7e111e86 100644 --- a/pineappl_cli/src/diff.rs +++ b/pineappl_cli/src/diff.rs @@ -6,6 +6,7 @@ use prettytable::{cell, Row}; use std::collections::HashSet; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; /// Compares the numerical content of two grids with each other. #[derive(Parser)] @@ -149,7 +150,7 @@ impl Subcommand for Opts { let results1 = helpers::convolve( &grid1, - &mut pdf, + slice::from_mut(&mut pdf), &orders1, &[], &[], @@ -159,7 +160,7 @@ impl Subcommand for Opts { ); let results2 = helpers::convolve( &grid2, - &mut pdf, + slice::from_mut(&mut pdf), &orders2, &[], &[], @@ -205,7 +206,7 @@ impl Subcommand for Opts { .map(|&order| { helpers::convolve( &grid1, - &mut pdf, + slice::from_mut(&mut pdf), &[order], &[], &[], @@ -220,7 +221,7 @@ impl Subcommand for Opts { .map(|&order| { helpers::convolve( &grid2, - &mut pdf, + slice::from_mut(&mut pdf), &[order], &[], &[], diff --git a/pineappl_cli/src/evolve.rs b/pineappl_cli/src/evolve.rs index 07cd297f..71f4e166 100644 --- a/pineappl_cli/src/evolve.rs +++ b/pineappl_cli/src/evolve.rs @@ -7,6 +7,7 @@ use pineappl::fk_table::FkTable; use pineappl::grid::Grid; use std::path::{Path, PathBuf}; use std::process::ExitCode; +use std::slice; #[cfg(feature = "evolve")] mod eko { @@ -545,7 +546,7 @@ impl Subcommand for Opts { let mut pdf = helpers::create_pdf(&self.pdfset)?; let results = helpers::convolve_scales( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &self.orders, &[], &[], @@ -565,7 +566,7 @@ impl Subcommand for Opts { )?; let evolved_results = helpers::convolve_scales( fk_table.grid(), - &mut pdf, + slice::from_mut(&mut pdf), &[], &[], &[], diff --git a/pineappl_cli/src/export.rs b/pineappl_cli/src/export.rs index 7986a6c8..684abb43 100644 --- a/pineappl_cli/src/export.rs +++ b/pineappl_cli/src/export.rs @@ -7,6 +7,7 @@ use pineappl::boc::Order; use pineappl::grid::Grid; use std::path::{Path, PathBuf}; use std::process::ExitCode; +use std::slice; #[cfg(feature = "applgrid")] mod applgrid; @@ -158,7 +159,7 @@ impl Subcommand for Opts { let mut pdf = helpers::create_pdf(&self.pdfset)?; let reference_results = helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &orders, &[], &[], diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 7947da34..6dd8f6c4 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -127,7 +127,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 +146,37 @@ 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); - } - - 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] => { + // if the field 'Particle' is missing we assume it's a proton PDF + let pdf_pdg_id = fun + .set() + .entry("Particle") + .map_or(Ok(2212), |string| string.parse::()) + .unwrap(); + + if cfg.force_positive { + fun.set_force_positive(1); + } + + 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(pdf_pdg_id, &mut fun, &mut alphas); + + grid.convolve(&mut cache, &orders, bins, channels, scales) } + [_fun0, _fun1] => todo!(), + _ => 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 +220,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 +230,7 @@ pub fn convolve( ) -> Vec { convolve_scales( grid, - lhapdf, + conv_funs, orders, bins, lumis, diff --git a/pineappl_cli/src/import.rs b/pineappl_cli/src/import.rs index 727bc718..db1c8c68 100644 --- a/pineappl_cli/src/import.rs +++ b/pineappl_cli/src/import.rs @@ -6,6 +6,7 @@ use clap::{Parser, ValueHint}; use pineappl::grid::Grid; use std::path::{Path, PathBuf}; use std::process::ExitCode; +use std::slice; #[cfg(feature = "applgrid")] mod applgrid; @@ -277,7 +278,7 @@ impl Subcommand for Opts { let mut pdf = helpers::create_pdf(&self.pdfset)?; let results = helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &[], &[], &[], diff --git a/pineappl_cli/src/orders.rs b/pineappl_cli/src/orders.rs index 77919d23..ef484086 100644 --- a/pineappl_cli/src/orders.rs +++ b/pineappl_cli/src/orders.rs @@ -5,6 +5,7 @@ use clap::{Parser, ValueHint}; use prettytable::{cell, Row}; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; /// Shows the predictions for all bin for each order separately. #[derive(Parser)] @@ -66,7 +67,7 @@ impl Subcommand for Opts { .map(|order| { helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &[(order.alphas, order.alpha)], &[], &[], diff --git a/pineappl_cli/src/plot.rs b/pineappl_cli/src/plot.rs index 6e988ef2..8b4d9391 100644 --- a/pineappl_cli/src/plot.rs +++ b/pineappl_cli/src/plot.rs @@ -13,6 +13,7 @@ use std::fmt::Write; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use std::process::ExitCode; +use std::slice; use std::thread; /// Creates a matplotlib script plotting the contents of the grid. @@ -219,8 +220,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, + slice::from_mut(&mut pdf), + &[], + &bins, + &[], + self.scales, + mode, + cfg, + ); let qcd_results = { let mut orders = grid.orders().to_vec(); @@ -239,7 +248,7 @@ impl Subcommand for Opts { helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &qcd_orders, &bins, &[], @@ -271,8 +280,16 @@ impl Subcommand for Opts { if self.no_pdf_unc { let mut pdf = helpers::create_pdf(pdfset).unwrap(); - let results = - helpers::convolve(&grid, &mut pdf, &[], &bins, &[], 1, mode, cfg); + let results = helpers::convolve( + &grid, + slice::from_mut(&mut pdf), + &[], + &bins, + &[], + 1, + mode, + cfg, + ); Ok(vec![results; 3]) } else { @@ -284,7 +301,7 @@ impl Subcommand for Opts { .flat_map(|mut pdf| { helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &[], &bins, &[], @@ -383,7 +400,7 @@ impl Subcommand for Opts { ), helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &[], &bins, &channel_mask, @@ -527,7 +544,7 @@ impl Subcommand for Opts { .map(|pdf| { let values = helpers::convolve( &grid, - pdf, + slice::from_mut(pdf), &[], &[bin], &[], @@ -544,7 +561,7 @@ impl Subcommand for Opts { .map(|pdf| { let values = helpers::convolve( &grid, - pdf, + slice::from_mut(pdf), &[], &[bin], &[], diff --git a/pineappl_cli/src/pull.rs b/pineappl_cli/src/pull.rs index e12cc0ad..ee39bd6e 100644 --- a/pineappl_cli/src/pull.rs +++ b/pineappl_cli/src/pull.rs @@ -8,6 +8,7 @@ use rayon::{prelude::*, ThreadPoolBuilder}; use std::num::NonZeroUsize; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; use std::thread; // TODO: do we need the CL parameter? @@ -68,7 +69,7 @@ impl Subcommand for Opts { .flat_map(|pdf| { helpers::convolve( &grid, - pdf, + slice::from_mut(pdf), &self.orders, &[], &[], @@ -83,7 +84,7 @@ impl Subcommand for Opts { .flat_map(|pdf| { helpers::convolve( &grid, - pdf, + slice::from_mut(pdf), &self.orders, &[], &[], @@ -149,7 +150,7 @@ impl Subcommand for Opts { channel_mask[channel] = true; match helpers::convolve( &grid, - &mut pdfset[member], + slice::from_mut(&mut pdfset[member]), &self.orders, &[bin], &channel_mask, @@ -174,7 +175,7 @@ impl Subcommand for Opts { channel_mask[channel] = true; match helpers::convolve( &grid, - pdf, + slice::from_mut(pdf), &self.orders, &[bin], &channel_mask, diff --git a/pineappl_cli/src/uncert.rs b/pineappl_cli/src/uncert.rs index aefe6f86..09bec460 100644 --- a/pineappl_cli/src/uncert.rs +++ b/pineappl_cli/src/uncert.rs @@ -8,6 +8,7 @@ use rayon::{prelude::*, ThreadPoolBuilder}; use std::num::NonZeroUsize; use std::path::PathBuf; use std::process::ExitCode; +use std::slice; use std::thread; #[derive(Args)] @@ -121,7 +122,7 @@ impl Subcommand for Opts { .flat_map(|mut pdf| { helpers::convolve( &grid, - &mut pdf, + slice::from_mut(&mut pdf), &self.orders, &[], &[], @@ -150,7 +151,7 @@ impl Subcommand for Opts { .unwrap_or(1); let scale_results = helpers::convolve( &grid, - &mut helpers::create_pdf(&self.pdfset)?, + slice::from_mut(&mut helpers::create_pdf(&self.pdfset)?), &self.orders, &[], &[], From 9556a504f175f4428af59eb89952daeed47a8715 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 10 Jun 2024 10:43:14 +0200 Subject: [PATCH 04/27] Add struct `ConvFun` and use it in `channels` --- pineappl_cli/src/channels.rs | 13 ++++++------ pineappl_cli/src/helpers.rs | 37 ++++++++++++++++++++++++++++++++++ pineappl_cli/tests/channels.rs | 25 ++++++++++++++++++++--- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index 4278eb5b..2bb74c93 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, ConvFun, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::TypedValueParser; @@ -7,7 +7,6 @@ use prettytable::{cell, Row}; use std::ops::RangeInclusive; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; /// Shows the contribution for each partonic channel. #[derive(Parser)] @@ -15,9 +14,9 @@ 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 of the PDF(s)/FF(s). + #[arg(num_args = 1, required = true, value_delimiter = ',')] + conv_funs: Vec, /// Show absolute numbers of each contribution. #[arg(long, short)] absolute: bool, @@ -66,7 +65,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(); @@ -94,7 +93,7 @@ impl Subcommand for Opts { channel_mask[channel] = true; helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &self.orders, &[], &channel_mask, diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 6dd8f6c4..8ec30e80 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -6,11 +6,48 @@ use pineappl::convolutions::LumiCache; use pineappl::grid::Grid; use prettytable::format::{FormatBuilder, LinePosition, LineSeparator}; use prettytable::Table; +use std::convert::Infallible; use std::fs::{File, OpenOptions}; use std::iter; use std::ops::RangeInclusive; use std::path::Path; use std::process::ExitCode; +use std::str::FromStr; + +#[derive(Clone)] +pub struct ConvFun { + lhapdf_name: String, + label: String, +} + +impl FromStr for ConvFun { + type Err = Infallible; + + fn from_str(arg: &str) -> std::result::Result { + Ok(arg.split_once('=').map_or_else( + || ConvFun { + lhapdf_name: arg.to_owned(), + label: arg.to_owned(), + }, + |(lhapdf_name, label)| ConvFun { + lhapdf_name: lhapdf_name.to_owned(), + label: label.to_owned(), + }, + )) + } +} + +pub fn create_conv_funs(funs: &[ConvFun]) -> Result> { + Ok(funs + .iter() + .map(|fun| { + fun.lhapdf_name.parse().map_or_else( + |_| Pdf::with_setname_and_nmem(&fun.lhapdf_name), + Pdf::with_lhaid, + ) + }) + .collect::>()?) +} pub fn create_pdf(pdf: &str) -> Result { let pdf = pdf.split_once('=').map_or(pdf, |(name, _)| name); diff --git a/pineappl_cli/tests/channels.rs b/pineappl_cli/tests/channels.rs index c6dcee11..21db2f5f 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 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") From 98de0bac794300be629b398906e3eae768f25407 Mon Sep 17 00:00:00 2001 From: t7phy Date: Mon, 10 Jun 2024 23:17:33 +0200 Subject: [PATCH 05/27] add two conv funcs support in convolve_scales --- pineappl_cli/src/helpers.rs | 50 ++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 8ec30e80..0463bbc1 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -186,7 +186,7 @@ pub fn convolve_scales( let mut results = match conv_funs { [fun] => { // if the field 'Particle' is missing we assume it's a proton PDF - let pdf_pdg_id = fun + let pdg_id = fun .set() .entry("Particle") .map_or(Ok(2212), |string| string.parse::()) @@ -207,11 +207,55 @@ pub fn convolve_scales( } }; - let mut cache = LumiCache::with_one(pdf_pdg_id, &mut fun, &mut alphas); + 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(); + + if cfg.force_positive { + fun1.set_force_positive(1); + fun2.set_force_positive(1); + } + + let x_max1 = fun1.x_max(); + let x_min1 = fun1.x_min(); + let mut alphas1 = |q2| fun1.alphas_q2(q2); + 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 x_max2 = fun2.x_max(); + let x_min2 = fun2.x_min(); + // is the following line needed? + // let mut alphas2 = |q2| fun2.alphas_q2(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 alphas1); grid.convolve(&mut cache, &orders, bins, channels, scales) } - [_fun0, _fun1] => todo!(), _ => unimplemented!(), }; From ed4cbc22256c9bd5c9f94c1a6309336f83991c9d Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Tue, 11 Jun 2024 15:19:38 +0200 Subject: [PATCH 06/27] Make `helpers::convolve_scales` a bit more generic --- pineappl_cli/src/helpers.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 0463bbc1..bb1fe320 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -183,6 +183,10 @@ pub fn convolve_scales( }) .collect(); + for fun in conv_funs.iter_mut() { + fun.set_force_positive(1); + } + let mut results = match conv_funs { [fun] => { // if the field 'Particle' is missing we assume it's a proton PDF @@ -192,10 +196,6 @@ pub fn convolve_scales( .map_or(Ok(2212), |string| string.parse::()) .unwrap(); - if cfg.force_positive { - fun.set_force_positive(1); - } - let x_max = fun.x_max(); let x_min = fun.x_min(); let mut alphas = |q2| fun.alphas_q2(q2); @@ -224,11 +224,6 @@ pub fn convolve_scales( .map_or(Ok(2212), |string| string.parse::()) .unwrap(); - if cfg.force_positive { - fun1.set_force_positive(1); - fun2.set_force_positive(1); - } - let x_max1 = fun1.x_max(); let x_min1 = fun1.x_min(); let mut alphas1 = |q2| fun1.alphas_q2(q2); From 5148a6c8d7dd7785bc4f30f695ab400261b9c3c1 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Tue, 11 Jun 2024 15:41:01 +0200 Subject: [PATCH 07/27] Fix bug from commit ed4cbc2 --- pineappl_cli/src/helpers.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index bb1fe320..5b7e6848 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -183,8 +183,10 @@ pub fn convolve_scales( }) .collect(); - for fun in conv_funs.iter_mut() { - fun.set_force_positive(1); + if cfg.force_positive { + for fun in conv_funs.iter_mut() { + fun.set_force_positive(1); + } } let mut results = match conv_funs { From f69ad05deb5c5134ec488979fa44873e0ac0633e Mon Sep 17 00:00:00 2001 From: t7phy Date: Thu, 13 Jun 2024 00:03:31 +0200 Subject: [PATCH 08/27] add flag to choose the pdfset from which alphas is taken --- pineappl_cli/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pineappl_cli/src/lib.rs b/pineappl_cli/src/lib.rs index d02e045b..57d815b8 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 alpha_s. + #[arg(long)] + pub use_alphas_from: usize } #[enum_dispatch] From cc01da96419cbbbfcd6dbc7a6346d85402d91f20 Mon Sep 17 00:00:00 2001 From: t7phy Date: Thu, 13 Jun 2024 00:04:35 +0200 Subject: [PATCH 09/27] add flag to choose the pdfset from which alphas is taken --- pineappl_cli/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pineappl_cli/src/lib.rs b/pineappl_cli/src/lib.rs index 57d815b8..4980dae4 100644 --- a/pineappl_cli/src/lib.rs +++ b/pineappl_cli/src/lib.rs @@ -40,7 +40,7 @@ pub struct GlobalConfiguration { pub allow_extrapolation: bool, /// Choose the PDF/FF set for alpha_s. #[arg(long)] - pub use_alphas_from: usize + pub use_alphas_from: usize, } #[enum_dispatch] From f47b8083a3fc10acc434e07675c1f73b91267769 Mon Sep 17 00:00:00 2001 From: t7phy Date: Thu, 13 Jun 2024 13:46:53 +0200 Subject: [PATCH 10/27] allow users to choose the conv_func for alphas --- pineappl_cli/src/helpers.rs | 20 ++++++++++++++------ pineappl_cli/src/lib.rs | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 5b7e6848..4a503f12 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -228,7 +228,18 @@ pub fn convolve_scales( let x_max1 = fun1.x_max(); let x_min1 = fun1.x_min(); - let mut alphas1 = |q2| fun1.alphas_q2(q2); + let x_max2 = fun2.x_max(); + let x_min2 = fun2.x_min(); + + let mut alphas = |q2| { + if cfg.use_alphas_from == 1 { + fun1.alphas_q2(q2) + } else if cfg.use_alphas_from == 2 { + fun2.alphas_q2(q2) + } else { + panic!("Invalid value for use_alphas_from, please use '1' or '2'") + } + }; let mut fun1 = |id, x, q2| { if !cfg.allow_extrapolation && (x < x_min1 || x > x_max1) { 0.0 @@ -236,10 +247,7 @@ pub fn convolve_scales( fun1.xfx_q2(id, x, q2) } }; - let x_max2 = fun2.x_max(); - let x_min2 = fun2.x_min(); - // is the following line needed? - // let mut alphas2 = |q2| fun2.alphas_q2(q2); + let mut fun2 = |id, x, q2| { if !cfg.allow_extrapolation && (x < x_min2 || x > x_max2) { 0.0 @@ -249,7 +257,7 @@ pub fn convolve_scales( }; let mut cache = - LumiCache::with_two(pdg_id1, &mut fun1, pdg_id2, &mut fun2, &mut alphas1); + LumiCache::with_two(pdg_id1, &mut fun1, pdg_id2, &mut fun2, &mut alphas); grid.convolve(&mut cache, &orders, bins, channels, scales) } diff --git a/pineappl_cli/src/lib.rs b/pineappl_cli/src/lib.rs index 4980dae4..9fee723c 100644 --- a/pineappl_cli/src/lib.rs +++ b/pineappl_cli/src/lib.rs @@ -39,7 +39,7 @@ pub struct GlobalConfiguration { #[arg(long)] pub allow_extrapolation: bool, /// Choose the PDF/FF set for alpha_s. - #[arg(long)] + #[arg(default_value = "1", long)] pub use_alphas_from: usize, } From 044c7741df30145cb859b83878c03c734bba4e26 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Thu, 13 Jun 2024 15:29:58 +0200 Subject: [PATCH 11/27] Use zero-based indexing for `use_alphas_from` parameter --- pineappl_cli/src/helpers.rs | 18 ++++++++++-------- pineappl_cli/src/lib.rs | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 4a503f12..c8a94043 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -191,6 +191,9 @@ pub fn convolve_scales( 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() @@ -231,14 +234,13 @@ pub fn convolve_scales( let x_max2 = fun2.x_max(); let x_min2 = fun2.x_min(); - let mut alphas = |q2| { - if cfg.use_alphas_from == 1 { - fun1.alphas_q2(q2) - } else if cfg.use_alphas_from == 2 { - fun2.alphas_q2(q2) - } else { - panic!("Invalid value for use_alphas_from, please use '1' or '2'") - } + 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) { diff --git a/pineappl_cli/src/lib.rs b/pineappl_cli/src/lib.rs index 9fee723c..fdcabb0d 100644 --- a/pineappl_cli/src/lib.rs +++ b/pineappl_cli/src/lib.rs @@ -38,8 +38,8 @@ pub struct GlobalConfiguration { /// Allow extrapolation of PDFs outside their region of validity. #[arg(long)] pub allow_extrapolation: bool, - /// Choose the PDF/FF set for alpha_s. - #[arg(default_value = "1", long)] + /// Choose the PDF/FF set for the strong coupling. + #[arg(default_value = "0", long)] pub use_alphas_from: usize, } From be221cdef3cc1ad093bf4a7f61f424a2bb376c38 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Sat, 15 Jun 2024 09:39:28 +0200 Subject: [PATCH 12/27] Use new struct `ConvFun` in most subcommands --- pineappl_cli/src/channels.rs | 2 +- pineappl_cli/src/diff.rs | 19 ++++++++-------- pineappl_cli/src/evolve.rs | 21 +++++++++--------- pineappl_cli/src/export.rs | 25 ++++++++++----------- pineappl_cli/src/export/applgrid.rs | 8 +++++-- pineappl_cli/src/helpers.rs | 4 ++-- pineappl_cli/src/import.rs | 34 +++++++++++++++-------------- pineappl_cli/src/import/applgrid.rs | 8 +++++-- pineappl_cli/src/lib.rs | 2 +- pineappl_cli/src/orders.rs | 13 +++++------ pineappl_cli/tests/channels.rs | 2 +- pineappl_cli/tests/diff.rs | 8 +++---- pineappl_cli/tests/evolve.rs | 10 ++++----- pineappl_cli/tests/export.rs | 8 +++---- pineappl_cli/tests/import.rs | 16 +++++++------- pineappl_cli/tests/main.rs | 11 +++++----- pineappl_cli/tests/orders.rs | 6 ++--- 17 files changed, 102 insertions(+), 95 deletions(-) diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index 2bb74c93..eb059820 100644 --- a/pineappl_cli/src/channels.rs +++ b/pineappl_cli/src/channels.rs @@ -14,7 +14,7 @@ pub struct Opts { /// Path to the input grid. #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, - /// LHAPDF ID(s) or name of the PDF(s)/FF(s). + /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). #[arg(num_args = 1, required = true, value_delimiter = ',')] conv_funs: Vec, /// Show absolute numbers of each contribution. diff --git a/pineappl_cli/src/diff.rs b/pineappl_cli/src/diff.rs index 7e111e86..f8ca45f3 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, ConvFun, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{bail, Result}; use clap::{Parser, ValueHint}; @@ -6,7 +6,6 @@ use prettytable::{cell, Row}; use std::collections::HashSet; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; /// Compares the numerical content of two grids with each other. #[derive(Parser)] @@ -17,9 +16,9 @@ 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). + #[arg(num_args = 1, required = true, value_delimiter = ',')] + conv_funs: Vec, /// Ignore differences in the orders and sum them. #[arg(long)] ignore_orders: bool, @@ -128,7 +127,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(); @@ -150,7 +149,7 @@ impl Subcommand for Opts { let results1 = helpers::convolve( &grid1, - slice::from_mut(&mut pdf), + &mut conv_funs, &orders1, &[], &[], @@ -160,7 +159,7 @@ impl Subcommand for Opts { ); let results2 = helpers::convolve( &grid2, - slice::from_mut(&mut pdf), + &mut conv_funs, &orders2, &[], &[], @@ -206,7 +205,7 @@ impl Subcommand for Opts { .map(|&order| { helpers::convolve( &grid1, - slice::from_mut(&mut pdf), + &mut conv_funs, &[order], &[], &[], @@ -221,7 +220,7 @@ impl Subcommand for Opts { .map(|&order| { helpers::convolve( &grid2, - slice::from_mut(&mut pdf), + &mut conv_funs, &[order], &[], &[], diff --git a/pineappl_cli/src/evolve.rs b/pineappl_cli/src/evolve.rs index 71f4e166..c79021f1 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, ConvFun, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::{Parser, ValueHint}; @@ -7,7 +7,6 @@ use pineappl::fk_table::FkTable; use pineappl::grid::Grid; use std::path::{Path, PathBuf}; use std::process::ExitCode; -use std::slice; #[cfg(feature = "evolve")] mod eko { @@ -426,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, @@ -447,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 { @@ -507,9 +506,9 @@ 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). + #[arg(num_args = 1, required = true, value_delimiter = ',')] + conv_funs: Vec, /// Relative threshold between the table and the converted grid when comparison fails. #[arg(default_value = "1e-3", long)] accuracy: f64, @@ -543,10 +542,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, - slice::from_mut(&mut pdf), + &mut conv_funs, &self.orders, &[], &[], @@ -558,7 +557,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, @@ -566,7 +565,7 @@ impl Subcommand for Opts { )?; let evolved_results = helpers::convolve_scales( fk_table.grid(), - slice::from_mut(&mut pdf), + &mut conv_funs, &[], &[], &[], diff --git a/pineappl_cli/src/export.rs b/pineappl_cli/src/export.rs index 684abb43..bc7d7c9f 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, ConvFun, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -7,7 +7,6 @@ use pineappl::boc::Order; use pineappl::grid::Grid; use std::path::{Path, PathBuf}; use std::process::ExitCode; -use std::slice; #[cfg(feature = "applgrid")] mod applgrid; @@ -16,7 +15,7 @@ mod applgrid; fn convert_into_applgrid( output: &Path, grid: &Grid, - pdfset: &str, + conv_funs: &[ConvFun], member: usize, _: usize, discard_non_matching_scales: bool, @@ -25,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(), pdfset, member); + let results = applgrid::convolve_applgrid(applgrid.pin_mut(), conv_funs, member); Ok(("APPLgrid", results, 1, order_mask)) } @@ -34,7 +33,7 @@ fn convert_into_applgrid( fn convert_into_applgrid( _: &Path, _: &Grid, - _: &str, + _: &[ConvFun], _: usize, _: usize, _: bool, @@ -47,7 +46,7 @@ fn convert_into_applgrid( fn convert_into_grid( output: &Path, grid: &Grid, - pdfset: &str, + conv_funs: &[ConvFun], member: usize, scales: usize, discard_non_matching_scales: bool, @@ -57,7 +56,7 @@ fn convert_into_grid( return convert_into_applgrid( output, grid, - pdfset, + conv_funs, member, scales, discard_non_matching_scales, @@ -77,9 +76,9 @@ 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. + #[arg(num_args = 1, required = true, value_delimiter = ',')] + conv_funs: Vec, /// Relative threshold between the table and the converted grid when comparison fails. #[arg(default_value = "1e-10", long)] accuracy: f64, @@ -112,7 +111,7 @@ impl Subcommand for Opts { let (grid_type, results, scale_variations, order_mask) = convert_into_grid( &self.output, &grid, - &self.pdfset, + &self.conv_funs, 0, self.scales, self.discard_non_matching_scales, @@ -156,10 +155,10 @@ impl Subcommand for Opts { if results.is_empty() { println!("file was converted, but we cannot check the conversion for this type"); } else { - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let reference_results = helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &orders, &[], &[], diff --git a/pineappl_cli/src/export/applgrid.rs b/pineappl_cli/src/export/applgrid.rs index 869105f0..de7bb763 100644 --- a/pineappl_cli/src/export/applgrid.rs +++ b/pineappl_cli/src/export/applgrid.rs @@ -1,3 +1,4 @@ +use super::helpers::ConvFun; use anyhow::{anyhow, bail, Result}; use cxx::{let_cxx_string, UniquePtr}; use float_cmp::approx_eq; @@ -302,12 +303,15 @@ pub fn convert_into_applgrid( } // TODO: deduplicate this function from import -pub fn convolve_applgrid(grid: Pin<&mut grid>, pdfset: &str, member: usize) -> Vec { +pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &[ConvFun], member: usize) -> Vec { let nloops = grid.nloops(); + // TODO: add support for convolving an APPLgrid with two functions + assert_eq!(conv_funs.len(), 1); + ffi::grid_convolve( grid, - pdfset, + &conv_funs[0].lhapdf_name, member.try_into().unwrap(), nloops, 1.0, diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index c8a94043..d08180e1 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, Result}; use lhapdf::{Pdf, PdfSet}; use ndarray::Array3; use pineappl::convolutions::LumiCache; @@ -16,7 +16,7 @@ use std::str::FromStr; #[derive(Clone)] pub struct ConvFun { - lhapdf_name: String, + pub lhapdf_name: String, label: String, } diff --git a/pineappl_cli/src/import.rs b/pineappl_cli/src/import.rs index db1c8c68..fe538887 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, ConvFun, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -6,7 +6,6 @@ use clap::{Parser, ValueHint}; use pineappl::grid::Grid; use std::path::{Path, PathBuf}; use std::process::ExitCode; -use std::slice; #[cfg(feature = "applgrid")] mod applgrid; @@ -19,7 +18,7 @@ mod fktable; fn convert_applgrid( input: &Path, alpha: u32, - pdfset: &str, + conv_funs: &[ConvFun], member: usize, dis_pid: i32, _: usize, @@ -30,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(), pdfset, member); + let results = applgrid::convolve_applgrid(grid.pin_mut(), conv_funs, member); Ok(("APPLgrid", pgrid, results, 1)) } @@ -39,7 +38,7 @@ fn convert_applgrid( fn convert_applgrid( _: &Path, _: u32, - _: &str, + _: &[ConvFun], _: usize, _: i32, _: usize, @@ -53,7 +52,7 @@ fn convert_applgrid( fn convert_fastnlo( input: &Path, alpha: u32, - pdfset: &str, + conv_funs: &[ConvFun], member: usize, dis_pid: i32, scales: usize, @@ -63,9 +62,12 @@ fn convert_fastnlo( use pineappl_fastnlo::ffi; use std::ptr; + // TODO: convert this into an error? + assert_eq!(conv_funs.len(), 1); + let mut file = ffi::make_fastnlo_lhapdf_with_name_file_set( input.to_str().unwrap(), - pdfset, + &conv_funs[0].lhapdf_name, member.try_into().unwrap(), ); @@ -148,7 +150,7 @@ fn convert_fktable(_: &Path, _: i32) -> Result<(&'static str, Grid, Vec, us fn convert_grid( input: &Path, alpha: u32, - pdfset: &str, + conv_funs: &[ConvFun], member: usize, dis_pid: i32, scales: usize, @@ -164,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, conv_funs, 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, pdfset, member, dis_pid, scales); + return convert_applgrid(input, alpha, conv_funs, member, dis_pid, scales); } } @@ -211,9 +213,9 @@ 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. + #[arg(num_args = 1, required = true, value_delimiter = ',')] + conv_funs: Vec, /// LO coupling power in alpha. #[arg(default_value_t = 0, long)] alpha: u32, @@ -258,7 +260,7 @@ impl Subcommand for Opts { let (grid_type, mut grid, reference_results, scale_variations) = convert_grid( &self.input, self.alpha, - &self.pdfset, + &self.conv_funs, 0, self.dis_pid, self.scales, @@ -275,10 +277,10 @@ impl Subcommand for Opts { if reference_results.is_empty() { println!("file was converted, but we cannot check the conversion for this type"); } else { - let mut pdf = helpers::create_pdf(&self.pdfset)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let results = helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &[], &[], &[], diff --git a/pineappl_cli/src/import/applgrid.rs b/pineappl_cli/src/import/applgrid.rs index 76baff86..025af06e 100644 --- a/pineappl_cli/src/import/applgrid.rs +++ b/pineappl_cli/src/import/applgrid.rs @@ -1,3 +1,4 @@ +use super::helpers::ConvFun; use anyhow::Result; use pineappl::boc::{Channel, Order}; use pineappl::convolutions::Convolution; @@ -245,12 +246,15 @@ pub fn convert_applgrid(grid: Pin<&mut grid>, alpha: u32, dis_pid: i32) -> Resul Ok(grid0) } -pub fn convolve_applgrid(grid: Pin<&mut grid>, pdfset: &str, member: usize) -> Vec { +pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &[ConvFun], member: usize) -> Vec { let nloops = grid.nloops(); + // TODO: add support for convolving an APPLgrid with two functions + assert_eq!(conv_funs.len(), 1); + ffi::grid_convolve( grid, - pdfset, + &conv_funs[0].lhapdf_name, member.try_into().unwrap(), nloops, 1.0, diff --git a/pineappl_cli/src/lib.rs b/pineappl_cli/src/lib.rs index fdcabb0d..04ee204b 100644 --- a/pineappl_cli/src/lib.rs +++ b/pineappl_cli/src/lib.rs @@ -39,7 +39,7 @@ pub struct GlobalConfiguration { #[arg(long)] pub allow_extrapolation: bool, /// Choose the PDF/FF set for the strong coupling. - #[arg(default_value = "0", long)] + #[arg(default_value = "0", long, value_name = "IDX")] pub use_alphas_from: usize, } diff --git a/pineappl_cli/src/orders.rs b/pineappl_cli/src/orders.rs index ef484086..d5346e73 100644 --- a/pineappl_cli/src/orders.rs +++ b/pineappl_cli/src/orders.rs @@ -1,11 +1,10 @@ -use super::helpers::{self, ConvoluteMode}; +use super::helpers::{self, ConvFun, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::{Parser, ValueHint}; use prettytable::{cell, Row}; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; /// Shows the predictions for all bin for each order separately. #[derive(Parser)] @@ -13,9 +12,9 @@ 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). + #[arg(num_args = 1, required = true, value_delimiter = ',')] + conv_funs: Vec, /// Show absolute numbers of each perturbative order. #[arg(long, short)] absolute: bool, @@ -43,7 +42,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() @@ -67,7 +66,7 @@ impl Subcommand for Opts { .map(|order| { helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &[(order.alphas, order.alpha)], &[], &[], diff --git a/pineappl_cli/tests/channels.rs b/pineappl_cli/tests/channels.rs index 21db2f5f..9ef0bfcc 100644 --- a/pineappl_cli/tests/channels.rs +++ b/pineappl_cli/tests/channels.rs @@ -6,7 +6,7 @@ Usage: pineappl channels [OPTIONS] ... Arguments: Path to the input grid - ... LHAPDF ID(s) or name of the PDF(s)/FF(s) + ... LHAPDF ID(s) or name(s) of the PDF(s)/FF(s) Options: -a, --absolute Show absolute numbers of each contribution diff --git a/pineappl_cli/tests/diff.rs b/pineappl_cli/tests/diff.rs index cba20144..b8213ba2 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..03920c70 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..ec74a1e2 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..4d420eb2 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..19191f15 100644 --- a/pineappl_cli/tests/main.rs +++ b/pineappl_cli/tests/main.rs @@ -23,11 +23,12 @@ Commands: 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..80ab1f6f 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 From cfcf02711cebb49028327012a4d31f9a7dfabecc Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 17 Jun 2024 09:02:41 +0200 Subject: [PATCH 13/27] Migrate `analyze` subcommand to use `ConvFun` --- pineappl_cli/src/analyze.rs | 16 ++++++++-------- pineappl_cli/src/helpers.rs | 13 ++++++++++++- pineappl_cli/tests/analyze.rs | 4 ++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/pineappl_cli/src/analyze.rs b/pineappl_cli/src/analyze.rs index 134556b1..62a6c99f 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, ConvoluteMode, VecConvFun}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::TypedValueParser; @@ -6,7 +6,6 @@ use clap::{value_parser, Parser, ValueHint}; use prettytable::{cell, Row}; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; /// Perform various analyses with grids. #[derive(Parser)] @@ -40,9 +39,10 @@ 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). + #[arg(value_parser = helpers::parse_conv_funs)] + // TODO: it would be better to use `Vec`, but this consumes all following arguments + conv_funs: VecConvFun, /// Order defining the K factors. #[arg(value_parser = helpers::parse_order)] order: (u32, u32), @@ -66,7 +66,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.0)?; let orders_den = if self.orders_den.is_empty() { grid.orders() @@ -88,7 +88,7 @@ impl Subcommand for CkfOpts { lumi_mask[lumi] = true; helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &[self.order], &[], &lumi_mask, @@ -104,7 +104,7 @@ impl Subcommand for CkfOpts { lumi_mask[lumi] = true; helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &orders_den, &[], &lumi_mask, diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index d08180e1..b8ac6523 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -1,5 +1,5 @@ use super::GlobalConfiguration; -use anyhow::{anyhow, ensure, Context, Result}; +use anyhow::{ensure, Context, Result}; use lhapdf::{Pdf, PdfSet}; use ndarray::Array3; use pineappl::convolutions::LumiCache; @@ -37,6 +37,17 @@ impl FromStr for ConvFun { } } +#[derive(Clone)] +pub struct VecConvFun(pub Vec); + +pub fn parse_conv_funs(arg: &str) -> std::result::Result { + Ok(VecConvFun( + arg.split(',') + .map(|conv_fun| ConvFun::from_str(conv_fun).map_err(|err| format!("{err}"))) + .collect::>()?, + )) +} + pub fn create_conv_funs(funs: &[ConvFun]) -> Result> { Ok(funs .iter() 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 From a507af80c939eaf04e213c3fb80d43efcd290dad Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 17 Jun 2024 09:50:25 +0200 Subject: [PATCH 14/27] Replace `ConvFun` with `ConvFuns` --- pineappl_cli/src/analyze.rs | 8 +++--- pineappl_cli/src/channels.rs | 5 ++-- pineappl_cli/src/diff.rs | 5 ++-- pineappl_cli/src/evolve.rs | 5 ++-- pineappl_cli/src/export.rs | 11 ++++---- pineappl_cli/src/export/applgrid.rs | 8 +++--- pineappl_cli/src/helpers.rs | 39 +++++++++++------------------ pineappl_cli/src/import.rs | 19 +++++++------- pineappl_cli/src/import/applgrid.rs | 8 +++--- pineappl_cli/src/orders.rs | 5 ++-- pineappl_cli/tests/channels.rs | 10 ++++---- pineappl_cli/tests/diff.rs | 8 +++--- pineappl_cli/tests/evolve.rs | 10 ++++---- pineappl_cli/tests/export.rs | 8 +++--- pineappl_cli/tests/import.rs | 16 ++++++------ pineappl_cli/tests/orders.rs | 6 ++--- 16 files changed, 76 insertions(+), 95 deletions(-) diff --git a/pineappl_cli/src/analyze.rs b/pineappl_cli/src/analyze.rs index 62a6c99f..3c644c48 100644 --- a/pineappl_cli/src/analyze.rs +++ b/pineappl_cli/src/analyze.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvoluteMode, VecConvFun}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::TypedValueParser; @@ -40,9 +40,7 @@ pub struct CkfOpts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). - #[arg(value_parser = helpers::parse_conv_funs)] - // TODO: it would be better to use `Vec`, but this consumes all following arguments - conv_funs: VecConvFun, + conv_funs: ConvFuns, /// Order defining the K factors. #[arg(value_parser = helpers::parse_order)] order: (u32, u32), @@ -66,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 conv_funs = helpers::create_conv_funs(&self.conv_funs.0)?; + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; let orders_den = if self.orders_den.is_empty() { grid.orders() diff --git a/pineappl_cli/src/channels.rs b/pineappl_cli/src/channels.rs index eb059820..53173a1e 100644 --- a/pineappl_cli/src/channels.rs +++ b/pineappl_cli/src/channels.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvFun, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::builder::TypedValueParser; @@ -15,8 +15,7 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). - #[arg(num_args = 1, required = true, value_delimiter = ',')] - conv_funs: Vec, + conv_funs: ConvFuns, /// Show absolute numbers of each contribution. #[arg(long, short)] absolute: bool, diff --git a/pineappl_cli/src/diff.rs b/pineappl_cli/src/diff.rs index f8ca45f3..4e6e4858 100644 --- a/pineappl_cli/src/diff.rs +++ b/pineappl_cli/src/diff.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvFun, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{bail, Result}; use clap::{Parser, ValueHint}; @@ -17,8 +17,7 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input2: PathBuf, /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). - #[arg(num_args = 1, required = true, value_delimiter = ',')] - conv_funs: Vec, + conv_funs: ConvFuns, /// Ignore differences in the orders and sum them. #[arg(long)] ignore_orders: bool, diff --git a/pineappl_cli/src/evolve.rs b/pineappl_cli/src/evolve.rs index c79021f1..b2fff58d 100644 --- a/pineappl_cli/src/evolve.rs +++ b/pineappl_cli/src/evolve.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvFun, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::{Parser, ValueHint}; @@ -507,8 +507,7 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] output: PathBuf, /// LHAPDF ID(s) or name of the PDF(s)/FF(s). - #[arg(num_args = 1, required = true, value_delimiter = ',')] - conv_funs: Vec, + conv_funs: ConvFuns, /// Relative threshold between the table and the converted grid when comparison fails. #[arg(default_value = "1e-3", long)] accuracy: f64, diff --git a/pineappl_cli/src/export.rs b/pineappl_cli/src/export.rs index bc7d7c9f..fd90b900 100644 --- a/pineappl_cli/src/export.rs +++ b/pineappl_cli/src/export.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvFun, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -15,7 +15,7 @@ mod applgrid; fn convert_into_applgrid( output: &Path, grid: &Grid, - conv_funs: &[ConvFun], + conv_funs: &ConvFuns, member: usize, _: usize, discard_non_matching_scales: bool, @@ -33,7 +33,7 @@ fn convert_into_applgrid( fn convert_into_applgrid( _: &Path, _: &Grid, - _: &[ConvFun], + _: &ConvFuns, _: usize, _: usize, _: bool, @@ -46,7 +46,7 @@ fn convert_into_applgrid( fn convert_into_grid( output: &Path, grid: &Grid, - conv_funs: &[ConvFun], + conv_funs: &ConvFuns, member: usize, scales: usize, discard_non_matching_scales: bool, @@ -77,8 +77,7 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] output: PathBuf, /// LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with. - #[arg(num_args = 1, required = true, value_delimiter = ',')] - conv_funs: Vec, + conv_funs: ConvFuns, /// Relative threshold between the table and the converted grid when comparison fails. #[arg(default_value = "1e-10", long)] accuracy: f64, diff --git a/pineappl_cli/src/export/applgrid.rs b/pineappl_cli/src/export/applgrid.rs index de7bb763..a900060f 100644 --- a/pineappl_cli/src/export/applgrid.rs +++ b/pineappl_cli/src/export/applgrid.rs @@ -1,4 +1,4 @@ -use super::helpers::ConvFun; +use super::helpers::ConvFuns; use anyhow::{anyhow, bail, Result}; use cxx::{let_cxx_string, UniquePtr}; use float_cmp::approx_eq; @@ -303,15 +303,15 @@ pub fn convert_into_applgrid( } // TODO: deduplicate this function from import -pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &[ConvFun], member: usize) -> Vec { +pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &ConvFuns, member: usize) -> Vec { let nloops = grid.nloops(); // TODO: add support for convolving an APPLgrid with two functions - assert_eq!(conv_funs.len(), 1); + assert_eq!(conv_funs.lhapdf_names.len(), 1); ffi::grid_convolve( grid, - &conv_funs[0].lhapdf_name, + &conv_funs.lhapdf_names[0], member.try_into().unwrap(), nloops, 1.0, diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index b8ac6523..14a3d21e 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -15,47 +15,36 @@ use std::process::ExitCode; use std::str::FromStr; #[derive(Clone)] -pub struct ConvFun { - pub lhapdf_name: String, - label: String, +pub struct ConvFuns { + pub lhapdf_names: Vec, + pub label: String, } -impl FromStr for ConvFun { +impl FromStr for ConvFuns { type Err = Infallible; fn from_str(arg: &str) -> std::result::Result { Ok(arg.split_once('=').map_or_else( - || ConvFun { - lhapdf_name: arg.to_owned(), + || Self { + lhapdf_names: arg.split(',').map(ToOwned::to_owned).collect(), label: arg.to_owned(), }, - |(lhapdf_name, label)| ConvFun { - lhapdf_name: lhapdf_name.to_owned(), + |(lhapdf_names, label)| Self { + lhapdf_names: lhapdf_names.split(',').map(ToOwned::to_owned).collect(), label: label.to_owned(), }, )) } } -#[derive(Clone)] -pub struct VecConvFun(pub Vec); - -pub fn parse_conv_funs(arg: &str) -> std::result::Result { - Ok(VecConvFun( - arg.split(',') - .map(|conv_fun| ConvFun::from_str(conv_fun).map_err(|err| format!("{err}"))) - .collect::>()?, - )) -} - -pub fn create_conv_funs(funs: &[ConvFun]) -> Result> { +pub fn create_conv_funs(funs: &ConvFuns) -> Result> { Ok(funs + .lhapdf_names .iter() - .map(|fun| { - fun.lhapdf_name.parse().map_or_else( - |_| Pdf::with_setname_and_nmem(&fun.lhapdf_name), - Pdf::with_lhaid, - ) + .map(|lhapdf_name| { + lhapdf_name + .parse() + .map_or_else(|_| Pdf::with_setname_and_nmem(lhapdf_name), Pdf::with_lhaid) }) .collect::>()?) } diff --git a/pineappl_cli/src/import.rs b/pineappl_cli/src/import.rs index fe538887..cfee13b1 100644 --- a/pineappl_cli/src/import.rs +++ b/pineappl_cli/src/import.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvFun, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::{anyhow, Result}; use clap::builder::{PossibleValuesParser, TypedValueParser}; @@ -18,7 +18,7 @@ mod fktable; fn convert_applgrid( input: &Path, alpha: u32, - conv_funs: &[ConvFun], + conv_funs: &ConvFuns, member: usize, dis_pid: i32, _: usize, @@ -38,7 +38,7 @@ fn convert_applgrid( fn convert_applgrid( _: &Path, _: u32, - _: &[ConvFun], + _: &ConvFuns, _: usize, _: i32, _: usize, @@ -52,7 +52,7 @@ fn convert_applgrid( fn convert_fastnlo( input: &Path, alpha: u32, - conv_funs: &[ConvFun], + conv_funs: &ConvFuns, member: usize, dis_pid: i32, scales: usize, @@ -63,11 +63,11 @@ fn convert_fastnlo( use std::ptr; // TODO: convert this into an error? - assert_eq!(conv_funs.len(), 1); + assert_eq!(conv_funs.lhapdf_names.len(), 1); let mut file = ffi::make_fastnlo_lhapdf_with_name_file_set( input.to_str().unwrap(), - &conv_funs[0].lhapdf_name, + &conv_funs.lhapdf_names[0], member.try_into().unwrap(), ); @@ -121,7 +121,7 @@ fn convert_fastnlo( fn convert_fastnlo( _: &Path, _: u32, - _: &str, + _: &ConvFuns, _: usize, _: i32, _: usize, @@ -150,7 +150,7 @@ fn convert_fktable(_: &Path, _: i32) -> Result<(&'static str, Grid, Vec, us fn convert_grid( input: &Path, alpha: u32, - conv_funs: &[ConvFun], + conv_funs: &ConvFuns, member: usize, dis_pid: i32, scales: usize, @@ -214,8 +214,7 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] output: PathBuf, /// LHAPDF ID(s) or name of the PDF(s)/FF(s) to check the converted grid with. - #[arg(num_args = 1, required = true, value_delimiter = ',')] - conv_funs: Vec, + conv_funs: ConvFuns, /// LO coupling power in alpha. #[arg(default_value_t = 0, long)] alpha: u32, diff --git a/pineappl_cli/src/import/applgrid.rs b/pineappl_cli/src/import/applgrid.rs index 025af06e..e567c24b 100644 --- a/pineappl_cli/src/import/applgrid.rs +++ b/pineappl_cli/src/import/applgrid.rs @@ -1,4 +1,4 @@ -use super::helpers::ConvFun; +use super::helpers::ConvFuns; use anyhow::Result; use pineappl::boc::{Channel, Order}; use pineappl::convolutions::Convolution; @@ -246,15 +246,15 @@ pub fn convert_applgrid(grid: Pin<&mut grid>, alpha: u32, dis_pid: i32) -> Resul Ok(grid0) } -pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &[ConvFun], member: usize) -> Vec { +pub fn convolve_applgrid(grid: Pin<&mut grid>, conv_funs: &ConvFuns, member: usize) -> Vec { let nloops = grid.nloops(); // TODO: add support for convolving an APPLgrid with two functions - assert_eq!(conv_funs.len(), 1); + assert_eq!(conv_funs.lhapdf_names.len(), 1); ffi::grid_convolve( grid, - &conv_funs[0].lhapdf_name, + &conv_funs.lhapdf_names[0], member.try_into().unwrap(), nloops, 1.0, diff --git a/pineappl_cli/src/orders.rs b/pineappl_cli/src/orders.rs index d5346e73..8a229251 100644 --- a/pineappl_cli/src/orders.rs +++ b/pineappl_cli/src/orders.rs @@ -1,4 +1,4 @@ -use super::helpers::{self, ConvFun, ConvoluteMode}; +use super::helpers::{self, ConvFuns, ConvoluteMode}; use super::{GlobalConfiguration, Subcommand}; use anyhow::Result; use clap::{Parser, ValueHint}; @@ -13,8 +13,7 @@ pub struct Opts { #[arg(value_hint = ValueHint::FilePath)] input: PathBuf, /// LHAPDF ID(s) or name(s) of the PDF(s)/FF(s). - #[arg(num_args = 1, required = true, value_delimiter = ',')] - conv_funs: Vec, + conv_funs: ConvFuns, /// Show absolute numbers of each perturbative order. #[arg(long, short)] absolute: bool, diff --git a/pineappl_cli/tests/channels.rs b/pineappl_cli/tests/channels.rs index 9ef0bfcc..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(s) or name(s) of the PDF(s)/FF(s) + 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 @@ -133,9 +133,9 @@ const DONT_SORT_STR: &str = "b etal c size c size c size c size c size "; const MISSING_CONV_FUN_STR: &str = "error: the following required arguments were not provided: - ... + -Usage: pineappl channels ... +Usage: pineappl channels For more information, try '--help'. "; diff --git a/pineappl_cli/tests/diff.rs b/pineappl_cli/tests/diff.rs index b8213ba2..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(s) or name(s) of the PDF(s)/FF(s) + 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 03920c70..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(s) or name of the PDF(s)/FF(s) + 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 ec74a1e2..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(s) or name of the PDF(s)/FF(s) 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 4d420eb2..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(s) or name of the PDF(s)/FF(s) 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(s) or name of the PDF(s)/FF(s) 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/orders.rs b/pineappl_cli/tests/orders.rs index 80ab1f6f..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(s) or name(s) of the PDF(s)/FF(s) + 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 From 14366184659adeaaac6930abb127e24a9483499a Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 17 Jun 2024 09:51:28 +0200 Subject: [PATCH 15/27] Migrate subcommand `convolve` to `ConvFuns` --- pineappl_cli/src/convolve.rs | 21 ++++++++++----------- pineappl_cli/tests/convolve.rs | 6 +++--- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/pineappl_cli/src/convolve.rs b/pineappl_cli/src/convolve.rs index 91ee8bfe..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}; @@ -6,7 +6,6 @@ use prettytable::{cell, Row}; use std::ops::RangeInclusive; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; /// Convolutes a PineAPPL grid with a PDF set. #[derive(Parser)] @@ -16,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, @@ -50,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, - slice::from_mut(&mut pdf), + &mut conv_funs_0, &self.orders, &bins, &[], @@ -78,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, - slice::from_mut(&mut pdf), + &mut conv_funs, &self.orders, &bins, &[], @@ -109,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/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 From 699851ce260b7a5cd354e447b4441a134b84f1e0 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Mon, 17 Jun 2024 16:07:14 +0200 Subject: [PATCH 16/27] Remove switch `--pdf-with-scale-cov` from `uncert` subcommand --- CHANGELOG.md | 1 + pineappl_cli/src/uncert.rs | 71 +++++++++--------------------------- pineappl_cli/tests/uncert.rs | 53 ++++++--------------------- 3 files changed, 30 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c24e4a4b..1b09c0da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,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/uncert.rs b/pineappl_cli/src/uncert.rs index 09bec460..81d7e25a 100644 --- a/pineappl_cli/src/uncert.rs +++ b/pineappl_cli/src/uncert.rs @@ -17,16 +17,6 @@ struct Group { /// Calculate the PDF uncertainties. #[arg(long)] pdf: bool, - /// Calculate the combined PDF and scale uncertainty using the covariance method. - #[arg( - default_missing_value = "7", - num_args = 0..=1, - long, - require_equals = true, - value_name = "SCALES", - value_parser = PossibleValuesParser::new(["3", "7", "9"]).try_map(|s| s.parse::()) - )] - pdf_with_scale_cov: Option, /// Show absolute numbers of the scale-varied results. #[arg( default_missing_value = "7", @@ -111,7 +101,7 @@ impl Subcommand for Opts { }, ); - let pdf_results = if self.group.pdf || self.group.pdf_with_scale_cov.is_some() { + let pdf_results = if self.group.pdf { ThreadPoolBuilder::new() .num_threads(self.threads) .build_global() @@ -145,7 +135,6 @@ impl Subcommand for Opts { .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); @@ -179,11 +168,6 @@ impl Subcommand for Opts { 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)); - } - if let Some(scales) = self.group.scale_abs { for scale in &helpers::SCALES_VECTOR[0..scales.into()] { title.add_cell(cell!(c->format!("(r={},f={})\n[{}]", scale.0, scale.1, y_unit))); @@ -206,24 +190,23 @@ 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)?; + let (pdf_cen, pdf_neg, pdf_pos) = if self.group.pdf { + 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) - }; + ( + 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}"))); @@ -240,26 +223,6 @@ impl Subcommand for Opts { 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))); - } - if let Some(scales) = self.group.scale_abs { for result in scale_res.iter().take(scales.into()) { row.add_cell(cell!(r->format!("{:.*e}", self.digits_abs, result))); diff --git a/pineappl_cli/tests/uncert.rs b/pineappl_cli/tests/uncert.rs index 43b46538..f0ab1b7d 100644 --- a/pineappl_cli/tests/uncert.rs +++ b/pineappl_cli/tests/uncert.rs @@ -4,25 +4,24 @@ use std::thread; const HELP_STR: &str = "Calculates scale and PDF uncertainties -Usage: pineappl uncert [OPTIONS] <--pdf|--pdf-with-scale-cov[=]|--scale-abs[=]|--scale-cov[=]|--scale-env[=]> +Usage: pineappl uncert [OPTIONS] <--pdf|--scale-abs[=]|--scale-cov[=]|--scale-env[=]> Arguments: Path to the input grid LHAPDF id or name of the PDF set 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 + --pdf Calculate the PDF 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 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 "; const DEFAULT_STR: &str = "b etal dsig/detal PDF central PDF @@ -143,19 +142,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") @@ -314,18 +300,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); -} From 5f8e576bff7ef0ea31251ea034de8d76bf430c2a Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Tue, 18 Jun 2024 22:45:01 +0200 Subject: [PATCH 17/27] Migrate `uncert` to use `ConvFun` --- CHANGELOG.md | 4 + pineappl_cli/src/uncert.rs | 137 ++++++++++++++++++----------------- pineappl_cli/tests/uncert.rs | 119 +++++++++++++++--------------- 3 files changed, 136 insertions(+), 124 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b09c0da..38c80703 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,10 @@ 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 ### Removed diff --git a/pineappl_cli/src/uncert.rs b/pineappl_cli/src/uncert.rs index 81d7e25a..539d75d3 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}; @@ -8,15 +8,21 @@ use rayon::{prelude::*, ThreadPoolBuilder}; use std::num::NonZeroUsize; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; use std::thread; #[derive(Args)] #[group(multiple = true, required = true)] struct Group { - /// Calculate the PDF uncertainties. - #[arg(long)] - pdf: bool, + /// Calculate convolution function uncertainties. + #[arg( + default_missing_value = "0", + num_args = 0..=1, + long, + require_equals = true, + value_delimiter = ',', + value_name = "IDX" + )] + conv_fun: Vec, /// Show absolute numbers of the scale-varied results. #[arg( default_missing_value = "7", @@ -49,18 +55,17 @@ struct Group { scale_env: Option, } -/// Calculates scale and PDF uncertainties. +/// Calculates 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. @@ -89,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, @@ -101,34 +106,53 @@ impl Subcommand for Opts { }, ); - let pdf_results = if self.group.pdf { - 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 = conv_funs[index].set(); + let results: Vec<_> = set + .mk_pdfs()? + .into_par_iter() + .map(|fun| { + // TODO: do not create objects that are getting overwritten in any case + let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; + conv_funs[index] = fun; - set.mk_pdfs()? - .into_par_iter() - .flat_map(|mut pdf| { - helpers::convolve( - &grid, - slice::from_mut(&mut pdf), - &self.orders, - &[], - &[], - 1, - if self.integrated { - ConvoluteMode::Integrated - } else { - ConvoluteMode::Normal - }, - cfg, - ) - }) - .collect() - } else { - vec![] - }; + Ok::<_, Error>(helpers::convolve( + &grid, + &mut conv_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(); + + results + .into_iter() + .map(|values| Ok(set.uncertainty(&values, self.cl, false)?)) + .collect::>() + }) + .collect::>()?; let scales_max = self .group .scale_env @@ -140,7 +164,7 @@ impl Subcommand for Opts { .unwrap_or(1); let scale_results = helpers::convolve( &grid, - slice::from_mut(&mut helpers::create_pdf(&self.pdfset)?), + &mut conv_funs, &self.orders, &[], &[], @@ -163,9 +187,10 @@ 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)); + for &index in &self.group.conv_fun { + title.add_cell( + cell!(c->format!("{}", self.conv_funs.lhapdf_names[index])).with_hspan(3), + ); } if let Some(scales) = self.group.scale_abs { @@ -190,24 +215,6 @@ impl Subcommand for Opts { .zip(scale_results.chunks_exact(scales_max)) .enumerate() { - let (pdf_cen, pdf_neg, pdf_pos) = if self.group.pdf { - 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 { @@ -217,10 +224,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))); + 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/uncert.rs b/pineappl_cli/tests/uncert.rs index f0ab1b7d..0492ea5b 100644 --- a/pineappl_cli/tests/uncert.rs +++ b/pineappl_cli/tests/uncert.rs @@ -2,20 +2,20 @@ use assert_cmd::Command; use std::num::NonZeroUsize; use std::thread; -const HELP_STR: &str = "Calculates scale and PDF uncertainties +const HELP_STR: &str = "Calculates scale and convolution function uncertainties -Usage: pineappl uncert [OPTIONS] <--pdf|--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 + --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 PDF uncertainties [default: 68.26894921370858] + --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: {}] @@ -24,56 +24,57 @@ Options: -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] +-+----+----+-----------+-----------+---------+---------+-----------+-------+------- +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] +-+----+----+-----------+-----------+---------+--------- +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] +-+----+----+-----------+-----------+---------+--------- +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 = @@ -160,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() @@ -176,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", @@ -193,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", @@ -210,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", From 0020bdec057e795b6af0cdd5b4e081597bde95c7 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Wed, 19 Jun 2024 07:27:16 +0200 Subject: [PATCH 18/27] Fix main test --- pineappl_cli/src/uncert.rs | 2 +- pineappl_cli/tests/main.rs | 2 +- pineappl_cli/tests/uncert.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pineappl_cli/src/uncert.rs b/pineappl_cli/src/uncert.rs index 539d75d3..fcae668b 100644 --- a/pineappl_cli/src/uncert.rs +++ b/pineappl_cli/src/uncert.rs @@ -55,7 +55,7 @@ struct Group { scale_env: Option, } -/// Calculates scale and convolution function uncertainties. +/// Calculate scale and convolution function uncertainties. #[derive(Parser)] pub struct Opts { /// Path to the input grid. diff --git a/pineappl_cli/tests/main.rs b/pineappl_cli/tests/main.rs index 19191f15..0ba04dce 100644 --- a/pineappl_cli/tests/main.rs +++ b/pineappl_cli/tests/main.rs @@ -19,7 +19,7 @@ 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: diff --git a/pineappl_cli/tests/uncert.rs b/pineappl_cli/tests/uncert.rs index 0492ea5b..774751e8 100644 --- a/pineappl_cli/tests/uncert.rs +++ b/pineappl_cli/tests/uncert.rs @@ -2,7 +2,7 @@ use assert_cmd::Command; use std::num::NonZeroUsize; use std::thread; -const HELP_STR: &str = "Calculates scale and convolution function uncertainties +const HELP_STR: &str = "Calculate scale and convolution function uncertainties Usage: pineappl uncert [OPTIONS] <--conv-fun[=]|--scale-abs[=]|--scale-cov[=]|--scale-env[=]> From ab9bd08e4e9aa5d633adbc18e5024d50be1ce6e3 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Fri, 21 Jun 2024 14:40:28 +0200 Subject: [PATCH 19/27] Add `members` variable to `ConvFuns` --- pineappl_cli/src/helpers.rs | 71 +++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 14a3d21e..b8035f49 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -1,12 +1,11 @@ use super::GlobalConfiguration; -use anyhow::{ensure, Context, Result}; +use anyhow::{ensure, Context, Error, Result}; use lhapdf::{Pdf, PdfSet}; use ndarray::Array3; use pineappl::convolutions::LumiCache; use pineappl::grid::Grid; use prettytable::format::{FormatBuilder, LinePosition, LineSeparator}; use prettytable::Table; -use std::convert::Infallible; use std::fs::{File, OpenOptions}; use std::iter; use std::ops::RangeInclusive; @@ -14,26 +13,34 @@ use std::path::Path; use std::process::ExitCode; use std::str::FromStr; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct ConvFuns { pub lhapdf_names: Vec, + pub members: Vec>, pub label: String, } impl FromStr for ConvFuns { - type Err = Infallible; + type Err = Error; fn from_str(arg: &str) -> std::result::Result { - Ok(arg.split_once('=').map_or_else( - || Self { - lhapdf_names: arg.split(',').map(ToOwned::to_owned).collect(), - label: arg.to_owned(), - }, - |(lhapdf_names, label)| Self { - lhapdf_names: lhapdf_names.split(',').map(ToOwned::to_owned).collect(), - label: label.to_owned(), - }, - )) + 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::>()?; + + Ok(Self { + lhapdf_names, + members, + label: label.to_owned(), + }) } } @@ -41,10 +48,16 @@ pub fn create_conv_funs(funs: &ConvFuns) -> Result> { Ok(funs .lhapdf_names .iter() - .map(|lhapdf_name| { - lhapdf_name - .parse() - .map_or_else(|_| Pdf::with_setname_and_nmem(lhapdf_name), Pdf::with_lhaid) + .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::>()?) } @@ -433,3 +446,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() + } + ); + } +} From 4ff0319148c4fb0a9d780fd81f7d20d035949d28 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Fri, 21 Jun 2024 14:45:47 +0200 Subject: [PATCH 20/27] Add new helper function `create_conv_funs_for_set` and use it in `uncert` --- pineappl_cli/src/helpers.rs | 35 ++++++++++++++++++++++++++++++++++- pineappl_cli/src/uncert.rs | 13 ++++--------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index b8035f49..34cab50e 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -1,5 +1,5 @@ use super::GlobalConfiguration; -use anyhow::{ensure, Context, Error, Result}; +use anyhow::{anyhow, ensure, Context, Error, Result}; use lhapdf::{Pdf, PdfSet}; use ndarray::Array3; use pineappl::convolutions::LumiCache; @@ -62,6 +62,39 @@ pub fn create_conv_funs(funs: &ConvFuns) -> Result> { .collect::>()?) } +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 create_pdf(pdf: &str) -> Result { let pdf = pdf.split_once('=').map_or(pdf, |(name, _)| name); diff --git a/pineappl_cli/src/uncert.rs b/pineappl_cli/src/uncert.rs index fcae668b..5334a14a 100644 --- a/pineappl_cli/src/uncert.rs +++ b/pineappl_cli/src/uncert.rs @@ -116,18 +116,13 @@ impl Subcommand for Opts { .conv_fun .iter() .map(|&index| { - let set = conv_funs[index].set(); - let results: Vec<_> = set - .mk_pdfs()? + let (set, funs) = helpers::create_conv_funs_for_set(&self.conv_funs, index)?; + let results: Vec<_> = funs .into_par_iter() - .map(|fun| { - // TODO: do not create objects that are getting overwritten in any case - let mut conv_funs = helpers::create_conv_funs(&self.conv_funs)?; - conv_funs[index] = fun; - + .map(|mut funs| { Ok::<_, Error>(helpers::convolve( &grid, - &mut conv_funs, + &mut funs, &self.orders, &[], &[], From a29639bd476971710672ec83fd6239832f532c9e Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Fri, 21 Jun 2024 14:54:48 +0200 Subject: [PATCH 21/27] Migrate `pull` subcommand to use `ConvFuns` --- pineappl_cli/src/pull.rs | 96 ++++++++++++++++++++------------------ pineappl_cli/tests/pull.rs | 9 ++-- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/pineappl_cli/src/pull.rs b/pineappl_cli/src/pull.rs index ee39bd6e..99b2c64f 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}; @@ -8,7 +8,6 @@ use rayon::{prelude::*, ThreadPoolBuilder}; use std::num::NonZeroUsize; use std::path::PathBuf; use std::process::ExitCode; -use std::slice; use std::thread; // TODO: do we need the CL parameter? @@ -19,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 for the convolution function 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, @@ -52,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) @@ -64,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, - slice::from_mut(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, - slice::from_mut(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(); @@ -113,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 { @@ -142,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| { @@ -150,7 +148,7 @@ impl Subcommand for Opts { channel_mask[channel] = true; match helpers::convolve( &grid, - slice::from_mut(&mut pdfset[member]), + &mut pdfset[member], &self.orders, &[bin], &channel_mask, @@ -168,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, - slice::from_mut(pdf), + &mut pdf, &self.orders, &[bin], &channel_mask, @@ -210,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/tests/pull.rs b/pineappl_cli/tests/pull.rs index 4cc2f686..2cbb506f 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 for the convolution function 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 From da7b9481fce62ed7f38e10fbe9784303c18f0b1e Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Fri, 21 Jun 2024 15:17:37 +0200 Subject: [PATCH 22/27] Change help text of `--pull-from` in `pull` --- pineappl_cli/src/pull.rs | 2 +- pineappl_cli/tests/pull.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pineappl_cli/src/pull.rs b/pineappl_cli/src/pull.rs index 99b2c64f..7669e846 100644 --- a/pineappl_cli/src/pull.rs +++ b/pineappl_cli/src/pull.rs @@ -22,7 +22,7 @@ pub struct Opts { conv_funs1: ConvFuns, /// LHAPDF ID(s) or name(s) of the second PDF(s)/FF(s). conv_funs2: ConvFuns, - /// Index for the convolution function for which the pull should be calculated. + /// 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. diff --git a/pineappl_cli/tests/pull.rs b/pineappl_cli/tests/pull.rs index 2cbb506f..5668a8f0 100644 --- a/pineappl_cli/tests/pull.rs +++ b/pineappl_cli/tests/pull.rs @@ -12,7 +12,7 @@ Arguments: LHAPDF ID(s) or name(s) of the second PDF(s)/FF(s) Options: - --pull-from Index for the convolution function for which the pull should be calculated [default: 0] + --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 From 8e0b172052e3bc9972655b1030073699eb3ee3d2 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Fri, 21 Jun 2024 15:36:33 +0200 Subject: [PATCH 23/27] Try to fix compilation error in CI --- pineappl_cli/src/helpers.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 34cab50e..4197f19d 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -34,7 +34,9 @@ impl FromStr for ConvFuns { (fun.to_owned(), None) }) }) - .collect::>()?; + .collect::, _>>()? + .into_iter() + .unzip(); Ok(Self { lhapdf_names, From a981f7e2241410c1c73bc495aebdda3c7a64e306 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Thu, 27 Jun 2024 10:30:15 +0200 Subject: [PATCH 24/27] Add missing units for PDF uncertainties --- pineappl_cli/src/uncert.rs | 4 +++- pineappl_cli/tests/uncert.rs | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pineappl_cli/src/uncert.rs b/pineappl_cli/src/uncert.rs index 5334a14a..fe1e7971 100644 --- a/pineappl_cli/src/uncert.rs +++ b/pineappl_cli/src/uncert.rs @@ -184,7 +184,9 @@ impl Subcommand for Opts { for &index in &self.group.conv_fun { title.add_cell( - cell!(c->format!("{}", self.conv_funs.lhapdf_names[index])).with_hspan(3), + // TODO: fix alignment for second title row + cell!(c->format!("{}\n[{y_unit}] [%] [%]", self.conv_funs.lhapdf_names[index])) + .with_hspan(3), ); } diff --git a/pineappl_cli/tests/uncert.rs b/pineappl_cli/tests/uncert.rs index 774751e8..c2e1da4d 100644 --- a/pineappl_cli/tests/uncert.rs +++ b/pineappl_cli/tests/uncert.rs @@ -25,21 +25,21 @@ Options: "; const DEFAULT_STR: &str = - "b etal dsig/detal NNPDF31_nlo_as_0118_luxqed NNPDF40_nnlo_as_01180 - [] [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 + "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 NNPDF31_nlo_as_0118_luxqed - [] [pb] + [] [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 @@ -52,7 +52,7 @@ const CL_90_STR: &str = "b etal dsig/detal NNPDF31_nlo_as_0118_luxqed "; 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 @@ -65,7 +65,7 @@ const INTEGRATED_STR: &str = "b etal integ NNPDF31_nlo_as_0118_luxq "; const ORDERS_A2_AS1A2_STR: &str = "b etal dsig/detal NNPDF31_nlo_as_0118_luxqed - [] [pb] + [] [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 From 1d4af9614b9338d477ab56a673b31a2685bc1940 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Thu, 27 Jun 2024 10:52:45 +0200 Subject: [PATCH 25/27] Migrate parts of `plot` to `ConvFuns` --- CHANGELOG.md | 3 ++ pineappl_cli/src/plot.py | 10 ++--- pineappl_cli/src/plot.rs | 78 +++++++++++++++++++++++--------------- pineappl_cli/tests/plot.rs | 11 +++--- 4 files changed, 62 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38c80703..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 @@ -43,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 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 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 8b4d9391..2bc9b5a8 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}; @@ -23,8 +23,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, @@ -50,7 +53,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 { @@ -129,11 +132,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!( " ( \"{}\", @@ -141,7 +144,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]), @@ -192,7 +195,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(); @@ -222,7 +225,7 @@ impl Subcommand for Opts { let results = helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &[], &bins, &[], @@ -248,7 +251,7 @@ impl Subcommand for Opts { helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &qcd_orders, &bins, &[], @@ -273,16 +276,16 @@ 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(); + .map(|conv_funs| { + if self.no_conv_fun_unc { + let mut conv_funs = helpers::create_conv_funs(conv_funs)?; let results = helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &[], &bins, &[], @@ -293,15 +296,17 @@ impl Subcommand for Opts { 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, - slice::from_mut(&mut pdf), + &mut funs, &[], &bins, &[], @@ -329,7 +334,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); @@ -400,7 +406,7 @@ impl Subcommand for Opts { ), helpers::convolve( &grid, - slice::from_mut(&mut pdf), + &mut conv_funs, &[], &bins, &channel_mask, @@ -442,7 +448,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), @@ -506,13 +512,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, @@ -523,7 +529,19 @@ impl Subcommand for Opts { metadata = format_metadata(&vector), ); } else { - let (pdfset1, pdfset2) = self.pdfsets.iter().collect_tuple().unwrap(); + let (pdfset1, pdfset2) = self + .conv_funs + .iter() + .map(|fun| { + assert_eq!(fun.lhapdf_names.len(), 1); + if let Some(member) = fun.members[0] { + format!("{}/{member}", fun.lhapdf_names[0]) + } else { + fun.lhapdf_names[0].clone() + } + }) + .collect_tuple() + .unwrap(); let (order, bin, channel) = self .subgrid_pull .iter() @@ -534,8 +552,8 @@ 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 (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()?; 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", From c59f38ee23e50e66dad1733a15b3c89852c1e3e2 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Thu, 27 Jun 2024 11:13:23 +0200 Subject: [PATCH 26/27] Remove obsolete helper functions --- pineappl_cli/src/helpers.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 4197f19d..102d03e4 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -97,14 +97,6 @@ pub fn create_conv_funs_for_set( Ok((set, conv_funs)) } -pub fn create_pdf(pdf: &str) -> Result { - let pdf = pdf.split_once('=').map_or(pdf, |(name, _)| name); - - Ok(pdf - .parse() - .map_or_else(|_| Pdf::with_setname_and_nmem(pdf), Pdf::with_lhaid)?) -} - pub fn create_pdfset(pdfset: &str) -> Result<(PdfSet, Option)> { let pdfset = pdfset.split_once('=').map_or(pdfset, |(name, _)| name); let (pdfset, member) = pdfset @@ -122,10 +114,6 @@ pub fn create_pdfset(pdfset: &str) -> Result<(PdfSet, Option)> { )) } -pub fn pdf_label(pdf: &str) -> &str { - pdf.split_once('=').map_or(pdf, |(_, label)| label) -} - pub fn read_grid(input: &Path) -> Result { Grid::read(File::open(input).context(format!("unable to open '{}'", input.display()))?) .context(format!("unable to read '{}'", input.display())) @@ -425,11 +413,6 @@ pub fn convolve_subgrid( 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()) -} - pub fn parse_integer_range(range: &str) -> Result> { if let Some(at) = range.find('-') { let (left, right) = range.split_at(at); From ddbf227937af035574372d6a76a34c990dc71d93 Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Thu, 27 Jun 2024 14:38:42 +0200 Subject: [PATCH 27/27] Migrate the remaining parts of `plot` to `ConvFuns` --- pineappl_cli/src/helpers.rs | 115 ++++++++++++++++++++++++------------ pineappl_cli/src/plot.rs | 63 +++++++++++--------- 2 files changed, 113 insertions(+), 65 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 102d03e4..d1871f19 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -97,23 +97,6 @@ pub fn create_conv_funs_for_set( Ok((set, conv_funs)) } -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 read_grid(input: &Path) -> Result { Grid::read(File::open(input).context(format!("unable to open '{}'", input.display()))?) .context(format!("unable to read '{}'", input.display())) @@ -381,36 +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); + [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) + grid.convolve_subgrid(&mut cache, order, bin, lumi, 1.0, 1.0) + } + _ => unimplemented!(), + } } pub fn parse_integer_range(range: &str) -> Result> { diff --git a/pineappl_cli/src/plot.rs b/pineappl_cli/src/plot.rs index 2bc9b5a8..87acbe1b 100644 --- a/pineappl_cli/src/plot.rs +++ b/pineappl_cli/src/plot.rs @@ -13,7 +13,6 @@ use std::fmt::Write; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use std::process::ExitCode; -use std::slice; use std::thread; /// Creates a matplotlib script plotting the contents of the grid. @@ -529,19 +528,13 @@ impl Subcommand for Opts { metadata = format_metadata(&vector), ); } else { - let (pdfset1, pdfset2) = self - .conv_funs - .iter() - .map(|fun| { - assert_eq!(fun.lhapdf_names.len(), 1); - if let Some(member) = fun.members[0] { - format!("{}/{member}", fun.lhapdf_names[0]) - } else { - fun.lhapdf_names[0].clone() - } - }) - .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() @@ -552,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, - slice::from_mut(pdf), + conv_funs, &[], &[bin], &[], @@ -574,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, - slice::from_mut(pdf), + conv_funs, &[], &[bin], &[], @@ -613,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();