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

Add external mixer support to QuAM. #271

Merged
merged 11 commits into from
Jan 6, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# %%
from qualang_tools.wirer.wirer.channel_specs import opx_spec, octave_spec, opx_iq_octave_spec
from qualang_tools.wirer import Instruments, Connectivity, allocate_wiring, visualize
from quam_libs.quam_builder.machine import build_quam_wiring

# Define static parameters
host_ip = "127.0.0.1" # QOP IP address
port = None # QOP Port
cluster_name = "Cluster_1" # Name of the cluster
# Desired location of wiring.json and state.json
# The folder must not contain other json files.
path = "./quam_state"

# Define the available instrument setup
instruments = Instruments()
instruments.add_opx_plus(controllers=[1])
instruments.add_external_mixer(indices=[1, 2, 3])

# Define which qubit indices are present in the system
qubits = [1, 2]
# Allocate the wiring to the connectivity object based on the available instruments
connectivity = Connectivity()

# Single feed-line for reading the resonators & individual qubit drive lines

# Define any custom/hardcoded channel addresses
# q1_res_ch = octave_spec(index=1, rf_out=1, rf_in=1) # pass to the `constraints` argument
connectivity.add_resonator_line(qubits=qubits, constraints=None)
connectivity.add_qubit_flux_lines(qubits=qubits)
connectivity.add_qubit_drive_lines(qubits=qubits)
# connectivity.add_qubit_pair_flux_lines(qubit_pairs=[(1,2)]) # Tunable coupler
allocate_wiring(connectivity, instruments)

# Single feed-line for reading the resonators & driving the qubits + flux on specific fem slot
# connectivity.add_resonator_line(qubits=qubits, constraints=None)
# connectivity.add_qubit_flux_lines(qubits=qubits)
# connectivity.add_qubit_drive_lines(qubits=qubits)
# # connectivity.add_qubit_pair_flux_lines(qubit_pairs=[(1,2)]) # Tunable coupler
# for qubit in qubits:
# connectivity.add_qubit_drive_lines(qubits=qubit)
# allocate_wiring(connectivity, instruments, block_used_channels=False)

# Build the wiring and network into a QuAM machine and save it as "wiring.json"
build_quam_wiring(connectivity, host_ip, cluster_name, path)

# View wiring schematic
visualize(connectivity.elements, available_channels=instruments.available_channels)
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import os
import warnings
from pathlib import Path

from quam.components import FrequencyConverter
from quam.core import QuamRoot, quam_dataclass
from quam.components.octave import Octave
from quam.components.ports import (
Expand Down Expand Up @@ -30,6 +32,7 @@ class QuAM(QuamRoot):
"""Example QuAM root component."""

octaves: Dict[str, Octave] = field(default_factory=dict)
mixers: Dict[str, FrequencyConverter] = field(default_factory=dict)

qubits: Dict[str, Transmon] = field(default_factory=dict)
qubit_pairs: Dict[str, TransmonPair] = field(default_factory=dict)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from pathlib import Path
from typing import Union, Dict

from quam.components import Octave
from quam.components import Octave, LocalOscillator, Mixer

from qualang_tools.wirer import Connectivity
from quam.components import FrequencyConverter
from quam_libs.quam_builder.pulses import add_default_transmon_pulses, add_default_transmon_pair_pulses
from quam_libs.quam_builder.transmons.add_transmon_drive_component import add_transmon_drive_component
from quam_libs.quam_builder.transmons.add_transmon_flux_component import add_transmon_flux_component
Expand All @@ -17,6 +18,7 @@

def build_quam(machine: QuAM, quam_state_path: Union[Path, str], octaves_settings: Dict = {}) -> QuAM:
add_octaves(machine, octaves_settings, quam_state_path)
add_external_mixers(machine, quam_state_path)
add_ports(machine)
add_transmons(machine)
add_pulses(machine)
Expand Down Expand Up @@ -142,6 +144,26 @@ def add_octaves(machine: QuAM, octaves_settings: Dict, quam_state_path: Union[Pa
return machine


def add_external_mixers(machine: QuAM, quam_state_path: Union[Path, str]):
if isinstance(quam_state_path, str):
quam_state_path = Path(quam_state_path)
quam_state_path = str(quam_state_path.parent.resolve())

for wiring_by_element in machine.wiring.values():
for wiring_by_line_type in wiring_by_element.values():
for references in wiring_by_line_type.values():
for reference in references:
if "mixers" in references.get_unreferenced_value(reference):
frequency_converter = FrequencyConverter(
deanpoulos marked this conversation as resolved.
Show resolved Hide resolved
local_oscillator=LocalOscillator(),
mixer=Mixer(),
)
mixer_name = references.get_unreferenced_value(reference).split('/')[2]
machine.mixers[mixer_name] = frequency_converter

return machine


def save_machine(machine: QuAM, quam_state_path: Union[Path, str]):
machine.save(
path=quam_state_path,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
from typing import List

from .paths import OCTAVES_BASE_JSON_PATH, PORTS_BASE_JSON_PATH
from .paths import OCTAVES_BASE_JSON_PATH, PORTS_BASE_JSON_PATH, MIXERS_BASE_JSON_PATH
from qualang_tools.wirer.instruments.instrument_channel import AnyInstrumentChannel


def create_external_mixer_reference(channel: AnyInstrumentChannel) -> (str, str):
"""
Generates a key/JSON reference pair from which a QuAM port can be created
for a single Octave channel.
"""
if channel.io_type == "output":
key = "frequency_converter_up"
elif channel.io_type == "input":
key = "frequency_converter_down"
else:
raise ValueError(f"Unknown IO type {channel.io_type}")

# todo: fix
reference = MIXERS_BASE_JSON_PATH
reference += f"/mixer_{channel.con}"

return key, reference


def create_octave_port(channel: AnyInstrumentChannel) -> (str, str):
"""
Generates a key/JSON reference pair from which a QuAM port can be created
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from qualang_tools.wirer.connectivity.wiring_spec import WiringLineType
from qualang_tools.wirer.instruments.instrument_channel import AnyInstrumentChannel

from .create_analog_ports import create_octave_port, create_mw_fem_port, create_lf_opx_plus_port
from .create_analog_ports import create_octave_port, create_mw_fem_port, create_lf_opx_plus_port, \
create_external_mixer_reference
from .create_digital_ports import create_digital_output_port
from .paths import *

Expand Down Expand Up @@ -74,6 +75,8 @@ def get_channel_port(channel: AnyInstrumentChannel, channels: List[AnyInstrument
key, reference = create_mw_fem_port(channel)
elif channel.instrument_id in ["lf-fem", "opx+"]:
key, reference = create_lf_opx_plus_port(channel, channels)
elif channel.instrument_id in ["external-mixer"]:
key, reference = create_external_mixer_reference(channel)
else:
raise ValueError(f"Unknown instrument type {channel.instrument_id}")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
MIXERS_BASE_JSON_PATH = "#/mixers"
OCTAVES_BASE_JSON_PATH = "#/octaves"
QUBITS_BASE_JSON_PATH = "#/qubits"
PORTS_BASE_JSON_PATH = "#/ports"
Loading