From 99b4734f29c5585d001c5bce9bd88586ad4b0b54 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Wed, 25 Mar 2026 12:28:00 +0200 Subject: [PATCH 1/5] Improve ConvFuns detection --- pineappl_cli/src/helpers.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index b3569358..79426230 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -13,6 +13,7 @@ use std::ops::RangeInclusive; use std::path::Path; use std::process::ExitCode; use std::str::FromStr; +use std::str::rsplit_once; #[derive(Clone, Debug, Eq, PartialEq)] pub struct ConvFuns { @@ -26,11 +27,11 @@ impl FromStr for ConvFuns { type Err = Error; fn from_str(arg: &str) -> std::result::Result { - let (names, label) = arg.split_once('=').unwrap_or((arg, arg)); + let (names, label) = arg.rsplit_once('=').unwrap_or((arg, arg)); let (lhapdf_names, members, conv_types) = names .split(',') .map(|fun| { - let (name, typ) = fun.split_once('+').unwrap_or((fun, "")); + let (name, typ) = fun.rsplit_once('+').unwrap_or((fun, "")); let (name, mem) = name.split_once('/').map_or((name, None), |(name, mem)| { ( name, @@ -520,6 +521,28 @@ mod test { ); } + #[test] + fn issue_386() { + // names may containt "special characters", such as `+` and `=`, in which case you need to + // enforce the special meaning (by giving the character again) and can not rely on the + // default behavior. + assert_eq!( + "n=p-PDF,D0+Dpm+f=blub".parse::().unwrap(), + ConvFuns { + lhapdf_names: vec![ + "n=p-PDF".to_owned(), + "D0+Dpm".to_owned() + ], + members: vec![None, None], + conv_types: vec![ + ConvType::UnpolPDF + ConvType::UnpolFF, + ], + label: "blub".to_owned() + } + ); + } + #[test] fn parse_order() { // that's OK From fb84dc8d865f8b3bdad770b9c0e4c0b611b84cdf Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Wed, 25 Mar 2026 12:31:19 +0200 Subject: [PATCH 2/5] Fix missing comma --- pineappl_cli/src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 79426230..9d33d903 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -535,7 +535,7 @@ mod test { ], members: vec![None, None], conv_types: vec![ - ConvType::UnpolPDF + ConvType::UnpolPDF, ConvType::UnpolFF, ], label: "blub".to_owned() From 5f77d7b36e2d351633e6c9785a8aa03b76f8782c Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Wed, 25 Mar 2026 12:32:34 +0200 Subject: [PATCH 3/5] Fix import --- pineappl_cli/src/helpers.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 9d33d903..166c125f 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -13,7 +13,6 @@ use std::ops::RangeInclusive; use std::path::Path; use std::process::ExitCode; use std::str::FromStr; -use std::str::rsplit_once; #[derive(Clone, Debug, Eq, PartialEq)] pub struct ConvFuns { From e89699218e9b37fd7452aa9316c7f5f4c0b844d3 Mon Sep 17 00:00:00 2001 From: Felix Hekhorn Date: Thu, 26 Mar 2026 14:41:11 +0200 Subject: [PATCH 4/5] Only check for + --- pineappl_cli/src/helpers.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index 166c125f..b38aac01 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -26,10 +26,11 @@ impl FromStr for ConvFuns { type Err = Error; fn from_str(arg: &str) -> std::result::Result { - let (names, label) = arg.rsplit_once('=').unwrap_or((arg, arg)); + let (names, label) = arg.split_once('=').unwrap_or((arg, arg)); let (lhapdf_names, members, conv_types) = names .split(',') .map(|fun| { + // Split from the right to recover weird names (#386) let (name, typ) = fun.rsplit_once('+').unwrap_or((fun, "")); let (name, mem) = name.split_once('/').map_or((name, None), |(name, mem)| { ( @@ -522,21 +523,15 @@ mod test { #[test] fn issue_386() { - // names may containt "special characters", such as `+` and `=`, in which case you need to + // names may contain the "special character" `+`, in which case you need to // enforce the special meaning (by giving the character again) and can not rely on the // default behavior. assert_eq!( - "n=p-PDF,D0+Dpm+f=blub".parse::().unwrap(), + "D0+Dpm+f=blub".parse::().unwrap(), ConvFuns { - lhapdf_names: vec![ - "n=p-PDF".to_owned(), - "D0+Dpm".to_owned() - ], - members: vec![None, None], - conv_types: vec![ - ConvType::UnpolPDF, - ConvType::UnpolFF, - ], + lhapdf_names: vec!["D0+Dpm".to_owned()], + members: vec![None], + conv_types: vec![ConvType::UnpolFF,], label: "blub".to_owned() } ); From e9adfd3a36bf9bae99613a5fa7143048948c7cce Mon Sep 17 00:00:00 2001 From: Christopher Schwan Date: Fri, 27 Mar 2026 16:16:18 +0100 Subject: [PATCH 5/5] Allow more freedom for convolution function names --- pineappl_cli/src/helpers.rs | 40 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/pineappl_cli/src/helpers.rs b/pineappl_cli/src/helpers.rs index b38aac01..adb6cc1f 100644 --- a/pineappl_cli/src/helpers.rs +++ b/pineappl_cli/src/helpers.rs @@ -26,12 +26,23 @@ impl FromStr for ConvFuns { type Err = Error; fn from_str(arg: &str) -> std::result::Result { + // split from the left, as '=' characters are allowed in labels but not in names let (names, label) = arg.split_once('=').unwrap_or((arg, arg)); let (lhapdf_names, members, conv_types) = names .split(',') .map(|fun| { - // Split from the right to recover weird names (#386) - let (name, typ) = fun.rsplit_once('+').unwrap_or((fun, "")); + // `fun` may contain an arbitrary number of '+' characters + let (name, typ) = if let Some(name) = fun.strip_suffix("+p") { + (name, ConvType::PolPDF) + } else if let Some(name) = fun.strip_suffix("+f") { + (name, ConvType::UnpolFF) + } else if let Some(name) = + fun.strip_suffix("+pf").or_else(|| fun.strip_suffix("+fp")) + { + (name, ConvType::PolFF) + } else { + (fun, ConvType::UnpolPDF) + }; let (name, mem) = name.split_once('/').map_or((name, None), |(name, mem)| { ( name, @@ -43,13 +54,6 @@ impl FromStr for ConvFuns { ) }); let name = name.to_owned(); - let typ = match typ { - "" => ConvType::UnpolPDF, - "p" => ConvType::PolPDF, - "f" => ConvType::UnpolFF, - "pf" | "fp" => ConvType::PolFF, - _ => bail!("unknown convolution type '{typ}'"), - }; Ok::<_, Error>((name, mem, typ)) }) .collect::, _>>()? @@ -523,18 +527,28 @@ mod test { #[test] fn issue_386() { - // names may contain the "special character" `+`, in which case you need to - // enforce the special meaning (by giving the character again) and can not rely on the - // default behavior. + // names may contain the character '+', which must not be confused with the convolution + // function types assert_eq!( "D0+Dpm+f=blub".parse::().unwrap(), ConvFuns { lhapdf_names: vec!["D0+Dpm".to_owned()], members: vec![None], - conv_types: vec![ConvType::UnpolFF,], + conv_types: vec![ConvType::UnpolFF], label: "blub".to_owned() } ); + + // even unpolarized PDFs may contain '+' characters + assert_eq!( + "D0+Dpm=blub++".parse::().unwrap(), + ConvFuns { + lhapdf_names: vec!["D0+Dpm".to_owned()], + members: vec![None], + conv_types: vec![ConvType::UnpolPDF], + label: "blub++".to_owned() + } + ); } #[test]