Source code for autoemx.core.em_runtime.xsp_spot_selection

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Programmatic X-ray spot selection on automatically navigated particles.

When ``PowderMeasurementConfig.par_spot_selection_mode`` is ``'callback'``, the
framework navigates to each particle automatically and invokes ``xsp_spot_selector``
repeatedly on the same particle until the callback returns an empty list.
"""
from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Callable, List, Sequence, Tuple, TYPE_CHECKING

if TYPE_CHECKING:
    from autoemx.core.em_runtime.particle_finder import EM_Particle_Finder

XSpSpotSelectorCallback = Callable[["XSpSpotSelectionContext"], Sequence[Tuple[int, int]]]


[docs] @dataclass(frozen=True) class XSpSpotSelectionContext: """ Context passed to ``xsp_spot_selector`` after automatic particle navigation. The callback is invoked once per spot batch on the current particle. Return a non-empty list of pixel coordinates to measure, then wait for the next invocation to supply more spots. Return ``[]`` when finished with this particle (including to skip it without measuring). ``ref_image`` is the frame captured at spot-selection time. It is the same image used as the drift-correction reference during subsequent acquisitions on this particle (see ``EM_Controller.ref_image``). """ particle_id: int n_tot_sp_collected: int ref_image: Any pixel_size_um: float frame_label: str im_width: int im_height: int particle_finder: "EM_Particle_Finder"
[docs] def validate_xsp_spot_pixels( spots: Sequence[Tuple[int, int]], *, im_width: int, im_height: int, ) -> List[Tuple[int, int]]: """ Validate and normalize programmatic spot pixel coordinates. Raises ------ ValueError If a spot is outside the image bounds. """ if im_width <= 0 or im_height <= 0: raise ValueError("Image dimensions must be positive.") validated: List[Tuple[int, int]] = [] seen = set() for spot in spots: if len(spot) != 2: raise ValueError(f"Each spot must be an (x, y) pair; got {spot!r}.") x, y = int(spot[0]), int(spot[1]) if not (0 <= x < im_width and 0 <= y < im_height): raise ValueError( f"Spot ({x}, {y}) is outside image bounds " f"(width={im_width}, height={im_height})." ) key = (x, y) if key not in seen: seen.add(key) validated.append(key) return validated