Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/changes/newsfragments/7771.improved_driver
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
On Keithly3706A, allow users to cache forbidden channels in order to bypass unnecessary `_validator()` calls when closing channels.
Results in significant time savings when running measurements with repeated calls to `close_channel()`.
38 changes: 36 additions & 2 deletions src/qcodes/instrument_drivers/Keithley/Keithley_3706A.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import itertools
import textwrap
import warnings
from time import sleep
from typing import TYPE_CHECKING

import qcodes.validators as vals
Expand Down Expand Up @@ -31,16 +32,23 @@ def __init__(
self,
name: str,
address: str,
use_forbidden_channels_cache: bool = False,
**kwargs: "Unpack[VisaInstrumentKWArgs]",
) -> None:
"""
Args:
name: Name to use internally in QCoDeS
address: VISA resource address
use_forbidden_channels_cache: If True, use local
forbidden channel cache instead of querying instrument.
See `Keithley3706A.get_forbidden_channels()` for
usage details and warnings.
**kwargs: kwargs are forwarded to base class.

"""
super().__init__(name, address, **kwargs)
self.use_forbidden_channels_cache: bool = use_forbidden_channels_cache
self.forbidden_channels_cache: str = ""

self.channel_connect_rule: Parameter = self.add_parameter(
"channel_connect_rule",
Expand Down Expand Up @@ -155,7 +163,9 @@ def close_channel(self, val: str) -> None:

"""
slots = ["allslots", *self._get_slot_names()]
forbidden_channels = self.get_forbidden_channels("allslots")
forbidden_channels = self.get_forbidden_channels(
"allslots", fetch_from_cache=self.use_forbidden_channels_cache
)
if val in slots:
raise Keithley3706AInvalidValue("Slots cannot be closed all together.")
if not self._validator(val):
Expand Down Expand Up @@ -331,7 +341,10 @@ def set_forbidden_channels(self, val: str) -> None:
)
self.write(f"channel.setforbidden('{val}')")

def get_forbidden_channels(self, val: str) -> str:
if self.use_forbidden_channels_cache:
self.forbidden_channels_cache = val

def get_forbidden_channels(self, val: str, fetch_from_cache: bool = False) -> str:
"""
Returns a string that lists the channels and backplane relays
that are forbidden to close.
Expand All @@ -340,8 +353,23 @@ def get_forbidden_channels(self, val: str) -> str:
val: A string representing the channels,
backplane relays or channel patterns to be queried to see
if they are forbidden to close.
fetch_from_cache: If True, will fetch forbidden channels from cache,
otherwise, it will query the instrument.
May save time during measurements
where closing channels happens frequently. Please use with
caution since the local cache may become out of sync with
the instrument in the case of an instrument reset and/or
powercycle. If intending to set forbidden channels, always
do so before running a measurement to minimize risk of
cache being out of sync.

"""

# NOTE: The cache string should already be validated from
# calling set_forbidden_channels, so we can just return it
if fetch_from_cache:
return self.forbidden_channels_cache

if not self._validator(val):
raise Keithley3706AInvalidValue(
f"{val} is not a valid specifier. "
Expand All @@ -367,6 +395,12 @@ def clear_forbidden_channels(self, val: str) -> None:
)
self.write(f"channel.clearforbidden('{val}')")

if self.use_forbidden_channels_cache:
wait_for_instrument_to_update_settings_delay = 0.25
sleep(wait_for_instrument_to_update_settings_delay)

self.forbidden_channels_cache = self.get_forbidden_channels("allslots")

def set_delay(self, val: str, delay_time: float) -> None:
"""
Sets an additional delay time for the specified channels.
Expand Down
Loading