Skip to content

Commit c14d948

Browse files
committed
Fix and improve order passing in the CLI
1 parent eb3d184 commit c14d948

2 files changed

Lines changed: 94 additions & 27 deletions

File tree

pineappl_cli/src/helpers.rs

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::GlobalConfiguration;
2-
use anyhow::{anyhow, bail, ensure, Context, Error, Result};
2+
use anyhow::{anyhow, bail, Context, Error, Result};
33
use itertools::Itertools;
44
use lhapdf::{Pdf, PdfSet};
55
use pineappl::boc::{ScaleFuncForm, Scales};
@@ -433,36 +433,61 @@ pub fn parse_integer_range(range: &str) -> Result<RangeInclusive<usize>> {
433433
}
434434

435435
pub fn parse_order(order: &str) -> Result<(u8, u8)> {
436-
let mut alphas = 0;
437-
let mut alpha = 0;
436+
const FORMAT: &str = "must be one of `asX`, `aY`, `asXaY` or `aYasX` with `X` and `Y` integer";
438437

439-
let matches: Vec<_> = order.match_indices('a').collect();
438+
// since 'a' is a substring of 'as', the latter must be given first
439+
let couplings = ["as", "a"];
440+
let mut variables = [None, None];
441+
let mut parsed;
440442

441-
ensure!(
442-
matches.len() <= 2,
443-
"unable to parse order; too many couplings in '{}'",
444-
order
445-
);
443+
let mut chunk = order;
446444

447-
for (index, _) in matches {
448-
if &order[index..index + 2] == "as" {
449-
let len = order[index + 2..]
450-
.chars()
451-
.take_while(|c| c.is_numeric())
452-
.count();
453-
alphas = str::parse::<u8>(&order[index + 2..index + 2 + len])
454-
.context(format!("unable to parse order '{order}'"))?;
455-
} else {
456-
let len = order[index + 1..]
457-
.chars()
458-
.take_while(|c| c.is_numeric())
459-
.count();
460-
alpha = str::parse::<u8>(&order[index + 1..index + 1 + len])
461-
.context(format!("unable to parse order '{order}'"))?;
445+
loop {
446+
parsed = false;
447+
448+
for (coupling, variable) in couplings.iter().zip(&mut variables) {
449+
if let Some(stripped) = chunk.strip_prefix(*coupling) {
450+
// find the index of the next coupling
451+
let len = couplings
452+
.iter()
453+
.filter_map(|c| stripped.find(c))
454+
.min()
455+
.unwrap_or(stripped.len());
456+
457+
let (exponent, new_chunk) = stripped.split_at(len);
458+
chunk = new_chunk;
459+
460+
if let Some(var) = variable {
461+
bail!("exponent of '{coupling}' has already been set to '{var}'");
462+
} else if exponent.is_empty() {
463+
// if there's no exponent, we assume it to be one
464+
*variable = Some(1);
465+
} else {
466+
*variable = Some(exponent.parse().map_err(|err| {
467+
anyhow!("parsing exponent '{exponent}' of '{coupling}' failed with '{err}'")
468+
})?);
469+
}
470+
471+
parsed = true;
472+
break;
473+
}
462474
}
475+
476+
if !parsed {
477+
break;
478+
}
479+
}
480+
481+
if !chunk.is_empty() {
482+
bail!("found remainder '{chunk}', but order {FORMAT}");
463483
}
464484

465-
Ok((alphas, alpha))
485+
Ok(match variables {
486+
[Some(alphas), Some(alpha)] => (alphas, alpha),
487+
[Some(alphas), None] => (alphas, 0),
488+
[None, Some(alpha)] => (0, alpha),
489+
[None, None] => bail!("{FORMAT}"),
490+
})
466491
}
467492

468493
#[cfg(test)]
@@ -494,4 +519,46 @@ mod test {
494519
}
495520
);
496521
}
522+
523+
#[test]
524+
fn parse_order() {
525+
// that's OK
526+
assert_eq!(super::parse_order("as16a28").unwrap(), (16, 28));
527+
528+
// empty exponents are set to 1
529+
assert_eq!(super::parse_order("asa28").unwrap(), (1, 28));
530+
assert_eq!(super::parse_order("as16a").unwrap(), (16, 1));
531+
assert_eq!(super::parse_order("asa").unwrap(), (1, 1));
532+
assert_eq!(super::parse_order("aas").unwrap(), (1, 1));
533+
534+
// exponent is not an integer
535+
assert_eq!(
536+
format!("{}", super::parse_order("asBLA").unwrap_err()),
537+
"parsing exponent 'BLA' of 'as' failed with 'invalid digit found in string'"
538+
);
539+
540+
// 'LO' was previous accepted: https://github.com/NNPDF/pineappl/issues/347
541+
assert_eq!(
542+
format!("{}", super::parse_order("LO").unwrap_err()),
543+
"found remainder 'LO', but order must be one of `asX`, `aY`, `asXaY` or `aYasX` with `X` and `Y` integer"
544+
);
545+
546+
// repeated couplings must raise an error
547+
assert_eq!(
548+
format!("{}", super::parse_order("as3as2").unwrap_err()),
549+
"exponent of 'as' has already been set to '3'"
550+
);
551+
552+
// different repeat coupling
553+
assert_eq!(
554+
format!("{}", super::parse_order("a3a2as2").unwrap_err()),
555+
"exponent of 'a' has already been set to '3'"
556+
);
557+
558+
// empty is wrong as well
559+
assert_eq!(
560+
format!("{}", super::parse_order("").unwrap_err()),
561+
"must be one of `asX`, `aY`, `asXaY` or `aYasX` with `X` and `Y` integer"
562+
);
563+
}
497564
}

pineappl_cli/tests/convolve.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ const ORDERS_A2_A3_STR: &str = "b etal dsig/detal
169169
7 4 4.5 2.2163265e1
170170
";
171171

172-
const WRONG_ORDERS_STR: &str = "error: invalid value 'a2a2as2' for '--orders <ORDERS>': unable to parse order; too many couplings in 'a2a2as2'
172+
const WRONG_ORDERS_STR: &str = "error: invalid value 'a2a3as2' for '--orders <ORDERS>': exponent of 'a' has already been set to '2'
173173
174174
For more information, try '--help'.
175175
";
@@ -423,7 +423,7 @@ fn wrong_orders() {
423423
.unwrap()
424424
.args([
425425
"convolve",
426-
"--orders=a2a2as2",
426+
"--orders=a2a3as2",
427427
"../test-data/LHCB_WP_7TEV_opt.pineappl.lz4",
428428
"NNPDF31_nlo_as_0118_luxqed",
429429
])

0 commit comments

Comments
 (0)