Skip to content

Commit

Permalink
Merge #4759 #4779
Browse files Browse the repository at this point in the history
4759: Add ability to get parameter after set to dond r=jenshnielsen a=jenshnielsen

For some instruments it may be a good idea to get the value after setting it and store that in the dataset rather than relying on the instrument being able to set the exact value. 

This implements that by extending the Sweeps classes with a boolean. This could be extended to read a flag from the parameter giving the parameter a trait to indicate if it has been set


This is also a small step towards fixing #4695 since it will become possible to get the value of a parameter that one sets

To make this easier to demonstrate ManualParameters have been improved to log using the instrument logger

TODO 
- [x] Documentation (examples + docstrings)
- [x] Tests
- [x] release notes

4779: Keithley calibration: adjust calibration date before saving new calibration r=jenshnielsen a=michieldemoor

When running the calibrate_keithley_smu_v method to calibrate a Keithley SMU, as documented [here](https://qcodes.github.io/Qcodes/examples/driver_examples/Qcodes%20example%20with%20Keithley%202600.html#Recalibration), the calibration gives the following error:

ERROR CODE: 5029

SMU A: Cannot save without changing cal adjustment date

SMU B: Cannot save without changing cal adjustment date

This PR addresses this error by changing the calibration adjustment date before saving the new calibration.

Co-authored-by: Jens H. Nielsen <[email protected]>
Co-authored-by: mdemoor <[email protected]>
Co-authored-by: Mikhail Astafev <[email protected]>
  • Loading branch information
4 people authored Oct 31, 2022
3 parents 2459ba8 + f57eadb + 5ca4325 commit faf2750
Show file tree
Hide file tree
Showing 10 changed files with 653 additions and 2,776 deletions.
2 changes: 2 additions & 0 deletions docs/changes/newsfragments/4759.improved
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The sweeps used by doNd has gained the ability to perform a get call after setting the parameter and storing
that value in the dataset rather than the value set.
1 change: 1 addition & 0 deletions docs/changes/newsfragments/4779.improved
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Keithley calibration: adjust calibration date before saving new calibration

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions qcodes/calibrations/keithley.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ def setup_dmm(dmm: Instrument) -> None:


def save_calibration(smu: Keithley_2600) -> None:
calibration_date = int(time.time())
for smu_channel in smu.channels:
smu.write(f"{smu_channel.channel}.cal.adjustdate = {calibration_date}")
smu.write(f"{smu_channel.channel}.cal.save()")


Expand Down
7 changes: 6 additions & 1 deletion qcodes/dataset/dond/do_nd.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class ParameterSetEvent:
should_set: bool
delay: float
actions: ActionsT
get_after_set: bool


class _Sweeper:
Expand Down Expand Up @@ -228,6 +229,7 @@ def __getitem__(self, index: int) -> tuple[ParameterSetEvent, ...]:
should_set=should_set,
delay=sweep.delay,
actions=sweep.post_actions,
get_after_set=sweep.get_after_set,
)
parameter_set_events.append(event)
return tuple(parameter_set_events)
Expand Down Expand Up @@ -708,7 +710,10 @@ def dond(
act()
time.sleep(set_event.delay)

results[set_event.parameter] = set_event.new_value
if set_event.get_after_set:
results[set_event.parameter] = set_event.parameter()
else:
results[set_event.parameter] = set_event.new_value

meas_value_pair = call_params_meas()
for meas_param, value in meas_value_pair:
Expand Down
39 changes: 38 additions & 1 deletion qcodes/dataset/dond/sweeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ def post_actions(self) -> ActionsT:
"""
pass

@property
def get_after_set(self) -> bool:
"""
Should we perform a call to get on the parameter after setting it
and store that rather than the setpoint value in the dataset?
This defaults to False for backwards compatibility
but subclasses should overwrite this to implement if correctly.
"""
return False


class LinSweep(AbstractSweep[np.float64]):
"""
Expand All @@ -67,7 +78,10 @@ class LinSweep(AbstractSweep[np.float64]):
start: Sweep start value.
stop: Sweep end value.
num_points: Number of sweep points.
delay: Time in seconds between two consecutive sweep points
delay: Time in seconds between two consecutive sweep points.
post_actions: Actions to do after each sweep point.
get_after_set: Should we perform a get on the parameter after setting it
and store the value returned by get rather than the set value in the dataset.
"""

def __init__(
Expand All @@ -78,13 +92,15 @@ def __init__(
num_points: int,
delay: float = 0,
post_actions: ActionsT = (),
get_after_set: bool = False,
):
self._param = param
self._start = start
self._stop = stop
self._num_points = num_points
self._delay = delay
self._post_actions = post_actions
self._get_after_set = get_after_set

def get_setpoints(self) -> npt.NDArray[np.float64]:
"""
Expand All @@ -109,6 +125,10 @@ def num_points(self) -> int:
def post_actions(self) -> ActionsT:
return self._post_actions

@property
def get_after_set(self) -> bool:
return self._get_after_set


class LogSweep(AbstractSweep[np.float64]):
"""
Expand All @@ -120,6 +140,9 @@ class LogSweep(AbstractSweep[np.float64]):
stop: Sweep end value.
num_points: Number of sweep points.
delay: Time in seconds between two consecutive sweep points.
post_actions: Actions to do after each sweep point.
get_after_set: Should we perform a get on the parameter after setting it
and store the value returned by get rather than the set value in the dataset.
"""

def __init__(
Expand All @@ -130,13 +153,15 @@ def __init__(
num_points: int,
delay: float = 0,
post_actions: ActionsT = (),
get_after_set: bool = False,
):
self._param = param
self._start = start
self._stop = stop
self._num_points = num_points
self._delay = delay
self._post_actions = post_actions
self._get_after_set = get_after_set

def get_setpoints(self) -> npt.NDArray[np.float64]:
"""
Expand All @@ -161,6 +186,10 @@ def num_points(self) -> int:
def post_actions(self) -> ActionsT:
return self._post_actions

@property
def get_after_set(self) -> bool:
return self._get_after_set


class ArraySweep(AbstractSweep, Generic[T]):
"""
Expand All @@ -171,6 +200,8 @@ class ArraySweep(AbstractSweep, Generic[T]):
array: array with values to sweep.
delay: Time in seconds between two consecutive sweep points.
post_actions: Actions to do after each sweep point.
get_after_set: Should we perform a get on the parameter after setting it
and store the value returned by get rather than the set value in the dataset.
"""

def __init__(
Expand All @@ -179,11 +210,13 @@ def __init__(
array: Sequence[Any] | npt.NDArray[T],
delay: float = 0,
post_actions: ActionsT = (),
get_after_set: bool = False,
):
self._param = param
self._array = np.array(array)
self._delay = delay
self._post_actions = post_actions
self._get_after_set = get_after_set

def get_setpoints(self) -> npt.NDArray[T]:
return self._array
Expand All @@ -204,6 +237,10 @@ def num_points(self) -> int:
def post_actions(self) -> ActionsT:
return self._post_actions

@property
def get_after_set(self) -> bool:
return self._get_after_set


class TogetherSweep:
"""
Expand Down
3 changes: 2 additions & 1 deletion qcodes/instrument/instrument_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

if TYPE_CHECKING:
from qcodes.instrument.channel import ChannelTuple, InstrumentModule
from qcodes.logger.instrument_logger import InstrumentLoggerAdapter

from qcodes.utils import QCoDeSDeprecationWarning

Expand Down Expand Up @@ -82,7 +83,7 @@ def __init__(
# This is needed for snapshot method to work
self._meta_attrs = ["name", "label"]

self.log = get_instrument_logger(self, __name__)
self.log: InstrumentLoggerAdapter = get_instrument_logger(self, __name__)

@property
def label(self) -> str:
Expand Down
19 changes: 17 additions & 2 deletions qcodes/parameters/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

if TYPE_CHECKING:
from qcodes.instrument.base import InstrumentBase
from qcodes.logger.instrument_logger import InstrumentLoggerAdapter
from qcodes.validators import Validator


Expand Down Expand Up @@ -180,15 +181,29 @@ def __init__(
**kwargs: Any,
) -> None:
def _get_manual_parameter() -> ParamRawDataType:
log.debug(
if self.root_instrument is not None:
mylogger: InstrumentLoggerAdapter | logging.Logger = (
self.root_instrument.log
)
else:
mylogger = log
mylogger.debug(
"Getting raw value of parameter: %s as %s",
self.full_name,
self.cache.raw_value,
)
return self.cache.raw_value

def _set_manual_parameter(x: ParamRawDataType) -> ParamRawDataType:
log.debug("Setting raw value of parameter: %s to %s", self.full_name, x)
if self.root_instrument is not None:
mylogger: InstrumentLoggerAdapter | logging.Logger = (
self.root_instrument.log
)
else:
mylogger = log
mylogger.debug(
"Setting raw value of parameter: %s to %s", self.full_name, x
)
return x

if instrument is not None and bind_to_instrument:
Expand Down
118 changes: 118 additions & 0 deletions qcodes/tests/dataset/dond/test_doNd.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,50 @@
from qcodes.validators import Ints


class TrackingParameter(Parameter):
"""Parameter that keeps track of number of get and set operations"""

def __init__(self, *args, **kwargs):
self.set_count = 0
self.get_count = 0
super().__init__(*args, **kwargs)

def set_raw(self, value):
self.set_count += 1
self.cache._set_from_raw_value(value)

def get_raw(self):
self.get_count += 1
return self.cache.raw_value

def reset_count(self) -> None:
self.get_count = 0
self.set_count = 0


class GetReturnsCountParameter(Parameter):
"""Parameter that keeps track of number of get and set operations
Allows you to set a value but returns the get count rather
than the value"""

def __init__(self, *args, **kwargs):
self.set_count = 0
self.get_count = 0
super().__init__(*args, **kwargs)

def set_raw(self, value):
self.set_count += 1
self.cache._set_from_raw_value(value)

def get_raw(self):
self.get_count += 1
return self.get_count

def reset_count(self) -> None:
self.get_count = 0
self.set_count = 0


def test_linear_sweep_get_setpoints(_param):
start = 0
stop = 1
Expand Down Expand Up @@ -1589,3 +1633,77 @@ def test_default_log_info(caplog):
dond(LinSweep(param_1, 0, 10, 10), param_2)

assert "Using 'qcodes.dataset.dond'" in caplog.text


def test_dond_get_after_set(_param_set, _param_set_2, _param):

n_points = 10

a = TrackingParameter("a", initial_value=0)
b = TrackingParameter("b", initial_value=0)

a.reset_count()
b.reset_count()

assert a.get_count == 0
assert a.set_count == 0
assert b.get_count == 0
assert b.set_count == 0

dond(LinSweep(a, 0, 10, n_points, get_after_set=True), b)

assert a.get_count == n_points
assert a.set_count == n_points
assert b.get_count == n_points
assert b.set_count == 0


def test_dond_no_get_after_set(_param_set, _param_set_2, _param):

n_points = 10

a = TrackingParameter("a", initial_value=0)
b = TrackingParameter("b", initial_value=0)

a.reset_count()
b.reset_count()

assert a.get_count == 0
assert a.set_count == 0
assert b.get_count == 0
assert b.set_count == 0

dond(LinSweep(a, 0, 10, n_points, get_after_set=False), b)

assert a.get_count == 0
assert a.set_count == n_points
assert b.get_count == n_points
assert b.set_count == 0


def test_dond_get_after_set_stores_get_value(_param_set, _param_set_2, _param):

n_points = 11

a = GetReturnsCountParameter("a", initial_value=0)
b = TrackingParameter("b", initial_value=0)

a.reset_count()
b.reset_count()

assert a.get_count == 0
assert a.set_count == 0
assert b.get_count == 0
assert b.set_count == 0

ds, _, _ = dond(LinSweep(a, -10, -20, n_points, get_after_set=True), b)

# since we are using the GetReturnsCountParameter the sweep should be count e.g. 0, 1, ... 11
# not the set parameters -10, .. - 20
np.testing.assert_array_equal(
ds.get_parameter_data()["b"]["a"], np.linspace(1, 11, n_points)
)
assert a.get_count == n_points
assert a.set_count == n_points
assert b.get_count == n_points
assert b.set_count == 0
12 changes: 10 additions & 2 deletions qcodes/tests/instrument_mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,11 @@ def get_raw(self):
dac = self.root_instrument._setter_instr
val = self._ed.send(dac.ch1.cache.get())
next(self._ed)
log.debug("Getting raw value of parameter: %s as %s", self.full_name, val)
if self.root_instrument is not None:
mylogger = self.root_instrument.log
else:
mylogger = log
mylogger.debug("Getting raw value of parameter: %s as %s", self.full_name, val)
return val

@staticmethod
Expand Down Expand Up @@ -241,7 +245,11 @@ def get_raw(self):
dac = self.root_instrument._setter_instr
val = self._gauss.send((dac.ch1.cache.get(), dac.ch2.cache.get()))
next(self._gauss)
log.debug("Getting raw value of parameter: %s as %s", self.full_name, val)
if self.root_instrument is not None:
mylogger = self.root_instrument.log
else:
mylogger = log
mylogger.debug("Getting raw value of parameter: %s as %s", self.full_name, val)
return val

def _gauss_model(self):
Expand Down

0 comments on commit faf2750

Please sign in to comment.