import numpy as np
import matplotlib.pyplot as plt
from ase.io import read
from abtem import *

Detectors and 4D-STEM

It is particularly easy to describe modern segmented and pixelated detectors used for 4D-STEM in abTEM. Let’s start by defining a probe and a scan over a graphene model.

atoms = read('data/orthogonal_graphene.cif')

probe = Probe(energy=80e3, semiangle_cutoff=30, defocus=50)

potential = Potential(atoms, sampling=.04)


gridscan = GridScan(start=[0, 0], end=[np.sqrt(3) * 1.42, 3 * 1.42], sampling=probe.ctf.nyquist_sampling * .9)

Segmented detector

The SegmentedDetector covers an annular angular range, and is partitioned into several integration regions divided to radial and angular segments whose number is given by the parameters nbins_radial and nbins_angular. This can be used for simulating differential phase contrast (DPC) imaging.

from abtem.detect import SegmentedDetector

dpc_detector = SegmentedDetector(inner=90, outer=200, nbins_radial=2, nbins_angular=4)

This detector is divided into eight different integration regions, which we illustrate below.

dpc_detector.show(probe, cmap='jet', cbar=True);

We then scan our probe over the potential and record the scattering intensity into our segmented detector.

dpc_measurement = probe.scan(gridscan, dpc_detector, potential)

The resulting measurement is 4D. The first two dimensions represent the scan dimensions, and the last two represent the radial and angular segments, respectively.

(8, 14, 2, 4)

To show the output we need to perform a reduction of the dimension of the data from 4d to 1d or 2d. The simplest reduction is just indexing; below we show the signal from the first scan position.

dpc_measurement[0, 0].show();

We may also reduce the dimension by taking the mean. Below we calculate the mean detector signal, which is just an ADF STEM image.


To obtain a differential signal, we can subtract the mean of detector regions 2 and 3 from regions 0 and 1.

signal_01 = dpc_measurement[:, :, 0, [0, 1]].mean(-1)
signal_23 = dpc_measurement[:, :, 0, [2, 3]].mean(-1)

differential_signal = signal_01 - signal_23

differential_signal.tile((3, 2)).show();

Flexible annular detector

The FlexibleAnnularDetector allows us to choose the integration limits after running the simulation. Here, we create a detector with a spacing between detector regions of 10 mrad.

from abtem.detect import FlexibleAnnularDetector

flexible_detector = FlexibleAnnularDetector(step_size=10)

Note that the maximum detected scattering angle is limited by the antialiasing aperture.

flexible_detector.show(probe, cmap='jet', cbar=True);

We can again scan our probe over the potential using this detector.

flexible_measurement = probe.scan(gridscan, flexible_detector, potential, pbar=True)

The resulting measurement data is 3D. The first two dimensions represent the scan dimensions, the last dimension represents the detector bins.

flexible_measurement.integrate(80, 200).show();

We can then sample the scattered intensity into a desired angular range (within the spacing resolution determined above). By choosing an angular range corresponding to an ADF detector, we can again recover a typical STEM image.

Pixelated detector

The PixelatedDetector records the intensity of the Fourier-transformed exit wave function, i.e. a complete convergent-beam electron diffraction pattern. Hence, a 2D scan with this detector results in a large four-dimensional dataset (a 2D diffraction pattern recorded at every 2D probe position). The 4D datasets thus generated can be used to reconstruct the results of any of the other detector geometries, hence the only downside of using this detector is the high memory or disk space requirements of storing the data.

from abtem.detect import PixelatedDetector

pixelated_detector = PixelatedDetector(max_angle=100)
pixelated_measurement = probe.scan(gridscan, pixelated_detector, potential)

Indexing the scan dimensions returns a single diffraction pattern.

pixelated_measurement[0,0].show(cmap='inferno', power=.2);

As an example, we can use these measurements to generate center-of-mass images.

from abtem.measure import center_of_mass

com_x, com_y = center_of_mass(pixelated_measurement)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (10, 4))
com_x.tile((3, 2)).show(cbar=True, ax=ax1);
com_y.tile((3, 2)).show(cbar=True, ax=ax2);
[ ]: