Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/instruments initial setup #519

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
759a7d0
work in progress
jjmartinezQT Aug 14, 2023
a788b61
Merge branch 'main' into feature/TAS-247
jjmartinezQT Aug 17, 2023
32f7fb3
fixing init
jjmartinezQT Aug 17, 2023
c169709
work in progress using the flag
jjmartinezQT Aug 18, 2023
ff464c3
Merge branch 'main' into feature/TAS-247
jjmartinezQT Aug 18, 2023
fe1d716
wip
jjmartinezQT Aug 21, 2023
00491d3
wip
jjmartinezQT Aug 21, 2023
746cd0e
changes needed in pulsar and data
jjmartinezQT Aug 22, 2023
316a415
new runcard class for new instruments and buses
jjmartinezQT Aug 22, 2023
a2c4381
checking for flag to be active in connection methods
jjmartinezQT Aug 22, 2023
0183a8a
changes in instrument and platform
jjmartinezQT Aug 22, 2023
7a59699
Merge branch 'main' into feature/TAS-247
jjmartinezQT Aug 22, 2023
c90d7df
sequencers arg
jjmartinezQT Aug 23, 2023
f09069b
initial setup
jjmartinezQT Aug 23, 2023
af3f663
changes in instruments
jjmartinezQT Aug 23, 2023
38ae6d4
Update src/qililab/drivers/instruments/instruments.py
jjmartinezQT Aug 23, 2023
36077d7
changes from PR
jjmartinezQT Aug 23, 2023
37718c7
Merge branch 'feature/instruments_initial_setup' of https://github.co…
jjmartinezQT Aug 23, 2023
bd35267
typo
jjmartinezQT Aug 23, 2023
80d9e33
removing casting
jjmartinezQT Aug 23, 2023
360dd64
redefinition typo
jjmartinezQT Aug 23, 2023
d6a3470
whitespace
jjmartinezQT Aug 23, 2023
6ff3b2c
moved docstrings
jjmartinezQT Aug 23, 2023
389c86d
documentation
jjmartinezQT Aug 23, 2023
74b1907
removing saved params
jjmartinezQT Aug 23, 2023
84d917f
cluster submodules and submodules params
jjmartinezQT Aug 23, 2023
531ca55
adding sequencers retrieval in cluster
jjmartinezQT Aug 23, 2023
ab08c6f
dynamic sequencers adding from list from runcard
jjmartinezQT Aug 23, 2023
0514070
format
jjmartinezQT Aug 23, 2023
05cc858
fix unittest for pulsar
jjmartinezQT Aug 23, 2023
3674e9e
fix for cluster using none
jjmartinezQT Aug 23, 2023
32944bc
fixing docstring
jjmartinezQT Aug 23, 2023
a31d461
fixing unittest for cluster
jjmartinezQT Aug 23, 2023
13d0714
fixing qcm_qrm unittests
jjmartinezQT Aug 23, 2023
267521b
removing new galadriel
jjmartinezQT Aug 23, 2023
c4c0410
Merge branch 'main' into feature/instruments_initial_setup
jjmartinezQT Aug 23, 2023
5992876
isort plus platform from main
jjmartinezQT Aug 23, 2023
54ce432
isort
jjmartinezQT Aug 23, 2023
2d635be
black formatting
jjmartinezQT Aug 23, 2023
60690c9
black formatting
jjmartinezQT Aug 23, 2023
ff6cda8
removing new runcard unittests
jjmartinezQT Aug 23, 2023
49c11a0
changes for pylint
jjmartinezQT Aug 23, 2023
f67822f
deleting new runcard
jjmartinezQT Aug 23, 2023
d02d6a7
formatting
jjmartinezQT Aug 23, 2023
62d5cda
pylint changes
jjmartinezQT Aug 23, 2023
06fafc1
pylint changes
jjmartinezQT Aug 23, 2023
af4391c
pylint changes
jjmartinezQT Aug 23, 2023
856058b
black formatting
jjmartinezQT Aug 23, 2023
9148282
increasing codecoverage
jjmartinezQT Aug 24, 2023
099cf08
formatting
jjmartinezQT Aug 24, 2023
aac5e08
removing file to move it to another PR
jjmartinezQT Aug 24, 2023
45c69a8
remove unused imports
jjmartinezQT Aug 24, 2023
7f6c4bc
adding instrument representations
jjmartinezQT Aug 25, 2023
590560f
instrument representations
jjmartinezQT Aug 25, 2023
6900446
moving internal logic for instrument representation
jjmartinezQT Aug 25, 2023
1c8996e
isort
jjmartinezQT Aug 25, 2023
437511a
isort
jjmartinezQT Aug 25, 2023
07c44a7
isort
jjmartinezQT Aug 25, 2023
c66423e
black formatting
jjmartinezQT Aug 25, 2023
c0acf85
removing prints
jjmartinezQT Aug 25, 2023
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
1 change: 1 addition & 0 deletions src/qililab/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class RUNCARD:
"""YAML constants."""

NAME = "name"
TYPE = "type"
DEVICE_ID = "device_id"
ALIAS = "alias"
INSTRUMENT = "instrument"
Expand Down
12 changes: 11 additions & 1 deletion src/qililab/drivers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,14 @@
~VoltageSource
~Attenuator
"""
from .instruments import GS200, Cluster, ERASynthPlus, Keithley2600, Pulsar, RhodeSchwarzSGS100A, SpiRack
from .instruments import (
GS200,
Cluster,
ERASynthPlus,
InstrumentDriverFactory,
Keithley2600,
Pulsar,
RhodeSchwarzSGS100A,
SpiRack,
)
from .interfaces import BaseInstrument
2 changes: 2 additions & 0 deletions src/qililab/drivers/instruments/keithley/keithley_2600.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Keithley2600 & Keithley2600Channel drivers."""
from typing import Any

from qcodes.instrument.channel import ChannelTuple, InstrumentModule
from qcodes.instrument_drivers.Keithley._Keithley_2600 import Keithley2600 as QCodesKeithley2600
from qcodes.instrument_drivers.Keithley._Keithley_2600 import Keithley2600Channel as QCodesKeithley2600Channel
Expand Down
165 changes: 138 additions & 27 deletions src/qililab/drivers/instruments/qblox/cluster.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from qblox_instruments.qcodes_drivers import Cluster as QcodesCluster
from qblox_instruments.qcodes_drivers.qcm_qrm import QcmQrm as QcodesQcmQrm
from qcodes import Instrument
Expand Down Expand Up @@ -25,15 +27,21 @@ class Cluster(QcodesCluster, BaseInstrument): # pylint: disable=abstract-method
<https://qblox-qblox-instruments.readthedocs-hosted.com/en/master/api_reference/cluster.html>`_.
"""

def __init__(self, name: str, address: str | None = None, **kwargs):
super().__init__(name, identifier=address, **kwargs)
def __init__(self, name: str, submodules: list[dict[str, Any]] | None = None, address: str | None = None, **kwargs):
port = kwargs.get("port", None)
debug = kwargs.get("debug", None)
dummy_cfg = kwargs.get("dummy_cfg", None)
super().__init__(name, identifier=address, port=port, debug=debug, dummy_cfg=dummy_cfg)

# registering only the slots specified in the dummy config if that is the case
if "dummy_cfg" in kwargs:
slot_ids = list(kwargs["dummy_cfg"].keys())
else:
slot_ids = list(range(1, self._num_slots + 1))

self._add_qcm_qrm_modules(slot_ids=slot_ids, submodules=submodules)

def _add_qcm_qrm_modules(self, slot_ids: list[int], submodules: list[dict[str, Any]] | None = None):
# Save information about modules actually being present in the cluster
old_submodules = self.submodules
submodules_present = [submodule.get("present") for submodule in old_submodules.values()]
Expand All @@ -43,13 +51,25 @@ def __init__(self, name: str, address: str | None = None, **kwargs):
self.instrument_modules: dict[str, InstrumentModule] = {} # resetting superclass instrument modules
self._channel_lists: dict[str, ChannelTuple] = {} # resetting superclass channel lists

for slot_idx in slot_ids:
if submodules_present[slot_idx - 1]:
module = QcmQrm(self, f"module{slot_idx}", slot_idx)
self.add_submodule(f"module{slot_idx}", module)
else:
old_module = old_submodules[f"module{slot_idx}"]
self.add_submodule(f"module{slot_idx}", old_module)
if submodules is not None:
for submodule in submodules:
alias = submodule["alias"]
slot_id = submodule["slot_id"]
module_params: dict | None = submodule.get("parameters", None)
sequencers: list[str] | None = submodule.get("sequencers", None)
if submodules_present[slot_id - 1]:
module = QcmQrm(parent=self, alias=alias, slot_idx=slot_id, sequencers=sequencers)
if module_params:
module.initial_setup(module_params)
self.add_submodule(alias, module)
else:
self.add_submodule(f"module{slot_id}", old_submodules[f"module{slot_id}"])
else:
for slot_idx in slot_ids:
if submodules_present[slot_idx - 1]:
self.add_submodule(f"module{slot_idx}", QcmQrm(self, f"module{slot_idx}", slot_idx))
else:
self.add_submodule(f"module{slot_idx}", old_submodules[f"module{slot_idx}"])

@property
def params(self):
Expand All @@ -61,44 +81,80 @@ def alias(self):
"""return the alias of the instrument, which corresponds to the QCodes name attribute"""
return self.name

def instrument_repr(self) -> dict[str, Any]:
"""Returns a dictionary representation of the instrument, parameters and submodules.

Returns:
inst_repr (dict[str, Any]): Instrument representation
"""
inst_repr: dict[str, Any] = {"alias": self.alias}
if self.identifier:
inst_repr["address"] = self.identifier
if self.debug:
inst_repr["debug"] = self.debug
if self.dummy_type:
inst_repr["dummy_cfg"] = self.dummy_cfg

params: dict[str, Any] = {}
for param_name in self.params:
param_value = self.get(param_name)
params[param_name] = param_value
inst_repr["parameters"] = params

submodules: list[dict[str, Any]] = []
for _, submodule in self.submodules.items():
if isinstance(submodule, BaseInstrument):
submodules.append(submodule.instrument_repr())
inst_repr["submodules"] = submodules

return inst_repr


class QcmQrm(QcodesQcmQrm, BaseInstrument):
"""Qililab's driver for QBlox-instruments QcmQrm"""
"""Qililab's driver for QBlox-instruments QcmQrm

def __init__(self, parent: Instrument, name: str, slot_idx: int):
"""Initialise the instrument.
Args:
parent (Instrument): Instrument's parent
name (str): Name of the instrument
slot_idx (int): Index of the slot
"""

Args:
parent (Instrument): Instrument´s parent
name (str): Name of the instrument
slot_idx (int): Index of the slot
"""
super().__init__(parent, name, slot_idx)
def __init__(self, parent: Instrument, alias: str, slot_idx: int, sequencers: list[str] | None = None):
super().__init__(parent=parent, name=alias, slot_idx=slot_idx)
self._add_sequencers(sequencers=sequencers)
self._add_rf_modules(alias=alias)

# Add sequencers
def _add_sequencers(self, sequencers: list[str] | None = None):
"""Adds sequencers to the instrument."""
self.submodules: dict[str, InstrumentModule | ChannelTuple] = {} # resetting superclass submodules
self.instrument_modules: dict[str, InstrumentModule] = {} # resetting superclass instrument modules
self._channel_lists: dict[str, ChannelTuple] = {} # resetting superclass channel lists
sequencer_class = SequencerQCM if self.is_qcm_type else SequencerQRM
for seq_idx in range(6):
seq = sequencer_class(parent=self, name=f"sequencer{seq_idx}", seq_idx=seq_idx) # type: ignore
self.add_submodule(f"sequencer{seq_idx}", seq)
if sequencers is not None:
for seq_idx, seq_name in enumerate(sequencers):
seq = sequencer_class(parent=self, name=seq_name, seq_idx=seq_idx) # type: ignore
self.add_submodule(seq_name, seq)
else:
for seq_idx in range(6):
seq = sequencer_class(parent=self, name=f"sequencer{seq_idx}", seq_idx=seq_idx) # type: ignore
self.add_submodule(f"sequencer{seq_idx}", seq)

# Add RF submodules
def _add_rf_modules(self, alias: str):
"""Adds RF modules to the instrument."""
if super().is_rf_type:
# Add local oscillators
# We use strings as channels to keep the in/out name and conserve the same
# logic as for the attenuator or other instruments
lo_channels = ["out0_in0"] if super().is_qrm_type else ["out0", "out1"]
for channel in lo_channels:
lo = QcmQrmRfLo(name=f"{name}_lo_{channel}", parent=self, channel=channel)
self.add_submodule(f"{name}_lo_{channel}", lo)
lo = QcmQrmRfLo(name=f"{alias}_lo_{channel}", parent=self, channel=channel)
self.add_submodule(f"{alias}_lo_{channel}", lo)

# Add attenuators
att_channels = ["out0", "in0"] if super().is_qrm_type else ["out0", "out1"]
for channel in att_channels:
att = QcmQrmRfAtt(name=f"{name}_attenuator_{channel}", parent=self, channel=channel)
self.add_submodule(f"{name}_attenuator_{channel}", att)
att = QcmQrmRfAtt(name=f"{alias}_attenuator_{channel}", parent=self, channel=channel)
self.add_submodule(f"{alias}_attenuator_{channel}", att)

@property
def params(self):
Expand All @@ -110,6 +166,25 @@ def alias(self):
"""return the alias of the instrument, which corresponds to the QCodes name attribute"""
return self.name

def instrument_repr(self) -> dict[str, Any]:
"""Returns a dictionary representation of the instrument, parameters and submodules.

Returns:
inst_repr (dict[str, Any]): Instrument representation
"""
inst_repr: dict[str, Any] = {"alias": self.alias, "slot_id": self.slot_idx}

params: dict[str, Any] = {}
for param_name in self.params:
param_value = self.get(param_name)
params[param_name] = param_value
inst_repr["parameters"] = params

sequencers = [submodule for submodule in self.submodules]
inst_repr["sequencers"] = sequencers

return inst_repr


class QcmQrmRfLo(InstrumentModule, LocalOscillator):
"""LO driver for the QCM / QRM - RF instrument
Expand Down Expand Up @@ -151,6 +226,24 @@ def on(self):
def off(self):
self.set("status", False)

def instrument_repr(self) -> dict[str, Any]:
"""Returns a dictionary representation of the instrument, parameters and submodules.

Returns:
inst_repr (dict[str, Any]): Instrument representation
"""
inst_repr: dict[str, Any] = {
"alias": self.alias,
}

params: dict[str, Any] = {}
for param_name in self.params:
param_value = self.get(param_name)
params[param_name] = param_value
inst_repr["parameters"] = params

return inst_repr


class QcmQrmRfAtt(InstrumentModule, Attenuator):
"""Attenuator driver for the QCM / QRM - RF instrument
Expand Down Expand Up @@ -179,3 +272,21 @@ def params(self):
def alias(self):
"""return the alias of the instrument, which corresponds to the QCodes name attribute"""
return self.name

def instrument_repr(self) -> dict[str, Any]:
"""Returns a dictionary representation of the instrument, parameters and submodules.

Returns:
inst_repr (dict[str, Any]): Instrument representation
"""
inst_repr: dict[str, Any] = {
"alias": self.alias,
}

params: dict[str, Any] = {}
for param_name in self.params:
param_value = self.get(param_name)
params[param_name] = param_value
inst_repr["parameters"] = params

return inst_repr
47 changes: 41 additions & 6 deletions src/qililab/drivers/instruments/qblox/pulsar.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Driver for the Qblox Pulsar class."""
from typing import Any

from qblox_instruments.qcodes_drivers import Pulsar as QcodesPulsar
from qcodes.instrument.channel import ChannelTuple, InstrumentModule

Expand All @@ -13,24 +15,32 @@
class Pulsar(QcodesPulsar, BaseInstrument): # pylint: disable=abstract-method
"""Qililab's driver for QBlox-instruments Pulsar"""

def __init__(self, name: str, address: str | None = None, **kwargs):
def __init__(self, alias: str, address: str | None = None, sequencers: list[str] | None = None, **kwargs):
"""Initialise the instrument.

Args:
name (str): Sequencer name
alias (str): Pulsar name
address (str): Instrument address
"""
super().__init__(name, identifier=address, **kwargs)
port = kwargs.get("port", None)
debug = kwargs.get("debug", None)
dummy_type = kwargs.get("dummy_type", None)
super().__init__(name=alias, identifier=address, port=port, debug=debug, dummy_type=dummy_type)

# Add sequencers
self.submodules: dict[str, SequencerQCM | SequencerQRM] = {} # resetting superclass submodules
self.instrument_modules: dict[str, InstrumentModule] = {} # resetting superclass instrument modules
self._channel_lists: dict[str, ChannelTuple] = {} # resetting superclass channel lists

sequencer_class = SequencerQCM if self.is_qcm_type else SequencerQRM
for seq_idx in range(6):
seq = sequencer_class(parent=self, name=f"sequencer{seq_idx}", seq_idx=seq_idx) # type: ignore
self.add_submodule(f"sequencer{seq_idx}", seq)
if sequencers is not None:
for seq_idx, seq_name in enumerate(sequencers):
seq = sequencer_class(parent=self, name=seq_name, seq_idx=seq_idx) # type: ignore
self.add_submodule(seq_name, seq)
else:
for seq_idx in range(6):
seq = sequencer_class(parent=self, name=f"sequencer{seq_idx}", seq_idx=seq_idx) # type: ignore
self.add_submodule(f"sequencer{seq_idx}", seq)

@property
def params(self):
Expand All @@ -41,3 +51,28 @@ def params(self):
def alias(self):
"""return the alias of the instrument, which corresponds to the QCodes name attribute"""
return self.name

def instrument_repr(self) -> dict[str, Any]:
"""Returns a dictionary representation of the instrument, parameters and submodules.

Returns:
inst_repr (dict[str, Any]): Instrument representation
"""
inst_repr: dict[str, Any] = {"alias": self.alias}
if self.identifier:
inst_repr["address"] = self.identifier
if self.port:
inst_repr["port"] = self.port
if self.dummy_type:
inst_repr["dummy_type"] = self.dummy_type

params: dict[str, Any] = {}
for param_name in self.params:
param_value = self.get(param_name)
params[param_name] = param_value
inst_repr["parameters"] = params

sequencers = [submodule for submodule in self.submodules]
inst_repr["sequencers"] = sequencers

return inst_repr
Loading