From 091f9a3641da12ba24e623c5d22e06023322cd5b Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 15:40:38 +1100 Subject: [PATCH 01/21] fix:save scaled value, perform initial get --- qcodes/instrument/parameter.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 8d4fe186a05..6abd69701f1 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -347,8 +347,13 @@ def set_wrapper(value, **kwargs): set_function(val, **kwargs) self.raw_value = val - self._save_val(val, validate=(self.val_mapping is None and - self.set_parser is None)) + if self.scale is not None: + scaled_val = val / self.scale + else: + scaled_val = val + self._save_val(scaled_val, + validate=(self.val_mapping is None and + self.set_parser is None)) # Update last set time (used for calculating delays) self._t_last_set = time.perf_counter() @@ -379,7 +384,9 @@ def get_ramp_values(self, value, step=None): if step is None: return [value] else: - start_value = self.get_latest() + if self.get_latest() is None: + self.get() + start_value = self.raw_value self.validate(start_value) From 983925f34c8c5cd7019b10d5e53154c37b14e6e9 Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 17:35:50 +1100 Subject: [PATCH 02/21] fix: self.get return raw_value when possible --- qcodes/instrument/parameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 6abd69701f1..be1bed17971 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -654,7 +654,8 @@ def __init__(self, name, instrument=None, label=None, unit=None, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = self.get_latest + self.get = lambda: self.state.get('raw_value', + self.state['value']) else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) From f2d0d16c996536e281dcf1e772da8f56f5cf8a26 Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 17:55:07 +1100 Subject: [PATCH 03/21] fix: the get function when get_cmd=None did not take any scaling into account --- qcodes/instrument/parameter.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index be1bed17971..1d357b4e844 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -178,7 +178,7 @@ def __init__(self, name, instrument, snapshot_get=True, metadata=None, # record of latest value and when it was set or measured # what exactly this means is different for different subclasses # but they all use the same attributes so snapshot is consistent. - self._latest = {'value': None, 'ts': None} + self._latest = {'value': None, 'ts': None, 'raw_value': None} self.get_latest = GetLatest(self, max_val_age=max_val_age) if hasattr(self, 'get'): @@ -267,7 +267,8 @@ def snapshot_base(self, update=False): def _save_val(self, value, validate=False): if validate: self.validate(value) - self._latest = {'value': value, 'ts': datetime.now()} + self._latest = {'value': value, 'ts': datetime.now(), + 'raw_value': self.raw_value} def _wrap_get(self, get_function): @wraps(get_function) @@ -654,8 +655,7 @@ def __init__(self, name, instrument=None, label=None, unit=None, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = lambda: self.state.get('raw_value', - self.state['value']) + self.get = lambda: self._latest.get('raw_value') else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) @@ -675,7 +675,7 @@ def __init__(self, name, instrument=None, label=None, unit=None, self.unit = unit if unit is not None else '' if initial_value is not None: - self._save_val(initial_value, validate=True) + self.set(initial_value) # generate default docstring self.__doc__ = os.linesep.join(( From ecf3d17368fc4f8bb243ff63f805e1645c5856be Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 18:08:19 +1100 Subject: [PATCH 04/21] fix: pop raw_value when snapshot_value=False --- qcodes/instrument/parameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 1d357b4e844..6c022e699e8 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -188,7 +188,7 @@ def __init__(self, name, instrument, snapshot_get=True, metadata=None, # subclasses should extend this list with extra attributes they # want automatically included in the snapshot - self._meta_attrs = ['name', 'instrument', 'step', 'scale', 'raw_value', + self._meta_attrs = ['name', 'instrument', 'step', 'scale', 'inter_delay', 'post_delay', 'val_mapping', 'vals'] # Specify time of last set operation, used when comparing to delay to @@ -243,6 +243,7 @@ def snapshot_base(self, update=False): if not self._snapshot_value: state.pop('value') + state.pop('raw_value', None) if isinstance(state['ts'], datetime): state['ts'] = state['ts'].strftime('%Y-%m-%d %H:%M:%S') From b466430695fa47b3eb8a41d676ca9aec5605cd1f Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 18:22:12 +1100 Subject: [PATCH 05/21] fix: return self._latest['value'] if self.scale is None --- qcodes/instrument/parameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 6c022e699e8..cb84e287588 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -656,7 +656,8 @@ def __init__(self, name, instrument=None, label=None, unit=None, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = lambda: self._latest.get('raw_value') + self.get = lambda: self._latest['value' if self.scale is None + else 'raw_value'] else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) From 0aaed214b3832e2bd10c22fdde2b251bc8d8f93a Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 15:40:38 +1100 Subject: [PATCH 06/21] fix:save scaled value, perform initial get --- qcodes/instrument/parameter.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index f45dd300ef4..4053a964a20 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -347,8 +347,13 @@ def set_wrapper(value, **kwargs): set_function(val, **kwargs) self.raw_value = val - self._save_val(val, validate=(self.val_mapping is None and - self.set_parser is None)) + if self.scale is not None: + scaled_val = val / self.scale + else: + scaled_val = val + self._save_val(scaled_val, + validate=(self.val_mapping is None and + self.set_parser is None)) # Update last set time (used for calculating delays) self._t_last_set = time.perf_counter() @@ -379,7 +384,9 @@ def get_ramp_values(self, value, step=None): if step is None: return [value] else: - start_value = self.get_latest() + if self.get_latest() is None: + self.get() + start_value = self.raw_value self.validate(start_value) From 7358753656945692fbeb9cdb61176730c55eaf5c Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 17:35:50 +1100 Subject: [PATCH 07/21] fix: self.get return raw_value when possible --- qcodes/instrument/parameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 4053a964a20..ac4cb8c2cd2 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -657,7 +657,8 @@ def __init__(self, name, instrument=None, label=None, unit=None, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = self.get_latest + self.get = lambda: self.state.get('raw_value', + self.state['value']) else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) From 5a4f0ea3544a61468036d991c1aed136a4aaa8d2 Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 17:55:07 +1100 Subject: [PATCH 08/21] fix: the get function when get_cmd=None did not take any scaling into account --- qcodes/instrument/parameter.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index ac4cb8c2cd2..4b37eb29399 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -178,7 +178,7 @@ def __init__(self, name, instrument, snapshot_get=True, metadata=None, # record of latest value and when it was set or measured # what exactly this means is different for different subclasses # but they all use the same attributes so snapshot is consistent. - self._latest = {'value': None, 'ts': None} + self._latest = {'value': None, 'ts': None, 'raw_value': None} self.get_latest = GetLatest(self, max_val_age=max_val_age) if hasattr(self, 'get'): @@ -267,7 +267,8 @@ def snapshot_base(self, update=False): def _save_val(self, value, validate=False): if validate: self.validate(value) - self._latest = {'value': value, 'ts': datetime.now()} + self._latest = {'value': value, 'ts': datetime.now(), + 'raw_value': self.raw_value} def _wrap_get(self, get_function): @wraps(get_function) @@ -657,8 +658,7 @@ def __init__(self, name, instrument=None, label=None, unit=None, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = lambda: self.state.get('raw_value', - self.state['value']) + self.get = lambda: self._latest.get('raw_value') else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) @@ -678,7 +678,7 @@ def __init__(self, name, instrument=None, label=None, unit=None, self.unit = unit if unit is not None else '' if initial_value is not None: - self._save_val(initial_value, validate=True) + self.set(initial_value) # generate default docstring self.__doc__ = os.linesep.join(( From b3e566a1366b7c2e9a957e13a9d88c5facdc8185 Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 18:08:19 +1100 Subject: [PATCH 09/21] fix: pop raw_value when snapshot_value=False --- qcodes/instrument/parameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 4b37eb29399..322b4e822b4 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -188,7 +188,7 @@ def __init__(self, name, instrument, snapshot_get=True, metadata=None, # subclasses should extend this list with extra attributes they # want automatically included in the snapshot - self._meta_attrs = ['name', 'instrument', 'step', 'scale', 'raw_value', + self._meta_attrs = ['name', 'instrument', 'step', 'scale', 'inter_delay', 'post_delay', 'val_mapping', 'vals'] # Specify time of last set operation, used when comparing to delay to @@ -243,6 +243,7 @@ def snapshot_base(self, update=False): if not self._snapshot_value: state.pop('value') + state.pop('raw_value', None) if isinstance(state['ts'], datetime): state['ts'] = state['ts'].strftime('%Y-%m-%d %H:%M:%S') From f19aeec3681a7942b1cafa26e70d7c236f271007 Mon Sep 17 00:00:00 2001 From: FQT Date: Tue, 3 Oct 2017 18:22:12 +1100 Subject: [PATCH 10/21] fix: return self._latest['value'] if self.scale is None --- qcodes/instrument/parameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 322b4e822b4..e2b29d9474d 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -659,7 +659,8 @@ def __init__(self, name, instrument=None, label=None, unit=None, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = lambda: self._latest.get('raw_value') + self.get = lambda: self._latest['value' if self.scale is None + else 'raw_value'] else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) From 7f27a6b212550e2d65ef1b5dcf58b7ac7acba886 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 6 Oct 2017 12:05:30 +0200 Subject: [PATCH 11/21] add test of paramter issue --- qcodes/tests/test_parameter.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/qcodes/tests/test_parameter.py b/qcodes/tests/test_parameter.py index c4a82371e55..958eac4c4a1 100644 --- a/qcodes/tests/test_parameter.py +++ b/qcodes/tests/test_parameter.py @@ -622,6 +622,17 @@ def test_val_mapping_with_parsers(self): self._p = 'PVAL: 1' self.assertEqual(p(), 'on') +class TestManualParameterValMapping(TestCase): + def test_val_mapping(self): + a = DummyInstrument('dummy_holder') + a.add_parameter('myparameter', set_cmd=None, get_cmd=None, val_mapping={'A': 0, 'B': 1}) + a.myparameter('A') + assert a.myparameter() == 'A' + assert a.myparameter() == 'A' + assert a.myparameter.raw_value == 0 + + + class TestInstrumentRefParameter(TestCase): def test_get_instr(self): From 95c058d36ddecd7c790798e97813ba0366c6b37a Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 9 Oct 2017 09:27:20 +0200 Subject: [PATCH 12/21] Add tests cleanup --- qcodes/tests/test_parameter.py | 41 +++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/qcodes/tests/test_parameter.py b/qcodes/tests/test_parameter.py index 958eac4c4a1..2b8872169be 100644 --- a/qcodes/tests/test_parameter.py +++ b/qcodes/tests/test_parameter.py @@ -623,24 +623,39 @@ def test_val_mapping_with_parsers(self): self.assertEqual(p(), 'on') class TestManualParameterValMapping(TestCase): - def test_val_mapping(self): - a = DummyInstrument('dummy_holder') - a.add_parameter('myparameter', set_cmd=None, get_cmd=None, val_mapping={'A': 0, 'B': 1}) - a.myparameter('A') - assert a.myparameter() == 'A' - assert a.myparameter() == 'A' - assert a.myparameter.raw_value == 0 + def setUp(self): + self.instrument = DummyInstrument('dummy_holder') + + def tearDown(self): + self.instrument.close() + del self.instrument + def test_val_mapping(self): + self.instrument.add_parameter('myparameter', set_cmd=None, get_cmd=None, val_mapping={'A': 0, 'B': 1}) + self.instrument.myparameter('A') + assert self.instrument.myparameter() == 'A' + assert self.instrument.myparameter() == 'A' + assert self.instrument.myparameter.raw_value == 0 + class TestInstrumentRefParameter(TestCase): + + def setUp(self): + self.a = DummyInstrument('dummy_holder') + self.d = DummyInstrument('dummy') + def test_get_instr(self): - a = DummyInstrument('dummy_holder') - d = DummyInstrument('dummy') - a.add_parameter('test', parameter_class=InstrumentRefParameter) + self.a.add_parameter('test', parameter_class=InstrumentRefParameter) + + self.a.test.set(self.d.name) - a.test.set(d.name) + self.assertEqual(self.a.test.get(), self.d.name) + self.assertEqual(self.a.test.get_instr(), self.d) - self.assertEqual(a.test.get(), d.name) - self.assertEqual(a.test.get_instr(), d) + def tearDown(self): + self.a.close() + self.d.close() + del self.a + del self.d From 7b93a14f623c85e2effc8def4b31f72e9dc03cc8 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 9 Oct 2017 09:29:47 +0200 Subject: [PATCH 13/21] try to write parameter code a bit cleaner --- qcodes/instrument/parameter.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index e2b29d9474d..14d957b77a0 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -297,11 +297,11 @@ def get_wrapper(*args, **kwargs): if self.val_mapping is not None: if value in self.inverse_val_mapping: value = self.inverse_val_mapping[value] - elif int(value) in self.inverse_val_mapping: - value = self.inverse_val_mapping[int(value)] else: - raise KeyError("'{}' not in val_mapping".format(value)) - + try: + value = self.inverse_val_mapping[int(value)] + except (ValueError, KeyError): + raise KeyError("'{}' not in val_mapping".format(value)) self._save_val(value) return value except Exception as e: @@ -317,25 +317,33 @@ def set_wrapper(value, **kwargs): self.validate(value) if self.val_mapping is not None: + if self.step is not None: + raise RuntimeError('Cannot ramp a value mapped parameter') # Convert set values using val_mapping dictionary - value = self.val_mapping[value] + mapped_value = self.val_mapping[value] + else: + mapped_value = value if self.scale is not None: if isinstance(self.scale, collections.Iterable): # Scale contains multiple elements, one for each value - value = tuple(val * scale for val, scale - in zip(value, self.scale)) + scaled_mapped_value = tuple(val * scale for val, scale + in zip(mapped_value, self.scale)) else: # Use single scale for all values - value *= self.scale + scaled_mapped_value = mapped_value*self.scale + else: + scaled_mapped_value = mapped_value if self.set_parser is not None: - value = self.set_parser(value) + parsed_scaled_mapped_value = self.set_parser(scaled_mapped_value) + else: + parsed_scaled_mapped_value = scaled_mapped_value # In some cases intermediate sweep values must be used. # Unless `self.step` is defined, get_sweep_values will return # a list containing only `value`. - for val in self.get_ramp_values(value, step=self.step): + for val in self.get_ramp_values(parsed_scaled_mapped_value, step=self.step): # Check if delay between set operations is required t_elapsed = time.perf_counter() - self._t_last_set @@ -660,7 +668,7 @@ def __init__(self, name, instrument=None, label=None, unit=None, raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') self.get = lambda: self._latest['value' if self.scale is None - else 'raw_value'] + else 'raw_val ue'] else: exec_str = instrument.ask if instrument else None self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) From 26288c646c67cb8899744aeba8eccd4acbe0e8b6 Mon Sep 17 00:00:00 2001 From: Jens H Nielsen Date: Mon, 9 Oct 2017 12:02:43 +0200 Subject: [PATCH 14/21] annotate parameters --- qcodes/instrument/parameter.py | 42 ++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 14d957b77a0..63990238d5b 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -57,6 +57,7 @@ import os import collections import warnings +from typing import Optional, Sequence, TYPE_CHECKING, Union, Callable from functools import partial, wraps import numpy @@ -70,6 +71,9 @@ from qcodes.instrument.sweep_values import SweepFixedValues from qcodes.data.data_array import DataArray +if TYPE_CHECKING: + from .base import Instrument + class _BaseParameter(Metadatable, DeferredOperations): """ @@ -144,10 +148,20 @@ class _BaseParameter(Metadatable, DeferredOperations): JSON snapshot of the parameter """ - def __init__(self, name, instrument, snapshot_get=True, metadata=None, - step=None, scale=None, inter_delay=0, post_delay=0, - val_mapping=None, get_parser=None, set_parser=None, - snapshot_value=True, max_val_age=None, vals=None): + def __init__(self, name: str, + instrument: Optional[Instrument], + snapshot_get: bool=True, + metadata: Optional[dict]=None, + step: Optional[Union[int, float]]=None, + scale: Optional[Union[int, float]]=None, + inter_delay: Union[int, float]=0, + post_delay: Union[int, float]=0, + val_mapping: Optional[dict]=None, + get_parser: Optional[Callable]=None, + set_parser: Optional[Callable]=None, + snapshot_value: bool=True, + max_val_age: Optional[float]=None, + vals: Optional[Validator]=None): super().__init__(metadata) self.name = str(name) self._instrument = instrument @@ -220,7 +234,8 @@ def __call__(self, *args, **kwargs): raise NotImplementedError('no set cmd found in' + ' Parameter {}'.format(self.name)) - def snapshot_base(self, update=False): + def snapshot_base(self, update: bool=False, + params_to_skip_update: Sequence[str]=None) -> dict: """ State of the parameter as a JSON-compatible dict. @@ -228,6 +243,7 @@ def snapshot_base(self, update=False): update (bool): If True, update the state by calling parameter.get(). If False, just use the latest values in memory. + params_to_skip_update: No effect but may be passed from super Class: Returns: dict: base snapshot @@ -328,7 +344,7 @@ def set_wrapper(value, **kwargs): if isinstance(self.scale, collections.Iterable): # Scale contains multiple elements, one for each value scaled_mapped_value = tuple(val * scale for val, scale - in zip(mapped_value, self.scale)) + in zip(mapped_value, self.scale)) else: # Use single scale for all values scaled_mapped_value = mapped_value*self.scale @@ -655,9 +671,17 @@ class Parameter(_BaseParameter): """ - def __init__(self, name, instrument=None, label=None, unit=None, - get_cmd=None, set_cmd=False, initial_value=None, - max_val_age=None, vals=None, docstring=None, **kwargs): + def __init__(self, name: str, + instrument: Optional[Instrument]=None, + label: Optional[str]=None, + unit: Optional[str]=None, + get_cmd: Optional[Union[str, function, bool]]=None, + set_cmd: Optional[Union[str, function, bool]]=False, + initial_value: Optional[Union[float, int, str]]=None, + max_val_age: Optional[float]=None, + vals: Optional[str]=None, + docstring: Optional[str]=None, + **kwargs): super().__init__(name=name, instrument=instrument, vals=vals, **kwargs) # Enable set/get methods if get_cmd/set_cmd is given From 30c00e07bb06961c627a47b699bb7f5af273e0db Mon Sep 17 00:00:00 2001 From: Jens H Nielsen Date: Mon, 9 Oct 2017 12:21:59 +0200 Subject: [PATCH 15/21] fix typechecking --- qcodes/instrument/parameter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 63990238d5b..6856b74a8e8 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -149,7 +149,7 @@ class _BaseParameter(Metadatable, DeferredOperations): """ def __init__(self, name: str, - instrument: Optional[Instrument], + instrument: Optional['Instrument'], snapshot_get: bool=True, metadata: Optional[dict]=None, step: Optional[Union[int, float]]=None, @@ -672,11 +672,11 @@ class Parameter(_BaseParameter): """ def __init__(self, name: str, - instrument: Optional[Instrument]=None, + instrument: Optional['Instrument']=None, label: Optional[str]=None, unit: Optional[str]=None, - get_cmd: Optional[Union[str, function, bool]]=None, - set_cmd: Optional[Union[str, function, bool]]=False, + get_cmd: Optional[Union[str, Callable, bool]]=None, + set_cmd: Optional[Union[str, Callable, bool]]=False, initial_value: Optional[Union[float, int, str]]=None, max_val_age: Optional[float]=None, vals: Optional[str]=None, From 61842ed4d2d6817155d3beb9de96468d0d85f38f Mon Sep 17 00:00:00 2001 From: Jens H Nielsen Date: Mon, 9 Oct 2017 12:34:06 +0200 Subject: [PATCH 16/21] set private variable in init This is how the official documentation does it and avoids a number of linter warnings --- qcodes/instrument/parameter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 6856b74a8e8..1311b150c9f 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -174,11 +174,11 @@ def __init__(self, name: str, vals = Enum(*val_mapping.keys()) self.vals = vals - self.step = step + self._step = step self.scale = scale self.raw_value = None - self.inter_delay = inter_delay - self.post_delay = post_delay + self._inter_delay = inter_delay + self._post_delay = post_delay self.val_mapping = val_mapping if val_mapping is None: From 0e3d55cb1f73a27e10185d30b214649515dfe5bf Mon Sep 17 00:00:00 2001 From: Jens H Nielsen Date: Mon, 9 Oct 2017 12:48:49 +0200 Subject: [PATCH 17/21] Rename unwrapped get to get_raw to avoid confusion --- qcodes/instrument/parameter.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 1311b150c9f..d9655b21950 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -691,20 +691,20 @@ def __init__(self, name: str, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get = lambda: self._latest['value' if self.scale is None - else 'raw_val ue'] + self.get_raw = lambda: self._latest['value' if self.scale is None + else 'raw_value'] else: exec_str = instrument.ask if instrument else None - self.get = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) - self.get = self._wrap_get(self.get) + self.get_raw = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) + self.get = self._wrap_get(self.get_raw) if not hasattr(self, 'set') and set_cmd is not False: if set_cmd is None: - self.set = partial(self._save_val, validate=False) + self.set_raw = partial(self._save_val, validate=False) else: exec_str = instrument.write if instrument else None - self.set = Command(arg_count=1, cmd=set_cmd, exec_str=exec_str) - self.set = self._wrap_set(self.set) + self.set_raw = Command(arg_count=1, cmd=set_cmd, exec_str=exec_str) + self.set = self._wrap_set(self.set_raw) self._meta_attrs.extend(['label', 'unit', 'vals']) From e216ceef3b3a1ed2799191c919fbe6ba3b92fd89 Mon Sep 17 00:00:00 2001 From: Jens H Nielsen Date: Mon, 9 Oct 2017 18:03:12 +0200 Subject: [PATCH 18/21] transform to step size before mapping, scaling and parsing@ --- qcodes/instrument/parameter.py | 70 ++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index d9655b21950..50202605840 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -282,8 +282,16 @@ def snapshot_base(self, update: bool=False, return state def _save_val(self, value, validate=False): + """ + Update latest + """ if validate: self.validate(value) + if (self.get_parser is None and + self.set_parser is None and + self.val_mapping is None and + self.scale is None): + self.raw_value = value self._latest = {'value': value, 'ts': datetime.now(), 'raw_value': self.raw_value} @@ -332,34 +340,33 @@ def set_wrapper(value, **kwargs): try: self.validate(value) - if self.val_mapping is not None: - if self.step is not None: - raise RuntimeError('Cannot ramp a value mapped parameter') - # Convert set values using val_mapping dictionary - mapped_value = self.val_mapping[value] - else: - mapped_value = value + # In some cases intermediate sweep values must be used. + # Unless `self.step` is defined, get_sweep_values will return + # a list containing only `value`. + steps = self.get_ramp_values(value, step=self.step) - if self.scale is not None: - if isinstance(self.scale, collections.Iterable): - # Scale contains multiple elements, one for each value - scaled_mapped_value = tuple(val * scale for val, scale - in zip(mapped_value, self.scale)) + for val_step in steps: + if self.val_mapping is not None: + # Convert set values using val_mapping dictionary + mapped_value = self.val_mapping[val_step] else: - # Use single scale for all values - scaled_mapped_value = mapped_value*self.scale - else: - scaled_mapped_value = mapped_value + mapped_value = val_step - if self.set_parser is not None: - parsed_scaled_mapped_value = self.set_parser(scaled_mapped_value) - else: - parsed_scaled_mapped_value = scaled_mapped_value + if self.scale is not None: + if isinstance(self.scale, collections.Iterable): + # Scale contains multiple elements, one for each value + scaled_mapped_value = tuple(val * scale for val, scale + in zip(mapped_value, self.scale)) + else: + # Use single scale for all values + scaled_mapped_value = mapped_value*self.scale + else: + scaled_mapped_value = mapped_value - # In some cases intermediate sweep values must be used. - # Unless `self.step` is defined, get_sweep_values will return - # a list containing only `value`. - for val in self.get_ramp_values(parsed_scaled_mapped_value, step=self.step): + if self.set_parser is not None: + parsed_scaled_mapped_value = self.set_parser(scaled_mapped_value) + else: + parsed_scaled_mapped_value = scaled_mapped_value # Check if delay between set operations is required t_elapsed = time.perf_counter() - self._t_last_set @@ -371,13 +378,9 @@ def set_wrapper(value, **kwargs): # Start timer to measure execution time of set_function t0 = time.perf_counter() - set_function(val, **kwargs) - self.raw_value = val - if self.scale is not None: - scaled_val = val / self.scale - else: - scaled_val = val - self._save_val(scaled_val, + set_function(parsed_scaled_mapped_value, **kwargs) + self.raw_value = parsed_scaled_mapped_value + self._save_val(val_step, validate=(self.val_mapping is None and self.set_parser is None)) @@ -410,6 +413,8 @@ def get_ramp_values(self, value, step=None): if step is None: return [value] else: + if isinstance(value, collections.Iterable) and len(value) > 1: + raise RuntimeError("Don't know how to step a parameter with more than one value") if self.get_latest() is None: self.get() start_value = self.raw_value @@ -691,8 +696,7 @@ def __init__(self, name: str, if max_val_age is not None: raise SyntaxError('Must have get method or specify get_cmd ' 'when max_val_age is set') - self.get_raw = lambda: self._latest['value' if self.scale is None - else 'raw_value'] + self.get_raw = lambda: self._latest['raw_value'] else: exec_str = instrument.ask if instrument else None self.get_raw = Command(arg_count=0, cmd=get_cmd, exec_str=exec_str) From 6835565c92deee4ca862a0f6f328e7f6a017aa50 Mon Sep 17 00:00:00 2001 From: Jens H Nielsen Date: Mon, 9 Oct 2017 18:03:33 +0200 Subject: [PATCH 19/21] one ome deprecate ManualParameter --- qcodes/measure.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qcodes/measure.py b/qcodes/measure.py index 74443d3b587..098b1222450 100644 --- a/qcodes/measure.py +++ b/qcodes/measure.py @@ -1,6 +1,6 @@ from datetime import datetime -from qcodes.instrument.parameter import ManualParameter +from qcodes.instrument.parameter import Parameter from qcodes.loops import Loop from qcodes.actions import _actions_snapshot from qcodes.utils.helpers import full_class @@ -18,8 +18,9 @@ class Measure(Metadatable): Scalars returned by an action will be saved as length-1 arrays, with a dummy setpoint for consistency with other DataSets. """ - dummy_parameter = ManualParameter(name='single', - label='Single Measurement') + dummy_parameter = Parameter(name='single', + label='Single Measurement', + set_cmd=None, get_cmd=None) def __init__(self, *actions): super().__init__() From 0486adfda5355ea67746553c8569ab4f53515213 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Thu, 12 Oct 2017 10:15:32 +0200 Subject: [PATCH 20/21] revert setting parameter via _private value --- qcodes/instrument/parameter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 50202605840..267f9c6e611 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -174,11 +174,11 @@ def __init__(self, name: str, vals = Enum(*val_mapping.keys()) self.vals = vals - self._step = step + self.step = step self.scale = scale self.raw_value = None - self._inter_delay = inter_delay - self._post_delay = post_delay + self.inter_delay = inter_delay + self.post_delay = post_delay self.val_mapping = val_mapping if val_mapping is None: From 7e5df577e0c8efd7512038348fb8c6f2d9965f99 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Thu, 12 Oct 2017 13:00:47 +0200 Subject: [PATCH 21/21] Try to wrap get/set_raw first in baseclass --- qcodes/instrument/parameter.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py index 267f9c6e611..c3cb6a97235 100644 --- a/qcodes/instrument/parameter.py +++ b/qcodes/instrument/parameter.py @@ -195,9 +195,19 @@ def __init__(self, name: str, self._latest = {'value': None, 'ts': None, 'raw_value': None} self.get_latest = GetLatest(self, max_val_age=max_val_age) - if hasattr(self, 'get'): + if hasattr(self, 'get_raw'): + self.get = self._wrap_get(self.get_raw) + elif hasattr(self, 'get'): + warnings.warn('Wrapping get method, original get method will not ' + 'be directly accessible. It is recommended to ' + 'define get_raw in your subclass instead.' ) self.get = self._wrap_get(self.get) - if hasattr(self, 'set'): + if hasattr(self, 'set_raw'): + self.set = self._wrap_get(self.set_raw) + elif hasattr(self, 'set'): + warnings.warn('Wrapping set method, original set method will not ' + 'be directly accessible. It is recommended to ' + 'define get_raw in your subclass instead.' ) self.set = self._wrap_set(self.set) # subclasses should extend this list with extra attributes they