{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Spot Calculation Using Ewald Construction\n", "\n", "This notebook demonstrates how to use the `xrheed.kinematics` module to superimpose calculated diffraction spot positions onto a RHEED image.\n", "\n", "Before proceeding, it is recommended to review the **Geometry** and **Kinematic Diffraction Model** sections of the documentation for a foundational understanding of the underlying principles.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from pathlib import Path\n", "\n", "import xrheed" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "## Preparation of RHEED Image Data\n", "\n", "As a representative example, we utilize a reflection high-energy electron diffraction (RHEED) image acquired from a clean Si(111) surface exhibiting the characteristic (7×7) surface reconstruction.\n", "\n", "The incident electron beam was aligned along the crystallographic direction $[11\\bar{2}]$. Consequently, the horizontal axis of the RHEED image corresponds to the $[1\\bar{1}0]$ direction.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": {}, "outputs": [], "source": [ "image_dir = Path(\"example_data\")\n", "image_path = image_dir / \"Si_111_7x7_112_phi_00.raw\"\n", "\n", "rheed_image = xrheed.load_data(image_path, plugin=\"dsnp_arpes_raw\")\n", "\n", "# Align the image rotation\n", "rheed_image.ri.rotate(-0.4)\n", "\n", "# Set the screen ROI\n", "rheed_image.ri.screen_roi_width = 60\n", "rheed_image.ri.screen_roi_height = 80\n", "\n", "# Apply automatic center search and calculate the incident angle\n", "rheed_image.ri.set_center_auto(update_incident_angle=True)\n", "\n", "# Use automatic levels adjustment\n", "rheed_image.ri.plot_image(\n", " auto_levels=0.5, show_center_lines=True, show_specular_spot=True\n", ")\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "## Construction of the 2D Lattice Object\n", "\n", "To begin, we calculate the positions of the (1×1) diffraction spots using a hexagonal two-dimensional lattice with a lattice constant of 3.84 Å.\n", "\n", "The lattice can be instantiated using the `Lattice` class, which accepts real-space basis vectors.\n", "\n", "Additional methods available for lattice generation include:\n", "\n", "- `from_bulk_cubic`: Constructs the lattice from a bulk cubic crystal by specifying the lattice constant `a`, the `cubic_type`, and the crystallographic `plane` (currently limited to low-index planes).\n", "- `from_surface_hex`: Generates a two-dimensional hexagonal lattice by specifying only the surface lattice constant.\n", "\n", "All available options are demonstrated below to generate the same lattice.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "from xrheed.kinematics import Lattice\n", "\n", "# Manually define a 2D lattice using real-space basis vectors.\n", "# This example uses a hexagonal configuration with a lattice constant of 3.84 Å.\n", "lattice = Lattice([0.0, 3.84], [3.325, 3.84 * 0.5], label=\"manual generation\")\n", "print(lattice)\n", "\n", "# Generate a surface lattice derived from a bulk cubic crystal.\n", "# Specify the lattice constant, crystal type (FCC), and Miller plane (111).\n", "lattice = Lattice.from_bulk_cubic(\n", " a=5.43, cubic_type=\"FCC\", plane=\"111\", label=\"from bulk\"\n", ")\n", "print(lattice)\n", "\n", "# Create a 2D hexagonal lattice using a simplified method.\n", "# Only the surface lattice constant is required.\n", "lattice = Lattice.from_surface_hex(a=3.84, label=\"as hex lattice\")\n", "print(lattice)" ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "### Generation and Visualization of the (1×1) Surface Lattice\n", "\n", "Finally, we generate a (1×1) surface lattice using a lattice constant of 3.84 Å, and visualize it using the `plot_real` method.\n", "\n", "The `space_size` parameter defines the plotting boundaries in the x and y directions, which correspond to the in-plane coordinates of the sample surface.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "si_111_1x1 = Lattice.from_surface_hex(a=3.84, label=\"Si(111)-(1x1)\")\n", "\n", "si_111_1x1.plot_real(space_size=7.0, show_vectors=True)\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "### Reciprocal Lattice Visualization\n", "\n", "The reciprocal lattice is generated automatically and can be visualized using the appropriate plotting method.\n", "\n", "> **Note:** In the reciprocal space plot, the vertical (y) axis represents the $k_x$ component, which corresponds to the direction of the incident electron beam.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "si_111_1x1.plot_reciprocal(space_size=2.5)\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "### Lattice azimuthal orientation\n", "\n", "By default, the hexagonal lattice is constructed such that the `x` axis - approximately aligned with the electron beam direction-corresponds to the crystallographic $[11\\bar{2}]$ direction.\n", "\n", "If the sample orientation differs, the lattice can be rotated accordingly. This can be achieved either manually or by specifying the `alpha` angle extracted from the RHEED image. In the latter case, the rotation is applied within the `Ewald` class object.\n", "\n", "Upon rotation, both the real-space and reciprocal-space representations are updated automatically to reflect the new orientation." ] }, { "cell_type": "markdown", "id": "11", "metadata": {}, "source": [ "## The `Ewald` Class\n", "\n", "With the two essential components prepared:\n", "- `rheed_image`: a loaded and properly aligned RHEED image,\n", "- `si_111_1x1`: a defined surface lattice object,\n", "\n", "the diffraction spot positions can be computed using kinematic theory based on the Ewald construction. The `Ewald` object is initialized using these two inputs.\n", "\n", "Although the RHEED image is technically optional, it is strongly recommended for realistic simulations. It provides key experimental parameters such as:\n", "- the sample-to-screen distance,\n", "- screen scaling factors,\n", "- and the incident angle $\\beta$ of the electron beam.\n", "\n", "> **Note:** The `Ewald` object internally generates its own lattice instance, which can be independently scaled or rotated to achieve precise alignment with experimental data.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "12", "metadata": {}, "outputs": [], "source": [ "from xrheed.kinematics import Ewald\n", "\n", "ew_si_111 = Ewald(lattice=si_111_1x1, image=rheed_image)\n", "\n", "print(ew_si_111)" ] }, { "cell_type": "markdown", "id": "13", "metadata": {}, "source": [ "Once the `Ewald` object is initialized, diffraction spot positions are automatically calculated.\n", "\n", "The `plot` method displays the computed spots, optionally superimposed on the RHEED image - if available and if the `show_image` argument is set to `True`.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "14", "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 4))\n", "\n", "ew_si_111.plot(ax=ax, show_image=True, show_center_lines=True, auto_levels=1.0)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "15", "metadata": {}, "source": [ "## Fine Adjustment\n", "\n", "Typically, the incident angle may not be perfectly set, and the image scaling may also require refinement. Two methods are available for adjusting the calculated spot positions:\n", "\n", "### Adjusting the `Ewald` Object\n", "\n", "For temporary corrections or simpler analyses, it is recommended to directly modify the following attributes of the `Ewald` object:\n", "- `incident_angle`\n", "- `shift_x`\n", "- `shift_y`\n", "- `fine_scaling`\n", "\n", "These adjustments are stored independently of the original `RHEEDImage` object.\n", "\n", "### Adjusting the `RHEEDImage` Object\n", "\n", "If more fundamental parameters-such as `screen_scale`-need to be corrected, these changes should be applied directly to the `RHEEDImage` object. In such cases, the `Ewald` object must be re-created to reflect the updated image parameters.\n", "\n", "The same applies to x/y shifts of the RHEED image, as described in the **Getting Started** notebook.\n" ] }, { "cell_type": "markdown", "id": "16", "metadata": {}, "source": [ "## Fine Adjustment Example\n", "\n", "Below, we apply corrections directly to the `Ewald` object and visualize the results using the `plot` method.\n", "\n", "This approach allows for quick tuning of parameters such as the incident angle and screen alignment, without modifying the original `RHEEDImage` object.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "17", "metadata": {}, "outputs": [], "source": [ "shift_y = -0.1\n", "fine_scaling = 1.0\n", "\n", "ew_si_111.shift_y = shift_y\n", "ew_si_111.fine_scaling = fine_scaling\n", "\n", "ew_si_111.plot(auto_levels=1.0, marker=\"d\", s=30, alpha=0.3, color=\"c\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "18", "metadata": {}, "source": [ "### Adding the reconstruction\n", "Having the (1x1) structure well adjusted we can add the (7x7) reconstruction." ] }, { "cell_type": "code", "execution_count": null, "id": "19", "metadata": {}, "outputs": [], "source": [ "si_111_7x7 = Lattice.from_surface_hex(a=3.84 * 7, label=\"Si(111)-(7x7)\")\n", "si_111_7x7" ] }, { "cell_type": "markdown", "id": "20", "metadata": {}, "source": [ "Create Ewald object for new lattice, and optionally copy already adjusted attributes." ] }, { "cell_type": "code", "execution_count": null, "id": "21", "metadata": {}, "outputs": [], "source": [ "ew_si_111_7x7 = Ewald(si_111_7x7, rheed_image)\n", "\n", "ew_si_111_7x7.shift_y = shift_y\n", "\n", "ew_si_111_7x7.plot(auto_levels=1.0)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "22", "metadata": {}, "source": [ "## Final Image\n", "\n", "Finally, a plot is prepared and saved, showcasing both reconstructions.\n", "\n", "For improved clarity, a high-pass filtered image is used in this visualization.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "23", "metadata": {}, "outputs": [], "source": [ "from xrheed.preparation.filters import high_pass_filter\n", "\n", "sigma = 5.0 # in mm\n", "sigma_px = sigma * rheed_image.ri.screen_scale\n", "threshold = 0.8\n", "\n", "hp_rheed_image = high_pass_filter(rheed_image, sigma=sigma, threshold=threshold)" ] }, { "cell_type": "code", "execution_count": null, "id": "24", "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 4), constrained_layout=True)\n", "\n", "hp_rheed_image.ri.plot_image(ax=ax, vmin=7, vmax=30)\n", "\n", "ew_si_111_7x7.plot(\n", " ax=ax, show_image=False, marker=\".\", s=5, alpha=0.5, color=\"y\"\n", ")\n", "\n", "ew_si_111.plot(ax=ax, show_image=False, marker=\"d\", s=40, alpha=0.5, color=\"c\")\n", "\n", "ax.set_xlabel(\" \")\n", "ax.set_ylabel(\" \")\n", "ax.set_xticks([])\n", "ax.set_yticks([])\n", "ax.set_ylim(-80, 5)\n", "fig.set_dpi(100)\n", "plt.show()\n", "# fig.savefig()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.10" } }, "nbformat": 4, "nbformat_minor": 5 }