From 0faa2d56b4a1a7d97aa42d09ad71c3871549e2cf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 28 May 2016 13:37:18 -0500 Subject: [PATCH] language/environment: autoset scale for common units. Closes #448 --- RELEASE_NOTES.rst | 2 ++ .../master/repository/arguments_demo.py | 4 +-- artiq/language/environment.py | 31 ++++++++++++++----- artiq/language/scan.py | 29 ++++++++++++++--- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 6a6269ab6..e4ca8cfb8 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -40,6 +40,8 @@ unreleased [2.x] has been replaced. Pass the parent as first argument instead. * In the dashboard's experiment windows, partial or full argument recomputation takes into account the repository revision field. +* By default, ``NumberValue`` and ``Scannable`` infer the scale from the unit + for common units. 1.1 (unreleased) diff --git a/artiq/examples/master/repository/arguments_demo.py b/artiq/examples/master/repository/arguments_demo.py index e561349ba..56187dcee 100644 --- a/artiq/examples/master/repository/arguments_demo.py +++ b/artiq/examples/master/repository/arguments_demo.py @@ -7,7 +7,7 @@ class SubComponent1(HasEnvironment): def build(self): self.setattr_argument("sc1_scan", Scannable(default=[NoScan(3250), RandomScan(10, 20, 6)], - scale=1e3, unit="kHz"), + unit="kHz"), "Flux capacitor") self.setattr_argument("sc1_enum", EnumerationValue(["1", "2", "3"]), "Flux capacitor") @@ -43,7 +43,7 @@ class ArgumentsDemo(EnvExperiment): self.setattr_argument("pyon_value", PYONValue(self.get_dataset("foo", default=42))) self.setattr_argument("number", NumberValue(42e-6, - unit="us", scale=1e-6, + unit="us", ndecimals=4)) self.setattr_argument("integer", NumberValue(42, step=1, ndecimals=0)) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index efab7a01a..102c684e6 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -2,6 +2,7 @@ from collections import OrderedDict from inspect import isclass from artiq.protocols import pyon +from artiq.language import units __all__ = ["NoDefault", @@ -79,7 +80,6 @@ class EnumerationValue(_SimpleArgProcessor): d["choices"] = self.choices return d - class NumberValue(_SimpleArgProcessor): """An argument that can take a numerical value. @@ -88,14 +88,20 @@ class NumberValue(_SimpleArgProcessor): The simplest way to represent an integer argument is ``NumberValue(step=1, ndecimals=0)``. - For arguments with units, use both the unit parameter (a string for - display) and the scale parameter (a numerical scale for experiments). - For example, ``NumberValue(1, unit="ms", scale=1*ms)`` will display as - 1 ms in the GUI window because of the unit setting, and appear as the + When ``scale`` is not specified, and the unit is a common one (i.e. + defined in ``artiq.language.units``), then the scale is obtained from + the unit using a simple string match. For example, milliseconds (``"ms"``) + units set the scale to 0.001. No unit (default) corresponds to a scale of + 1.0. + + For arguments with uncommon or complex units, use both the unit parameter + (a string for display) and the scale parameter (a numerical scale for + experiments). + For example, ``NumberValue(1, unit="xyz", scale=0.001)`` will display as + 1 xyz in the GUI window because of the unit setting, and appear as the numerical value 0.001 in the code because of the scale setting. - :param unit: A string representing the unit of the value, for display - purposes only. + :param unit: A string representing the unit of the value. :param scale: A numerical scaling factor by which the displayed value is multiplied when referenced in the experiment. :param step: The step with which the value should be modified by up/down @@ -104,8 +110,17 @@ class NumberValue(_SimpleArgProcessor): :param max: The maximum value of the argument. :param ndecimals: The number of decimals a UI should use. """ - def __init__(self, default=NoDefault, unit="", scale=1.0, + def __init__(self, default=NoDefault, unit="", scale=None, step=None, min=None, max=None, ndecimals=2): + if scale is None: + if unit == "": + scale = 1.0 + else: + try: + scale = getattr(units, unit) + except AttributeError: + raise KeyError("Unit {} is unknown, you must specify " + "the scale manually".format(unit)) if step is None: step = scale/10.0 if default is not NoDefault: diff --git a/artiq/language/scan.py b/artiq/language/scan.py index 5c149b3e1..6d59e1f7d 100644 --- a/artiq/language/scan.py +++ b/artiq/language/scan.py @@ -23,6 +23,7 @@ import inspect from artiq.language.core import * from artiq.language.environment import NoDefault, DefaultMissing +from artiq.language import units __all__ = ["ScanObject", @@ -143,8 +144,18 @@ class Scannable: """An argument (as defined in :class:`artiq.language.environment`) that takes a scan object. - For arguments with units, use both the unit parameter (a string for - display) and the scale parameter (a numerical scale for experiments). + When ``scale`` is not specified, and the unit is a common one (i.e. + defined in ``artiq.language.units``), then the scale is obtained from + the unit using a simple string match. For example, milliseconds (``"ms"``) + units set the scale to 0.001. No unit (default) corresponds to a scale of + 1.0. + + For arguments with uncommon or complex units, use both the unit parameter + (a string for display) and the scale parameter (a numerical scale for + experiments). + For example, a scan shown between 1 xyz and 10 xyz in the GUI with + ``scale=0.001`` and ``unit="xyz"`` results in values between 0.001 and + 0.01 being scanned. :param default: The default scan object. This parameter can be a list of scan objects, in which case the first one is used as default and the @@ -157,15 +168,23 @@ class Scannable: :param global_step: The step with which the value should be modified by up/down buttons in a user interface. The default is the scale divided by 10. - :param unit: A string representing the unit of the scanned variable, for - display purposes only. + :param unit: A string representing the unit of the scanned variable. :param scale: A numerical scaling factor by which the displayed values are multiplied when referenced in the experiment. :param ndecimals: The number of decimals a UI should use. """ - def __init__(self, default=NoDefault, unit="", scale=1.0, + def __init__(self, default=NoDefault, unit="", scale=None, global_step=None, global_min=None, global_max=None, ndecimals=2): + if scale is None: + if unit == "": + scale = 1.0 + else: + try: + scale = getattr(units, unit) + except AttributeError: + raise KeyError("Unit {} is unknown, you must specify " + "the scale manually".format(unit)) if global_step is None: global_step = scale/10.0 if default is not NoDefault: