QuEL-3 experiment configure check¶
This notebook verifies Experiment(...); exp.configure(...) against your QuEL-3 server. The target planner produces an InstrumentConfiguration containing five-field InstrumentSpec values: port ID, alias, role, and minimum/maximum frequency in Hz.
Inject the controller through Experiment(..., backend_controller=...). Configuration deploys the selected targets and reads complete hardware information into the controller's private runtime cache. Include every target that should remain on each touched port.
The final cells use controller APIs to refresh, inspect, save, and load configuration. Hardware-state and SystemManager pull snapshots are independent diagnostic data and do not populate the runtime cache.
from pathlib import Path
import qubex as qx
from qubex.backend.quel3 import Quel3BackendController
from qubex.system.quel3 import Quel3TargetDeployPlanner
# Example selection
system_id = "144Q-LF-Q3"
if system_id != "144Q-LF-Q3":
raise ValueError(
"This notebook is intended for the QuEL-3 example system `144Q-LF-Q3`."
)
candidate_root_dirs = [
Path.cwd(),
Path.cwd() / "docs/examples/system",
Path.cwd().parent,
Path.cwd().parent.parent,
]
example_root = next(
(
path
for path in candidate_root_dirs
if (path / "config").is_dir() and (path / "params").is_dir()
),
None,
)
if example_root is None:
raise FileNotFoundError(
"Could not find `docs/examples/system/{config,params}` from the current working directory."
)
config_dir = example_root / "config"
params_dir = example_root / "params" / system_id
server_host = "localhost"
server_port = 50051
client_mode = "server"
box_ids = ["quel3-02-a01"]
example_qubits = [f"Q{index:03d}" for index in range(8)]
print(f"example_root: {example_root.resolve()}")
print(f"system_id: {system_id}")
print(f"config_dir: {config_dir.resolve()}")
print(f"params_dir: {params_dir.resolve()}")
print(f"server: {server_host}:{server_port}")
print(f"client_mode: {client_mode}")
print(f"box_ids: {box_ids}")
print(f"example_qubits: {example_qubits}")
backend_controller = Quel3BackendController(
quelware_endpoint=server_host,
quelware_port=server_port,
client_mode=client_mode,
)
exp = qx.Experiment(
system_id=system_id,
qubits=example_qubits,
config_dir=config_dir,
params_dir=params_dir,
backend_controller=backend_controller,
)
print("backend_kind:", exp.system_manager.backend_kind)
print("system_id:", exp.config_loader.system_id)
print("chip_id:", exp.config_loader.chip_id)
print("loaded box_ids:", exp.ctx.box_ids)
print("experiment qubits:", exp.qubit_labels)
print("controller client_mode:", backend_controller.client_mode)
unit_targets = {
label: target
for label, target in sorted(exp.experiment_system.gen_targets.items())
if target.channel.port.box_id == "quel3-02-a01"
}
unit_readout_labels = tuple(
label for label, target in unit_targets.items() if target.type.value == "READ"
)
unit_non_readout_labels = tuple(
label for label, target in unit_targets.items() if target.type.value != "READ"
)
print("quel3-02-a01 generator targets:")
for label, target in unit_targets.items():
print(
f"- {label}: type={target.type.value}, port={target.channel.port.id}, frequency={target.frequency:.6f} GHz"
)
print("quel3-02-a01 readout labels:", unit_readout_labels)
print("quel3-02-a01 non-readout labels:", unit_non_readout_labels)
print(
"quel3-02-a01 has control/readout coverage:",
len(unit_non_readout_labels) > 0 and len(unit_readout_labels) > 0,
)
planner = Quel3TargetDeployPlanner()
preview_configuration = planner.build_configuration(
experiment_system=exp.experiment_system,
box_ids=box_ids,
)
role_counts: dict[str, int] = {}
for spec in preview_configuration.instruments:
role_counts[spec.role] = role_counts.get(spec.role, 0) + 1
print("Planned instrument configuration:")
for spec in preview_configuration.instruments:
print(f"- port_id={spec.port_id}, alias={spec.alias}, role={spec.role}")
print("role counts:", role_counts)
print("role coverage check:", set(role_counts) == {"TRANSMITTER", "TRANSCEIVER"})
exp.configure(box_ids=box_ids)
print("exp.configure() completed.")
unit_labels = sorted(
{spec.port_id.split(":", 1)[0] for spec in preview_configuration.instruments}
)
backend_controller.refresh_instrument_cache(unit_labels=unit_labels)
current_configuration = backend_controller.get_instrument_configuration()
current_aliases = {spec.alias for spec in current_configuration.instruments}
configured_target_labels = tuple(
spec.alias for spec in preview_configuration.instruments
)
missing_target_labels = tuple(
label for label in configured_target_labels if label not in current_aliases
)
print("missing target labels:", missing_target_labels)
print("all configured targets present:", len(missing_target_labels) == 0)
for spec in current_configuration.instruments:
print(f"- {spec.alias}: port_id={spec.port_id}, role={spec.role}")
Save and load specifications¶
Save exports the current cached configuration to YAML. The file contains instrument specifications only; resource IDs and driver configuration are runtime information.
Load parses the file without hardware access or cache changes. Deployment remains an explicit call to backend_controller.deploy_instruments(configuration=loaded).
For independent hardware diagnostics, use backend_controller.print_hardware_state(view="instruments"). Diagnostic snapshots can be partial and are never used to rebuild the execution cache.
configuration_path = example_root / "quel3_instruments.yaml"
saved_path = backend_controller.save_instrument_configuration(configuration_path)
loaded = backend_controller.load_instrument_configuration(saved_path)
assert loaded == current_configuration
print("saved configuration:", saved_path)
print("loaded specifications:", len(loaded.instruments))