From f2c37932bcfb86f8429c1f335758d8446f748f8b Mon Sep 17 00:00:00 2001 From: Tobias Spohn Date: Tue, 7 Jan 2025 17:30:03 +0100 Subject: [PATCH 1/6] fixed default initialization behavior for less than 3 scanning axes simplifying default scan sequence search --- src/qudi/logic/scanning_optimize_logic.py | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/qudi/logic/scanning_optimize_logic.py b/src/qudi/logic/scanning_optimize_logic.py index 0bd66196c..5b81c34e6 100644 --- a/src/qudi/logic/scanning_optimize_logic.py +++ b/src/qudi/logic/scanning_optimize_logic.py @@ -448,12 +448,28 @@ def _set_default_scan_settings(self): self._back_scan_frequency = {} def _set_default_scan_sequence(self): - possible_scan_sequences = self._allowed_sequences(self._optimizer_sequence_dimensions) - if self._scan_sequence is None or self._scan_sequence not in possible_scan_sequences: + if ( + self._optimizer_sequence_dimensions + not in self.allowed_optimizer_sequence_dimensions + ): + fallback_dimension = self.allowed_optimizer_sequence_dimensions[0] self.log.info( - f"No valid scan sequence existing ({self._scan_sequence=}), setting scan sequence to {possible_scan_sequences[0]}." + f"Selected optimization dimensions ({self._optimizer_sequence_dimensions}) are not in the allowed optimizer dimensions ({self.allowed_optimizer_sequence_dimensions}), choosing fallback dimension {fallback_dimension}. " ) - self._scan_sequence = possible_scan_sequences[0] + self._optimizer_sequence_dimensions = fallback_dimension + + possible_scan_sequences = self._allowed_sequences( + self._optimizer_sequence_dimensions + ) + if ( + self._scan_sequence is None + or self._scan_sequence not in possible_scan_sequences + ): + fallback_scan_sequence = possible_scan_sequences[0] + self.log.info( + f"No valid scan sequence existing ({self._scan_sequence=}), setting scan sequence to {fallback_scan_sequence}." + ) + self._scan_sequence = fallback_scan_sequence @_optimizer_sequence_dimensions.constructor def sequence_dimension_constructor(self, dimensions: Union[list, tuple]) -> tuple: From 8a6d3fbd7fbc48e0df187ce7cfd2e397071651c4 Mon Sep 17 00:00:00 2001 From: Tobias Spohn Date: Tue, 7 Jan 2025 18:07:07 +0100 Subject: [PATCH 2/6] changelog --- docs/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.md b/docs/changelog.md index dca9ca00d..5a1905178 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -24,6 +24,7 @@ - Fixed `t1_sequencing` predefined method's `counting_length` for gated mode - `QDPlotterGui` will continue to show fit results if new plot was added - Added `PulseSequence.generation_method_parameters` variable to correctly save `generation_method_parameters` of a `PulseSequence` and save these parameters in the output file +- Fixed `ScanningOptimizeLogic` crashing on first start when using scanner with less than the default 3 axes configured ### New Features - New `qudi.interface.scanning_probe_interface.ScanSettings` dataclass added. From e60b3f273d4685a39c40a8490a9908bbeae4ba29 Mon Sep 17 00:00:00 2001 From: timoML Date: Sat, 11 Jan 2025 17:53:00 +0100 Subject: [PATCH 3/6] better handling of scan axes configuration from invalid status variables --- src/qudi/gui/scanning/scannergui.py | 6 +++++- src/qudi/logic/scanning_probe_logic.py | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/qudi/gui/scanning/scannergui.py b/src/qudi/gui/scanning/scannergui.py index d50af5689..f2c8de1dd 100644 --- a/src/qudi/gui/scanning/scannergui.py +++ b/src/qudi/gui/scanning/scannergui.py @@ -541,7 +541,11 @@ def _restore_tilt_correction(self): tilt_settings = self._scanning_logic().tilt_correction_settings self.tilt_corr_support_vector_updated(tilt_settings) - self.apply_tilt_corr_support_vectors() + try: + self.apply_tilt_corr_support_vectors() + except ValueError: + self.log.warning("Couldn't restore tilt correction settings.") + pass @QtCore.Slot(tuple) def save_scan_data(self, scan_axes: Union[None, Tuple[str], Tuple[str, str]]): diff --git a/src/qudi/logic/scanning_probe_logic.py b/src/qudi/logic/scanning_probe_logic.py index 917d126d9..bb7a77735 100644 --- a/src/qudi/logic/scanning_probe_logic.py +++ b/src/qudi/logic/scanning_probe_logic.py @@ -243,6 +243,13 @@ def create_back_scan_settings(self, scan_axes: Sequence[str]) -> ScanSettings: def check_scan_settings(self): """Validate current scan settings for all possible 1D and 2D scans.""" + for stg in [self.scan_ranges, self.scan_resolution, self.scan_frequency]: + axs = stg.keys() + for ax in axs: + if ax not in self.scanner_axes.keys(): + self.log.debug(f"Axis {ax} from scan settings not available on scanner" ) + raise ValueError + for dim in [1, 2]: for axes in combinations(self.scanner_axes, dim): settings = self.create_scan_settings(axes) From ba42194e297c225eaf817c15cc767f4e9620cb8f Mon Sep 17 00:00:00 2001 From: timoML Date: Sat, 11 Jan 2025 18:14:23 +0100 Subject: [PATCH 4/6] re-format line breaks --- src/qudi/logic/scanning_optimize_logic.py | 29 ++++++++++------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/qudi/logic/scanning_optimize_logic.py b/src/qudi/logic/scanning_optimize_logic.py index 5b81c34e6..adb73c16e 100644 --- a/src/qudi/logic/scanning_optimize_logic.py +++ b/src/qudi/logic/scanning_optimize_logic.py @@ -448,27 +448,22 @@ def _set_default_scan_settings(self): self._back_scan_frequency = {} def _set_default_scan_sequence(self): - if ( - self._optimizer_sequence_dimensions - not in self.allowed_optimizer_sequence_dimensions - ): + + if self._optimizer_sequence_dimensions not in self.allowed_optimizer_sequence_dimensions: fallback_dimension = self.allowed_optimizer_sequence_dimensions[0] - self.log.info( - f"Selected optimization dimensions ({self._optimizer_sequence_dimensions}) are not in the allowed optimizer dimensions ({self.allowed_optimizer_sequence_dimensions}), choosing fallback dimension {fallback_dimension}. " - ) + self.log.info(f"Selected optimization dimensions ({self._optimizer_sequence_dimensions}) " + f"are not in the allowed optimizer dimensions ({self.allowed_optimizer_sequence_dimensions})," + f" choosing fallback dimension {fallback_dimension}. ") self._optimizer_sequence_dimensions = fallback_dimension - possible_scan_sequences = self._allowed_sequences( - self._optimizer_sequence_dimensions - ) - if ( - self._scan_sequence is None - or self._scan_sequence not in possible_scan_sequences - ): + possible_scan_sequences = self._allowed_sequences(self._optimizer_sequence_dimensions) + + if self._scan_sequence is None or self._scan_sequence not in possible_scan_sequences: + fallback_scan_sequence = possible_scan_sequences[0] - self.log.info( - f"No valid scan sequence existing ({self._scan_sequence=}), setting scan sequence to {fallback_scan_sequence}." - ) + self.log.info(f"No valid scan sequence existing ({self._scan_sequence=})," + f" setting scan sequence to {fallback_scan_sequence}.") + self._scan_sequence = fallback_scan_sequence @_optimizer_sequence_dimensions.constructor From df408243d63d5c27b8c48f8a1a5fbee04046da67 Mon Sep 17 00:00:00 2001 From: timoML Date: Sat, 11 Jan 2025 18:41:59 +0100 Subject: [PATCH 5/6] improve handling of restoring from invalid StatusVar --- src/qudi/logic/scanning_optimize_logic.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/qudi/logic/scanning_optimize_logic.py b/src/qudi/logic/scanning_optimize_logic.py index adb73c16e..564f4c3e6 100644 --- a/src/qudi/logic/scanning_optimize_logic.py +++ b/src/qudi/logic/scanning_optimize_logic.py @@ -26,6 +26,7 @@ from PySide2 import QtCore import copy as cp from typing import Dict, Tuple, List, Optional, Union +import itertools from qudi.core.module import LogicBase from qudi.interface.scanning_probe_interface import ScanData, BackScanCapability @@ -35,7 +36,6 @@ from qudi.core.statusvariable import StatusVar from qudi.util.fit_models.gaussian import Gaussian2D, Gaussian from qudi.core.configoption import ConfigOption -import itertools class ScanningOptimizeLogic(LogicBase): @@ -425,6 +425,14 @@ def _get_pos_from_1d_gauss_fit(self, x, data): def _check_scan_settings(self): """Basic check of scan settings for all axes.""" scan_logic: ScanningProbeLogic = self._scan_logic() + + for stg in [self.scan_range, self.scan_resolution, self.scan_frequency]: + axs = stg.keys() + for ax in axs: + if ax not in scan_logic.scanner_axes.keys(): + self.log.debug(f"Axis {ax} from optimizer scan settings not available on scanner" ) + raise ValueError + capability = scan_logic.back_scan_capability if self._back_scan_resolution and (BackScanCapability.RESOLUTION_CONFIGURABLE not in capability): raise AssertionError('Back scan resolution cannot be configured for this scanner hardware.') From 9c8617a938d73d3666508005fc2545e521bb63c1 Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 14 Jan 2025 12:24:59 +0100 Subject: [PATCH 6/6] prevent restoring scan history with incompatible axis config - fixes crashes trying to restore incompatible scanner_target_at_start --- src/qudi/logic/scanning_data_logic.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/qudi/logic/scanning_data_logic.py b/src/qudi/logic/scanning_data_logic.py index 8b9f7b66b..3083ac44a 100644 --- a/src/qudi/logic/scanning_data_logic.py +++ b/src/qudi/logic/scanning_data_logic.py @@ -114,13 +114,27 @@ def __scan_history_to_dicts(self, history: List[Tuple[ScanData, Optional[ScanDat def __scan_history_from_dicts(self, history_dicts: List[List[Optional[Dict]]])\ -> List[Tuple[ScanData, Optional[ScanData]]]: history = [] + + scan_axes = self._scan_logic().scanner_axes + scan_axes_avail = [ax.name for ax in scan_axes.values()] + + data_dropped = False try: for data_dict, back_data_dict in history_dicts: data = ScanData.from_dict(data_dict) back_data = ScanData.from_dict(back_data_dict) if back_data_dict is not None else None + data_axs = data.scanner_target_at_start.keys() + if not (set(data_axs) <= set(scan_axes_avail)): + data_dropped = True + continue + history.append((data, back_data)) except Exception as e: self.log.warning("Unable to load scan history. Deleting scan history.", exc_info=e) + + if data_dropped: + self.log.warning("Deleted scan history entries containing an incompatible scan axes configuration.") + return history def get_last_history_entry(self, scan_axes: Optional[Tuple[str, ...]] = None)\