Skip to content

Commit fce8e2b

Browse files
committed
Use Phase.expand_asymmetric_unit
1 parent 9c06e7d commit fce8e2b

File tree

3 files changed

+53
-86
lines changed

3 files changed

+53
-86
lines changed

diffsims/crystallography/_diffracting_vector.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ class RotatedPhase(Phase):
3737
"""
3838

3939
def __init__(self, phase: Phase, rotation: Rotation):
40+
# Copy structure to not override the input phase.
41+
# Use private members to avoid re-computing
4042
self._structure = Structure(phase.structure)
43+
self._diffpy_lattice = phase._diffpy_lattice
4144
self.name = phase.name
4245
self.space_group = phase.space_group
4346
self.point_group = phase.point_group

diffsims/crystallography/reciprocal_lattice_vector.py

Lines changed: 9 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
from collections import defaultdict
2020
from copy import deepcopy
2121

22-
from diffpy.structure.symmetryutilities import expandPosition
23-
from diffpy.structure import Structure, Lattice
2422
import numba as nb
2523
import numpy as np
2624
from orix.vector import Miller, Vector3d
@@ -919,22 +917,12 @@ def sanitise_phase(self):
919917

920918
self._raise_if_no_space_group()
921919

922-
space_group = self.phase.space_group
923-
structure = self.phase.structure
920+
self.phase.expand_asymmetric_unit()
924921

925-
# Lattice basis transform for hexagonal crystals can sometimes move atoms below 0
926-
for atom in structure:
927-
for i in range(3):
928-
if -1e-6 < atom.xyz[i] < 0:
929-
atom.xyz[i] = 0
930-
931-
new_structure = _expand_unit_cell(space_group, structure)
932-
for atom in new_structure:
922+
for atom in self.phase.structure:
933923
if np.issubdtype(type(atom.element), np.integer):
934924
atom.element = _get_string_from_element_id(atom.element)
935925

936-
self.phase.structure = new_structure
937-
938926
def symmetrise(self, return_multiplicity=False, return_index=False):
939927
"""Unique vectors symmetrically equivalent to the vectors.
940928
@@ -1528,7 +1516,9 @@ def unique(self, use_symmetry=False, return_index=False, return_inverse=False):
15281516

15291517
# TODO: Reduce floating point precision in orix!
15301518
def miller_unique(miller, use_symmetry=False):
1531-
v, idx, inv = Vector3d(miller).unique(return_index=True, return_inverse=True)
1519+
v, idx, inv = Vector3d(miller).unique(
1520+
return_index=True, return_inverse=True, ignore_zero=False
1521+
)
15321522

15331523
if use_symmetry:
15341524
operations = miller.phase.point_group
@@ -1540,8 +1530,10 @@ def miller_unique(miller, use_symmetry=False):
15401530
for i in range(n_v):
15411531
a = data[i]
15421532
order = np.lexsort(a.T) # Sort by column 1, 2, then 3
1543-
data_sorted[i] = a[order[::-1]] # Reverse to preserve order
1544-
_, idx, inv = np.unique(data_sorted, return_index=True, return_inverse=True, axis=0)
1533+
data_sorted[i] = a[order[::-1]] # Reverse to preserve order
1534+
_, idx, inv = np.unique(
1535+
data_sorted, return_index=True, return_inverse=True, axis=0
1536+
)
15451537
v = v[idx]
15461538

15471539
m = miller.__class__(xyz=v.data, phase=miller.phase)
@@ -1598,74 +1590,6 @@ def stack(cls, sequence):
15981590
return new
15991591

16001592

1601-
# TODO: Upstream to diffpy.structure.Atom.__eq__()
1602-
def _atom_eq(atom1, atom2):
1603-
"""Determine whether two atoms are equal.
1604-
1605-
Parameters
1606-
----------
1607-
atom1, atom2 : diffpy.structure.Atom
1608-
1609-
Returns
1610-
-------
1611-
bool
1612-
1613-
"""
1614-
1615-
return (
1616-
atom1.element == atom2.element
1617-
and np.allclose(atom1.xyz_cartn, atom2.xyz_cartn, atol=1e-7)
1618-
and atom1.occupancy == atom2.occupancy
1619-
and np.allclose(atom1.U, atom2.U, atol=1e-7)
1620-
and np.allclose(atom1.Uisoequiv, atom2.Uisoequiv, atol=1e-7)
1621-
)
1622-
1623-
1624-
# TODO: Upstream to orix.crystal_map.Phase.expand_structure()
1625-
def _expand_unit_cell(space_group, structure):
1626-
"""Expand a unit cell with symmetrically equivalent atoms.
1627-
1628-
Parameters
1629-
----------
1630-
space_group : diffpy.structure.spacegroupmod.SpaceGroup
1631-
Space group describing the symmetry operations of the unit cell.
1632-
structure : diffpy.structure.Structure
1633-
Initial structure with atoms.
1634-
1635-
Returns
1636-
-------
1637-
new_structure : diffpy.structure.Structure
1638-
1639-
"""
1640-
# Transform to diffpy axis conventions
1641-
structure_matrix = structure.lattice.base
1642-
pos = structure.xyz_cartn
1643-
structure = Structure(
1644-
atoms=list(structure),
1645-
lattice=Lattice(*structure.lattice.abcABG()),
1646-
)
1647-
new_structure = Structure(lattice=structure.lattice)
1648-
structure.xyz_cartn = pos
1649-
1650-
# Perform symmetry expansion
1651-
for atom in structure:
1652-
equal = []
1653-
for atom2 in new_structure:
1654-
equal.append(_atom_eq(atom, atom2))
1655-
if not any(equal):
1656-
new_positions = expandPosition(space_group, atom.xyz)[0]
1657-
for new_position in new_positions:
1658-
new_atom = deepcopy(atom)
1659-
new_atom.xyz = new_position
1660-
new_structure.append(new_atom)
1661-
1662-
# Transform back to orix convention
1663-
old_xyz_cartn = new_structure.xyz_cartn
1664-
new_structure.lattice.setLatBase(structure_matrix)
1665-
new_structure.xyz_cartn = old_xyz_cartn
1666-
return new_structure
1667-
1668-
16691593
@nb.njit(
16701594
"int64[:](float64[:, :], float64[:, :], int64[:])",
16711595
cache=True,

diffsims/tests/generators/test_simulation_generator.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ def test_appropriate_scaling(self, diffraction_calculator: SimulationGenerator):
197197
phase=big_silicon, reciprocal_radius=5.0
198198
)
199199
indices = [tuple(i.tolist()) for i in diffraction.coordinates.hkl.astype(int)]
200-
big_indices = [tuple(i.tolist()) for i in big_diffraction.coordinates.hkl.astype(int)]
200+
big_indices = [
201+
tuple(i.tolist()) for i in big_diffraction.coordinates.hkl.astype(int)
202+
]
201203
target = (2, 2, 0)
202204
assert target in indices
203205
assert target in big_indices
@@ -413,3 +415,41 @@ def test_calculate_diffraction2d_progressbar_multi_phase(capsys):
413415
expected2 = "B: 100\%\|█+\| 10\/10 "
414416
assert re.findall(expected1, captured.err)
415417
assert re.findall(expected2, captured.err)
418+
def test_space_group_is_accounted_for():
419+
structure = diffpy.structure.Structure(
420+
atoms=[diffpy.structure.Atom("Au", xyz=(0, 0, 0))],
421+
lattice=diffpy.structure.Lattice(4, 4, 4, 90, 90, 90),
422+
)
423+
P1 = Phase(space_group=1, structure=structure)
424+
Fd3m = Phase(space_group=227, structure=structure)
425+
426+
gen = SimulationGenerator()
427+
P1_sim = gen.calculate_diffraction2d(P1)
428+
Fd3m_sim = gen.calculate_diffraction2d(Fd3m)
429+
430+
# Use ReciprocalLatticeVector.sanitize_phase
431+
Fd3m_expanded = Fd3m.deepcopy()
432+
Fd3m_expanded.expand_asymmetric_unit()
433+
Fd3m_expanded_sim = gen.calculate_diffraction2d(Fd3m_expanded)
434+
435+
# Check coordinates. There are many extinct reflections in Fd3m, so look for those in P1
436+
P1_hkl = [tuple(hkl.round().astype(int).tolist()) for hkl in P1_sim.coordinates.hkl]
437+
Fd3m_hkl = [
438+
tuple(hkl.round().astype(int).tolist()) for hkl in Fd3m_sim.coordinates.hkl
439+
]
440+
Fd3m_expanded_hkl = [
441+
tuple(hkl.round().astype(int).tolist())
442+
for hkl in Fd3m_expanded_sim.coordinates.hkl
443+
]
444+
assert set(P1_hkl).issuperset(set(Fd3m_hkl))
445+
assert set(P1_hkl).issuperset(set(Fd3m_expanded_hkl))
446+
assert set(Fd3m_hkl) == set(Fd3m_expanded_hkl)
447+
448+
# Check intensities, should be different
449+
order = [P1_hkl.index(hkl) for hkl in Fd3m_hkl]
450+
assert not np.allclose(
451+
P1_sim.coordinates.intensity[order], Fd3m_sim.coordinates.intensity
452+
)
453+
assert np.allclose(
454+
Fd3m_sim.coordinates.intensity, Fd3m_expanded_sim.coordinates.intensity
455+
)

0 commit comments

Comments
 (0)