Skip to content

Commit

Permalink
Merge 2ad4567 into bb359b9
Browse files Browse the repository at this point in the history
  • Loading branch information
CSSFrancis committed Apr 25, 2024
2 parents bb359b9 + 2ad4567 commit badf019
Show file tree
Hide file tree
Showing 18 changed files with 2,214 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -46,7 +46,7 @@ jobs:
- os: ubuntu-latest
python-version: 3.8
OLDEST_SUPPORTED_VERSION: true
DEPENDENCIES: diffpy.structure==3.0.2 matplotlib==3.5 numpy==1.17.3 orix==0.9.0 scipy==1.8 tqdm==4.9
DEPENDENCIES: diffpy.structure==3.0.2 matplotlib==3.5 numpy==1.17.3 orix==0.12.1 scipy==1.8 tqdm==4.9
LABEL: -oldest
steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 2 additions & 0 deletions diffsims/crystallography/__init__.py
Expand Up @@ -27,11 +27,13 @@
get_hkl,
)
from diffsims.crystallography.reciprocal_lattice_vector import ReciprocalLatticeVector
from diffsims.crystallography.diffracting_vector import DiffractingVector

__all__ = [
"get_equivalent_hkl",
"get_highest_hkl",
"get_hkl",
"ReciprocalLatticePoint",
"ReciprocalLatticeVector",
"DiffractingVector",
]
116 changes: 116 additions & 0 deletions diffsims/crystallography/diffracting_vector.py
@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
# Copyright 2017-2024 The diffsims developers
#
# This file is part of diffsims.
#
# diffsims is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# diffsims is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with diffsims. If not, see <http://www.gnu.org/licenses/>.

from diffsims.crystallography import ReciprocalLatticeVector
import numpy as np


class DiffractingVector(ReciprocalLatticeVector):
r"""Reciprocal lattice vectors :math:`(hkl)` for use in electron
diffraction analysis and simulation.
All lengths are assumed to be given in Å or inverse Å.
This extends the :class:`ReciprocalLatticeVector` class. Diffracting Vectors
focus on the subset of reciporical lattice vectors that are relevant for
electron diffraction based on the intersection of the Ewald sphere with the
reciprocal lattice.
Parameters
----------
phase : orix.crystal_map.Phase
A phase with a crystal lattice and symmetry.
xyz : numpy.ndarray, list, or tuple, optional
Cartesian coordinates of indices of reciprocal lattice vector(s)
``hkl``. Default is ``None``. This, ``hkl``, or ``hkil`` is
required.
hkl : numpy.ndarray, list, or tuple, optional
Indices of reciprocal lattice vector(s). Default is ``None``.
This, ``xyz``, or ``hkil`` is required.
hkil : numpy.ndarray, list, or tuple, optional
Indices of reciprocal lattice vector(s), often preferred over
``hkl`` in trigonal and hexagonal lattices. Default is ``None``.
This, ``xyz``, or ``hkl`` is required.
Examples
--------
>>> from diffpy.structure import Atom, Lattice, Structure
>>> from orix.crystal_map import Phase
>>> from diffsims.crystallography import DiffractingVector
>>> phase = Phase(
... "al",
... space_group=225,
... structure=Structure(
... lattice=Lattice(4.04, 4.04, 4.04, 90, 90, 90),
... atoms=[Atom("Al", [0, 0, 1])],
... ),
... )
>>> rlv = DiffractingVector(phase, hkl=[[1, 1, 1], [2, 0, 0]])
>>> rlv
ReciprocalLatticeVector (2,), al (m-3m)
[[1. 1. 1.]
[2. 0. 0.]]
"""

def __init__(self, phase, xyz=None, hkl=None, hkil=None, intensity=None):
super().__init__(phase, xyz=xyz, hkl=hkl, hkil=hkil)
if intensity is None:
self._intensity = np.full(self.shape, np.nan)
elif len(intensity) != self.size:
raise ValueError("Length of intensity array must match number of vectors")
else:
self._intensity = np.array(intensity)

def __getitem__(self, key):
dv_new = super().__getitem__(key)
if np.isnan(self.intensity).all():
dv_new._intensity = np.full(dv_new.shape, np.nan)
else:
slic = self.intensity[key]
if not hasattr(slic, "__len__"):
slic = np.array(
[
slic,
]
)
dv_new._intensity = slic

return dv_new

@property
def intensity(self):
return self._intensity

@intensity.setter
def intensity(self, value):
if not hasattr(value, "__len__"):
value = np.array(
[
value,
]
* self.size
)
if len(value) != self.size:
raise ValueError("Length of intensity array must match number of vectors")
self._intensity = np.array(value)

def calculate_structure_factor(self):
raise NotImplementedError(
"Structure factor calculation not implemented for DiffractingVector"
)
16 changes: 13 additions & 3 deletions diffsims/crystallography/reciprocal_lattice_vector.py
Expand Up @@ -18,6 +18,7 @@

from collections import defaultdict
from copy import deepcopy
from typing import Tuple

from diffpy.structure.symmetryutilities import expandPosition
from diffpy.structure import Structure
Expand Down Expand Up @@ -124,8 +125,8 @@ def __init__(self, phase, xyz=None, hkl=None, hkil=None):
self._structure_factor = np.full(self.shape, np.nan, dtype="complex128")

def __getitem__(self, key):
miller_new = self.to_miller().__getitem__(key)
rlv_new = self.from_miller(miller_new)
new_data = self.data[key]
rlv_new = self.__class__(self.phase, xyz=new_data)

if np.isnan(self.structure_factor).all():
rlv_new._structure_factor = np.full(
Expand Down Expand Up @@ -502,6 +503,11 @@ def scattering_parameter(self):

return 0.5 * self.gspacing

def rotate_from_matrix(self, rotation_matrix):
return ReciprocalLatticeVector(
phase=self.phase, xyz=np.matmul(rotation_matrix.T, self.data.T).T
)

@property
def structure_factor(self):
r"""Kinematical structure factors :math:`F`.
Expand Down Expand Up @@ -1070,7 +1076,7 @@ def from_highest_hkl(cls, phase, hkl):
return cls(phase, hkl=idx).unique()

@classmethod
def from_min_dspacing(cls, phase, min_dspacing=0.7):
def from_min_dspacing(cls, phase, min_dspacing=0.7, include_zero_beam=False):
"""Create a set of unique reciprocal lattice vectors with a
a direct space interplanar spacing greater than a lower
threshold.
Expand All @@ -1083,6 +1089,8 @@ def from_min_dspacing(cls, phase, min_dspacing=0.7):
Smallest interplanar spacing to consider. Default is 0.7,
in the unit used to define the lattice parameters in
``phase``, which is assumed to be Ångström.
include_zero_beam: bool
If ``True``, include the zero beam in the set of vectors.
Examples
--------
Expand Down Expand Up @@ -1128,6 +1136,8 @@ def from_min_dspacing(cls, phase, min_dspacing=0.7):
dspacing = 1 / phase.structure.lattice.rnorm(hkl)
idx = dspacing >= min_dspacing
hkl = hkl[idx]
if include_zero_beam:
hkl = np.vstack((hkl, np.zeros(3, dtype=int)))
return cls(phase, hkl=hkl).unique()

@classmethod
Expand Down
2 changes: 2 additions & 0 deletions diffsims/generators/__init__.py
Expand Up @@ -26,12 +26,14 @@
rotation_list_generators,
sphere_mesh_generators,
zap_map_generator,
simulation_generator,
)

__all__ = [
"diffraction_generator",
"library_generator",
"rotation_list_generators",
"sphere_mesh_generators",
"simulation_generator",
"zap_map_generator",
]

0 comments on commit badf019

Please sign in to comment.