From b6dcf0b70a8ad32d4f8c45ab7defb8a7ae66bed1 Mon Sep 17 00:00:00 2001 From: Thomas Kittelmann Date: Thu, 1 Oct 2026 06:39:49 +0000 Subject: [PATCH] mcrun: only take values made of numbers as scan syntax Values which are not numbers separated by ":" or "," are now used as they are, so NCrystal cfg-strings like "Ge_sg227.ncmat;dir1=@crys_hkl:5,1,1@lab:0,0,1" (or Windows paths like "C:\data\a.dat") can be given on the command line. With -L, values are still lists separated by commas, where commas within an entry can now be escaped as "\,". Co-Authored-By: Claude Opus 5.5 --- tools/Python/mcrun/mcrun.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tools/Python/mcrun/mcrun.py b/tools/Python/mcrun/mcrun.py index c2dc20dc9..cd5bb7758 100644 --- a/tools/Python/mcrun/mcrun.py +++ b/tools/Python/mcrun/mcrun.py @@ -12,6 +12,7 @@ from decimal import Decimal, InvalidOperation from datetime import datetime import multiprocessing +import re from mccode import McStas, Process from optimisation import Scanner, Scanner_split, LinearInterval, MultiInterval, Optimizer @@ -131,7 +132,8 @@ def add_mcrun_adv_options(parser): ' 3) Any parameter given as "min:delta:max" is expanded into its ' ' own explicit list of equidistant points and may be freely mixed ' ' with other, explicitly-listed parameters ' - ' (e.g. a list of filenames) under -L.') + ' (e.g. a list of filenames) under -L.' + ' Commas within a list entry must be escaped as "\\,".') add('-M', '--multi', action='store_true', @@ -536,18 +538,29 @@ def get_parameters(options): if '=' in param: key, value = param.split('=', 1) + # Only values made of numbers separated by ":" or "," are scan + # syntax. Other values, like NCrystal cfg-strings (e.g. + # "Ge_sg227.ncmat;dir1=@crys_hkl:5,1,1@lab:0,0,1"), are used as + # they are, except with -L, where they are lists separated by + # commas (commas within an entry must be escaped as "\,"): + numeric = all(is_decimal(p) for p in re.split('[:,]', value) if p) + if not numeric and not options.list: + # Earlier versions of mcrun ignored trailing commas (with a + # warning), so keep doing that to not break existing commands: + if value.endswith(','): + LOG.warning('Ignoring trailing comma(s) in parameter "%s"', key) + value = value.rstrip(',') + fixed_params[key] = value + continue + # "par=a:delta:b" - an equidistant scan specified by its bin # width (delta) rather than an explicit point count: mcrun # computes how many points are needed to cover [a, b] in steps # of (approximately - see rounding below) delta, rather than # the user needing to work out -N by hand. Checked before the # comma-based interval parsing below, since a colon can never - # appear in a numeric value/list, so a colon anywhere in the - # value would otherwise unambiguously mean this syntax was - # intended - EXCEPT double-colon syntax from NCrystal-backed - # reflections="stdlib::ZnO_sg186_ZincOxide.ncmat;temp=300K" - # used in context of PowderN. Filter out from the start: - if ':' in value and '::' not in value: + # appear in a numeric value/list: + if ':' in value and numeric: parts = value.split(':') if len(parts) != 3: raise OptionValueError( @@ -598,7 +611,7 @@ def get_parameters(options): key, intervals[key], delta, n_points) continue - interval = value.split(',') + interval = [v.replace('\\,', ',') for v in re.split(r'(?