Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/video_mode/example_video_mode_opx.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
# --- QMM Connection ---
# Replace with your actual OPX host and cluster name
# Example: qmm = QuantumMachinesManager(host="your_opx_ip", cluster_name="your_cluster")
qmm = QuantumMachinesManager(host="`127.0.0.1", cluster_name="CS_1")
qmm = QuantumMachinesManager(host="172.16.33.101", cluster_name="CS_1")

# Generate the QUA configuration from the QUAM machine object
config = machine.generate_config()
Expand Down Expand Up @@ -160,7 +160,7 @@
# Run the Dash server.
# `host="0.0.0.0"` makes it accessible on your network.
# `use_reloader=False` is often recommended for stability with background threads.
app.run(debug=True, host="0.0.0.0", port=8050, use_reloader=False)
app.run(debug=True, host="127.0.0.1", port=8050, use_reloader=False)


# %% --- Debugging Sections (Optional) ---
Expand Down
4 changes: 2 additions & 2 deletions src/qua_dashboards/core/base_updatable_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, *args: Any, component_id: str, **kwargs: Any) -> None:
# Pass through component_id and any other args/kwargs to BaseComponent
super().__init__(component_id=component_id, *args, **kwargs) # type: ignore

def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFlags:
def update_parameters(self, parameters: Dict[str, Dict[str, Any]]):
"""
Update the component's attributes based on the input values from the UI.

Expand All @@ -59,7 +59,7 @@ def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFl
and might require further action (e.g., re-generating a program).
Defaults to ModifiedFlags.NONE.
"""
return ModifiedFlags.NONE
return None

def get_dash_components(self, include_subcomponents: bool = True) -> List[html.Div]:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ def get_latest_data(self) -> Dict[str, Any]:
"status": self._acquisition_status,
}

def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFlags:
flags = super().update_parameters(parameters) # From BaseUpdatableComponent
def update_parameters(self, parameters: Dict[str, Dict[str, Any]]):

if self.component_id in parameters:
params = parameters[self.component_id]
Expand All @@ -232,7 +231,6 @@ def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFl
new_interval = float(params["acquisition_interval_s"])
if new_interval > 0:
self.acquisition_interval_s = new_interval
flags |= ModifiedFlags.PARAMETERS_MODIFIED
else:
logger.warning(
f"Invalid acquisition_interval_s: {new_interval}. Not updated."
Expand All @@ -245,7 +243,6 @@ def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFl
new_averages = int(params["num_software_averages"])
if new_averages >= 1:
self.num_software_averages = new_averages
flags |= ModifiedFlags.PARAMETERS_MODIFIED
with self._data_lock: # Clear history as averaging window changed
self._data_history_raw.clear()
self._latest_processed_data = None
Expand All @@ -259,9 +256,9 @@ def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFl
continue

if component.component_id in parameters:
flags |= component.update_parameters(parameters)
component.update_parameters(parameters)


return flags

def get_dash_components(self, include_subcomponents: bool = True) -> List[Any]:
components = super().get_dash_components(include_subcomponents)
Expand Down
53 changes: 34 additions & 19 deletions src/qua_dashboards/video_mode/data_acquirers/opx_data_acquirer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from qua_dashboards.video_mode.data_acquirers.base_2d_data_acquirer import (
Base2DDataAcquirer,
)
from qua_dashboards.core import ModifiedFlags
from qua_dashboards.video_mode.sweep_axis import SweepAxis
from qua_dashboards.video_mode.scan_modes import ScanMode

Expand Down Expand Up @@ -104,13 +103,15 @@ def __init__(
self.initial_delay_s: Optional[float] = initial_delay_s
self.qua_program: Optional[Program] = None
self.qm_job: Optional[RunningQmJob] = None
self._compilation_flags: ModifiedFlags = ModifiedFlags.NONE

self.result_type: str = result_type
self._raw_qua_results: Dict[str, np.ndarray] = {}
self.stream_vars: List[str] = stream_vars or self.stream_vars_default
self.result_types: List[str] = self.result_types_default

#Initial parameters upon instantialisation of the data_acquirer
self.current_parameters = self._program_parameters()

def generate_qua_program(self) -> Program:
"""
Generates the QUA program for the 2D scan.
Expand Down Expand Up @@ -183,12 +184,26 @@ def initialize_qm(self):

if self.qm is None:
self.qm = self.qmm.open_qm(self.qua_config) # type: ignore

def _program_parameters(self):
inner_loop = self.qua_inner_loop_action

params = (
self.x_axis.span, self.x_axis.points,
self.y_axis.span, self.y_axis.points,
# self.scan_mode.__name__,
tuple(self.stream_vars), self.result_type, self.initial_delay_s,
inner_loop.readout_pulse.channel.intermediate_frequency, inner_loop.readout_pulse.length, inner_loop.readout_pulse.amplitude,
self.num_software_averages, self.acquisition_interval_s
)
return params


def execute_program(self, validate_running: bool = True):
if self.qua_program is None:
logger.info(f"Generating QUA program for {self.component_id}.")
self.generate_qua_program()

self.qua_program = None
logger.info(f"Generating QUA program for {self.component_id}.")
self.generate_qua_program()
logger.info(f"Executing QUA program for {self.component_id}.")
self.qm_job = self.qm.execute(self.qua_program) # type: ignore

Expand All @@ -202,6 +217,8 @@ def execute_program(self, validate_running: bool = True):
f"QM job for {self.component_id} failed to start or produce initial values: {e}"
)
raise
#Update the internal programme parameters, if anything has changed. Only done after a successful execution
self.current_parameters = self._program_parameters()

def _process_fetched_results(self, fetched_qua_results: Tuple) -> np.ndarray:
"""
Expand Down Expand Up @@ -252,15 +269,8 @@ def _process_fetched_results(self, fetched_qua_results: Tuple) -> np.ndarray:
return output_data_2d

def perform_actual_acquisition(self) -> np.ndarray:
if self._compilation_flags & ModifiedFlags.CONFIG_MODIFIED:
logger.info(f"Config regeneration triggered for {self.component_id}.")
if self.current_parameters != self._program_parameters():
self._regenerate_config_and_reopen_qm()
self._compilation_flags = ModifiedFlags.NONE
elif self._compilation_flags & ModifiedFlags.PROGRAM_MODIFIED:
logger.info(f"Program recompile triggered for {self.component_id}.")
self.qua_program = None # Clear the program to force a re-generation
self.execute_program()
self._compilation_flags = ModifiedFlags.NONE

if self.qm_job is None or self.qm_job.status != "running":
logger.warning(
Expand Down Expand Up @@ -293,20 +303,25 @@ def perform_actual_acquisition(self) -> np.ndarray:
def _regenerate_config_and_reopen_qm(self) -> None:
logger.info(f"Regenerating QUA config for {self.component_id} from machine.")
self.qua_config = self.machine.generate_config()

try:
if self.qm_job and self.qm_job.status == "running":
self.qm_job.halt()
except Exception:
logger.exception("Error halting job before reopen")

self.qm_job = None
self.qm = None
self.initialize_qm()
self.execute_program()

def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFlags:
flags = super().update_parameters(parameters)

def update_parameters(self, parameters: Dict[str, Dict[str, Any]]):
super().update_parameters(parameters)
if self.component_id in parameters:
params = parameters[self.component_id]
if "result-type" in params and self.result_type != params["result-type"]:
self.result_type = params["result-type"]
flags |= ModifiedFlags.PARAMETERS_MODIFIED

self._compilation_flags = flags
return flags

def get_dash_components(self, include_subcomponents: bool = True) -> List[Any]:
components = super().get_dash_components(include_subcomponents)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from qua_dashboards.core.base_updatable_component import ModifiedFlags
from qua_dashboards.utils.dash_utils import create_input_field
from dash import html
from qm.qua.lib import Cast, Math
Expand Down Expand Up @@ -187,42 +186,28 @@ def get_dash_components(self, include_subcomponents: bool = True) -> List[html.D

return components

def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFlags:
def update_parameters(self, parameters: Dict[str, Dict[str, Any]]):
"""Update the data acquirer's attributes based on the input values."""
if self.component_id not in parameters:
return ModifiedFlags.NONE

return None
params = parameters[self.component_id]

flags = ModifiedFlags.NONE
if (
self.readout_pulse.channel.intermediate_frequency
!= params["readout_frequency"]
):
self.readout_pulse.channel.intermediate_frequency = params[
"readout_frequency"
]
flags |= ModifiedFlags.PARAMETERS_MODIFIED
flags |= ModifiedFlags.PROGRAM_MODIFIED
flags |= ModifiedFlags.CONFIG_MODIFIED

if self.readout_pulse.length != params["readout_duration"]:
self.readout_pulse.length = params["readout_duration"]
flags |= ModifiedFlags.PARAMETERS_MODIFIED
flags |= ModifiedFlags.PROGRAM_MODIFIED
flags |= ModifiedFlags.CONFIG_MODIFIED

if self.use_dBm:
if unit.volts2dBm(self.readout_pulse.amplitude) != params["readout_power"]:
self.readout_pulse.amplitude = unit.dBm2volts(params["readout_power"])
flags |= ModifiedFlags.PARAMETERS_MODIFIED
flags |= ModifiedFlags.PROGRAM_MODIFIED
flags |= ModifiedFlags.CONFIG_MODIFIED
else:
if self.readout_pulse.amplitude != params["readout_amplitude"]:
self.readout_pulse.amplitude = params["readout_amplitude"]
flags |= ModifiedFlags.PARAMETERS_MODIFIED
flags |= ModifiedFlags.PROGRAM_MODIFIED
flags |= ModifiedFlags.CONFIG_MODIFIED

return flags
10 changes: 3 additions & 7 deletions src/qua_dashboards/video_mode/sweep_axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
import dash_bootstrap_components as dbc

from qua_dashboards.core import BaseUpdatableComponent, ModifiedFlags
from qua_dashboards.core import BaseUpdatableComponent
from qua_dashboards.utils.basic_parameter import BasicParameter
from qua_dashboards.utils.dash_utils import create_input_field

Expand Down Expand Up @@ -126,21 +126,17 @@ def create_axis_layout(
className="mb-3",
)

def update_parameters(self, parameters: Dict[str, Dict[str, Any]]) -> ModifiedFlags:
def update_parameters(self, parameters: Dict[str, Dict[str, Any]]):
"""
Updates 2D data acquirer parameters (axes, averages).
"""
flags = super().update_parameters(parameters)

if self.component_id not in parameters:
return flags
return None

params = parameters[self.component_id]

if "span" in params and self.span != params["span"]:
self.span = params["span"]
flags |= ModifiedFlags.PARAMETERS_MODIFIED | ModifiedFlags.PROGRAM_MODIFIED
if "points" in params and self.points != params["points"]:
self.points = params["points"]
flags |= ModifiedFlags.PARAMETERS_MODIFIED | ModifiedFlags.PROGRAM_MODIFIED
return flags