Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating ACOM, new phase mapping module code, some fixes #664

Merged
merged 55 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9cb63d4
Merge remote-tracking branch 'cophus/dev' into dev
cophus Nov 14, 2023
a15b5d9
initial commit for projected potential
cophus Nov 14, 2023
5b9080d
Atom coordinates mostly working
cophus Nov 14, 2023
36ddbcc
Projected potential now working with bugs
cophus Nov 14, 2023
a0d0f15
minor tweak
cophus Nov 14, 2023
9b726e5
Projected potentials fixed?
cophus Dec 8, 2023
a9b05ed
adding figsize
cophus Feb 2, 2024
a004b7a
Merge remote-tracking branch 'py4dstem/dev' into potential2D
cophus Mar 4, 2024
43a396c
update docstring
cophus Mar 4, 2024
16c727f
Adding thickness projection
cophus Mar 4, 2024
a1c83c3
Fourier method makes boundary conditions difficult
cophus Mar 4, 2024
c8d661a
Updated plotting
cophus Mar 4, 2024
3905e8d
Adding robust fitting to ACOM strain mapping
cophus Mar 8, 2024
771ab1f
Updating matching
cophus Mar 13, 2024
4ffa1a6
Merge remote-tracking branch 'py4dstem/dev' into diffraction
cophus Mar 20, 2024
26834d9
Merge branch 'potential2D' into diffraction
cophus Mar 20, 2024
938c965
Fixing thickness projection in 2D potentials
cophus Mar 20, 2024
6938fe3
black
cophus Mar 20, 2024
2650831
Remove testing lines.
cophus Mar 21, 2024
1e70080
Trying (and failing) to figure out the potential units
cophus Mar 21, 2024
c8a81f5
Black formatting
cophus Mar 21, 2024
cf55d7f
Merge remote-tracking branch 'py4dstem/dev' into diffraction
cophus Mar 21, 2024
e362b6b
Black again
cophus Mar 21, 2024
a2b9eca
Merge remote-tracking branch 'py4dstem/dev' into diffraction
cophus Apr 1, 2024
721250e
Merge remote-tracking branch 'py4dstem/dev' into diffraction
cophus Apr 8, 2024
0d772ad
updating phase mapping
cophus Apr 9, 2024
eababdc
Merge remote-tracking branch 'py4dstem/dev' into diffraction
cophus Apr 9, 2024
304e35b
adding single phase method
cophus Apr 10, 2024
909b84f
updating plotting function
cophus Apr 10, 2024
932fe56
Adding new weights for cost function
cophus Apr 10, 2024
e306c5d
change to strain iteration default
cophus Apr 11, 2024
217d71f
precession electron diffraction added
cophus Apr 28, 2024
264deba
New default values for diffraction sigma and intensity threshold
cophus Apr 28, 2024
ba5e0a2
Adding precession to orientation plans, update docstring
cophus Apr 28, 2024
3ee1adf
adding precession to orientation plans
cophus May 6, 2024
19058a5
precession added to orientation plans!
cophus May 6, 2024
3e656b6
Fiddling with matching routines
cophus May 7, 2024
e768a51
adding intensity scaling back into experiment
cophus May 7, 2024
8792a72
adding normalization testing
cophus May 8, 2024
04bbbaf
Making kernel a Gaussian function instead of cone
cophus May 9, 2024
e8a02ae
tweaking multiple match finder
cophus May 9, 2024
daae225
fix typo
cophus May 17, 2024
ee13501
Merge remote-tracking branch 'py4dstem/dev' into diffraction
cophus Jun 21, 2024
4a183df
Changing default settings, fiddling with plots
cophus Jun 21, 2024
7f3eca7
adding robust fitting to polar
cophus Jun 24, 2024
b921a47
Adding docstrings, cleaning up code
cophus Jun 27, 2024
cd48bea
more docstrings added
cophus Jun 27, 2024
316bded
Cleaning up, removing residual comments
cophus Jun 27, 2024
9ada2d8
black
cophus Jun 27, 2024
8899487
black formatting, updated variable name
cophus Jul 18, 2024
0ecf427
updating black version
cophus Jul 18, 2024
564999c
testing fix for drawing legend
cophus Jul 18, 2024
fece355
Revert "testing fix for drawing legend"
cophus Jul 18, 2024
a709705
adding option to hide legend
cophus Jul 18, 2024
f7bde15
option to hide legend axes
cophus Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 119 additions & 40 deletions py4DSTEM/process/diffraction/crystal.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,41 +710,69 @@ def generate_diffraction_pattern(
zone_axis_cartesian: Optional[np.ndarray] = None,
proj_x_cartesian: Optional[np.ndarray] = None,
foil_normal_cartesian: Optional[Union[list, tuple, np.ndarray]] = None,
sigma_excitation_error: float = 0.02,
sigma_excitation_error: float = 0.01,
tol_excitation_error_mult: float = 3,
tol_intensity: float = 1e-4,
tol_intensity: float = 1e-5,
k_max: Optional[float] = None,
precession_angle_degrees=None,
keep_qz=False,
return_orientation_matrix=False,
):
"""
Generate a single diffraction pattern, return all peaks as a pointlist.
Generate a single diffraction pattern, return all peaks as a pointlist. This function performs a
kinematical calculation, with optional precession of the beam.

Args:
orientation (Orientation): an Orientation class object
ind_orientation If input is an Orientation class object with multiple orientations,
this input can be used to select a specific orientation.

orientation_matrix (array): (3,3) orientation matrix, where columns represent projection directions.
zone_axis_lattice (array): (3,) projection direction in lattice indices
proj_x_lattice (array): (3,) x-axis direction in lattice indices
zone_axis_cartesian (array): (3,) cartesian projection direction
proj_x_cartesian (array): (3,) cartesian projection direction

foil_normal: 3 element foil normal - set to None to use zone_axis
proj_x_axis (np float vector): 3 element vector defining image x axis (vertical)
accel_voltage (float): Accelerating voltage in Volts. If not specified,
we check to see if crystal already has voltage specified.
sigma_excitation_error (float): sigma value for envelope applied to s_g (excitation errors) in units of inverse Angstroms
tol_excitation_error_mult (float): tolerance in units of sigma for s_g inclusion
tol_intensity (np float): tolerance in intensity units for inclusion of diffraction spots
k_max (float): Maximum scattering vector
keep_qz (bool): Flag to return out-of-plane diffraction vectors
return_orientation_matrix (bool): Return the orientation matrix
TODO - switch from numerical precession to analytic (requires geometry projection).
TODO - verify projection geometry for 2D material diffraction.

Parameters
----------

orientation (Orientation)
an Orientation class object
ind_orientation
If input is an Orientation class object with multiple orientations,
this input can be used to select a specific orientation.

orientation_matrix (3,3) numpy.array
orientation matrix, where columns represent projection directions.
zone_axis_lattice (3,) numpy.array
projection direction in lattice indices
proj_x_lattice (3,) numpy.array
x-axis direction in lattice indices
zone_axis_cartesian (3,) numpy.array
cartesian projection direction
proj_x_cartesian (3,) numpy.array
cartesian projection direction
foil_normal
3 element foil normal - set to None to use zone_axis
proj_x_axis (3,) numpy.array
3 element vector defining image x axis (vertical)
accel_voltage (float)
Accelerating voltage in Volts. If not specified,
we check to see if crystal already has voltage specified.
sigma_excitation_error (float)
sigma value for envelope applied to s_g (excitation errors) in units of inverse Angstroms
tol_excitation_error_mult (float)
tolerance in units of sigma for s_g inclusion
tol_intensity (numpy float)
tolerance in intensity units for inclusion of diffraction spots
k_max (float)
Maximum scattering vector
precession_angle_degrees (float)
Precession angle for library calculation. Set to None for no precession.
keep_qz (bool)
Flag to return out-of-plane diffraction vectors
return_orientation_matrix (bool)
Return the orientation matrix

Returns
----------
bragg_peaks (PointList)
list of all Bragg peaks with fields [qx, qy, intensity, h, k, l]
orientation_matrix (array, optional)
3x3 orientation matrix

Returns:
bragg_peaks (PointList): list of all Bragg peaks with fields [qx, qy, intensity, h, k, l]
orientation_matrix (array): 3x3 orientation matrix (optional)
"""

if not (hasattr(self, "wavelength") and hasattr(self, "accel_voltage")):
Expand Down Expand Up @@ -779,17 +807,27 @@ def generate_diffraction_pattern(

# Calculate excitation errors
if foil_normal is None:
sg = self.excitation_errors(g)
sg = self.excitation_errors(
g,
precession_angle_degrees=precession_angle_degrees,
)
sezelt marked this conversation as resolved.
Show resolved Hide resolved
else:
foil_normal = (
orientation_matrix.T
@ (-1 * foil_normal[:, None] / np.linalg.norm(foil_normal))
).ravel()
sg = self.excitation_errors(g, foil_normal)
sg = self.excitation_errors(
g,
foil_normal=foil_normal,
precession_angle_degrees=precession_angle_degrees,
)
sezelt marked this conversation as resolved.
Show resolved Hide resolved

# Threshold for inclusion in diffraction pattern
sg_max = sigma_excitation_error * tol_excitation_error_mult
keep = np.abs(sg) <= sg_max
if precession_angle_degrees is None:
keep = np.abs(sg) <= sg_max
else:
keep = np.min(np.abs(sg), axis=1) <= sg_max

# Maximum scattering angle cutoff
if k_max is not None:
Expand All @@ -799,9 +837,15 @@ def generate_diffraction_pattern(
g_diff = g[:, keep]

# Diffracted peak intensities and labels
g_int = self.struct_factors_int[keep] * np.exp(
(sg[keep] ** 2) / (-2 * sigma_excitation_error**2)
)
if precession_angle_degrees is None:
g_int = self.struct_factors_int[keep] * np.exp(
(sg[keep] ** 2) / (-2 * sigma_excitation_error**2)
)
else:
g_int = self.struct_factors_int[keep] * np.mean(
np.exp((sg[keep] ** 2) / (-2 * sigma_excitation_error**2)),
axis=1,
)
hkl = self.hkl[:, keep]

# Intensity tolerance
Expand Down Expand Up @@ -1323,20 +1367,55 @@ def excitation_errors(
self,
g,
foil_normal=None,
precession_angle_degrees=None,
precession_steps=72,
):
"""
Calculate the excitation errors, assuming k0 = [0, 0, -1/lambda].
If foil normal is not specified, we assume it is [0,0,-1].

Precession is currently implemented using numerical integration.
"""
if foil_normal is None:
return (2 * g[2, :] - self.wavelength * np.sum(g * g, axis=0)) / (
2 - 2 * self.wavelength * g[2, :]
)

if precession_angle_degrees is None:
if foil_normal is None:
return (2 * g[2, :] - self.wavelength * np.sum(g * g, axis=0)) / (
2 - 2 * self.wavelength * g[2, :]
)
else:
return (2 * g[2, :] - self.wavelength * np.sum(g * g, axis=0)) / (
2 * self.wavelength * np.sum(g * foil_normal[:, None], axis=0)
- 2 * foil_normal[2]
)

else:
return (2 * g[2, :] - self.wavelength * np.sum(g * g, axis=0)) / (
2 * self.wavelength * np.sum(g * foil_normal[:, None], axis=0)
- 2 * foil_normal[2]
t = np.deg2rad(precession_angle_degrees)
p = np.linspace(
0,
2.0 * np.pi,
precession_steps,
endpoint=False,
)
if foil_normal is None:
foil_normal = np.array((0.0, 0.0, -1.0))

k = np.reshape(
(-1 / self.wavelength)
* np.vstack(
(
np.sin(t) * np.cos(p),
np.sin(t) * np.sin(p),
np.cos(t) * np.ones(p.size),
)
),
(3, 1, p.size),
)

term1 = np.sum((g[:, :, None] + k) * foil_normal[:, None, None], axis=0)
term2 = np.sum((g[:, :, None] + 2 * k) * g[:, :, None], axis=0)
sg = np.sqrt(term1**2 - term2) - term1

return sg

def calculate_bragg_peak_histogram(
self,
Expand Down
Loading