Source code for qblox_scheduler.device_under_test.mock_setup
# type: ignore[reportCallIssue] # TODO: Remove after refactoring SchedulerBaseModel.__init__
# Repository: https://gitlab.com/qblox/packages/software/qblox-scheduler
# Licensed according to the LICENSE file on the main branch
#
# Copyright 2020-2025, Quantify Consortium
# Copyright 2025, Qblox B.V.
"""Code to set up a mock setup for use in tutorials and testing."""
from __future__ import annotations
from typing import Any
import numpy as np
from qblox_scheduler.device_under_test.composite_square_edge import (
CompositeSquareEdge,
)
from qblox_scheduler.device_under_test.nv_element import BasicElectronicNVElement
from qblox_scheduler.device_under_test.quantum_device import QuantumDevice
from qblox_scheduler.device_under_test.transmon_element import BasicTransmonElement
from qblox_scheduler.instrument_coordinator import InstrumentCoordinator
from quantify_core.measurement.control import MeasurementControl
[docs]
def set_up_mock_transmon_setup() -> dict:
r"""
Set up a system containing 5 transmon device elements connected in a star shape.
.. code-block::
q0 q1
\ /
q2
/ \
q3 q4
Returns a dictionary containing the instruments that are instantiated as part of
this setup. The keys corresponds to the names of the instruments.
"""
meas_ctrl = MeasurementControl("meas_ctrl")
instrument_coordinator = InstrumentCoordinator(
name="instrument_coordinator", add_default_generic_icc=False
)
q0 = BasicTransmonElement("q0")
q1 = BasicTransmonElement("q1")
q2 = BasicTransmonElement("q2")
q3 = BasicTransmonElement("q3")
q4 = BasicTransmonElement("q4")
# Ensure the readout pulse is not replaced by offsets on Qblox backend for testing purposes.
q0.measure.pulse_duration = 50e-9
edge_q0_q2 = CompositeSquareEdge(parent_element=q0, child_element=q2)
edge_q1_q2 = CompositeSquareEdge(parent_element=q1, child_element=q2)
edge_q2_q3 = CompositeSquareEdge(parent_element=q2, child_element=q3)
edge_q2_q4 = CompositeSquareEdge(parent_element=q2, child_element=q4)
quantum_device = QuantumDevice(name="quantum_device")
quantum_device.add_element(q0)
quantum_device.add_element(q1)
quantum_device.add_element(q2)
quantum_device.add_element(q3)
quantum_device.add_element(q4)
quantum_device.add_edge(edge_q0_q2)
quantum_device.add_edge(edge_q1_q2)
quantum_device.add_edge(edge_q2_q3)
quantum_device.add_edge(edge_q2_q4)
quantum_device.instr_instrument_coordinator = instrument_coordinator
# Rationale of the dict format is that all instruments can be cleaned up by
# iterating over the values and calling close. It also avoids that the instruments
# get garbage-collected while their name is still recorded and used to refer to the
# instruments.
return {
"meas_ctrl": meas_ctrl,
"instrument_coordinator": instrument_coordinator,
"q0": q0,
"q1": q1,
"q2": q2,
"q3": q3,
"q4": q4,
"q0_q2": edge_q0_q2,
"q1_q2": edge_q1_q2,
"q2_q3": edge_q2_q3,
"q2_q4": edge_q2_q4,
"quantum_device": quantum_device,
}
[docs]
def set_standard_params_transmon(mock_setup: dict) -> None:
"""
Set somewhat standard parameters to the mock setup generated above.
These parameters serve so that the quantum-device is capable of generating
a configuration that can be used for compiling schedules.
In normal use, unknown parameters are set as 'nan' values, forcing the user to
set these. However for testing purposes it can be useful to set some semi-random
values. The values here are chosen to reflect typical values as used in practical
experiments.
"""
q0 = mock_setup["q0"]
q0.rxy.amp180 = 0.115
q0.rxy.beta = 2.5e-10
q0.clock_freqs.f01 = 7.3e9
q0.clock_freqs.f12 = 7.0e9
q0.clock_freqs.readout = 8.0e9
q0.measure.acq_delay = 100e-9
q0.measure.acq_channel = 0
q1 = mock_setup["q1"]
q1.rxy.amp180 = 0.325
q1.rxy.beta = 2.5e-10
q1.clock_freqs.f01 = 7.25e9
q1.clock_freqs.f12 = 6.89e9
q1.clock_freqs.readout = 8.3e9
q1.measure.acq_delay = 100e-9
q1.measure.acq_channel = 1
q2 = mock_setup["q2"]
# controlled by a QCM-RF max output amp is 0.25V
q2.rxy.amp180 = 0.213
q2.rxy.beta = 2.5e-10
q2.clock_freqs.f01 = 6.33e9
q2.clock_freqs.f12 = 6.09e9
q2.clock_freqs.readout = 8.5e9
q2.measure.acq_delay = 100e-9
q2.measure.acq_channel = 2
q3 = mock_setup["q3"]
q3.rxy.amp180 = 0.215
q3.rxy.beta = 2.5e-10
q3.clock_freqs.f01 = 5.71e9
q3.clock_freqs.f12 = 5.48e9
q3.clock_freqs.readout = 8.7e9
q3.measure.acq_delay = 100e-9
q3.measure.acq_channel = 3
q4 = mock_setup["q4"]
q4.rxy.amp180 = 0.208
q4.rxy.beta = 2.5e-10
q4.clock_freqs.f01 = 5.68e9
q4.clock_freqs.f12 = 5.41e9
q4.clock_freqs.readout = 9.1e9
q4.measure.acq_delay = 100e-9
q4.measure.acq_channel = 4
for i in range(5):
qi: BasicTransmonElement = mock_setup[f"q{i}"]
sample_rate = 500 # MHz
acq_duration_us = 2
qi.measure.acq_weights_a = np.ones(sample_rate * acq_duration_us) * 0.6 # type: ignore[reportAttributeAccessIssue]
qi.measure.acq_weights_b = np.ones(sample_rate * acq_duration_us) * 0.4 # type: ignore[reportAttributeAccessIssue]
qi.measure.acq_weights_sampling_rate = sample_rate * 1e6
qi.measure.acq_weight_type = "Numerical"
[docs]
def set_up_mock_basic_nv_setup() -> dict:
"""
Set up a system containing 2 electronic device elements in an NV center.
After usage, close all instruments.
Returns
-------
All instruments created. Containing a "quantum_device", electronic qubit "qe0",
"meas_ctrl" and "instrument_coordinator".
"""
meas_ctrl = MeasurementControl("meas_ctrl")
instrument_coordinator = InstrumentCoordinator(
name="instrument_coordinator", add_default_generic_icc=False
)
qe0 = BasicElectronicNVElement("qe0")
qe1 = BasicElectronicNVElement("qe1")
quantum_device = QuantumDevice(name="quantum_device")
quantum_device.add_element(qe0)
quantum_device.add_element(qe1)
quantum_device.instr_instrument_coordinator = instrument_coordinator
# Rationale of the dict format is that all instruments can be cleaned up by
# iterating over the values and calling close. It also avoids that the instruments
# get garbage-collected while their name is still recorded and used to refer to the
# instruments.
return {
"meas_ctrl": meas_ctrl,
"instrument_coordinator": instrument_coordinator,
"qe0": qe0,
"qe1": qe1,
"quantum_device": quantum_device,
}
[docs]
def set_standard_params_basic_nv(mock_nv_device: dict[str, Any]) -> None:
"""
Set somewhat standard parameters to the mock setup generated above.
These parameters serve so that the quantum-device is capable of generating
a configuration that can be used for compiling schedules.
In normal use, unknown parameters are set as 'nan' values, forcing the user to
set these. However for testing purposes it can be useful to set some semi-random
values. The values here are chosen to reflect typical values as used in practical
experiments. All amplitudes for pulses are set to 1e-3.
"""
quantum_device = mock_nv_device["quantum_device"]
qe0: BasicElectronicNVElement = quantum_device.get_element("qe0")
qe0.clock_freqs.f01 = 3.592e9
qe0.clock_freqs.spec = 2.2e9
qe0.clock_freqs.ionization = 564e12
qe0.clock_freqs.ge0 = 470.4e12
qe0.clock_freqs.ge1 = 470.4e12 - 5e9
qe0.charge_reset.amplitude = 1e-3
qe0.cr_count.readout_pulse_amplitude = 1e-3
qe0.cr_count.spinpump_pulse_amplitude = 1e-3
qe0.reset.amplitude = 1e-3
qe0.measure.pulse_amplitude = 1e-3
qe0.measure.acq_channel = 0
qe0.spectroscopy_operation.amplitude = 1e-3
qe0.pulse_compensation.max_compensation_amp = 0.1
qe0.pulse_compensation.time_grid = 4e-9
qe0.pulse_compensation.sampling_rate = 1e9
qe0.rxy.amp180 = 0.5
qe1: BasicElectronicNVElement = quantum_device.get_element("qe1")
qe1.clock_freqs.f01 = 4.874e9
qe1.clock_freqs.spec = 1.4e9
qe1.clock_freqs.ionization = 420e12
qe1.clock_freqs.ge0 = 470.4e12
qe1.clock_freqs.ge1 = 470.4e12 - 5e9
qe1.charge_reset.amplitude = 1e-3
qe1.cr_count.readout_pulse_amplitude = 1e-3
qe1.cr_count.spinpump_pulse_amplitude = 1e-3
qe1.reset.amplitude = 1e-3
qe1.measure.pulse_amplitude = 1e-3
qe1.measure.acq_channel = 1
qe1.spectroscopy_operation.amplitude = 1e-3
qe1.pulse_compensation.max_compensation_amp = 0.1
qe1.pulse_compensation.time_grid = 4e-9
qe1.pulse_compensation.sampling_rate = 1e9
qe1.rxy.amp180 = 0.5