Source code for xrheed.conversion.base

import logging
from typing import Optional, Tuple

import numpy as np
from numpy.typing import NDArray

logger = logging.getLogger(__name__)


[docs] def convert_sx_to_ky( x_coords_mm: NDArray, ewald_radius: float, screen_sample_distance_mm: float, ) -> NDArray: """Convert sx coordinates from mm to ky [1/Å] using the Ewald sphere radius and screen-sample distance. Parameters ---------- x_coords_mm : NDArray Array of x coordinates in millimeters (mm). ewald_radius : float Radius of the Ewald sphere in reciprocal space (1/Å). screen_sample_distance_mm : float Distance from the sample to the screen in millimeters (mm). Returns ------- NDArray Converted x coordinates in ky [1/Å]. """ kx: NDArray = (x_coords_mm / screen_sample_distance_mm) * ewald_radius logger.debug( "convert_sx_to_ky: x_coords_mm.shape=%s ewald_radius=%s screen_sample_distance_mm=%s", getattr(x_coords_mm, "shape", None), ewald_radius, screen_sample_distance_mm, ) return kx
[docs] def convert_gx_gy_to_sx_sy( gx: NDArray[np.float32], gy: NDArray[np.float32], ewald_radius: float, incident_angle: float, screen_sample_distance: float, remove_outside: Optional[bool] = True, **kwargs, ) -> Tuple[NDArray[np.float32], NDArray[np.float32]]: """ Convert reciprocal lattice coordinates (gx, gy) to RHEED screen coordinates (sx, sy) using the Ewald sphere construction. Parameters ---------- gx : NDArray Array of reciprocal lattice x-coordinates. gy : NDArray Array of reciprocal lattice y-coordinates. ewald_radius : float Radius of the Ewald sphere in reciprocal space (1/Å or same units as gx, gy). incident_angle : float Incident beam angle in degrees relative to the surface normal. screen_sample_distance : float Distance from the sample to the detector/screen. remove_outside : Optional[bool], default=True If True, points outside the Ewald sphere are removed. If False, points outside are set to NaN. **kwargs Additional keyword arguments (currently unused). Returns ------- sx : NDArray Array of x-coordinates on the RHEED screen corresponding to input gx, gy. sy : NDArray Array of y-coordinates on the RHEED screen corresponding to input gx, gy. Notes ----- - The function assumes a simple planar screen perpendicular to the z-axis. - The coordinate transformation accounts for the Ewald sphere geometry and the projection of diffraction spots onto the screen. - `incident angle` (beta) of the electron beam relative to the sample surface. - Points outside the Ewald sphere can be optionally removed or set as NaN using the `remove_outside` flag. """ # Ewald sphere radius k0: np.float32 = np.float32(ewald_radius) # Ewald sphere radius square kk: np.float32 = np.float32(k0**2) # calculate the shift between the center of Ewald sphere and the center of reciprocal lattice delta_x: np.float32 = np.float32(k0 * np.cos(np.deg2rad(incident_angle))) logger.debug( "called convert_gx_gy_to_sx_sy: gx.shape=%s gy.shape=%s ewald_radius=%s beta=%s screen_sample_distance=%s remove_outside=%s", getattr(gx, "shape", None), getattr(gy, "shape", None), ewald_radius, incident_angle, screen_sample_distance, remove_outside, ) # shift the center of reciprocal lattice kx: NDArray[np.float32] = gx + delta_x ky: NDArray[np.float32] = gy # Check if the kx, ky points are inside Ewald sphere kxy2: NDArray[np.float32] = kx**2 + ky**2 ind: NDArray[np.bool_] = kxy2 < kk # remove those outside or mark as nans if remove_outside: kx = kx[ind] ky = ky[ind] else: kx[~ind] = np.nan ky[~ind] = np.nan # calculate the radius r_k rk: NDArray[np.float32] = np.sqrt(k0**2 - kx**2) # calculate theta and phi (cos) values phi: NDArray[np.float32] = np.arccos(ky / rk) theta: NDArray[np.float32] = np.arcsin(rk / k0) # calculate the radius on the RHEED screen rho: NDArray[np.float32] = screen_sample_distance * np.tan(theta) # calculate the spot positions sx: NDArray[np.float32] = rho * np.cos(phi) sy: NDArray[np.float32] = -rho * np.sin(phi) logger.debug( "convert_gx_gy_to_sx_sy: result shapes sx=%s sy=%s", getattr(sx, "shape", None), getattr(sy, "shape", None), ) return sx, sy