xrheed 0.5.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. xrheed-0.5.13/LICENSE +21 -0
  2. xrheed-0.5.13/PKG-INFO +135 -0
  3. xrheed-0.5.13/README.md +99 -0
  4. xrheed-0.5.13/pyproject.toml +47 -0
  5. xrheed-0.5.13/setup.cfg +4 -0
  6. xrheed-0.5.13/src/xrheed/__init__.py +61 -0
  7. xrheed-0.5.13/src/xrheed/conversion/__init__.py +9 -0
  8. xrheed-0.5.13/src/xrheed/conversion/base.py +120 -0
  9. xrheed-0.5.13/src/xrheed/conversion/image.py +138 -0
  10. xrheed-0.5.13/src/xrheed/io.py +76 -0
  11. xrheed-0.5.13/src/xrheed/kinematics/__init__.py +10 -0
  12. xrheed-0.5.13/src/xrheed/kinematics/cache_utils.py +50 -0
  13. xrheed-0.5.13/src/xrheed/kinematics/ewald.py +645 -0
  14. xrheed-0.5.13/src/xrheed/kinematics/lattice.py +455 -0
  15. xrheed-0.5.13/src/xrheed/plotting/__init__.py +11 -0
  16. xrheed-0.5.13/src/xrheed/plotting/base.py +116 -0
  17. xrheed-0.5.13/src/xrheed/plotting/overview.py +75 -0
  18. xrheed-0.5.13/src/xrheed/plotting/profiles.py +82 -0
  19. xrheed-0.5.13/src/xrheed/plugins/__init__.py +114 -0
  20. xrheed-0.5.13/src/xrheed/plugins/dsnp_arpes_bmp.py +77 -0
  21. xrheed-0.5.13/src/xrheed/plugins/dsnp_arpes_raw.py +109 -0
  22. xrheed-0.5.13/src/xrheed/preparation/__init__.py +9 -0
  23. xrheed-0.5.13/src/xrheed/preparation/alignment.py +195 -0
  24. xrheed-0.5.13/src/xrheed/preparation/filters.py +114 -0
  25. xrheed-0.5.13/src/xrheed/xarray_accessors.py +476 -0
  26. xrheed-0.5.13/src/xrheed.egg-info/PKG-INFO +135 -0
  27. xrheed-0.5.13/src/xrheed.egg-info/SOURCES.txt +33 -0
  28. xrheed-0.5.13/src/xrheed.egg-info/dependency_links.txt +1 -0
  29. xrheed-0.5.13/src/xrheed.egg-info/requires.txt +19 -0
  30. xrheed-0.5.13/src/xrheed.egg-info/top_level.txt +1 -0
  31. xrheed-0.5.13/tests/test_conversion.py +35 -0
  32. xrheed-0.5.13/tests/test_data_loading.py +96 -0
  33. xrheed-0.5.13/tests/test_ewald.py +82 -0
  34. xrheed-0.5.13/tests/test_lattice.py +127 -0
  35. xrheed-0.5.13/tests/test_preparation.py +38 -0
xrheed-0.5.13/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Marek Kopciuszynski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
xrheed-0.5.13/PKG-INFO ADDED
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: xrheed
3
+ Version: 0.5.13
4
+ Summary: An xarray-based toolkit for RHEED image analysis
5
+ Author-email: Marek Kopciuszynski <mkopciuszynski@gmail.com>
6
+ License-Expression: MIT
7
+ Keywords: RHEED,diffraction,xarray,analysis
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Scientific/Engineering
12
+ Classifier: Topic :: Scientific/Engineering :: Physics
13
+ Classifier: Intended Audience :: Science/Research
14
+ Requires-Python: >=3.12
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: xarray>=0.18.2
18
+ Requires-Dist: numpy>=1.21.0
19
+ Requires-Dist: scipy>=1.7.0
20
+ Requires-Dist: matplotlib>=3.4.2
21
+ Requires-Dist: ruptures>=1.1.7
22
+ Requires-Dist: tqdm>=4.62.0
23
+ Requires-Dist: lmfit>=1.1.0
24
+ Requires-Dist: dill>=0.3.4
25
+ Requires-Dist: Pillow>=9.0.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: ruff; extra == "dev"
28
+ Requires-Dist: pytest; extra == "dev"
29
+ Requires-Dist: sphinx; extra == "dev"
30
+ Requires-Dist: myst-parser; extra == "dev"
31
+ Requires-Dist: myst-nb; extra == "dev"
32
+ Requires-Dist: nbsphinx; extra == "dev"
33
+ Requires-Dist: sphinx-rtd-theme; extra == "dev"
34
+ Requires-Dist: build; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # xRHEED
38
+
39
+ 📡 An **xarray-based toolkit** for RHEED image analysis.
40
+
41
+ ---
42
+
43
+ [![CI](https://github.com/mkopciuszynski/xrheed/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mkopciuszynski/xrheed/actions/workflows/ci.yml)
44
+ [![Documentation Status](https://readthedocs.org/projects/xrheed/badge/?version=latest)](https://xrheed.readthedocs.io/en/latest/?badge=latest)
45
+ [![PyPI version](https://img.shields.io/pypi/v/xrheed.svg)](https://pypi.org/project/xrheed/)
46
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
47
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
48
+ [![Linter: ruff](https://img.shields.io/badge/linter-ruff-46a2f1.svg?logo=ruff)](https://github.com/astral-sh/ruff)
49
+ [![Package manager: uv](https://img.shields.io/badge/packaging-uv-blue)](https://github.com/astral-sh/uv)
50
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.xxxxx.svg)](https://doi.org/10.5281/zenodo.xxxxx)
51
+
52
+ ---
53
+
54
+ ## 🔬 What is RHEED?
55
+
56
+ **Reflection High-Energy Electron Diffraction (RHEED)** is an experimental technique used to monitor and control the quality of crystal surfaces.
57
+ A high-energy electron beam (∼20 keV) strikes the surface at a grazing angle (< 5°), making the method highly **surface-sensitive** and probing only a few atomic layers.
58
+
59
+ ---
60
+
61
+ ## 🎯 Project Goals
62
+
63
+ **xRHEED** provides a flexible and extensible **Python toolkit** for RHEED image analysis:
64
+
65
+ - 🖼️ Load and preprocess RHEED images
66
+ - 📈 Generate and analyze intensity profiles
67
+ - ✨ Overlay predicted diffraction spot positions (kinematic theory & Ewald construction)
68
+ - 🔄 Transform RHEED images into kx–ky space
69
+ - 🔍 Search for reconstruction lattice constants and rotations by calculating the matching coefficient between predicted and experimental data
70
+
71
+ 👉 **Note:** xRHEED is **not a GUI application**. It is designed as an **xarray accessory library**, intended for use in **interactive environments** such as Jupyter notebooks.
72
+
73
+ ---
74
+
75
+ ## ⚡ Installation
76
+
77
+ You can install **xRHEED** using either [`uv`](https://github.com/astral-sh/uv) or `pip`.
78
+
79
+ ### Using pip (editable install for development)
80
+
81
+ ```bash
82
+ git clone https://github.com/mkopciuszynski/xrheed
83
+ cd xrheed
84
+ pip install -e .
85
+ ```
86
+
87
+ ### Using uv (with a virtual environment)
88
+
89
+ 1. Install [`uv`](https://docs.astral.sh/uv/guides/projects/).
90
+ 2. Clone the repository:
91
+ ```bash
92
+ git clone https://github.com/mkopciuszynski/xrheed
93
+ cd xrheed
94
+ ```
95
+ 3. Create and activate a virtual environment (depending on your shell: bash, zsh, fish, PowerShell).
96
+ 4. Sync dependencies:
97
+ ```bash
98
+ uv sync
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 🚀 Quick Usage
104
+
105
+ ```python
106
+ import matplotlib.pyplot as plt
107
+ import xrheed
108
+ from xrheed.io import load_data
109
+
110
+ # Load a RHEED image
111
+ rheed_image = load_data("rheed_image.raw", plugin="dsnp_arpes_raw")
112
+
113
+ # Show image with auto-adjusted levels
114
+ rheed_image.ri.plot_image(auto_levels=2.0)
115
+ plt.show()
116
+
117
+ # Get intensity profile and plot its origin
118
+ profile = rheed_image.ri.get_profile(center=(0, -5), width=40, height=4,
119
+ plot_origin=True)
120
+ ```
121
+
122
+ ---
123
+
124
+ ## 📖 Citation
125
+
126
+ If you use **xRHEED** in your research, please consider citing this repository:
127
+
128
+ > Kopciuszynski, M. (2025). *xRHEED: An xarray-based toolkit for RHEED image analysis*.
129
+ > GitHub. https://github.com/mkopciuszynski/xrheed
130
+
131
+ 📌 A formal DOI will be provided in the future via [Zenodo](https://zenodo.org/).
132
+
133
+ ---
134
+
135
+ 📚 👉 See the [full documentation](https://xrheed.readthedocs.io/en/latest/) for tutorials and advanced examples.
@@ -0,0 +1,99 @@
1
+ # xRHEED
2
+
3
+ 📡 An **xarray-based toolkit** for RHEED image analysis.
4
+
5
+ ---
6
+
7
+ [![CI](https://github.com/mkopciuszynski/xrheed/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mkopciuszynski/xrheed/actions/workflows/ci.yml)
8
+ [![Documentation Status](https://readthedocs.org/projects/xrheed/badge/?version=latest)](https://xrheed.readthedocs.io/en/latest/?badge=latest)
9
+ [![PyPI version](https://img.shields.io/pypi/v/xrheed.svg)](https://pypi.org/project/xrheed/)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
12
+ [![Linter: ruff](https://img.shields.io/badge/linter-ruff-46a2f1.svg?logo=ruff)](https://github.com/astral-sh/ruff)
13
+ [![Package manager: uv](https://img.shields.io/badge/packaging-uv-blue)](https://github.com/astral-sh/uv)
14
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.xxxxx.svg)](https://doi.org/10.5281/zenodo.xxxxx)
15
+
16
+ ---
17
+
18
+ ## 🔬 What is RHEED?
19
+
20
+ **Reflection High-Energy Electron Diffraction (RHEED)** is an experimental technique used to monitor and control the quality of crystal surfaces.
21
+ A high-energy electron beam (∼20 keV) strikes the surface at a grazing angle (< 5°), making the method highly **surface-sensitive** and probing only a few atomic layers.
22
+
23
+ ---
24
+
25
+ ## 🎯 Project Goals
26
+
27
+ **xRHEED** provides a flexible and extensible **Python toolkit** for RHEED image analysis:
28
+
29
+ - 🖼️ Load and preprocess RHEED images
30
+ - 📈 Generate and analyze intensity profiles
31
+ - ✨ Overlay predicted diffraction spot positions (kinematic theory & Ewald construction)
32
+ - 🔄 Transform RHEED images into kx–ky space
33
+ - 🔍 Search for reconstruction lattice constants and rotations by calculating the matching coefficient between predicted and experimental data
34
+
35
+ 👉 **Note:** xRHEED is **not a GUI application**. It is designed as an **xarray accessory library**, intended for use in **interactive environments** such as Jupyter notebooks.
36
+
37
+ ---
38
+
39
+ ## ⚡ Installation
40
+
41
+ You can install **xRHEED** using either [`uv`](https://github.com/astral-sh/uv) or `pip`.
42
+
43
+ ### Using pip (editable install for development)
44
+
45
+ ```bash
46
+ git clone https://github.com/mkopciuszynski/xrheed
47
+ cd xrheed
48
+ pip install -e .
49
+ ```
50
+
51
+ ### Using uv (with a virtual environment)
52
+
53
+ 1. Install [`uv`](https://docs.astral.sh/uv/guides/projects/).
54
+ 2. Clone the repository:
55
+ ```bash
56
+ git clone https://github.com/mkopciuszynski/xrheed
57
+ cd xrheed
58
+ ```
59
+ 3. Create and activate a virtual environment (depending on your shell: bash, zsh, fish, PowerShell).
60
+ 4. Sync dependencies:
61
+ ```bash
62
+ uv sync
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 🚀 Quick Usage
68
+
69
+ ```python
70
+ import matplotlib.pyplot as plt
71
+ import xrheed
72
+ from xrheed.io import load_data
73
+
74
+ # Load a RHEED image
75
+ rheed_image = load_data("rheed_image.raw", plugin="dsnp_arpes_raw")
76
+
77
+ # Show image with auto-adjusted levels
78
+ rheed_image.ri.plot_image(auto_levels=2.0)
79
+ plt.show()
80
+
81
+ # Get intensity profile and plot its origin
82
+ profile = rheed_image.ri.get_profile(center=(0, -5), width=40, height=4,
83
+ plot_origin=True)
84
+ ```
85
+
86
+ ---
87
+
88
+ ## 📖 Citation
89
+
90
+ If you use **xRHEED** in your research, please consider citing this repository:
91
+
92
+ > Kopciuszynski, M. (2025). *xRHEED: An xarray-based toolkit for RHEED image analysis*.
93
+ > GitHub. https://github.com/mkopciuszynski/xrheed
94
+
95
+ 📌 A formal DOI will be provided in the future via [Zenodo](https://zenodo.org/).
96
+
97
+ ---
98
+
99
+ 📚 👉 See the [full documentation](https://xrheed.readthedocs.io/en/latest/) for tutorials and advanced examples.
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "xrheed"
3
+ version = "0.5.13"
4
+ authors = [
5
+ {name = "Marek Kopciuszynski", email = "mkopciuszynski@gmail.com"},
6
+ ]
7
+ description = "An xarray-based toolkit for RHEED image analysis"
8
+ readme = "README.md"
9
+ requires-python = ">=3.12"
10
+ keywords = ["RHEED", "diffraction", "xarray", "analysis"]
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "Operating System :: OS Independent",
17
+ "Topic :: Scientific/Engineering",
18
+ "Topic :: Scientific/Engineering :: Physics",
19
+ "Intended Audience :: Science/Research",
20
+ ]
21
+ dependencies = [
22
+ "xarray>=0.18.2",
23
+ "numpy>=1.21.0",
24
+ "scipy>=1.7.0",
25
+ "matplotlib>=3.4.2",
26
+ "ruptures>=1.1.7",
27
+ "tqdm>=4.62.0",
28
+ "lmfit>=1.1.0",
29
+ "dill>=0.3.4",
30
+ "Pillow>=9.0.0",
31
+ ]
32
+
33
+ [build-system]
34
+ requires = ["setuptools>=61", "wheel", "build"]
35
+ build-backend = "setuptools.build_meta"
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "ruff",
40
+ "pytest",
41
+ "sphinx",
42
+ "myst-parser",
43
+ "myst-nb",
44
+ "nbsphinx",
45
+ "sphinx-rtd-theme",
46
+ "build",
47
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,61 @@
1
+ """
2
+ xRHEED: An xarray-based toolkit for RHEED image analysis.
3
+
4
+ This package provides tools to:
5
+ - Load and preprocess RHEED images
6
+ - Extract and analyze intensity profiles
7
+ - Transform images to kx-ky space
8
+ - Predict and visualize diffraction spot positions using kinematic theory and Ewald construction
9
+ xRHEED is designed as an **xarray accessory library** for interactive analysis
10
+ in environments such as Jupyter notebooks. It is **not a GUI application**.
11
+ """
12
+
13
+ import importlib
14
+ import logging
15
+ import pkgutil
16
+ from importlib.metadata import PackageNotFoundError, version
17
+
18
+ # Import xarray accessors
19
+ from . import xarray_accessors as xarray_accessors
20
+
21
+ # Package version
22
+ try:
23
+ __version__ = version("xrheed")
24
+ except PackageNotFoundError:
25
+ __version__ = "0.0.0"
26
+
27
+ # Configure logging
28
+ logger = logging.getLogger(__name__)
29
+ logger.info(f"xrheed {__version__} initialized successfully. Accessors registered.")
30
+
31
+
32
+ # Check if running inside a Jupyter notebook
33
+ def _in_jupyter():
34
+ try:
35
+ from IPython import get_ipython
36
+
37
+ shell = get_ipython()
38
+ return shell is not None and shell.__class__.__name__ == "ZMQInteractiveShell"
39
+ except Exception:
40
+ return False
41
+
42
+
43
+ # Show a welcome message in Jupyter
44
+ if _in_jupyter():
45
+ print(f"\n🎉 xrheed v{__version__} loaded!")
46
+
47
+
48
+ # Plugin discovery
49
+ def discover_plugins():
50
+ try:
51
+ import xrheed.plugins
52
+
53
+ for _, module_name, is_pkg in pkgutil.iter_modules(xrheed.plugins.__path__):
54
+ if not is_pkg:
55
+ importlib.import_module(f"xrheed.plugins.{module_name}")
56
+ except Exception as e:
57
+ logger.warning(f"Plugin discovery failed: {e}")
58
+
59
+
60
+ # Run plugin discovery after all imports
61
+ discover_plugins()
@@ -0,0 +1,9 @@
1
+ """
2
+ Submodule `conversion` handles coordinate and unit conversions for RHEED images,
3
+ e.g., transforming between pixel space and kx-ky space.
4
+ """
5
+
6
+ from .base import convert_gx_gy_to_sx_sy, convert_sx_to_ky
7
+ from .image import transform_image_to_kxky
8
+
9
+ __all__ = ["convert_gx_gy_to_sx_sy", "convert_sx_to_ky", "transform_image_to_kxky"]
@@ -0,0 +1,120 @@
1
+ from typing import Optional, Tuple
2
+
3
+ import numpy as np
4
+ from numpy.typing import NDArray
5
+
6
+
7
+ def convert_sx_to_ky(
8
+ x_coords_mm: NDArray,
9
+ ewald_sphere_radius: float,
10
+ screen_sample_distance_mm: float,
11
+ ) -> NDArray:
12
+ """Convert sx coordinates from mm to ky [1/Å] using the Ewald sphere radius and screen-sample distance.
13
+ Parameters
14
+ ----------
15
+ x_coords_mm : NDArray
16
+ Array of x coordinates in millimeters (mm).
17
+ ewald_sphere_radius : float
18
+ Radius of the Ewald sphere in reciprocal space (1/Å).
19
+ screen_sample_distance_mm : float
20
+ Distance from the sample to the screen in millimeters (mm).
21
+
22
+ Returns
23
+ -------
24
+ NDArray
25
+ Converted x coordinates in ky [1/Å].
26
+ """
27
+
28
+ kx: NDArray = (x_coords_mm / screen_sample_distance_mm) * ewald_sphere_radius
29
+
30
+ return kx
31
+
32
+
33
+ def convert_gx_gy_to_sx_sy(
34
+ gx: NDArray[np.float32],
35
+ gy: NDArray[np.float32],
36
+ ewald_radius: float,
37
+ beta: float,
38
+ screen_sample_distance: float,
39
+ remove_outside: Optional[bool] = True,
40
+ **kwargs,
41
+ ) -> Tuple[NDArray[np.float32], NDArray[np.float32]]:
42
+ """
43
+ Convert reciprocal lattice coordinates (gx, gy) to RHEED screen coordinates (sx, sy)
44
+ using the Ewald sphere construction.
45
+
46
+ Parameters
47
+ ----------
48
+ gx : NDArray
49
+ Array of reciprocal lattice x-coordinates.
50
+ gy : NDArray
51
+ Array of reciprocal lattice y-coordinates.
52
+ ewald_radius : float
53
+ Radius of the Ewald sphere in reciprocal space (1/Å or same units as gx, gy).
54
+ beta : float
55
+ Incident beam angle in degrees relative to the surface normal.
56
+ screen_sample_distance : float
57
+ Distance from the sample to the detector/screen.
58
+ remove_outside : Optional[bool], default=True
59
+ If True, points outside the Ewald sphere are removed.
60
+ If False, points outside are set to NaN.
61
+ **kwargs
62
+ Additional keyword arguments (currently unused).
63
+
64
+ Returns
65
+ -------
66
+ sx : NDArray
67
+ Array of x-coordinates on the RHEED screen corresponding to input gx, gy.
68
+ sy : NDArray
69
+ Array of y-coordinates on the RHEED screen corresponding to input gx, gy.
70
+
71
+ Notes
72
+ -----
73
+ - The function assumes a simple planar screen perpendicular to the z-axis.
74
+ - The coordinate transformation accounts for the Ewald sphere geometry
75
+ and the projection of diffraction spots onto the screen.
76
+ - `beta` is the incident angle of the electron beam relative to the sample surface.
77
+ - Points outside the Ewald sphere can be optionally removed or set as NaN
78
+ using the `remove_outside` flag.
79
+ """
80
+
81
+ # Ewald sphere radius
82
+ k0: np.float32 = np.float32(ewald_radius)
83
+ # Ewald sphere radius square
84
+ kk: np.float32 = np.float32(k0**2)
85
+
86
+ # calculate the shift between the center of Ewald sphere and the center of reciprocal lattice
87
+ delta_x: np.float32 = np.float32(k0 * np.cos(np.deg2rad(beta)))
88
+
89
+ # shift the center of reciprocal lattice
90
+ kx: NDArray[np.float32] = gx + delta_x
91
+ ky: NDArray[np.float32] = gy
92
+
93
+ # Check if the kx, ky points are inside Ewald sphere
94
+ kxy2: NDArray[np.float32] = kx**2 + ky**2
95
+
96
+ ind: NDArray[np.bool_] = kxy2 < kk
97
+
98
+ # remove those outside or mark as nans
99
+ if remove_outside:
100
+ kx = kx[ind]
101
+ ky = ky[ind]
102
+ else:
103
+ kx[~ind] = np.nan
104
+ ky[~ind] = np.nan
105
+
106
+ # calculate the radius r_k
107
+ rk: NDArray[np.float32] = np.sqrt(k0**2 - kx**2)
108
+
109
+ # calculate theta and phi (cos) values
110
+ phi: NDArray[np.float32] = np.arccos(ky / rk)
111
+ theta: NDArray[np.float32] = np.arcsin(rk / k0)
112
+
113
+ # calculate the radius on the RHEED screen
114
+ rho: NDArray[np.float32] = screen_sample_distance * np.tan(theta)
115
+
116
+ # calculate the spot positions
117
+ sx: NDArray[np.float32] = rho * np.cos(phi)
118
+ sy: NDArray[np.float32] = -rho * np.sin(phi)
119
+
120
+ return sx, sy
@@ -0,0 +1,138 @@
1
+ import numpy as np
2
+ import xarray as xr
3
+ from numpy.typing import NDArray
4
+ from scipy import ndimage # type: ignore
5
+
6
+ from .base import convert_gx_gy_to_sx_sy
7
+
8
+
9
+ def transform_image_to_kxky(
10
+ rheed_image: xr.DataArray,
11
+ rotate: bool = False,
12
+ point_symmetry: bool = False,
13
+ ) -> xr.DataArray:
14
+ """
15
+ Transform the RHEED image to kx-ky coordinates.
16
+
17
+ Parameters
18
+ ----------
19
+ rotate : bool, optional
20
+ If True, rotate the transformed image (default: True).
21
+ mirror : bool, optional
22
+ If True, add mirrored image (default: False).
23
+
24
+ Returns
25
+ -------
26
+ xr.DataArray
27
+ Transformed image in kx-ky coordinates.
28
+ """
29
+
30
+ # prepare the data for calculations
31
+ screen_sample_distance: float = rheed_image.ri.screen_sample_distance
32
+ beta: float = rheed_image.ri.beta
33
+ alpha: float = rheed_image.ri.alpha
34
+
35
+ ewald_radius: float = np.sqrt(rheed_image.ri.beam_energy) * 0.5123
36
+
37
+ # new coordinates for transformation
38
+ # TODO add the parameter that allows to set kx, ky
39
+ kx: NDArray[np.float32] = np.arange(-10, 10, 0.01, dtype=np.float32)
40
+ ky: NDArray[np.float32] = np.arange(-10, 10, 0.01, dtype=np.float32)
41
+
42
+ gx: NDArray[np.float32]
43
+ gy: NDArray[np.float32]
44
+
45
+ gx, gy = np.meshgrid(kx, ky, indexing="ij")
46
+
47
+ sx_to_kx: NDArray[np.float32]
48
+ sy_to_ky: NDArray[np.float32]
49
+
50
+ sx_to_kx, sy_to_ky = convert_gx_gy_to_sx_sy(
51
+ gx,
52
+ gy,
53
+ ewald_radius=ewald_radius,
54
+ beta=beta,
55
+ screen_sample_distance=screen_sample_distance,
56
+ remove_outside=False,
57
+ )
58
+
59
+ # relation between old and new
60
+ sx: xr.DataArray = xr.DataArray(
61
+ sx_to_kx, dims=["kx", "ky"], coords={"kx": kx, "ky": ky}
62
+ )
63
+ sy: xr.DataArray = xr.DataArray(
64
+ sy_to_ky, dims=["kx", "ky"], coords={"kx": kx, "ky": ky}
65
+ )
66
+
67
+ trans_image: xr.DataArray = rheed_image.interp(sx=sx, sy=sy, method="linear")
68
+
69
+ if rotate:
70
+ trans_image_rotated = _rotate_trans_image(trans_image, alpha)
71
+ trans_image = trans_image_rotated
72
+
73
+ if point_symmetry:
74
+ trans_image_rotated = _rotate_trans_image(trans_image, 180)
75
+ trans_image = xr.where(np.isnan(trans_image), trans_image_rotated, trans_image)
76
+
77
+ trans_image.attrs = rheed_image.attrs
78
+
79
+ return trans_image
80
+
81
+
82
+ def _rotate_trans_image(
83
+ trans_image: xr.DataArray, angle: float, mode: str = "nearest"
84
+ ) -> xr.DataArray:
85
+ """
86
+ Rotate a 2D xarray.DataArray around its center by a given angle.
87
+
88
+ Parameters
89
+ ----------
90
+ rheed_image : xr.DataArray
91
+ 2D image-like DataArray to rotate.
92
+ angle : float
93
+ Rotation angle in degrees (counter-clockwise).
94
+ mode : str
95
+ How to handle values outside boundaries ('constant', 'nearest', 'reflect', ...).
96
+
97
+ Returns
98
+ -------
99
+ rotated : xr.DataArray
100
+ Rotated DataArray with NaNs preserved.
101
+ """
102
+ if trans_image.ndim != 2:
103
+ raise ValueError("rotate_xarray expects a 2D DataArray")
104
+
105
+ # Assert that coordinates exist
106
+ if "kx" not in trans_image.coords or "ky" not in trans_image.coords:
107
+ raise ValueError("rotate_xarray requires coordinates 'kx' and 'ky'")
108
+
109
+ # Assert that kx and ky are identical
110
+ if not np.allclose(trans_image["kx"].values, trans_image["ky"].values):
111
+ raise ValueError("rotate_xarray requires kx and ky coordinates to be identical")
112
+
113
+ # Build mask for NaNs
114
+ nan_mask: NDArray[np.bool_] = ~np.isnan(trans_image.values)
115
+ filled: xr.DataArray = trans_image.fillna(0)
116
+
117
+ # Rotate data and mask
118
+ rotated_data: NDArray[np.uint8] = ndimage.rotate(
119
+ filled.values, angle, reshape=False, mode=mode, order=1
120
+ ).astype(np.uint8)
121
+
122
+ rotated_mask: NDArray[np.bool_] = (
123
+ ndimage.rotate(
124
+ nan_mask.astype(np.uint8), angle, reshape=False, mode=mode, order=0
125
+ )
126
+ > 0
127
+ ).astype(np.bool)
128
+
129
+ # Wrap back into DataArray, reusing same coords/dims
130
+ rotated = xr.DataArray(
131
+ rotated_data,
132
+ coords=trans_image.coords,
133
+ dims=trans_image.dims,
134
+ attrs=trans_image.attrs,
135
+ name=trans_image.name,
136
+ )
137
+
138
+ return rotated.where(rotated_mask)