From 1a8e69aaf4328bea0fba76c91b6eab0d1ff2de24 Mon Sep 17 00:00:00 2001 From: Carter Francis Date: Sun, 7 Apr 2024 14:40:20 -0500 Subject: [PATCH 1/2] New Feature: Allow passing phase to sample generation --- orix/sampling/sample_generators.py | 19 +++++++++-- orix/tests/sampling/test_sampling.py | 50 ++++++++++++++++++---------- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/orix/sampling/sample_generators.py b/orix/sampling/sample_generators.py index 921d7ea0..e7b27e0f 100644 --- a/orix/sampling/sample_generators.py +++ b/orix/sampling/sample_generators.py @@ -33,6 +33,7 @@ def get_sample_fundamental( resolution: Union[int, float] = 2, point_group: Optional[Symmetry] = None, space_group: Optional[int] = None, + phase: Optional[Phase] = None, method: str = "cubochoric", **kwargs ) -> Rotation: @@ -48,6 +49,10 @@ def get_sample_fundamental( must be. space_group Between 1 and 231. Must be given if ``point_group`` is not. + phase + The phase for which the fundamental zone rotations are sampled. + If not given, the point group or space group is used to determine + the crystal system. method ``"cubochoric"`` (default), ``"haar_euler"`` or ``"quaternion"``. See :func:`~orix.sampling.uniform_SO3_sample` @@ -79,6 +84,8 @@ def get_sample_fundamental( [ 0.877 0.2884 0.2884 0.2538] [ 0.877 0.2774 0.2774 0.2774]] """ + if phase is not None: + point_group = phase.point_group if point_group is None: point_group = get_point_group(space_group, proper=True) @@ -173,6 +180,7 @@ def _remove_larger_than_angle(rot: Rotation, max_angle: Union[int, float]) -> Ro def get_sample_reduced_fundamental( resolution: float, mesh: str = None, + phase: Phase = None, point_group: Symmetry = None, ) -> Rotation: """Produces rotations to align various crystallographic directions with @@ -189,16 +197,23 @@ def get_sample_reduced_fundamental( Type of meshing of the sphere that defines how the grid is created. See orix.sampling.sample_S2 for all the options. A suitable default is chosen depending on the crystal system. + phase + The phase for which the reduced fundamental zone rotations are + sampled. If not given, the point group is used to determine the + crystal system. point_group - Symmetry operations that determines the unique directions. Defaults to + Symmetry operations that determines the unique directions. If ``Phase`` + is given the ``Phase.point_group`` is used instead. Defaults to no symmetry, which means sampling all 3D unit vectors. Returns ------- Rotation (N, 3) array representing Euler angles for the different orientations """ - if point_group is None: + if point_group is None and phase is None: point_group = symmetry.C1 + if phase is not None: + point_group = phase.point_group if mesh is None: s2_auto_sampling_map = { diff --git a/orix/tests/sampling/test_sampling.py b/orix/tests/sampling/test_sampling.py index 4c9a546f..6c93b93f 100644 --- a/orix/tests/sampling/test_sampling.py +++ b/orix/tests/sampling/test_sampling.py @@ -170,6 +170,23 @@ class TestSampleFundamental: def C6_sample(self): return get_sample_fundamental(resolution=4, point_group=C6, method="haar_euler") + @pytest.fixture(scope="session") + def phase(self): + a = 5.431 + latt = Lattice(a, a, a, 90, 90, 90) + atom_list = [] + for coords in [[0, 0, 0], [0.5, 0, 0.5], [0, 0.5, 0.5], [0.5, 0.5, 0]]: + x, y, z = coords[0], coords[1], coords[2] + atom_list.append( + Atom(atype="Si", xyz=[x, y, z], lattice=latt) + ) # Motif part A + atom_list.append( + Atom(atype="Si", xyz=[x + 0.25, y + 0.25, z + 0.25], lattice=latt) + ) # Motif part B + struct = Structure(atoms=atom_list, lattice=latt) + p = Phase(structure=struct, space_group=227) + return p + def test_get_sample_fundamental_zone_order(self, C6_sample): """Cross check point counts to group order terms.""" D6_sample = get_sample_fundamental(4, point_group=D6, method="haar_euler") @@ -200,30 +217,29 @@ def test_get_sample_reduced_fundamental(self): np.abs(rotations.size / rotations6.size) - 6 < 0.1 ) # about 6 times more rotations + def test_get_sample_reduced_fundamental_phase(self, phase): + rotations = get_sample_reduced_fundamental(resolution=4, phase=phase) + rotations2 = get_sample_reduced_fundamental( + resolution=4, point_group=phase.point_group + ) + np.testing.assert_allclose(rotations.data, rotations2.data) + + def test_get_sample_fundamental_phase(self, phase): + rotations = get_sample_fundamental(resolution=4, phase=phase) + rotations2 = get_sample_fundamental(resolution=4, point_group=phase.point_group) + np.testing.assert_allclose(rotations.data, rotations2.data) + @pytest.mark.parametrize("density", ("3", "7", "5")) @pytest.mark.parametrize("get_directions", (True, False)) - def test_get_zone_axis(self, density, get_directions): - a = 5.431 - latt = Lattice(a, a, a, 90, 90, 90) - atom_list = [] - for coords in [[0, 0, 0], [0.5, 0, 0.5], [0, 0.5, 0.5], [0.5, 0.5, 0]]: - x, y, z = coords[0], coords[1], coords[2] - atom_list.append( - Atom(atype="Si", xyz=[x, y, z], lattice=latt) - ) # Motif part A - atom_list.append( - Atom(atype="Si", xyz=[x + 0.25, y + 0.25, z + 0.25], lattice=latt) - ) # Motif part B - struct = Structure(atoms=atom_list, lattice=latt) - p = Phase(structure=struct, space_group=227) + def test_get_zone_axis(self, density, get_directions, phase): if density == "5": with pytest.raises(ValueError): - get_sample_zone_axis(phase=p, density=density) + get_sample_zone_axis(phase=phase, density=density) else: if get_directions: rot, _ = get_sample_zone_axis( - phase=p, density=density, return_directions=True + phase=phase, density=density, return_directions=True ) else: - rot = get_sample_zone_axis(phase=p, density=density) + rot = get_sample_zone_axis(phase=phase, density=density) assert isinstance(rot, Rotation) From c62227e44b8e4d3640c041aca1bad46e4a8ebf6e Mon Sep 17 00:00:00 2001 From: Carter Francis Date: Thu, 11 Apr 2024 11:22:18 -0500 Subject: [PATCH 2/2] Documentation: Added CHANGELOG.rst --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f84b0e01..f8ca5a4e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,6 +34,9 @@ Added - ``Added orix.sampling.get_sample_zone_axis`` for getting zone axes for some point group. - ``Added orix.sampling.get_sample_reduced_fundamental`` for getting reduced fundamental zone for some point group. +- Added ``phase`` argument to ``orix.sampling.get_sample_fundamental`` and + ``orix.sampling.get_sample_reduced_fundamental`` for passing a + phase to the functions rather than a space group or point group. Changed -------