From 2885fd811ef62171478827e56ea1fa2e0863ebdc Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Fri, 15 Nov 2024 12:47:38 +0100 Subject: [PATCH 1/8] resontor based nodes can load adata, and be multiplexed. Flux is set via the machine --- .../02a_Resonator_Spectroscopy.py | 38 +++--- .../02b_resonator_spectroscopy_vs_flux.py | 104 ++++++++-------- ...02c_resonator_spectroscopy_vs_amplitude.py | 116 +++++++++--------- .../quam_libs/components/quam_root.py | 40 ++++-- .../quam_libs/lib/save_utils.py | 62 +++++++--- 5 files changed, 203 insertions(+), 157 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py index 75c58dfe1..c915b3961 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py @@ -46,7 +46,7 @@ class Parameters(NodeParameters): simulation_duration_ns: int = 2500 timeout: int = 100 load_data_id: Optional[int] = None - multiplexed: bool = False + multiplexed: bool = True node = QualibrationNode(name="02a_Resonator_Spectroscopy", parameters=Parameters()) @@ -146,24 +146,24 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: - ds = load_dataset(node.parameters.load_data_id) + ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) - ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) - # Derive the phase IQ_abs = angle(I + j*Q) - ds = ds.assign({"phase": subtract_slope(apply_angle(ds.I + 1j * ds.Q, dim="freq"), dim="freq")}) - # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting - ds = ds.assign_coords( - { - "freq_full": ( - ["qubit", "freq"], - np.array([dfs + q.resonator.RF_frequency for q in qubits]), - ) - } - ) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) + ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) + # Derive the phase IQ_abs = angle(I + j*Q) + ds = ds.assign({"phase": subtract_slope(apply_angle(ds.I + 1j * ds.Q, dim="freq"), dim="freq")}) + # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting + ds = ds.assign_coords( + { + "freq_full": ( + ["qubit", "freq"], + np.array([dfs + q.resonator.RF_frequency for q in qubits]), + ) + } + ) # Add the dataset to the node node.results = {"ds": ds} @@ -233,9 +233,13 @@ class Parameters(NodeParameters): q.resonator.intermediate_frequency += int(fits[q.name].params["omega_r"].value) # %% {Save_results} + if node.parameters.load_data_id is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() print("Results saved") + +# %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py index 2f0d08675..fafd0a532 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py @@ -24,7 +24,7 @@ from quam_libs.macros import qua_declaration from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_oscillation from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -51,11 +51,11 @@ class Parameters(NodeParameters): flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" input_line_impedance_in_ohm: float = 50 line_attenuation_in_db: float = 0 - update_flux_min: bool = False + update_flux_min: bool = True simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = 7 node = QualibrationNode(name="02b_Resonator_Spectroscopy_vs_Flux", parameters=Parameters()) @@ -111,13 +111,8 @@ class Parameters(NodeParameters): # resonator of the qubit rr = resonators[i] # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -163,7 +158,7 @@ class Parameters(NodeParameters): node.results = {"figure": plt.gcf()} node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(multi_res_spec_vs_flux) results = fetching_tool(job, ["n"], mode="live") @@ -175,27 +170,30 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs, "flux": dcs}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) - ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) - # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting - RF_freq = np.array([dfs + q.resonator.RF_frequency for q in qubits]) - ds = ds.assign_coords({"freq_full": (["qubit", "freq"], RF_freq)}) - ds.freq_full.attrs["long_name"] = "Frequency" - ds.freq_full.attrs["units"] = "GHz" - # Add the current axis of each qubit to the dataset coordinates for plotting - current = np.array([ds.flux.values / node.parameters.input_line_impedance_in_ohm for q in qubits]) - ds = ds.assign_coords({"current": (["qubit", "flux"], current)}) - ds.current.attrs["long_name"] = "Current" - ds.current.attrs["units"] = "A" - # Add attenuated current to dataset - attenuation_factor = 10 ** (-node.parameters.line_attenuation_in_db / 20) - attenuated_current = ds.current * attenuation_factor - ds = ds.assign_coords({"attenuated_current": (["qubit", "flux"], attenuated_current.values)}) - ds.attenuated_current.attrs["long_name"] = "Attenuated Current" - ds.attenuated_current.attrs["units"] = "A" + if node.parameters.load_data_id is not None: + ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + else: + ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs, "flux": dcs}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) + ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) + # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting + RF_freq = np.array([dfs + q.resonator.RF_frequency for q in qubits]) + ds = ds.assign_coords({"freq_full": (["qubit", "freq"], RF_freq)}) + ds.freq_full.attrs["long_name"] = "Frequency" + ds.freq_full.attrs["units"] = "GHz" + # Add the current axis of each qubit to the dataset coordinates for plotting + current = np.array([ds.flux.values / node.parameters.input_line_impedance_in_ohm for q in qubits]) + ds = ds.assign_coords({"current": (["qubit", "flux"], current)}) + ds.current.attrs["long_name"] = "Current" + ds.current.attrs["units"] = "A" + # Add attenuated current to dataset + attenuation_factor = 10 ** (-node.parameters.line_attenuation_in_db / 20) + attenuated_current = ds.current * attenuation_factor + ds = ds.assign_coords({"attenuated_current": (["qubit", "flux"], attenuated_current.values)}) + ds.attenuated_current.attrs["long_name"] = "Attenuated Current" + ds.attenuated_current.attrs["units"] = "A" # Add the dataset to the node node.results = {"ds": ds} @@ -214,15 +212,16 @@ class Parameters(NodeParameters): flux_min = flux_min * (np.abs(flux_min) < 0.5) + 0.5 * (flux_min > 0.5) - 0.5 * (flux_min < -0.5) # finding the frequency as the sweet spot flux rel_freq_shift = peak_freq.sel(flux=idle_offset, method="nearest") - + abs_freqs = ds.sel(flux=idle_offset, method="nearest").sel(freq = rel_freq_shift).freq_full # Save fitting results fit_results = {} for q in qubits: fit_results[q.name] = {} - fit_results[q.name]["resonator_frequency"] = rel_freq_shift.sel(qubit=q.name).values + q.resonator.RF_frequency + fit_results[q.name]["resonator_frequency"] = abs_freqs.sel(qubit=q.name).values fit_results[q.name]["min_offset"] = float(flux_min.sel(qubit=q.name).data) fit_results[q.name]["offset"] = float(idle_offset.sel(qubit=q.name).data) fit_results[q.name]["dv_phi0"] = 1 / fit_osc.sel(fit_vals="f", qubit=q.name).values + attenuation_factor = 10 ** (-node.parameters.line_attenuation_in_db / 20) fit_results[q.name]["m_pH"] = ( 1e12 * 2.068e-15 @@ -277,7 +276,7 @@ class Parameters(NodeParameters): # Location of the current resonator frequency ax.plot( idle_offset.loc[qubit].values, - (machine.qubits[qubit["qubit"]].resonator.RF_frequency + rel_freq_shift.sel(qubit=qubit["qubit"]).values) + (abs_freqs.sel(qubit=qubit["qubit"]).values) * 1e-9, "r*", markersize=10, @@ -291,25 +290,30 @@ class Parameters(NodeParameters): node.results["figure"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for q in qubits: - if not (np.isnan(float(idle_offset.sel(qubit=q.name).data))): - if flux_point == "independent": - q.z.independent_offset = float(idle_offset.sel(qubit=q.name).data) - else: - q.z.joint_offset = float(idle_offset.sel(qubit=q.name).data) - - if update_flux_min: - q.z.min_offset = float(flux_min.sel(qubit=q.name).data) - q.resonator.intermediate_frequency += float(rel_freq_shift.sel(qubit=q.name).data) - q.phi0_voltage = fit_results[q.name]["dv_phi0"] - q.phi0_current = ( - fit_results[q.name]["dv_phi0"] * node.parameters.input_line_impedance_in_ohm * attenuation_factor - ) + if not node.parameters.load_data_id: + with node.record_state_updates(): + for q in qubits: + if not (np.isnan(float(idle_offset.sel(qubit=q.name).data))): + if flux_point == "independent": + q.z.independent_offset = float(idle_offset.sel(qubit=q.name).data) + else: + q.z.joint_offset = float(idle_offset.sel(qubit=q.name).data) + + if update_flux_min: + q.z.min_offset = float(flux_min.sel(qubit=q.name).data) + q.resonator.intermediate_frequency += float(rel_freq_shift.sel(qubit=q.name).data) + q.phi0_voltage = fit_results[q.name]["dv_phi0"] + q.phi0_current = ( + fit_results[q.name]["dv_phi0"] * node.parameters.input_line_impedance_in_ohm * attenuation_factor + ) # %% {Save_results} + if node.parameters.load_data_id is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() + +# %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py index fa9a229ac..dbea29a3f 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py @@ -27,7 +27,7 @@ from quam_libs.macros import qua_declaration from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import peaks_dips from quam_libs.trackable_object import tracked_updates from qualang_tools.results import progress_counter, fetching_tool @@ -52,14 +52,14 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - max_power_dbm: int = -30 + max_power_dbm: int = -20 min_power_dbm: int = -50 num_power_points: int = 100 max_amp: float = 0.1 flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" ro_line_attenuation_dB: float = 0 multiplexed: bool = False - + load_data_id: Optional[int] = None node = QualibrationNode(name="02c_Resonator_Spectroscopy_vs_Amplitude", parameters=Parameters()) @@ -158,14 +158,9 @@ def set_output_power( for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() - + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.align() + # resonator of this qubit rr = qubit.resonator @@ -186,7 +181,7 @@ def set_output_power( save(I[i], I_st[i]) save(Q[i], Q_st[i]) if not node.parameters.multiplexed: - align(*[rr.name for rr in resonators]) + align() with stream_processing(): n_st.save("n") @@ -213,11 +208,9 @@ def set_output_power( node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(multi_res_spec_vs_amp) - - # %% {Live_plot} results = fetching_tool(job, ["n"], mode="live") while results.is_processing(): # Fetch results @@ -227,47 +220,50 @@ def set_output_power( # %% {Data_fetching_and_dataset_creation} # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "freq": dfs}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) - ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) - # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting - RF_freq = np.array([dfs + q.resonator.RF_frequency for q in qubits]) - ds = ds.assign_coords({"freq_full": (["qubit", "freq"], RF_freq)}) - ds.freq_full.attrs["long_name"] = "Frequency" - ds.freq_full.attrs["units"] = "GHz" - - # Add the absolute readout pulse amplitude to the dataset - def abs_amp(q): - def foo(amp): - return amp * node.parameters.max_amp - - return foo - - def abs_pow(q): - def foo(amp): - return amp + q.resonator.get_output_power("readout") - - return foo - - ds = ds.assign_coords({"abs_amp": (["qubit", "amp"], np.array([abs_amp(q)(amps) for q in qubits]))}) - ds.abs_amp.attrs["long_name"] = "Amplitude" - ds.abs_amp.attrs["units"] = "V" - # Add the absolute readout power to the dataset - # ds = ds.assign_coords({'power_dbm': (['qubit', 'amp'], np.array([u.volts2dBm(a) - node.parameters.ro_line_attenuation_dB for a in ds.abs_amp.values]))}) - ds = ds.assign_coords( - { - "power_dbm": ( - ["qubit", "amp"], - np.array([abs_pow(q)(20 * np.log10(amps)) - node.parameters.ro_line_attenuation_dB for q in qubits]), - ) - } - ) - ds.power_dbm.attrs["long_name"] = "Power" - ds.power_dbm.attrs["units"] = "dBm" - # Normalize the IQ_abs with respect to the amplitude axis - ds = ds.assign({"IQ_abs_norm": ds["IQ_abs"] / ds.IQ_abs.mean(dim=["freq"])}) + if node.parameters.load_data_id is not None: + ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + else: + ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "freq": dfs}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) + ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) + # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting + RF_freq = np.array([dfs + q.resonator.RF_frequency for q in qubits]) + ds = ds.assign_coords({"freq_full": (["qubit", "freq"], RF_freq)}) + ds.freq_full.attrs["long_name"] = "Frequency" + ds.freq_full.attrs["units"] = "GHz" + + # Add the absolute readout pulse amplitude to the dataset + def abs_amp(q): + def foo(amp): + return amp * node.parameters.max_amp + + return foo + + def abs_pow(q): + def foo(amp): + return amp + q.resonator.get_output_power("readout") + + return foo + + ds = ds.assign_coords({"abs_amp": (["qubit", "amp"], np.array([abs_amp(q)(amps) for q in qubits]))}) + ds.abs_amp.attrs["long_name"] = "Amplitude" + ds.abs_amp.attrs["units"] = "V" + # Add the absolute readout power to the dataset + # ds = ds.assign_coords({'power_dbm': (['qubit', 'amp'], np.array([u.volts2dBm(a) - node.parameters.ro_line_attenuation_dB for a in ds.abs_amp.values]))}) + ds = ds.assign_coords( + { + "power_dbm": ( + ["qubit", "amp"], + np.array([abs_pow(q)(20 * np.log10(amps)) - node.parameters.ro_line_attenuation_dB for q in qubits]), + ) + } + ) + ds.power_dbm.attrs["long_name"] = "Power" + ds.power_dbm.attrs["units"] = "dBm" + # Normalize the IQ_abs with respect to the amplitude axis + ds = ds.assign({"IQ_abs_norm": ds["IQ_abs"] / ds.IQ_abs.mean(dim=["freq"])}) # Add the dataset to the node node.results = {"ds": ds} @@ -319,7 +315,7 @@ def foo(amp): ) # Plot where the optimum readout power was found ax2.axhline( - y=abs_amp(machine.qubits[qubit["qubit"]])(rr_pwr.loc[qubit]).values, + y=ds.sel(amp = rr_pwr, method = "nearest").abs_amp.loc[qubit].data, color="r", linestyle="--", ) @@ -334,7 +330,7 @@ def foo(amp): fit_results = {} for q in qubits: fit_results[q.name] = {} - if float(rr_pwr.sel(qubit=q.name)) > 0: + if node.parameters.load_data_id is None and float(rr_pwr.sel(qubit=q.name)) > 0: with node.record_state_updates(): q.resonator.operations["readout"].amplitude = float(rr_pwr.sel(qubit=q.name)) q.resonator.intermediate_frequency += int(res_low_power.sel(qubit=q.name).values) @@ -347,8 +343,12 @@ def foo(amp): tracked_qubit.revert_changes() # %% {Save_results} + if node.parameters.load_data_id is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() + +# %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/components/quam_root.py b/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/components/quam_root.py index 59642ea72..623f58d8a 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/components/quam_root.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/components/quam_root.py @@ -16,7 +16,6 @@ from .transmon import Transmon from .transmon_pair import TransmonPair -from qm.qua import align from qm import QuantumMachinesManager, QuantumMachine from qualang_tools.results.data_handler import DataHandler @@ -98,49 +97,64 @@ def thermalization_time(self) -> int: def apply_all_couplers_to_min(self) -> None: """Apply the offsets that bring all the active qubit pairs to a decoupled point.""" - align() for qp in self.active_qubit_pairs: if qp.coupler is not None: qp.coupler.to_decouple_idle() - align() def apply_all_flux_to_joint_idle(self) -> None: """Apply the offsets that bring all the active qubits to the joint sweet spot.""" - align() for q in self.active_qubits: if q.z is not None: q.z.to_joint_idle() - q.z.settle() else: warnings.warn(f"Didn't find z-element on qubit {q.name}, didn't set to joint-idle") for q in self.qubits: if self.qubits[q] not in self.active_qubits: if self.qubits[q].z is not None: self.qubits[q].z.to_min() - self.qubits[q].z.settle() else: warnings.warn(f"Didn't find z-element on qubit {q}, didn't set to min") - align() + self.apply_all_couplers_to_min() def apply_all_flux_to_min(self) -> None: """Apply the offsets that bring all the active qubits to the minimum frequency point.""" - align() for q in self.qubits: if self.qubits[q].z is not None: self.qubits[q].z.to_min() - self.qubits[q].z.settle() else: warnings.warn(f"Didn't find z-element on qubit {q}, didn't set to min") self.apply_all_couplers_to_min() - align() def apply_all_flux_to_zero(self) -> None: """Apply the offsets that bring all the active qubits to the zero bias point.""" - align() for q in self.active_qubits: q.z.to_zero() - q.z.settle() - align() + + + def set_all_fluxes(self, flux_point : str, target : Union[Transmon, TransmonPair]): + if flux_point == "independent": + assert isinstance(target, Transmon), "Independent flux point is only supported for individual transmons" + elif flux_point == "pairwise": + assert isinstance(target, TransmonPair), "Pairwise flux point is only supported for transmon pairs" + + if flux_point == "joint": + self.apply_all_flux_to_joint_idle() + if isinstance(target, TransmonPair): + target_bias =target.mutual_flux_bias + else: + target_bias = target.z.joint_offset + else: + self.apply_all_flux_to_min() + + if flux_point == "independent": + target.z.to_independent_idle() + target_bias = target.z.independent_offset + + elif flux_point == "pairwise": + target.to_mutual_idle() + target_bias = target.mutual_flux_bias + + return target_bias def connect(self) -> QuantumMachinesManager: """Open a Quantum Machine Manager with the credentials ("host" and "cluster_name") as defined in the network file. diff --git a/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py b/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py index 0a2fa07ac..aed2ff586 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py @@ -3,7 +3,7 @@ import os from pathlib import Path import xarray as xr - +import json def extract_string(input_string): # Find the index of the first occurrence of a digit in the input string @@ -50,44 +50,68 @@ def get_storage_path(): return Path(storage_location) -def find_folder(path, id): - for root, dirs, _ in os.walk(path): - for dir in dirs: - if f"#{id}" in dir: - return os.path.join(root, dir) +def find_numbered_folder(base_path, number): + """ + Find folder that starts with '#number_' + Will match '#number_something' but not '#number' alone + """ + search_prefix = f"#{number}_" + + # Manual search for folder starting with #number_ and having something after + for root, dirs, _ in os.walk(base_path): + matching_dirs = [d for d in dirs if d.startswith(search_prefix) and len(d) > len(search_prefix)] + if matching_dirs: + return os.path.join(root, matching_dirs[0]) + return None -def load_dataset(serial_number): + +def load_dataset(serial_number, target_filename = "ds", parameters = None): """ Loads a dataset from a file based on the serial number. - + Args: serial_number: The serial number to search for. base_folder: The base directory to search in. - + Returns: An xarray Dataset if found, None otherwise. """ - if type(serial_number) == int: - serial_number = str(serial_number) - - base_folder = find_folder(get_storage_path(), serial_number) + if not isinstance(serial_number, int): + raise ValueError("serial_number must be an integer") + + base_folder = find_numbered_folder(get_storage_path(),serial_number) # Look for .nc files in the subfolder - nc_files = [f for f in os.listdir(base_folder) if f.endswith(".h5")] - + nc_files = [f for f in os.listdir(base_folder) if f.endswith('.h5')] + + # look for filename.h5 + is_present = target_filename in [file.split('.')[0] for file in nc_files] + filename = [file for file in nc_files if target_filename == file.split('.')[0]][0] if is_present else None + json_filename = "data.json" + if nc_files: # Assuming there's only one .nc file per folder - file_path = os.path.join(base_folder, nc_files[0]) - + file_path = os.path.join(base_folder, filename) + json_path = os.path.join(base_folder, json_filename) # Open the dataset ds = xr.open_dataset(file_path) + with open(json_path, 'r') as f: + json_data = json.load(f) try: - machine = QuAM.load(base_folder) + machine = QuAM.load(base_folder + "//quam_state.json") except Exception as e: print(f"Error loading machine: {e}") machine = None - return ds, machine + + if parameters is not None: + for param_name, param_value in parameters: + if param_name is not "load_data_id": + if param_name in json_data["initial_parameters"]: + setattr(parameters, param_name, json_data["initial_parameters"][param_name]) + return ds, machine, json_data, parameters + else: + return ds, machine, json_data else: print(f"No .nc file found in folder: {base_folder}") return None From 6c3ead575f824d1b88918b9e99599f8f0368968a Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Fri, 15 Nov 2024 16:36:28 +0100 Subject: [PATCH 2/8] qubit spec and vs flux can load data, qubit spec vs flux using pulses --- .../02a_Resonator_Spectroscopy.py | 3 +- .../02b_resonator_spectroscopy_vs_flux.py | 8 +- ...02c_resonator_spectroscopy_vs_amplitude.py | 3 +- .../03a_Qubit_Spectroscopy.py | 201 ++++++++---------- .../03b_qubit_spectroscopy_vs_flux.py | 112 +++++----- 5 files changed, 155 insertions(+), 172 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py index c915b3961..5fa2dd10b 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py @@ -234,7 +234,8 @@ class Parameters(NodeParameters): # %% {Save_results} if node.parameters.load_data_id is not None: - node.storage_manager.active_machine_path = None + if node.storage_manager is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py index fafd0a532..e812b2c7b 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py @@ -51,11 +51,11 @@ class Parameters(NodeParameters): flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" input_line_impedance_in_ohm: float = 50 line_attenuation_in_db: float = 0 - update_flux_min: bool = True + update_flux_min: bool = False simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - load_data_id: Optional[int] = 7 + load_data_id: Optional[int] = None node = QualibrationNode(name="02b_Resonator_Spectroscopy_vs_Flux", parameters=Parameters()) @@ -309,11 +309,13 @@ class Parameters(NodeParameters): # %% {Save_results} if node.parameters.load_data_id is not None: - node.storage_manager.active_machine_path = None + if node.storage_manager is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() + # %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py index dbea29a3f..d5eca0a15 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py @@ -344,7 +344,8 @@ def foo(amp): # %% {Save_results} if node.parameters.load_data_id is not None: - node.storage_manager.active_machine_path = None + if node.storage_manager is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py index ce27d5eb4..18dff6028 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py @@ -28,7 +28,7 @@ from quam_libs.macros import qua_declaration from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import peaks_dips from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -51,13 +51,15 @@ class Parameters(NodeParameters): operation_len_in_ns: Optional[int] = None frequency_span_in_mhz: float = 50 frequency_step_in_mhz: float = 0.25 - flux_point_joint_or_independent_or_arbitrary: Literal["joint", "independent", "arbitrary"] = "independent" + flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" target_peak_width: Optional[float] = 2e6 arbitrary_flux_bias: Optional[float] = None arbitrary_qubit_frequency_in_ghz: Optional[float] = None simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="03a_Qubit_Spectroscopy", parameters=Parameters()) @@ -95,30 +97,20 @@ class Parameters(NodeParameters): span = node.parameters.frequency_span_in_mhz * u.MHz step = node.parameters.frequency_step_in_mhz * u.MHz dfs = np.arange(-span // 2, +span // 2, step, dtype=np.int32) -flux_point = node.parameters.flux_point_joint_or_independent_or_arbitrary +flux_point = node.parameters.flux_point_joint_or_independent qubit_freqs = {q.name: q.xy.RF_frequency for q in qubits} # for opx # qubit_freqs = {q.name : q.xy.intermediate_frequency + q.xy.opx_output.upconverter_frequency for q in qubits} # TODO: for MW # Set the qubit frequency for a given flux point -if flux_point == "arbitrary": - if node.parameters.arbitrary_flux_bias is None and node.parameters.arbitrary_qubit_frequency_in_ghz is None: - raise ValueError( - "arbitrary_flux_bias or arbitrary_qubit_frequency_in_ghz must be provided when flux_point is 'arbitrary'" - ) - elif ( - node.parameters.arbitrary_flux_bias is not None and node.parameters.arbitrary_qubit_frequency_in_ghz is not None - ): - raise ValueError( - "provide either arbitrary_flux_bias or arbitrary_qubit_frequency_in_ghz, not both when flux_point is 'arbitrary'" - ) - elif node.parameters.arbitrary_flux_bias is not None: - arb_flux_bias_offset = {q.name: node.parameters.arbitrary_flux_bias for q in qubits} - detunings = {q.name: q.freq_vs_flux_01_quad_term * arb_flux_bias_offset[q.name] ** 2 for q in qubits} - else: - detunings = { - q.name: 1e9 * node.parameters.arbitrary_qubit_frequency_in_ghz - qubit_freqs[q.name] for q in qubits - } - arb_flux_bias_offset = {q.name: np.sqrt(detunings[q.name] / q.freq_vs_flux_01_quad_term) for q in qubits} +if node.parameters.arbitrary_flux_bias is not None: + arb_flux_bias_offset = {q.name: node.parameters.arbitrary_flux_bias for q in qubits} + detunings = {q.name: q.freq_vs_flux_01_quad_term * arb_flux_bias_offset[q.name] ** 2 for q in qubits} +elif node.parameters.arbitrary_qubit_frequency_in_ghz is not None: + detunings = { + q.name: 1e9 * node.parameters.arbitrary_qubit_frequency_in_ghz - qubit_freqs[q.name] for q in qubits + } + arb_flux_bias_offset = {q.name: np.sqrt(detunings[q.name] / q.freq_vs_flux_01_quad_term) for q in qubits} + else: arb_flux_bias_offset = {q.name: 0.0 for q in qubits} detunings = {q.name: 0.0 for q in qubits} @@ -136,39 +128,26 @@ class Parameters(NodeParameters): df = declare(int) # QUA variable for the qubit frequency for i, qubit in enumerate(qubits): - # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - dc_offset = qubit.z.independent_offset - elif flux_point == "joint" or "arbitrary": - machine.apply_all_flux_to_joint_idle() - dc_offset = qubit.z.joint_offset - else: - machine.apply_all_flux_to_zero() - dc_offset = 0.0 - + # Bring the active qubits to the desired frequency point + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.align() + with for_(n, 0, n < n_avg, n + 1): save(n, n_st) with for_(*from_array(df, dfs)): - # Bring the qubit to the desired point - qubit.z.set_dc_offset(dc_offset + arb_flux_bias_offset[qubit.name]) - qubit.z.settle() # Update the qubit frequency qubit.xy.update_frequency(df + qubit.xy.intermediate_frequency + detunings[qubit.name]) qubit.align() - + duration = operation_len * u.ns if operation_len is not None else qubit.xy.operations[operation].length // 4 + # Bring the qubit to the desired point during the satruration pulse + qubit.z.play("const", amplitude_scale=arb_flux_bias_offset[qubit.name] / qubit.z.operations["const"].amplitude, duration=duration) # Play the saturation pulse qubit.xy.play( operation, amplitude_scale=operation_amp, - duration=(operation_len * u.ns if operation_len is not None else None), + duration=duration, ) qubit.align() - # Bring back the flux for readout - qubit.z.set_dc_offset(dc_offset) - qubit.z.settle() - qubit.align() # readout the resonator qubit.resonator.measure("readout", qua_vars=(I[i], Q[i])) @@ -179,7 +158,8 @@ class Parameters(NodeParameters): save(Q[i], Q_st[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -206,11 +186,9 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(qubit_spec) - - # %% {Live_plot} results = fetching_tool(job, ["n"], mode="live") while results.is_processing(): # Fetch results @@ -219,24 +197,27 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) and phase - ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) - ds = ds.assign({"phase": np.arctan2(ds.Q, ds.I)}) - # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting - ds = ds.assign_coords( - { - "freq_full": ( - ["qubit", "freq"], - np.array([dfs + qubit_freqs[q.name] + detunings[q.name] for q in qubits]), - ) - } - ) - ds.freq_full.attrs["long_name"] = "Frequency" - ds.freq_full.attrs["units"] = "GHz" + if node.parameters.load_data_id is not None: + ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + else: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) and phase + ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) + ds = ds.assign({"phase": np.arctan2(ds.Q, ds.I)}) + # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting + ds = ds.assign_coords( + { + "freq_full": ( + ["qubit", "freq"], + np.array([dfs + qubit_freqs[q.name] + detunings[q.name] for q in qubits]), + ) + } + ) + ds.freq_full.attrs["long_name"] = "Frequency" + ds.freq_full.attrs["units"] = "GHz" # Add the dataset to the node node.results = {"ds": ds} @@ -249,7 +230,7 @@ class Parameters(NodeParameters): ds.sel(freq=shifts).I - ds.I.mean(dim="freq"), ) # rotate the data to the new I axis - ds = ds.assign({"I_rot": np.real(ds.IQ_abs * np.exp(1j * (ds.phase - angle)))}) + ds = ds.assign({"I_rot" : ds.I * np.cos(angle) + ds.Q * np.sin(angle)}) # Find the peak with minimal prominence as defined, if no such peak found, returns nan result = peaks_dips(ds.I_rot, dim="freq", prominence_factor=5) # The resonant RF frequency of the qubits @@ -257,9 +238,9 @@ class Parameters(NodeParameters): [ ( q.name, - result.sel(qubit=q.name).position.values + qubit_freqs[q.name] + detunings[q.name], + ds.freq_full.sel(freq = result.position).sel(qubit=q.name).values, ) - for q in qubits + for q in qubits if not np.isnan(result.sel(qubit=q.name).position.values) ] ) @@ -303,15 +284,16 @@ class Parameters(NodeParameters): # Plot the line (ds.assign_coords(freq_GHz=ds.freq_full / 1e9).loc[qubit].I_rot * 1e3).plot(ax=ax, x="freq_GHz") # Identify the resonance peak - ax.plot( - abs_freqs[qubit["qubit"]] / 1e9, - ds.loc[qubit].sel(freq=result.loc[qubit].position.values, method="nearest").I_rot * 1e3, - ".r", - ) - # Identify the width - (approx_peak.assign_coords(freq_GHz=ds.freq_full / 1e9).loc[qubit] * 1e3).plot( - ax=ax, x="freq_GHz", linewidth=0.5, linestyle="--" - ) + if not np.isnan(result.sel(qubit=qubit["qubit"]).position.values): + ax.plot( + abs_freqs[qubit["qubit"]] / 1e9, + ds.loc[qubit].sel(freq=result.loc[qubit].position.values, method="nearest").I_rot * 1e3, + ".r", + ) + # # Identify the width + (approx_peak.assign_coords(freq_GHz=ds.freq_full / 1e9).loc[qubit] * 1e3).plot( + ax=ax, x="freq_GHz", linewidth=0.5, linestyle="--" + ) ax.set_xlabel("Qubit freq [GHz]") ax.set_ylabel("Trans. amp. [mV]") ax.set_title(qubit["qubit"]) @@ -321,41 +303,46 @@ class Parameters(NodeParameters): node.results["figure"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for q in qubits: - if not np.isnan(result.sel(qubit=q.name).position.values): - if flux_point == "arbitrary": - q.arbitrary_intermediate_frequency = float( - result.sel(qubit=q.name).position.values + detunings[q.name] + q.xy.intermediate_frequency - ) - q.z.arbitrary_offset = arb_flux_bias_offset[q.name] - else: - q.xy.intermediate_frequency += float(result.sel(qubit=q.name).position.values) - if not flux_point == "arbitrary": - prev_angle = q.resonator.operations["readout"].integration_weights_angle - if not prev_angle: - prev_angle = 0.0 - q.resonator.operations["readout"].integration_weights_angle = ( - prev_angle + angle.sel(qubit=q.name).values - ) % (2 * np.pi) - Pi_length = q.xy.operations["x180"].length - used_amp = q.xy.operations["saturation"].amplitude * operation_amp - factor_cw = float(target_peak_width / result.sel(qubit=q.name).width.values) - factor_pi = np.pi / (result.sel(qubit=q.name).width.values * Pi_length * 1e-9) - if factor_cw * used_amp / operation_amp < 0.5: # TODO: 1 for OPX1000 MW - q.xy.operations["saturation"].amplitude = factor_cw * used_amp / operation_amp + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + if not np.isnan(result.sel(qubit=q.name).position.values): + if flux_point == "arbitrary": + q.arbitrary_intermediate_frequency = float( + result.sel(qubit=q.name).position.values + detunings[q.name] + q.xy.intermediate_frequency + ) + q.z.arbitrary_offset = arb_flux_bias_offset[q.name] else: - q.xy.operations["saturation"].amplitude = 0.5 # TODO: 1 for OPX1000 MW - - if factor_pi * used_amp < 0.3: # TODO: 1 for OPX1000 MW - q.xy.operations["x180"].amplitude = factor_pi * used_amp - elif factor_pi * used_amp >= 0.3: # TODO: 1 for OPX1000 MW - q.xy.operations["x180"].amplitude = 0.3 - node.results["ds"] = ds + q.xy.intermediate_frequency += float(result.sel(qubit=q.name).position.values) + if not flux_point == "arbitrary": + prev_angle = q.resonator.operations["readout"].integration_weights_angle + if not prev_angle: + prev_angle = 0.0 + q.resonator.operations["readout"].integration_weights_angle = ( + prev_angle + angle.sel(qubit=q.name).values + ) % (2 * np.pi) + Pi_length = q.xy.operations["x180"].length + used_amp = q.xy.operations["saturation"].amplitude * operation_amp + factor_cw = float(target_peak_width / result.sel(qubit=q.name).width.values) + factor_pi = np.pi / (result.sel(qubit=q.name).width.values * Pi_length * 1e-9) + if factor_cw * used_amp / operation_amp < 0.5: # TODO: 1 for OPX1000 MW + q.xy.operations["saturation"].amplitude = factor_cw * used_amp / operation_amp + else: + q.xy.operations["saturation"].amplitude = 0.5 # TODO: 1 for OPX1000 MW + + if factor_pi * used_amp < 0.3: # TODO: 1 for OPX1000 MW + q.xy.operations["x180"].amplitude = factor_pi * used_amp + elif factor_pi * used_amp >= 0.3: # TODO: 1 for OPX1000 MW + q.xy.operations["x180"].amplitude = 0.3 # %% {Save_results} + if node.parameters.load_data_id is not None: + if node.storage_manager is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() + +# %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py index 361a987c2..6d114c097 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py @@ -22,7 +22,7 @@ from quam_libs.macros import qua_declaration from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import peaks_dips from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -43,15 +43,16 @@ class Parameters(NodeParameters): operation: str = "saturation" operation_amplitude_factor: Optional[float] = 0.1 operation_len_in_ns: Optional[int] = None - frequency_span_in_mhz: float = 20 - frequency_step_in_mhz: float = 0.1 + frequency_span_in_mhz: float = 30 + frequency_step_in_mhz: float = 0.25 min_flux_offset_in_v: float = -0.01 max_flux_offset_in_v: float = 0.01 - num_flux_points: int = 51 + num_flux_points: int = 21 flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 + load_data_id: Optional[int] = 40 node = QualibrationNode(name="03b_Qubit_Spectroscopy_vs_Flux", parameters=Parameters()) @@ -105,13 +106,9 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -119,34 +116,19 @@ class Parameters(NodeParameters): with for_(*from_array(df, dfs)): # Update the qubit frequency qubit.xy.update_frequency(df + qubit.xy.intermediate_frequency) - with for_(*from_array(dc, dcs)): # Flux sweeping for a qubit - if flux_point == "independent": - qubit.z.set_dc_offset(dc + qubit.z.independent_offset) - elif flux_point == "joint": - qubit.z.set_dc_offset(dc + qubit.z.joint_offset) - else: - raise RuntimeError(f"unknown flux_point") - qubit.z.settle() qubit.align() - + duration = operation_len * u.ns if operation_len is not None else qubit.xy.operations[operation].length // 4 + # Bring the qubit to the desired point during the satruration pulse + qubit.z.play("const", amplitude_scale=dc / qubit.z.operations["const"].amplitude, duration=duration) # Apply saturation pulse to all qubits qubit.xy.play( operation, amplitude_scale=operation_amp, - duration=(operation_len * u.ns if operation_len is not None else None), + duration=duration, ) qubit.align() - # Bring back the flux for readout - if flux_point == "independent": - qubit.z.set_dc_offset(qubit.z.independent_offset) - elif flux_point == "joint": - qubit.z.set_dc_offset(qubit.z.joint_offset) - else: - raise RuntimeError(f"unknown flux_point") - qubit.z.settle() - qubit.align() # QUA macro to read the state of the active resonators qubit.resonator.measure("readout", qua_vars=(I[i], Q[i])) # save data @@ -183,7 +165,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(multi_qubit_spec_vs_flux) results = fetching_tool(job, ["n"], mode="live") @@ -194,29 +176,33 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"flux": dcs, "freq": dfs}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) - ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) - # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting - ds = ds.assign_coords( - { - "freq_full": ( - ["qubit", "freq"], - np.array([dfs + q.xy.RF_frequency for q in qubits]), - ) - } - ) - ds.freq_full.attrs["long_name"] = "Frequency" - ds.freq_full.attrs["units"] = "GHz" + + if node.parameters.load_data_id is not None: + ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + else: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"flux": dcs, "freq": dfs}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) + ds = ds.assign({"IQ_abs": np.sqrt(ds["I"] ** 2 + ds["Q"] ** 2)}) + # Add the resonator RF frequency axis of each qubit to the dataset coordinates for plotting + ds = ds.assign_coords( + { + "freq_full": ( + ["qubit", "freq"], + np.array([dfs + q.xy.RF_frequency for q in qubits]), + ) + } + ) + ds.freq_full.attrs["long_name"] = "Frequency" + ds.freq_full.attrs["units"] = "GHz" # Add the dataset to the node node.results = {"ds": ds} # %% {Data_analysis} # Find the resonance dips for each flux point - peaks = peaks_dips(ds.I, dim="freq", prominence_factor=6) + peaks = peaks_dips(ds.I, dim="freq", prominence_factor=5) # Fit the result with a parabola parabolic_fit_results = peaks.position.polyfit("flux", 2) # Try to fit again with a smaller prominence factor (may need some adjustment) @@ -280,22 +266,28 @@ class Parameters(NodeParameters): node.results["figure"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for q in qubits: - if not np.isnan(flux_shift.sel(qubit=q.name).values): - if flux_point == "independent": - q.z.independent_offset += fit_results[q.name]["flux_shift"] - elif flux_point == "joint": - q.z.joint_offset += fit_results[q.name]["flux_shift"] - q.xy.intermediate_frequency += fit_results[q.name]["drive_freq"] - q.freq_vs_flux_01_quad_term = fit_results[q.name]["quad_term"] - - ds = ds.drop_vars("freq_full") + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + if not np.isnan(flux_shift.sel(qubit=q.name).values): + if flux_point == "independent": + q.z.independent_offset += fit_results[q.name]["flux_shift"] + elif flux_point == "joint": + q.z.joint_offset += fit_results[q.name]["flux_shift"] + q.xy.intermediate_frequency += fit_results[q.name]["drive_freq"] + q.freq_vs_flux_01_quad_term = fit_results[q.name]["quad_term"] + + # ds = ds.drop_vars("freq_full") node.results["ds"] = ds # %% {Save_results} + if node.parameters.load_data_id is not None: + if node.storage_manager is not None: + node.storage_manager.active_machine_path = None node.outcomes = {q.name: "successful" for q in qubits} node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() + +# %% From 0aa270c39697c7f90094327a83c62ca42c84f999 Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Fri, 15 Nov 2024 16:49:47 +0100 Subject: [PATCH 3/8] loading used qubits when loading prev data --- .../calibration_graph/02a_Resonator_Spectroscopy.py | 2 +- .../calibration_graph/02b_resonator_spectroscopy_vs_flux.py | 2 +- .../02c_resonator_spectroscopy_vs_amplitude.py | 2 +- .../calibration_graph/03a_Qubit_Spectroscopy.py | 2 +- .../calibration_graph/03b_qubit_spectroscopy_vs_flux.py | 4 ++-- .../Superconducting/quam_libs/lib/save_utils.py | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py index 5fa2dd10b..e0bdd15d7 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py @@ -146,7 +146,7 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: - ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) # Convert IQ data into volts diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py index e812b2c7b..b21be5a4f 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py @@ -171,7 +171,7 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: - ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs, "flux": dcs}) # Convert IQ data into volts diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py index d5eca0a15..6b0b425ef 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py @@ -221,7 +221,7 @@ def set_output_power( # %% {Data_fetching_and_dataset_creation} # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: - ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "freq": dfs}) # Convert IQ data into volts diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py index 18dff6028..1541876cb 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py @@ -198,7 +198,7 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} if node.parameters.load_data_id is not None: - ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py index 6d114c097..3adec13db 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py @@ -52,7 +52,7 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - load_data_id: Optional[int] = 40 + load_data_id: Optional[int] = None node = QualibrationNode(name="03b_Qubit_Spectroscopy_vs_Flux", parameters=Parameters()) @@ -178,7 +178,7 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} if node.parameters.load_data_id is not None: - ds, machine, json_data, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"flux": dcs, "freq": dfs}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py b/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py index aed2ff586..eee959033 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/quam_libs/lib/save_utils.py @@ -103,15 +103,15 @@ def load_dataset(serial_number, target_filename = "ds", parameters = None): except Exception as e: print(f"Error loading machine: {e}") machine = None - + qubits = [machine.qubits[qname] for qname in ds.qubit.values] if parameters is not None: for param_name, param_value in parameters: if param_name is not "load_data_id": if param_name in json_data["initial_parameters"]: setattr(parameters, param_name, json_data["initial_parameters"][param_name]) - return ds, machine, json_data, parameters + return ds, machine, json_data, qubits,parameters else: - return ds, machine, json_data + return ds, machine, json_data, qubits else: print(f"No .nc file found in folder: {base_folder}") return None From 3541775d0ff18ffbc533e7d437e41655b42f2387 Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Sun, 17 Nov 2024 11:42:45 +0100 Subject: [PATCH 4/8] all nods OPX+ until RB have loaded data and multiplex mode enabled, fix small bugs --- .../02b_resonator_spectroscopy_vs_flux.py | 4 +- ...02c_resonator_spectroscopy_vs_amplitude.py | 4 +- .../03a_Qubit_Spectroscopy.py | 5 +- .../03b_qubit_spectroscopy_vs_flux.py | 3 +- .../calibration_graph/04_Power_Rabi.py | 63 +++++----- .../calibration_graph/05_T1.py | 53 +++++---- .../calibration_graph/06_Ramsey.py | 59 ++++++---- .../calibration_graph/07a_IQ_Blobs.py | 110 +++++++++--------- .../07b_Readout_Frequency_Optimization.py | 82 ++++++------- .../07c_Readout_Power_Optimization.py | 98 ++++++++-------- .../08a_Power_Rabi_Error_Amplification.py | 50 ++++---- .../08b_Ramsey_vs_Flux_Calibration.py | 51 ++++---- .../calibration_graph/09a_Stark_Detuning.py | 45 +++---- .../09b_DRAG_Calibration_180_minus_180.py | 53 +++++---- .../09c_DRAG_Calibration_180_90.py | 43 +++---- ...0a_Single_Qubit_Randomized_Benchmarking.py | 26 +++-- 16 files changed, 408 insertions(+), 341 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py index b21be5a4f..bf43532a4 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py @@ -81,7 +81,9 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() + # %% {QUA_program} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py index 6b0b425ef..b31b58fbd 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py @@ -132,7 +132,9 @@ def set_output_power( # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() + # %% {QUA_program} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py index 1541876cb..6e88fbdc8 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py @@ -73,8 +73,9 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() - +if node.parameters.load_data_id is None: + qmm = machine.connect() + # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py index 3adec13db..8fff21d9e 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py @@ -66,7 +66,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py index ad0a870bf..49e31e6d2 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py @@ -23,7 +23,7 @@ from quam_libs.macros import qua_declaration from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_oscillation, oscillation from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -40,17 +40,18 @@ class Parameters(NodeParameters): qubits: Optional[List[str]] = None - num_averages: int = 200 + num_averages: int = 100 operation: str = "x180" min_amp_factor: float = 0.001 max_amp_factor: float = 2.0 - amp_factor_step: float = 0.005 + amp_factor_step: float = 0.01 max_number_rabi_pulses_per_sweep: int = 1 flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = False + multiplexed: bool = False node = QualibrationNode(name="04_Power_Rabi", parameters=Parameters()) @@ -63,7 +64,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": @@ -95,27 +97,26 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) with for_(*from_array(npi, N_pi_vec)): with for_(*from_array(a, amps)): + qubit.resonator.wait(5*qubit.thermalization_time * u.ns) # Loop for error amplification (perform many qubit pulses) + qubit.align() with for_(count, 0, count < npi, count + 1): qubit.xy.play(operation, amplitude_scale=a) - align() + qubit.align() qubit.resonator.measure("readout", qua_vars=(I[i], Q[i])) save(I[i], I_st[i]) save(Q[i], Q_st[i]) - qubit.resonator.wait(qubit.thermalization_time * u.ns) - align() + + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -142,7 +143,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(power_rabi) results = fetching_tool(job, ["n"], mode="live") @@ -153,19 +154,22 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Add the qubit pulse absolute amplitude to the dataset - ds = ds.assign_coords( + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Add the qubit pulse absolute amplitude to the dataset + ds = ds.assign_coords( { "abs_amp": ( ["qubit", "amp"], np.array([q.xy.operations[operation].amplitude * amps for q in qubits]), ) - } - ) + } + ) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -240,11 +244,12 @@ class Parameters(NodeParameters): node.results["figure"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for q in qubits: - q.xy.operations[operation].amplitude = fit_results[q.name]["Pi_amplitude"] - if operation == "x180": - q.xy.operations["x90"].amplitude = fit_results[q.name]["Pi_amplitude"] / 2 + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + q.xy.operations[operation].amplitude = fit_results[q.name]["Pi_amplitude"] + if operation == "x180": + q.xy.operations["x90"].amplitude = fit_results[q.name]["Pi_amplitude"] / 2 # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py index e4e7675e8..8bde757f7 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py @@ -19,7 +19,7 @@ from quam_libs.macros import qua_declaration, active_reset, readout_state from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_decay_exp, decay_exp from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -45,7 +45,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="05_T1", parameters=Parameters()) @@ -58,8 +59,9 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() - +if node.parameters.load_data_id is None: + qmm = machine.connect() + # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits @@ -94,13 +96,9 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint" or "arbitrary": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -132,7 +130,8 @@ class Parameters(NodeParameters): save(I[i], I_st[i]) save(Q[i], Q_st[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -162,7 +161,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(t1) results = fetching_tool(job, ["n"], mode="live") @@ -173,13 +172,16 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"idle_time": idle_times}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Convert time into µs - ds = ds.assign_coords(idle_time=4 * ds.idle_time / u.us) # convert to µs - ds.idle_time.attrs = {"long_name": "idle time", "units": "µs"} + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"idle_time": idle_times}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Convert time into µs + ds = ds.assign_coords(idle_time=4 * ds.idle_time / u.us) # convert to µs + ds.idle_time.attrs = {"long_name": "idle time", "units": "µs"} + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -235,13 +237,14 @@ class Parameters(NodeParameters): node.results["figure_raw"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for index, q in enumerate(qubits): - if ( + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for index, q in enumerate(qubits): + if ( float(tau.sel(qubit=q.name).values) > 0 and tau_error.sel(qubit=q.name).values / float(tau.sel(qubit=q.name).values) < 1 - ): - q.T1 = float(tau.sel(qubit=q.name).values) * 1e-6 + ): + q.T1 = float(tau.sel(qubit=q.name).values) * 1e-6 # %% {Save_results} node.results["initial_parameters"] = node.parameters.model_dump() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py index f04bcd34d..adbbb3364 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py @@ -24,7 +24,7 @@ from quam_libs.macros import qua_declaration, readout_state from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_oscillation_decay_exp, oscillation_decay_exp from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -44,7 +44,7 @@ class Parameters(NodeParameters): num_averages: int = 100 frequency_detuning_in_mhz: float = 1.0 min_wait_time_in_ns: int = 16 - max_wait_time_in_ns: int = 30000 + max_wait_time_in_ns: int = 3000 num_time_points: int = 500 log_or_linear_sweep: Literal["log", "linear"] = "log" flux_point_joint_or_independent: Literal["joint", "independent"] = "independent" @@ -52,7 +52,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="06a_Ramsey", parameters=Parameters()) @@ -65,8 +66,9 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() - +if node.parameters.load_data_id is None: + qmm = machine.connect() + # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits @@ -132,16 +134,16 @@ class Parameters(NodeParameters): assign(phi, Cast.mul_fixed_by_int(detuning * 1e-9, 4 * t)) with else_(): assign(phi, Cast.mul_fixed_by_int(-detuning * 1e-9, 4 * t)) - align() + qubit.align() # # Strict_timing ensures that the sequence will be played without gaps - with strict_timing_(): - qubit.xy.play("x90") - qubit.xy.wait(t) - qubit.xy.frame_rotation_2pi(phi) - qubit.xy.play("x90") + # with strict_timing_(): + qubit.xy.play("x90") + qubit.xy.wait(t) + qubit.xy.frame_rotation_2pi(phi) + qubit.xy.play("x90") # Align the elements to measure after playing the qubit pulse. - align() + qubit.align() # Measure the state of the resonators and save data if node.parameters.use_state_discrimination: readout_state(qubit, state[i]) @@ -156,6 +158,7 @@ class Parameters(NodeParameters): # Reset the frame of the qubits in order not to accumulate rotations reset_frame(qubit.xy.name) # Measure sequentially + align() with stream_processing(): @@ -186,7 +189,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(ramsey) results = fetching_tool(job, ["n"], mode="live") @@ -198,14 +201,17 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"sign": [-1, 1], "time": idle_times}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) - # Add the absolute time to the dataset - ds = ds.assign_coords({"time": (["time"], 4 * idle_times)}) - ds.time.attrs["long_name"] = "idle_time" - ds.time.attrs["units"] = "ns" + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"sign": [-1, 1], "time": idle_times}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + # Add the absolute time to the dataset + ds = ds.assign_coords({"time": (["time"], 4 * idle_times)}) + ds.time.attrs["long_name"] = "idle_time" + ds.time.attrs["units"] = "ns" + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -314,10 +320,11 @@ class Parameters(NodeParameters): # %% {Update_state} - with node.record_state_updates(): - for q in qubits: - q.xy.intermediate_frequency -= float(fit_results[q.name]["freq_offset"]) - q.T2ramsey = float(fit_results[qubit["qubit"]]["decay"]) + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + q.xy.intermediate_frequency -= float(fit_results[q.name]["freq_offset"]) + q.T2ramsey = float(fit_results[q.name]["decay"]) # %% {Save_results} @@ -325,3 +332,5 @@ class Parameters(NodeParameters): node.results["initial_parameters"] = node.parameters.model_dump() node.machine = machine node.save() + +# %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py index 9a3b69cd8..53e0a9aa2 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py @@ -27,7 +27,7 @@ from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from qualang_tools.analysis.discriminator import two_state_discriminator from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.multi_user import qm_session @@ -51,6 +51,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="07a_IQ_Blobs", parameters=Parameters()) @@ -64,8 +66,9 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() - +if node.parameters.load_data_id is None: + qmm = machine.connect() + # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits @@ -86,13 +89,9 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint" or "arbitrary": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_runs, n + 1): # ground iq blobs for all qubits @@ -119,16 +118,18 @@ class Parameters(NodeParameters): qubit.wait(qubit.thermalization_time * u.ns) else: raise ValueError(f"Unrecognized reset type {reset_type}.") - align() + qubit.align() qubit.xy.play("x180") - align() + qubit.align() qubit.resonator.measure(operation_name, qua_vars=(I_e[i], Q_e[i])) qubit.resonator.wait(qubit.resonator.depletion_time * u.ns) # save data save(I_e[i], I_e_st[i]) save(Q_e[i], Q_e_st[i]) + # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -156,8 +157,8 @@ class Parameters(NodeParameters): node.results = {"figure": plt.gcf()} node.machine = machine node.save() - -else: + +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(iq_blobs) for i in range(num_qubits): @@ -167,24 +168,28 @@ class Parameters(NodeParameters): progress_counter(n, n_runs, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"N": np.linspace(1, n_runs, n_runs)}) - - # Fix the structure of ds to avoid tuples - def extract_value(element): - if isinstance(element, tuple): - return element[0] - return element - - ds = xr.apply_ufunc( - extract_value, - ds, - vectorize=True, # This ensures the function is applied element-wise - dask="parallelized", # This allows for parallel processing - output_dtypes=[float], # Specify the output data type - ) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits, ["I_g", "Q_g", "I_e", "Q_e"]) + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"N": np.linspace(1, n_runs, n_runs)}) + + # Fix the structure of ds to avoid tuples + def extract_value(element): + if isinstance(element, tuple): + return element[0] + return element + + ds = xr.apply_ufunc( + extract_value, + ds, + vectorize=True, # This ensures the function is applied element-wise + dask="parallelized", # This allows for parallel processing + output_dtypes=[float], # Specify the output data type + ) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits, ["I_g", "Q_g", "I_e", "Q_e"]) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + # %% {Data_analysis} node.results = {"ds": ds, "figs": {}, "results": {}} plot_individual = False @@ -301,25 +306,26 @@ def extract_value(element): node.results["figure_fidelity"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for qubit in qubits: - qubit.resonator.operations[operation_name].integration_weights_angle -= float( - node.results["results"][qubit.name]["angle"] - ) - # Convert the thresholds back in demod units - qubit.resonator.operations[operation_name].threshold = ( - float(node.results["results"][qubit.name]["threshold"]) - * qubit.resonator.operations[operation_name].length - / 2**12 - ) - # todo: add conf matrix to the readout operation rather than the resonator - qubit.resonator.operations[operation_name].rus_exit_threshold = ( - float(node.results["results"][qubit.name]["rus_threshold"]) - * qubit.resonator.operations[operation_name].length - / 2**12 - ) - if operation_name == "readout": - qubit.resonator.confusion_matrix = node.results["results"][qubit.name]["confusion_matrix"].tolist() + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for qubit in qubits: + qubit.resonator.operations[operation_name].integration_weights_angle -= float( + node.results["results"][qubit.name]["angle"] + ) + # Convert the thresholds back in demod units + qubit.resonator.operations[operation_name].threshold = ( + float(node.results["results"][qubit.name]["threshold"]) + * qubit.resonator.operations[operation_name].length + / 2**12 + ) + # todo: add conf matrix to the readout operation rather than the resonator + qubit.resonator.operations[operation_name].rus_exit_threshold = ( + float(node.results["results"][qubit.name]["rus_threshold"]) + * qubit.resonator.operations[operation_name].length + / 2**12 + ) + if operation_name == "readout": + qubit.resonator.confusion_matrix = node.results["results"][qubit.name]["confusion_matrix"].tolist() # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py index 61021b372..f878f31ed 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py @@ -22,7 +22,7 @@ from quam_libs.components import QuAM from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array from qualang_tools.multi_user import qm_session @@ -45,7 +45,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="07b_Readout_Frequency_Optimization", parameters=Parameters()) @@ -58,7 +59,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": @@ -92,13 +94,10 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() + with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -127,7 +126,8 @@ class Parameters(NodeParameters): save(I_e[i], I_e_st[i]) save(Q_e[i], Q_e_st[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -156,7 +156,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(ro_freq_opt) results = fetching_tool(job, ["n"], mode="live") @@ -165,29 +165,32 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits, ["I_g", "Q_g", "I_e", "Q_e"]) - # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) for |g> and |e> as well as the distance between the two blobs D - ds = ds.assign( - { - "D": np.sqrt((ds.I_g - ds.I_e) ** 2 + (ds.Q_g - ds.Q_e) ** 2), - "IQ_abs_g": np.sqrt(ds.I_g**2 + ds.Q_g**2), - "IQ_abs_e": np.sqrt(ds.I_e**2 + ds.Q_e**2), - } - ) - # Add the absolute frequency to the dataset - ds = ds.assign_coords( - { - "freq_full": ( - ["qubit", "freq"], - np.array([dfs + q.resonator.RF_frequency for q in qubits]), - ) - } - ) - ds.freq_full.attrs["long_name"] = "Frequency" - ds.freq_full.attrs["units"] = "GHz" + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits, ["I_g", "Q_g", "I_e", "Q_e"]) + # Derive the amplitude IQ_abs = sqrt(I**2 + Q**2) for |g> and |e> as well as the distance between the two blobs D + ds = ds.assign( + { + "D": np.sqrt((ds.I_g - ds.I_e) ** 2 + (ds.Q_g - ds.Q_e) ** 2), + "IQ_abs_g": np.sqrt(ds.I_g**2 + ds.Q_g**2), + "IQ_abs_e": np.sqrt(ds.I_e**2 + ds.Q_e**2), + } + ) + # Add the absolute frequency to the dataset + ds = ds.assign_coords( + { + "freq_full": ( + ["qubit", "freq"], + np.array([dfs + q.resonator.RF_frequency for q in qubits]), + ) + } + ) + ds.freq_full.attrs["long_name"] = "Frequency" + ds.freq_full.attrs["units"] = "GHz" + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -240,10 +243,11 @@ class Parameters(NodeParameters): node.results["figure2"] = grid.fig # %% {Update_state} - for q in qubits: - with node.record_state_updates(): - q.resonator.intermediate_frequency += int(fit_results[q.name]["detuning"]) - q.chi = float(fit_results[q.name]["chi"]) + if node.parameters.load_data_id is None: + for q in qubits: + with node.record_state_updates(): + q.resonator.intermediate_frequency += int(fit_results[q.name]["detuning"]) + q.chi = float(fit_results[q.name]["chi"]) # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py index d63175a01..e83afcf98 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py @@ -25,7 +25,7 @@ from quam_libs.components import QuAM from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from qualang_tools.analysis import two_state_discriminator from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -54,6 +54,8 @@ class Parameters(NodeParameters): end_amp: float = 1.99 num_amps: int = 10 outliers_threshold: float = 0.98 + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="07c_Readout_Power_Optimization", parameters=Parameters()) @@ -67,7 +69,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": @@ -90,14 +93,10 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): - # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + # Bring the active qubits to the desired frequency point + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_runs, n + 1): # ground iq blobs for all qubits @@ -131,7 +130,8 @@ class Parameters(NodeParameters): save(Q_e[i], Q_e_st[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -159,7 +159,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(iq_blobs) @@ -174,29 +174,34 @@ class Parameters(NodeParameters): # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"amplitude": amps, "N": np.linspace(1, n_runs, n_runs)}) - # Add the absolute readout power to the dataset - ds = ds.assign_coords({"readout_amp": (["qubit", "amplitude"], np.array([amps * q.resonator.operations["readout"].amplitude for q in qubits]))}) - # Rearrange the data to combine I_g and I_e into I, and Q_g and Q_e into Q - ds_rearranged = xr.Dataset() - # Combine I_g and I_e into I - ds_rearranged["I"] = xr.concat([ds.I_g, ds.I_e], dim="state") - ds_rearranged["I"] = ds_rearranged["I"].assign_coords(state=[0, 1]) - # Combine Q_g and Q_e into Q - ds_rearranged["Q"] = xr.concat([ds.Q_g, ds.Q_e], dim="state") - ds_rearranged["Q"] = ds_rearranged["Q"].assign_coords(state=[0, 1]) - # Copy other coordinates and data variables - for var in ds.coords: - if var not in ds_rearranged.coords: - ds_rearranged[var] = ds[var] - - for var in ds.data_vars: - if var not in ["I_g", "I_e", "Q_g", "Q_e"]: - ds_rearranged[var] = ds[var] - - # Replace the original dataset with the rearranged one - ds = ds_rearranged + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"amplitude": amps, "N": np.linspace(1, n_runs, n_runs)}) + # Add the absolute readout power to the dataset + ds = ds.assign_coords({"readout_amp": (["qubit", "amplitude"], np.array([amps * q.resonator.operations["readout"].amplitude for q in qubits]))}) + # Rearrange the data to combine I_g and I_e into I, and Q_g and Q_e into Q + ds_rearranged = xr.Dataset() + # Combine I_g and I_e into I + ds_rearranged["I"] = xr.concat([ds.I_g, ds.I_e], dim="state") + ds_rearranged["I"] = ds_rearranged["I"].assign_coords(state=[0, 1]) + # Combine Q_g and Q_e into Q + ds_rearranged["Q"] = xr.concat([ds.Q_g, ds.Q_e], dim="state") + ds_rearranged["Q"] = ds_rearranged["Q"].assign_coords(state=[0, 1]) + # Copy other coordinates and data variables + for var in ds.coords: + if var not in ds_rearranged.coords: + ds_rearranged[var] = ds[var] + + for var in ds.data_vars: + if var not in ["I_g", "I_e", "Q_g", "Q_e"]: + ds_rearranged[var] = ds[var] + + # Replace the original dataset with the rearranged one + ds = ds_rearranged + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) + + node.results = {"ds": ds, "results": {}, "figs": {}} plot_raw = False @@ -384,17 +389,18 @@ def apply_fit_gmm(I, Q): # %% {Update_state} - with node.record_state_updates(): - for qubit in qubits: - qubit.resonator.operations["readout"].integration_weights_angle -= float( - node.results["results"][qubit.name]["angle"] - ) - qubit.resonator.operations["readout"].threshold = float(node.results["results"][qubit.name]["threshold"]) - qubit.resonator.operations["readout"].rus_exit_threshold = float( - node.results["results"][qubit.name]["rus_threshold"] - ) - qubit.resonator.operations["readout"].amplitude = float(node.results["results"][qubit.name]["best_amp"]) - qubit.resonator.confusion_matrix = node.results["results"][qubit.name]["confusion_matrix"].tolist() + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for qubit in qubits: + qubit.resonator.operations["readout"].integration_weights_angle -= float( + node.results["results"][qubit.name]["angle"] + ) + qubit.resonator.operations["readout"].threshold = float(node.results["results"][qubit.name]["threshold"]) + qubit.resonator.operations["readout"].rus_exit_threshold = float( + node.results["results"][qubit.name]["rus_threshold"] + ) + qubit.resonator.operations["readout"].amplitude = float(node.results["results"][qubit.name]["best_amp"]) + qubit.resonator.confusion_matrix = node.results["results"][qubit.name]["confusion_matrix"].tolist() # %% {Save_results} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py index 0d33389ca..856901395 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py @@ -23,7 +23,7 @@ from quam_libs.components import QuAM from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_oscillation, oscillation from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -51,6 +51,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="08_Power_Rabi_Error_Amplification", parameters=Parameters()) @@ -64,7 +66,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": @@ -104,14 +107,10 @@ class Parameters(NodeParameters): count = declare(int) # QUA variable for counting the qubit pulses for i, qubit in enumerate(qubits): - # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + # Bring the active qubits to the desired frequency point + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -127,11 +126,12 @@ class Parameters(NodeParameters): # Loop for error amplification (perform many qubit pulses) with for_(count, 0, count < npi, count + 1): qubit.xy.play(operation, amplitude_scale=a) - align() + qubit.align() qubit.resonator.measure("readout", qua_vars=(I[i], Q[i])) assign(state[i], I[i] > qubit.resonator.operations["readout"].threshold) save(state[i], state_stream[i]) - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -166,28 +166,29 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(power_rabi) - - # %% {Live_plot} results = fetching_tool(job, ["n"], mode="live") while results.is_processing(): n = results.fetch_all()[0] progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) - # Add the qubit pulse absolute amplitude to the dataset - ds = ds.assign_coords( + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) + # Add the qubit pulse absolute amplitude to the dataset + ds = ds.assign_coords( { "abs_amp": ( ["qubit", "amp"], np.array([q.xy.operations[operation].amplitude * amps for q in qubits]), ) - } - ) + } + ) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -261,9 +262,10 @@ class Parameters(NodeParameters): node.results["figure"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for q in qubits: - q.xy.operations[operation].amplitude = fit_results[q.name]["Pi_amplitude"] + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + q.xy.operations[operation].amplitude = fit_results[q.name]["Pi_amplitude"] # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py index 0a2e2c7bf..fd8d7d4d8 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py @@ -24,7 +24,7 @@ from quam_libs.macros import qua_declaration, readout_state from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_oscillation_decay_exp, oscillation_decay_exp from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -51,7 +51,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="08b_Ramsey_vs_Flux_Calibration", parameters=Parameters()) @@ -64,7 +65,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # Get the relevant QuAM components if node.parameters.qubits is None or node.parameters.qubits == "": @@ -143,7 +145,8 @@ class Parameters(NodeParameters): reset_frame(qubit.xy.name) qubit.align() - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -169,7 +172,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(ramsey) results = fetching_tool(job, ["n"], mode="live") @@ -180,11 +183,14 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - ds = fetch_results_as_xarray(job.result_handles, qubits, {"idle_time": idle_times, "flux": fluxes}) - # Add the absolute time in µs to the dataset - ds = ds.assign_coords(idle_time=4 * ds.idle_time / 1e3) - ds.flux.attrs = {"long_name": "flux", "units": "V"} - ds.idle_time.attrs = {"long_name": "idle time", "units": "µs"} + if node.parameters.load_data_id is None: + ds = fetch_results_as_xarray(job.result_handles, qubits, {"idle_time": idle_times, "flux": fluxes}) + # Add the absolute time in µs to the dataset + ds = ds.assign_coords(idle_time=4 * ds.idle_time / 1e3) + ds.flux.attrs = {"long_name": "flux", "units": "V"} + ds.idle_time.attrs = {"long_name": "idle time", "units": "µs"} + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -226,7 +232,9 @@ class Parameters(NodeParameters): / fitvals.sel(qubit=q.name, degree=2).polyfit_coefficients ).values ) - freq_offset[q.name] = 1e6 * float(fitvals.sel(qubit=q.name, degree=0).polyfit_coefficients.values) - detuning + freq_offset[q.name] = 1e6 * (flux_offset[q.name]**2 * float(fitvals.sel(qubit=q.name, degree=2).polyfit_coefficients.values) + + flux_offset[q.name] * float(fitvals.sel(qubit=q.name, degree=1).polyfit_coefficients.values) + + float(fitvals.sel(qubit=q.name, degree=0).polyfit_coefficients.values)) - detuning # Save fitting results node.results["fit_results"] = {} @@ -270,16 +278,17 @@ class Parameters(NodeParameters): node.results["figure"] = grid.fig # %% {Update_state} - with node.record_state_updates(): - for qubit in qubits: - qubit.xy.intermediate_frequency -= freq_offset[qubit.name] - if flux_point == "independent": - qubit.z.independent_offset += flux_offset[qubit.name] - elif flux_point == "joint": - qubit.z.joint_offset += flux_offset[qubit.name] - else: - raise RuntimeError(f"unknown flux_point") - qubit.freq_vs_flux_01_quad_term = float(a[qubit.name]) + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for qubit in qubits: + qubit.xy.intermediate_frequency -= freq_offset[qubit.name] + if flux_point == "independent": + qubit.z.independent_offset += flux_offset[qubit.name] + elif flux_point == "joint": + qubit.z.joint_offset += flux_offset[qubit.name] + else: + raise RuntimeError(f"unknown flux_point") + qubit.freq_vs_flux_01_quad_term = float(a[qubit.name]) # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py index abf5833ef..d78b7c4cf 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py @@ -26,7 +26,7 @@ from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.qua_datasets import convert_IQ_to_V from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.trackable_object import tracked_updates from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -53,7 +53,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="09a_Stark_Detuning", parameters=Parameters()) @@ -84,7 +85,8 @@ class Parameters(NodeParameters): # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # %% {QUA_program} @@ -109,13 +111,9 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -149,7 +147,8 @@ class Parameters(NodeParameters): save(I[i], I_st[i]) save(Q[i], Q_st[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -177,7 +176,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(stark_detuning) results = fetching_tool(job, ["n"], mode="live") @@ -188,10 +187,13 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs, "N": N_pi_vec}) - # Convert IQ data into volts - ds = convert_IQ_to_V(ds, qubits) + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs, "N": N_pi_vec}) + # Convert IQ data into volts + ds = convert_IQ_to_V(ds, qubits) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -224,11 +226,12 @@ class Parameters(NodeParameters): # Revert the change done at the beginning of the node for qubit in tracked_qubits: qubit.revert_changes() - with node.record_state_updates(): - for qubit in qubits: - qubit.xy.operations[operation].detuning = float(fit_results[qubit.name]["detuning"]) - if node.parameters.DRAG_setpoint is not None: - qubit.xy.operations[operation].alpha = node.parameters.DRAG_setpoint + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for qubit in qubits: + qubit.xy.operations[operation].detuning = float(fit_results[qubit.name]["detuning"]) + if node.parameters.DRAG_setpoint is not None: + qubit.xy.operations[operation].alpha = node.parameters.DRAG_setpoint # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py index 4ef5c0a1c..a06b8d1fd 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py @@ -23,7 +23,7 @@ from quam_libs.components import QuAM from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.trackable_object import tracked_updates from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -50,6 +50,10 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 + alpha_setpoint: Optional[float] = -1.0 + load_data_id: Optional[int] = None + multiplexed: bool = False + node = QualibrationNode(name="09b_DRAG_Calibration_180_minus_180", parameters=Parameters()) @@ -70,15 +74,17 @@ class Parameters(NodeParameters): # Update the readout power to match the desired range, this change will be reverted at the end of the node. tracked_qubits = [] -for q in qubits: - with tracked_updates(q, auto_revert=False, dont_assign_to_none=True) as q: - q.xy.operations[operation].alpha = -1.0 - tracked_qubits.append(q) +if node.parameters.alpha_setpoint is not None: + for q in qubits: + with tracked_updates(q, auto_revert=False, dont_assign_to_none=True) as q: + q.xy.operations[operation].alpha = node.parameters.alpha_setpoint + tracked_qubits.append(q) # Generate the OPX and Octave configurations config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits @@ -111,13 +117,9 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -145,7 +147,8 @@ class Parameters(NodeParameters): assign(state[i], I[i] > qubit.resonator.operations["readout"].threshold) save(state[i], state_stream[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -171,7 +174,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(drag_calibration) results = fetching_tool(job, ["n"], mode="live") @@ -182,17 +185,20 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) - # Add the qubit pulse absolute alpha coefficient to the dataset - ds = ds.assign_coords( + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) + # Add the qubit pulse absolute alpha coefficient to the dataset + ds = ds.assign_coords( { "alpha": ( ["qubit", "amp"], np.array([q.xy.operations[operation].alpha * amps for q in qubits]), ) } - ) + ) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -228,9 +234,10 @@ class Parameters(NodeParameters): for qubit in tracked_qubits: qubit.revert_changes() # Update the state - with node.record_state_updates(): - for q in qubits: - q.xy.operations[operation].alpha = fit_results[q.name]["alpha"] + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + q.xy.operations[operation].alpha = fit_results[q.name]["alpha"] # %% {Save_results} node.outcomes = {q.name: "successful" for q in qubits} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py index 83de09713..444dfa15e 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py @@ -24,7 +24,7 @@ from quam_libs.components import QuAM from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.trackable_object import tracked_updates from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.loops import from_array @@ -51,7 +51,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="09c_DRAG_Calibration_180_90", parameters=Parameters()) @@ -77,7 +78,8 @@ class Parameters(NodeParameters): config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() # %% {QUA_program} @@ -102,13 +104,10 @@ class Parameters(NodeParameters): for i, qubit in enumerate(qubits): # Bring the active qubits to the desired frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() + with for_(n, 0, n < n_avg, n + 1): save(n, n_st) @@ -158,7 +157,7 @@ class Parameters(NodeParameters): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: job = qm.execute(drag_calibration) results = fetching_tool(job, ["n"], mode="live") @@ -169,12 +168,15 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "sequence": [0, 1]}) - # Add the qubit pulse absolute alpha coefficient to the dataset - ds = ds.assign_coords( - {"alpha": (["qubit", "amp"], np.array([q.xy.operations[operation].alpha * amps for q in qubits]))} - ) + if node.parameters.load_data_id is None: + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "sequence": [0, 1]}) + # Add the qubit pulse absolute alpha coefficient to the dataset + ds = ds.assign_coords( + {"alpha": (["qubit", "amp"], np.array([q.xy.operations[operation].alpha * amps for q in qubits]))} + ) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} @@ -215,9 +217,10 @@ class Parameters(NodeParameters): for qubit in tracked_qubits: qubit.revert_changes() # Update the state - with node.record_state_updates(): - for q in qubits: - q.xy.operations[operation].alpha = fit_results[q.name]["alpha"] + if node.parameters.load_data_id is None: + with node.record_state_updates(): + for q in qubits: + q.xy.operations[operation].alpha = fit_results[q.name]["alpha"] # %% {Save_results} node.results["initial_parameters"] = node.parameters.model_dump() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py index e73b95833..bd438d063 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py @@ -24,7 +24,7 @@ from quam_libs.components import QuAM, Transmon from quam_libs.macros import qua_declaration, active_reset from quam_libs.lib.plot_utils import QubitGrid, grid_iter -from quam_libs.lib.save_utils import fetch_results_as_xarray +from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_decay_exp, decay_exp from qualang_tools.results import progress_counter, fetching_tool from qualang_tools.bakery.randomized_benchmark_c1 import c1_table @@ -54,7 +54,8 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - + load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="10a_Single_Qubit_Randomized_Benchmarking", parameters=Parameters()) @@ -68,7 +69,8 @@ class Parameters(NodeParameters): config = machine.generate_config() # Open Communication with the QOP -qmm = machine.connect() +if node.parameters.load_data_id is None: + qmm = machine.connect() if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits @@ -299,7 +301,7 @@ def play_sequence(sequence_list, depth, qubit: Transmon): node.machine = machine node.save() -else: +elif node.parameters.load_data_id is None: # Prepare data for saving node.results = {} with qm_session(qmm, config, timeout=node.parameters.timeout) as qm: @@ -314,17 +316,19 @@ def play_sequence(sequence_list, depth, qubit: Transmon): progress_counter(m, num_of_sequences, start_time=results.start_time) # %% {Data_fetching_and_dataset_creation} - depths = np.arange(0, max_circuit_depth + 0.1, delta_clifford) - depths[0] = 1 - # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) - ds = fetch_results_as_xarray( + if node.parameters.load_data_id is None: + depths = np.arange(0, max_circuit_depth + 0.1, delta_clifford) + depths[0] = 1 + # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) + ds = fetch_results_as_xarray( job.result_handles, qubits, - {"depths": depths, "sequence": np.arange(num_of_sequences)}, - ) + {"depths": depths, "sequence": np.arange(num_of_sequences)}, + ) + else: + ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) # Add the dataset to the node node.results = {"ds": ds} - # %% {Data_analysis} da_state = 1 - ds["state"].mean(dim="sequence") da_state: xr.DataArray From afc5ee61ab5fe713d5d15f56d91e3d13f314cdac Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Sun, 17 Nov 2024 11:52:12 +0100 Subject: [PATCH 5/8] added extra if not node.parameters.simulate: whn loading data --- .../calibration_graph/02a_Resonator_Spectroscopy.py | 3 ++- .../calibration_graph/02b_resonator_spectroscopy_vs_flux.py | 3 ++- .../02c_resonator_spectroscopy_vs_amplitude.py | 3 ++- .../calibration_graph/03a_Qubit_Spectroscopy.py | 4 +++- .../calibration_graph/03b_qubit_spectroscopy_vs_flux.py | 4 ++-- .../Superconducting/calibration_graph/04_Power_Rabi.py | 3 ++- .../Superconducting/calibration_graph/05_T1.py | 3 ++- .../Superconducting/calibration_graph/06_Ramsey.py | 3 ++- .../Superconducting/calibration_graph/07a_IQ_Blobs.py | 3 ++- .../calibration_graph/07b_Readout_Frequency_Optimization.py | 3 ++- .../calibration_graph/07c_Readout_Power_Optimization.py | 3 ++- .../calibration_graph/08a_Power_Rabi_Error_Amplification.py | 3 ++- .../calibration_graph/08b_Ramsey_vs_Flux_Calibration.py | 3 ++- .../Superconducting/calibration_graph/09a_Stark_Detuning.py | 3 ++- .../calibration_graph/09b_DRAG_Calibration_180_minus_180.py | 3 ++- .../calibration_graph/09c_DRAG_Calibration_180_90.py | 3 ++- 16 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py index e0bdd15d7..ae49e6640 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py @@ -143,7 +143,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py index bf43532a4..71c586a34 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py @@ -170,7 +170,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py index 51e572b97..36692ce13 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02c_resonator_spectroscopy_vs_amplitude.py @@ -184,7 +184,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) if node.parameters.load_data_id is not None: ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py index 6e88fbdc8..212df435e 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py @@ -197,7 +197,9 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: + if node.parameters.load_data_id is not None: ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py index 8fff21d9e..9196aea10 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py @@ -176,8 +176,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} - +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is not None: ds, machine, json_data, qubits, node.parameters = load_dataset(node.parameters.load_data_id, parameters = node.parameters) else: diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py index 49e31e6d2..03b113cd4 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py @@ -153,7 +153,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py index 8bde757f7..324480f5c 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py @@ -171,7 +171,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"idle_time": idle_times}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py index adbbb3364..902bf3e36 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py @@ -200,7 +200,8 @@ class Parameters(NodeParameters): progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"sign": [-1, 1], "time": idle_times}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py index 53e0a9aa2..d05bee41a 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py @@ -167,7 +167,8 @@ class Parameters(NodeParameters): n = results.fetch_all()[0] progress_counter(n, n_runs, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"N": np.linspace(1, n_runs, n_runs)}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py index f878f31ed..2cba45453 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py @@ -164,7 +164,8 @@ class Parameters(NodeParameters): n = results.fetch_all()[0] progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py index e83afcf98..63859d5f0 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py @@ -173,7 +173,8 @@ class Parameters(NodeParameters): progress_counter(n, n_runs, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"amplitude": amps, "N": np.linspace(1, n_runs, n_runs)}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py index 856901395..33dfced28 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py @@ -174,7 +174,8 @@ class Parameters(NodeParameters): n = results.fetch_all()[0] progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py index fd8d7d4d8..475a34d69 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py @@ -182,7 +182,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: ds = fetch_results_as_xarray(job.result_handles, qubits, {"idle_time": idle_times, "flux": fluxes}) # Add the absolute time in µs to the dataset diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py index d78b7c4cf..6e14bad49 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py @@ -186,7 +186,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"freq": dfs, "N": N_pi_vec}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py index a06b8d1fd..b14e8d7ae 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py @@ -184,7 +184,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "N": N_pi_vec}) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py index 444dfa15e..d27317d6e 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py @@ -167,7 +167,8 @@ class Parameters(NodeParameters): # Progress bar progress_counter(n, n_avg, start_time=results.start_time) - # %% {Data_fetching_and_dataset_creation} +# %% {Data_fetching_and_dataset_creation} +if not node.parameters.simulate: if node.parameters.load_data_id is None: # Fetch the data from the OPX and convert it into a xarray with corresponding axes (from most inner to outer loop) ds = fetch_results_as_xarray(job.result_handles, qubits, {"amp": amps, "sequence": [0, 1]}) From 72bba2604b5d324dcea066d467aeccddb542cc8d Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Mon, 18 Nov 2024 12:07:32 +0100 Subject: [PATCH 6/8] no machine saving when loading data --- .../02a_Resonator_Spectroscopy.py | 19 ++++++++----------- .../02b_resonator_spectroscopy_vs_flux.py | 13 +++++-------- .../03a_Qubit_Spectroscopy.py | 13 +++++-------- .../03b_qubit_spectroscopy_vs_flux.py | 19 ++++++++----------- .../calibration_graph/04_Power_Rabi.py | 12 ++++++------ .../calibration_graph/05_T1.py | 10 +++++----- .../calibration_graph/06_Ramsey.py | 16 ++++++++-------- .../calibration_graph/07a_IQ_Blobs.py | 10 +++++----- .../07b_Readout_Frequency_Optimization.py | 10 +++++----- .../07c_Readout_Power_Optimization.py | 10 +++++----- .../08a_Power_Rabi_Error_Amplification.py | 10 +++++----- .../08b_Ramsey_vs_Flux_Calibration.py | 10 +++++----- .../calibration_graph/09a_Stark_Detuning.py | 10 +++++----- .../09b_DRAG_Calibration_180_minus_180.py | 10 +++++----- .../09c_DRAG_Calibration_180_90.py | 11 ++++++----- 15 files changed, 86 insertions(+), 97 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py index ae49e6640..a2215fbe3 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02a_Resonator_Spectroscopy.py @@ -103,8 +103,8 @@ class Parameters(NodeParameters): # save data save(I[i], I_st[i]) save(Q[i], Q_st[i]) - if not node.parameters.multiplexed: - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -233,15 +233,12 @@ class Parameters(NodeParameters): for index, q in enumerate(qubits): q.resonator.intermediate_frequency += int(fits[q.name].params["omega_r"].value) - # %% {Save_results} - if node.parameters.load_data_id is not None: - if node.storage_manager is not None: - node.storage_manager.active_machine_path = None - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() - print("Results saved") + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() + print("Results saved") # %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py index 71c586a34..33318fa88 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/02b_resonator_spectroscopy_vs_flux.py @@ -310,14 +310,11 @@ class Parameters(NodeParameters): fit_results[q.name]["dv_phi0"] * node.parameters.input_line_impedance_in_ohm * attenuation_factor ) - # %% {Save_results} - if node.parameters.load_data_id is not None: - if node.storage_manager is not None: - node.storage_manager.active_machine_path = None - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py index 212df435e..f514b35b8 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03a_Qubit_Spectroscopy.py @@ -338,14 +338,11 @@ class Parameters(NodeParameters): elif factor_pi * used_amp >= 0.3: # TODO: 1 for OPX1000 MW q.xy.operations["x180"].amplitude = 0.3 - # %% {Save_results} - if node.parameters.load_data_id is not None: - if node.storage_manager is not None: - node.storage_manager.active_machine_path = None - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() # %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py index 9196aea10..dffcd8574 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/03b_qubit_spectroscopy_vs_flux.py @@ -53,6 +53,7 @@ class Parameters(NodeParameters): simulation_duration_ns: int = 2500 timeout: int = 100 load_data_id: Optional[int] = None + multiplexed: bool = False node = QualibrationNode(name="03b_Qubit_Spectroscopy_vs_Flux", parameters=Parameters()) @@ -139,7 +140,8 @@ class Parameters(NodeParameters): qubit.resonator.wait(machine.depletion_time * u.ns) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -278,17 +280,12 @@ class Parameters(NodeParameters): q.xy.intermediate_frequency += fit_results[q.name]["drive_freq"] q.freq_vs_flux_01_quad_term = fit_results[q.name]["quad_term"] - # ds = ds.drop_vars("freq_full") - node.results["ds"] = ds + # %% {Save_results} - # %% {Save_results} - if node.parameters.load_data_id is not None: - if node.storage_manager is not None: - node.storage_manager.active_machine_path = None - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() # %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py index 03b113cd4..7646bc617 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/04_Power_Rabi.py @@ -50,7 +50,7 @@ class Parameters(NodeParameters): simulate: bool = False simulation_duration_ns: int = 2500 timeout: int = 100 - load_data_id: Optional[int] = False + load_data_id: Optional[int] = None multiplexed: bool = False node = QualibrationNode(name="04_Power_Rabi", parameters=Parameters()) @@ -252,9 +252,9 @@ class Parameters(NodeParameters): if operation == "x180": q.xy.operations["x90"].amplitude = fit_results[q.name]["Pi_amplitude"] / 2 - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py index 324480f5c..d0391ac8e 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/05_T1.py @@ -66,7 +66,7 @@ class Parameters(NodeParameters): if node.parameters.qubits is None or node.parameters.qubits == "": qubits = machine.active_qubits else: - qubits = [machine.qubits[q] for q in node.parameters.qubits.replace(" ", "").split(",")] + qubits = [machine.qubits[q] for q in node.parameters.qubits] num_qubits = len(qubits) @@ -247,8 +247,8 @@ class Parameters(NodeParameters): ): q.T1 = float(tau.sel(qubit=q.name).values) * 1e-6 - # %% {Save_results} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py index 902bf3e36..e015c6268 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/06_Ramsey.py @@ -55,7 +55,7 @@ class Parameters(NodeParameters): load_data_id: Optional[int] = None multiplexed: bool = False -node = QualibrationNode(name="06a_Ramsey", parameters=Parameters()) +node = QualibrationNode(name="06_Ramsey", parameters=Parameters()) # %% {Initialize_QuAM_and_QOP} @@ -158,8 +158,8 @@ class Parameters(NodeParameters): # Reset the frame of the qubits in order not to accumulate rotations reset_frame(qubit.xy.name) # Measure sequentially - - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -328,10 +328,10 @@ class Parameters(NodeParameters): q.T2ramsey = float(fit_results[q.name]["decay"]) - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() # %% diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py index d05bee41a..9e671fa4a 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py @@ -328,9 +328,9 @@ def extract_value(element): if operation_name == "readout": qubit.resonator.confusion_matrix = node.results["results"][qubit.name]["confusion_matrix"].tolist() - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py index 2cba45453..d7f612359 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py @@ -250,9 +250,9 @@ class Parameters(NodeParameters): q.resonator.intermediate_frequency += int(fit_results[q.name]["detuning"]) q.chi = float(fit_results[q.name]["chi"]) - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py index 63859d5f0..2c194acff 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07c_Readout_Power_Optimization.py @@ -404,8 +404,8 @@ def apply_fit_gmm(I, Q): qubit.resonator.confusion_matrix = node.results["results"][qubit.name]["confusion_matrix"].tolist() - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py index 33dfced28..e039f5b4d 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py @@ -268,8 +268,8 @@ class Parameters(NodeParameters): for q in qubits: q.xy.operations[operation].amplitude = fit_results[q.name]["Pi_amplitude"] - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py index 475a34d69..c213bfaef 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py @@ -291,8 +291,8 @@ class Parameters(NodeParameters): raise RuntimeError(f"unknown flux_point") qubit.freq_vs_flux_01_quad_term = float(a[qubit.name]) - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py index 6e14bad49..39a7840f5 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09a_Stark_Detuning.py @@ -234,9 +234,9 @@ class Parameters(NodeParameters): if node.parameters.DRAG_setpoint is not None: qubit.xy.operations[operation].alpha = node.parameters.DRAG_setpoint - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py index b14e8d7ae..b143a862c 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py @@ -240,9 +240,9 @@ class Parameters(NodeParameters): for q in qubits: q.xy.operations[operation].alpha = fit_results[q.name]["alpha"] - # %% {Save_results} - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py index d27317d6e..78d881b27 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09c_DRAG_Calibration_180_90.py @@ -131,7 +131,8 @@ class Parameters(NodeParameters): assign(state[i], I[i] > qubit.resonator.operations["readout"].threshold) save(state[i], state_stream[i]) # Measure sequentially - align() + if not node.parameters.multiplexed: + align() with stream_processing(): n_st.save("n") @@ -223,7 +224,7 @@ class Parameters(NodeParameters): for q in qubits: q.xy.operations[operation].alpha = fit_results[q.name]["alpha"] - # %% {Save_results} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() From 41741f2613ff30a9e24dd2d616cb8edeaabb6743 Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Mon, 18 Nov 2024 12:55:33 +0100 Subject: [PATCH 7/8] small bug fix, also RB has multiplexed and data loading options --- .../08a_Power_Rabi_Error_Amplification.py | 16 +++++++++------- .../08b_Ramsey_vs_Flux_Calibration.py | 13 ++++--------- .../09b_DRAG_Calibration_180_minus_180.py | 2 +- .../10a_Single_Qubit_Randomized_Benchmarking.py | 14 ++++++++------ 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py index e039f5b4d..70df9076c 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08a_Power_Rabi_Error_Amplification.py @@ -21,7 +21,7 @@ # %% {Imports} from qualibrate import QualibrationNode, NodeParameters from quam_libs.components import QuAM -from quam_libs.macros import qua_declaration, active_reset +from quam_libs.macros import qua_declaration, active_reset, readout_state from quam_libs.lib.plot_utils import QubitGrid, grid_iter from quam_libs.lib.save_utils import fetch_results_as_xarray, load_dataset from quam_libs.lib.fit import fit_oscillation, oscillation @@ -100,7 +100,7 @@ class Parameters(NodeParameters): with program() as power_rabi: I, _, Q, _, n, n_st = qua_declaration(num_qubits=num_qubits) - state = [declare(bool) for _ in range(num_qubits)] + state = [declare(int) for _ in range(num_qubits)] state_stream = [declare_stream() for _ in range(num_qubits)] a = declare(fixed) # QUA variable for the qubit drive amplitude pre-factor npi = declare(int) # QUA variable for the number of qubit pulses @@ -120,16 +120,18 @@ class Parameters(NodeParameters): if reset_type == "active": active_reset(qubit, "readout") else: - wait(qubit.thermalization_time * u.ns) + qubit.wait(qubit.thermalization_time * u.ns) qubit.align() # Loop for error amplification (perform many qubit pulses) with for_(count, 0, count < npi, count + 1): qubit.xy.play(operation, amplitude_scale=a) qubit.align() - qubit.resonator.measure("readout", qua_vars=(I[i], Q[i])) - assign(state[i], I[i] > qubit.resonator.operations["readout"].threshold) + # qubit.resonator.measure("readout", qua_vars=(I[i], Q[i])) + # assign(state[i], I[i] > qubit.resonator.operations["readout"].threshold) + readout_state(qubit, state[i]) save(state[i], state_stream[i]) + if not node.parameters.multiplexed: align() @@ -137,11 +139,11 @@ class Parameters(NodeParameters): n_st.save("n") for i, qubit in enumerate(qubits): if operation == "x180": - state_stream[i].boolean_to_int().buffer(len(amps)).buffer(np.ceil(N_pi / 2)).average().save( + state_stream[i].buffer(len(amps)).buffer(np.ceil(N_pi / 2)).average().save( f"state{i + 1}" ) elif operation in ["x90", "-x90", "y90", "-y90"]: - state_stream[i].boolean_to_int().buffer(len(amps)).buffer(np.ceil(N_pi / 4)).average().save( + state_stream[i].buffer(len(amps)).buffer(np.ceil(N_pi / 4)).average().save( f"state{i + 1}" ) else: diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py index c213bfaef..7fc974624 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/08b_Ramsey_vs_Flux_Calibration.py @@ -103,15 +103,10 @@ class Parameters(NodeParameters): flux = declare(fixed) # QUA variable for the flux dc level for i, qubit in enumerate(qubits): - - # Bring the active qubits to the minimum frequency point - if flux_point == "independent": - machine.apply_all_flux_to_min() - qubit.z.to_independent_idle() - elif flux_point == "joint": - machine.apply_all_flux_to_joint_idle() - else: - machine.apply_all_flux_to_zero() + # Bring the active qubits to the desired frequency point + machine.set_all_fluxes(flux_point=flux_point, target=qubit) + qubit.z.settle() + qubit.align() with for_(n, 0, n < n_avg, n + 1): save(n, n_st) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py index b143a862c..d23096646 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/09b_DRAG_Calibration_180_minus_180.py @@ -129,7 +129,7 @@ class Parameters(NodeParameters): if reset_type == "active": active_reset(qubit, "readout") else: - qubit.resonator.wait(qubit.thermalization_time * u.ns) + qubit.wait(qubit.thermalization_time * u.ns) qubit.align() # Loop for error amplification (perform many qubit pulses) with for_(count, 0, count < npi, count + 1): diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py index bd438d063..2124e4323 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/10a_Single_Qubit_Randomized_Benchmarking.py @@ -244,6 +244,8 @@ def play_sequence(sequence_list, depth, qubit: Transmon): if flux_point == "independent": machine.apply_all_flux_to_min() qubit.z.to_independent_idle() + if node.parameters.multiplexed: + qubit.align() else: align() # Initialize the qubits @@ -388,10 +390,10 @@ def play_sequence(sequence_list, depth, qubit: Transmon): node.results["figure"] = grid.fig -# %% {Save_results} -if not node.parameters.simulate: - node.outcomes = {q.name: "successful" for q in qubits} - node.results["initial_parameters"] = node.parameters.model_dump() - node.machine = machine - node.save() + # %% {Save_results} + if not node.parameters.simulate: + node.outcomes = {q.name: "successful" for q in qubits} + node.results["initial_parameters"] = node.parameters.model_dump() + node.machine = machine + node.save() From c9aa183f9ca78695ee142a3e9d163a95404ac833 Mon Sep 17 00:00:00 2001 From: TomDvirQM Date: Mon, 18 Nov 2024 13:02:11 +0100 Subject: [PATCH 8/8] small refactor: 07a <-> 07b --- ...cy_Optimization.py => 07a_Readout_Frequency_Optimization.py} | 2 +- .../calibration_graph/{07a_IQ_Blobs.py => 07b_IQ_Blobs.py} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/{07b_Readout_Frequency_Optimization.py => 07a_Readout_Frequency_Optimization.py} (99%) rename Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/{07a_IQ_Blobs.py => 07b_IQ_Blobs.py} (99%) diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_Readout_Frequency_Optimization.py similarity index 99% rename from Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py rename to Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_Readout_Frequency_Optimization.py index d7f612359..15b4c268d 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_Readout_Frequency_Optimization.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_Readout_Frequency_Optimization.py @@ -48,7 +48,7 @@ class Parameters(NodeParameters): load_data_id: Optional[int] = None multiplexed: bool = False -node = QualibrationNode(name="07b_Readout_Frequency_Optimization", parameters=Parameters()) +node = QualibrationNode(name="07a_Readout_Frequency_Optimization", parameters=Parameters()) # %% {Initialize_QuAM_and_QOP} diff --git a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_IQ_Blobs.py similarity index 99% rename from Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py rename to Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_IQ_Blobs.py index 9e671fa4a..656c2cd42 100644 --- a/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07a_IQ_Blobs.py +++ b/Quantum-Control-Applications-QuAM/Superconducting/calibration_graph/07b_IQ_Blobs.py @@ -55,7 +55,7 @@ class Parameters(NodeParameters): multiplexed: bool = False -node = QualibrationNode(name="07a_IQ_Blobs", parameters=Parameters()) +node = QualibrationNode(name="07b_IQ_Blobs", parameters=Parameters()) # %% {Initialize_QuAM_and_QOP}