diff --git a/docs/changelog.md b/docs/changelog.md index 09df55a76..905556cf8 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -25,6 +25,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. 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_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)\ diff --git a/src/qudi/logic/scanning_optimize_logic.py b/src/qudi/logic/scanning_optimize_logic.py index 0bd66196c..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.') @@ -448,12 +456,23 @@ 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: + fallback_dimension = self.allowed_optimizer_sequence_dimensions[0] + 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: - self.log.info( - f"No valid scan sequence existing ({self._scan_sequence=}), setting scan sequence to {possible_scan_sequences[0]}." - ) - self._scan_sequence = possible_scan_sequences[0] + + fallback_scan_sequence = possible_scan_sequences[0] + 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 def sequence_dimension_constructor(self, dimensions: Union[list, tuple]) -> tuple: 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)