Skip to content

Commit

Permalink
Preparing for new section by moving examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
TomaSusi committed Sep 3, 2024
1 parent b70f104 commit 75af0c9
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 15 deletions.
2 changes: 1 addition & 1 deletion 01_intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ The text can be broken into three sections:
We finish by offer our perspective on the outlook for such simulations.
The first section consists of a brief overview to the [Python programming language](./02_code.md), and instructions on how to run the interactive figures.
This is followed by a primer on the [mathematical concepts](./03_math.md) that underpin image simulations.
The second section addresses the theory of S/TEM image simulation, beginning with a discussion on the [underlying physics](./04_physics.md) of electron-atom interactions, after which the [algorithms](./05_algorithms.ms) used to simulate images are detailed.
The second section addresses the theory of S/TEM image simulation, beginning with a discussion on the [underlying physics](./04_physics.md) of electron-atom interactions, after which the [algorithms](./05_algorithms.md) used to simulate images are detailed.
In the final section the practicalities of image simulation are discussed, covering [creating simulation inputs](./06_sim_inputs.md), [TEM simulations](./07_TEM.md), [STEM simulations](./08_STEM.md), post-processing simulated images to create more experimentally realistic images, common errors and helpful tips.
Finally we conclude with an outlook for image simulations.
3 changes: 3 additions & 0 deletions 06_sim_inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ label : sim_inputs_page
---

text

(atomic-models)=
### Building atomic models
18 changes: 18 additions & 0 deletions 09_STEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ It is important to remember the difference between the wavefunction sampling and
Aluminum, iron and gold nanoparticles on a carbon film: **Left** image from a circular detector. **Middle** image from an annular detector **Right** differential phase contrast reconstruction. Notice how changing the collection angles impacts the contrast and signal to noise.
```

#### Image simulation: STO/LTO

Scanning imaging modes such as STEM works by rastering an electron probe across a sample pixel by pixel and recording the scattering signal. The computational cost of the simulation is directly proportional to the number of scan pixels, each requiring a separate multislice simulation. For periodic speciments, even though the potential needs to be large enough to fit the probe, there is no need to scan over repated unit cells as tiling afterwards can yield the same result.

As an example, we simulate the BF (0 to 20 mrad), MAADF (40 to 100 mrad) and HAADF (100 to 180 mrad) images of a STO/LTO interface that we built in the [simulation inputs](./06_sim_inputs.md) chapter. Note that since the structure repeats in the $x$-direction, we only scan over the unit cell, as shown in [](#fig_stem_specimen) below. The images simulated with a primary beam energy of 150 keV, a defocus of 50 Å, and a probe convergence-semiangle of 20 mrad are shown in [](#fig_stem_sto-lto_image) below. Note that these are quite pixelated since we simulated at Nyqvist sampling to save computational effort; see [post-processing](./10_post.md) for how these are interpolated to a higher resolution.

```{figure} #app:stem_sto-lto_scan
:name: fig_stem_specimen
:placeholder: ./static/stem_specimen.png
A SrTiO<sub>3</sub>/LaTiO<sub>3</sub> (STO/LTO) interface model. The red overlaid rectangle indicates the area of the scan.
```

```{figure} #app:stem_sto-lto_image
:name: fig_stem_image
:placeholder: ./static/stem_image.png
Bright-field (BF), medium-angle annular dark-field (MAADF), and high-angle annular dark-field (HAADF) imges of the SrTiO<sub>3</sub>/LaTiO<sub>3</sub> (STO/LTO) interface.
```

(differential-phase-contrast)=
### Differential Phase Contrast
The phase problem, namely the loss of phase information when taking a measurement, is well known in many fields including electron microscopy. Because detectors collect the square modulus of the exit wave ({math}`|\Psi_t(\bm{k}, \bm{r}_p)|^2`), much of the phase information is lost. Methods that can reconstruct the phase of the sample provide dose-efficient imaging of materials and the ability to simultaneously characterize heavy and light elements. There are a number of approaches to recovering the phase of the sample, some of which will be discussed in the [4D-STEM](#id-4d-stem) section.
Expand Down
16 changes: 4 additions & 12 deletions 10_post.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,15 @@ numbering:
## STEM Post-Processing
STEM simulations usually requires some post-processing, we apply some of the most common steps post-processing step in this tutorial.

Scanning imaging modes such as STEM works by rastering an el„ectron probe across a sample pixel by pixel and recording the scattering signal. The computational cost of the simulation is directly proportional to the number of scan pixels, each requiring a separate multislice simulation.
For these examples, we use an STO/LTO heterointerface as a specimen. The structure was built earlier in the [simulation inputs](./06_sim_inputs.md) chapter, and simple BF/ADF images simulated in the chapter on [STEM](./09_STEM.md).

For periodic speciments, even though the potential needs to be large enough to fit the probe, there is no need to scan over repated unit cells as tiling afterwards can yield the same result. For the post-processing examples below, we use an STO-LTO heterointerface as a specimen, as shown below in [](#fig_stem_specimen).

```{figure} #app:stem_specimen
:name: fig_stem_specimen
:placeholder: ./static/stem_specimen.png
A SrTiO<sub>3</sub>/LaTiO<sub>3</sub> (STO/LTO) interface model. The red overlaid rectangle indicates the area of the scan.
```

### Interpolation
#### Interpolation
We can save a great deal of computational effort by scanning at the Nyquist frequency [https://en.wikipedia.org/wiki/Nyquist_frequency], which is information-theoretically guaranteed to be sufficient -- but the result is visually quite pixelated. To address this, we can interpolate the images to a sampling of 0.05 Å. *ab*TEM’s default interpolation algorithm is Fourier-space padding, but spline interpolation is also available, which is more appropriate if the image in non-periodic.

### Blurring
#### Blurring
Standard multislice simulations are too idealized to describe a realistic experimental image. For example, a finite Gaussian-shaped source will result in a blurring of the image, and vibrations and other instabilities may further contribute to the blur. It is typical and convenient to approximate these by applying a Gaussian blur with a standard deviation of $0.35 \ \mathrm{Å}$ (corresponding to a source of approximately that size). However, note that correctly including spatial and temporal incoherence is a bit more complicated and may be necessary for quantitative comparisons with experiment.

### Noise
#### Noise
Simulations correspond to the limit of infinite electron dose, which again is not realistic for an experimental image. Leaving aside other factors, the main source of noise in STEM is so-called shot noise arising from the discrete nature of electrons. We can effectively emulate finite dose by drawing random numbers from a Poisson distribution for every pixel. We apply this so-called Poisson noise corresponding a dose per area of $10^5 \ \mathrm{e}^- / \mathrm{Å}^2$ to form a more realistic image.

The different STEM post-processing steps can be explored in [](#fig_stem_processing).
Expand Down
85 changes: 85 additions & 0 deletions notebooks/06.1_Atoms_STO-LTO.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "7a3a4bfa-cc68-4624-9965-0e2dbb65061d",
"metadata": {},
"source": [
"# STO-LTO model creation\n",
"\n",
"authors: [Toma Susi]\n",
"date: 2024/09/02"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "95c10e75-d7d3-40fa-a127-142d5f84438d",
"metadata": {},
"outputs": [],
"source": [
"import abtem\n",
"import ase\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"from ase.build import surface\n",
"\n",
"srtio3 = ase.io.read(\"data/SrTiO3.cif\")\n",
"\n",
"srtio3_110 = surface(srtio3, indices=(1, 1, 0), layers=2, periodic=True)\n",
"srtio3_110.wrap()\n",
"\n",
"repeated_srtio3 = srtio3_110.copy()\n",
"repeated_srtio3 *= (3, 4, 10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ceddcd58-e901-4ad8-b599-2a616854d072",
"metadata": {},
"outputs": [],
"source": [
"sto_lto = repeated_srtio3.copy()\n",
"\n",
"mask = sto_lto.symbols == \"Sr\"\n",
"\n",
"mask = mask * (sto_lto.positions[:, 1] < 7.5)\n",
"\n",
"sto_lto.numbers[mask] = 57\n",
"\n",
"ase.io.write(\"data/sto_lto.cif\", sto_lto)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23163094-afba-4bb7-8de8-1e8c3f92f92a",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "guide-tem-simulation",
"language": "python",
"name": "guide-tem-simulation"
},
"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.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
173 changes: 173 additions & 0 deletions notebooks/09.x_STEM_STO-LTO.ipynb

Large diffs are not rendered by default.

106 changes: 104 additions & 2 deletions notebooks/10_STEM_post_processing.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,110 @@
"---"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2ffd8bad-37bd-4c78-88a2-0732409ce31a",
"metadata": {},
"outputs": [],
"source": [
"import abtem\n",
"stacked_measurements = abtem.from_zarr(\"data/STO_LTO_STEM.zarr\").compute()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9c47f158-5b5b-468b-b7c0-cb7ab8598ad6",
"metadata": {},
"outputs": [],
"source": [
"interpolated_measurements = stacked_measurements.interpolate(0.05)\n",
"\n",
"interpolated_measurements.show(explode=True);"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41f18f3c-fe90-431d-b100-4423b16a4b66",
"metadata": {},
"outputs": [],
"source": [
"blurred_measurements = interpolated_measurements.gaussian_filter(0.35)\n",
"\n",
"blurred_measurements.show(explode=True);"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9448b6ea-f247-4c09-8171-c69f4e68f451",
"metadata": {},
"outputs": [],
"source": [
"noisy_measurements = blurred_measurements.poisson_noise(dose_per_area=1e5, seed=100)\n",
"\n",
"noisy_measurements.show(explode=True, figsize=(12, 4));"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cb4251ff-cf1e-4ebe-ba67-244a0b145308",
"metadata": {},
"outputs": [],
"source": [
"processed_measurements = abtem.stack([interpolated_measurements, blurred_measurements, noisy_measurements],\n",
" (\"Interpolated\", \"Blurred\", \"Noised\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6e967555-f69b-4721-82dd-92c61ffe9769",
"metadata": {},
"outputs": [],
"source": [
"from scipy.ndimage import zoom\n",
"\n",
"scalex = interpolated_measurements[0].shape[0]/stacked_measurements[0].array.shape[0]\n",
"scaley = interpolated_measurements[1].shape[1]/stacked_measurements[0].array.shape[1]\n",
"\n",
"zoomed0 = zoom(stacked_measurements[0].array, (scalex, scaley), order=0)\n",
"zoomed1 = zoom(stacked_measurements[1].array, (scalex, scaley), order=0)\n",
"zoomed2 = zoom(stacked_measurements[2].array, (scalex, scaley), order=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "015cb6d8-b082-413f-81b7-8fd1c8d18616",
"metadata": {},
"outputs": [],
"source": [
"from abtem import Images\n",
"\n",
"image0 = Images(zoomed0, sampling = interpolated_measurements[0].sampling)\n",
"image1 = Images(zoomed1, sampling = interpolated_measurements[1].sampling)\n",
"image2 = Images(zoomed2, sampling = interpolated_measurements[2].sampling)\n",
"\n",
"zoomed_measurements = abtem.stack([image0, image1, image2], (\"BF\", \"MAADF\", \"HAADF\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18b32105-3adc-4fbb-b956-58c5f3995c3b",
"metadata": {},
"outputs": [],
"source": [
"all_measurements = abtem.stack([zoomed_measurements, interpolated_measurements, blurred_measurements, noisy_measurements],\n",
" (\"Nyquist-sampled\", \"Interpolated\", \"Blurred\", \"Noised\"))\n",
"\n",
"all_measurements.to_zarr(\"data/processed_STEM.zarr\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
Expand All @@ -20,8 +124,6 @@
"outputs": [],
"source": [
"%matplotlib ipympl\n",
"import abtem\n",
"\n",
"\n",
"abtem.config.set({\"visualize.cmap\": \"viridis\"})\n",
"abtem.config.set({\"visualize.continuous_update\": True})\n",
Expand Down
Binary file modified notebooks/data/STO_LTO_STEM.zarr/array0/0.0.0
Binary file not shown.
Binary file added static/stem_images.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

1 comment on commit 75af0c9

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curvenote Preview

📭 No submissions available to inspect.

Please sign in to comment.