Source code for quantify_scheduler.device_under_test.mock_setup
# Repository: https://gitlab.com/quantify-os/quantify-scheduler
# Licensed according to the LICENCE file on the main branch
"""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 quantify_core.measurement.control import MeasurementControl
from quantify_scheduler.device_under_test.composite_square_edge import (
CompositeSquareEdge,
)
from quantify_scheduler.device_under_test.nv_element import BasicElectronicNVElement
from quantify_scheduler.device_under_test.quantum_device import QuantumDevice
from quantify_scheduler.device_under_test.transmon_element import BasicTransmonElement
from quantify_scheduler.instrument_coordinator import InstrumentCoordinator
[docs]
def set_up_mock_transmon_setup() -> dict:
r"""
Set up a system containing 5 transmon qubits 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.
""" # noqa: D301
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")
edge_q0_q2 = CompositeSquareEdge(parent_element_name=q0.name, child_element_name=q2.name)
edge_q1_q2 = CompositeSquareEdge(parent_element_name=q1.name, child_element_name=q2.name)
edge_q2_q3 = CompositeSquareEdge(parent_element_name=q2.name, child_element_name=q3.name)
edge_q2_q4 = CompositeSquareEdge(parent_element_name=q2.name, child_element_name=q4.name)
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_measurement_control(meas_ctrl.name)
quantum_device.instr_instrument_coordinator(instrument_coordinator.name)
# 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.motzoi(0.1)
q0.clock_freqs.f01(7.3e9)
q0.clock_freqs.f12(7.0e9)
q0.clock_freqs.readout(8.0e9)
q0.measure.acq_delay(100e-9)
q1 = mock_setup["q1"]
q1.rxy.amp180(0.325)
q1.rxy.motzoi(0.1)
q1.clock_freqs.f01(7.25e9)
q1.clock_freqs.f12(6.89e9)
q1.clock_freqs.readout(8.3e9)
q1.measure.acq_delay(100e-9)
q2 = mock_setup["q2"]
# controlled by a QCM-RF max output amp is 0.25V
q2.rxy.amp180(0.213)
q2.rxy.motzoi(0.1)
q2.clock_freqs.f01(6.33e9)
q2.clock_freqs.f12(6.09e9)
q2.clock_freqs.readout(8.5e9)
q2.measure.acq_delay(100e-9)
q3 = mock_setup["q3"]
q3.rxy.amp180(0.215)
q3.rxy.motzoi(0.1)
q3.clock_freqs.f01(5.71e9)
q3.clock_freqs.f12(5.48e9)
q3.clock_freqs.readout(8.7e9)
q3.measure.acq_delay(100e-9)
q4 = mock_setup["q4"]
q4.rxy.amp180(0.208)
q4.rxy.motzoi(0.1)
q4.clock_freqs.f01(5.68e9)
q4.clock_freqs.f12(5.41e9)
q4.clock_freqs.readout(9.1e9)
q4.measure.acq_delay(100e-9)
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)
qi.measure.acq_weights_b(np.ones(sample_rate * acq_duration_us) * 0.4)
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 qubits 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_measurement_control(meas_ctrl.name)
quantum_device.instr_instrument_coordinator(instrument_coordinator.name)
# 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.set(3.592e9)
qe0.clock_freqs.spec.set(2.2e9)
qe0.clock_freqs.ionization.set(564e12)
qe0.clock_freqs.ge0.set(470.4e12)
qe0.clock_freqs.ge1.set(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.spectroscopy_operation.amplitude.set(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.set(4.874e9)
qe1.clock_freqs.spec.set(1.4e9)
qe1.clock_freqs.ionization.set(420e12)
qe1.clock_freqs.ge0.set(470.4e12)
qe1.clock_freqs.ge1.set(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.spectroscopy_operation.amplitude.set(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)