diff --git a/diffsims/generators/structure_library_generator.py b/diffsims/generators/structure_library_generator.py
deleted file mode 100644
index 5bb5a428..00000000
--- a/diffsims/generators/structure_library_generator.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2017-2019 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 .
-
-import numpy as np
-
-from diffsims.libraries.structure_library import StructureLibrary
-from diffsims.utils.sim_utils import rotation_list_stereographic
-
-"""Generating structure libraries."""
-
-# Inverse pole figure corners for crystal systems
-stereographic_corners = {
- 'cubic': [(0, 0, 1), (1, 0, 1), (1, 1, 1)],
- 'hexagonal': [(0, 0, 0, 1), (1, 0, -1, 0), (1, 1, -2, 0)],
- 'orthorhombic': [(0, 0, 1), (1, 0, 0), (0, 1, 0)],
- 'tetragonal': [(0, 0, 1), (1, 0, 0), (1, 1, 0)],
- 'trigonal': [(0, 0, 0, 1), (0, -1, 1, 0), (1, -1, 0, 0)],
- 'monoclinic': [(0, 0, 1), (0, 1, 0), (0, -1, 0)]
-}
-
-
-class StructureLibraryGenerator:
- """Generates a structure library for the given phases
-
- Parameters
- ----------
- phases : list
- Array of three-component phase descriptions, where the phase
- description is [ : string, :
- diffpy.structure.Structure, : string], and crystal
- system is one of 'cubic', 'hexagonal', 'orthorhombic', 'tetragonal',
- 'trigonal', 'monoclinic'.
-
- Attributes
- ----------
- phase_names : list of string
- List of phase names.
- structures : list of diffpy.structure.Structure
- List of structures.
- systems : list of string
- List of crystal systems.
-
- Examples
- --------
- >>> gen = StructureLibraryGenerator([
- ... ('ZB', structure_zb, 'cubic'),
- ... ('WZ', structure_wz, 'hexagonal')])
- """
-
- def __init__(self, phases):
- self.phase_names = [phase[0] for phase in phases]
- self.structures = [phase[1] for phase in phases]
- self.systems = [phase[2] for phase in phases]
-
- def get_orientations_from_list(self, orientations):
- """Create a structure library from a list of rotations.
-
- Parameters
- ----------
- orientations : list
- A list over identifiers of lists of euler angles (as tuples) in the rzxz
- convention and in degrees.
-
- Returns
- -------
- structure_library : StructureLibrary
- Structure library for the given phase names, structures and orientations.
- """
- return StructureLibrary(self.phase_names, self.structures, orientations)
-
- def get_orientations_from_stereographic_triangle(self, inplane_rotations, resolution):
- """
- Create a structure library from the stereographic triangles of the
- given crystal systems.
-
- Parameters
- ----------
- inplane_rotations : list
- List over identifiers of lists of inplane rotations of the
- diffraction patterns, in degrees.
- resolution : float
- Rotation list resolution in degrees.
-
- Returns
- -------
- structure_library : StructureLibrary
- Structure library for the given phase names, structures and crystal system.
- """
- rotation_lists = [
- rotation_list_stereographic(structure, *stereographic_corners[system],
- np.deg2rad(inplane_rotation), np.deg2rad(resolution))
- for phase_name, structure, system, inplane_rotation in
- zip(self.phase_names, self.structures, self.systems, inplane_rotations)]
- return StructureLibrary(self.phase_names, self.structures, rotation_lists)
diff --git a/diffsims/libraries/structure_library.py b/diffsims/libraries/structure_library.py
index b81f0f07..b1969868 100644
--- a/diffsims/libraries/structure_library.py
+++ b/diffsims/libraries/structure_library.py
@@ -17,6 +17,7 @@
# along with diffsims. If not, see .
import diffsims as ds
+from diffsims.generators.rotation_list_generators import get_grid_streographic
class StructureLibrary():
@@ -54,3 +55,51 @@ def __init__(self,
self.struct_lib = dict()
for ident, struct, ori in zip(identifiers, structures, orientations):
self.struct_lib[ident] = (struct, ori)
+
+ @classmethod
+ def from_orientation_lists(cls,identifiers,structures,orientations):
+ """
+ Creates a structure library from "manual" orientation lists
+
+ Parameters
+ ----------
+ identifiers : list of strings/ints
+ A list of phase identifiers referring to different atomic structures.
+ structures : list of diffpy.structure.Structure objects.
+ A list of diffpy.structure.Structure objects describing the atomic
+ structure associated with each phase in the library.
+ orientations : list of lists of tuples
+ A list over identifiers of lists of euler angles (as tuples) in the rzxz
+ convention and in degrees.
+ Returns
+ -------
+ StructureLibrary
+ """
+ return cls(identifiers,structures,orientations)
+
+ @classmethod
+ def from_crystal_systems(cls,identifiers,structures,systems,resolution,equal='angle'):
+ """
+ Creates a structure library from crystal system derived orientation lists
+
+ Parameters
+ ----------
+ identifiers : list of strings/ints
+ A list of phase identifiers referring to different atomic structures.
+ structures : list of diffpy.structure.Structure objects.
+ A list of diffpy.structure.Structure objects describing the atomic
+ structure associated with each phase in the library.
+ systems : list
+ A list over indentifiers of crystal systems
+ resolution : float
+ resolution in degrees
+ equal : str
+ Default is 'angle'
+ Returns
+ -------
+ StructureLibrary
+ """
+ orientations = []
+ for system in systems:
+ orientations.append(get_grid_streographic(system,resolution,equal))
+ return cls(identifiers,structures,orientations)
diff --git a/diffsims/tests/test_generators/test_structure_library_generator.py b/diffsims/tests/test_generators/test_structure_library_generator.py
deleted file mode 100644
index 49b34b5c..00000000
--- a/diffsims/tests/test_generators/test_structure_library_generator.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2017-2019 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 .
-
-import numpy as np
-
-from diffsims.generators.structure_library_generator import StructureLibraryGenerator
-from diffsims.tests.test_utils.test_sim_utils import create_structure_cubic
-
-
-def test_orientations_from_list():
- expected_orientations = [(0, 0, 0), (0, 90, 0)]
- structure_library_generator = StructureLibraryGenerator([
- ('a', None, 'cubic'),
- ('b', None, 'hexagonal')
- ])
- structure_library = structure_library_generator.get_orientations_from_list(expected_orientations)
- assert structure_library.identifiers == ['a', 'b']
- assert structure_library.structures == [None, None]
- np.testing.assert_almost_equal(structure_library.orientations, expected_orientations)
-
-
-def test_orientations_from_stereographic_triangle():
- structure_cubic = create_structure_cubic()
- structure_library_generator = StructureLibraryGenerator([('a', structure_cubic, 'cubic')])
- structure_library = structure_library_generator.get_orientations_from_stereographic_triangle([[0]], np.pi / 8)
- assert structure_library.identifiers == ['a']
- assert structure_library.structures == [structure_cubic]
- # Tests for rotation_list_stereographic checks correctness of list content
- assert len(structure_library.orientations) == 1
diff --git a/diffsims/tests/test_library/test_structure_library.py b/diffsims/tests/test_library/test_structure_library.py
index f9ce5bb7..bff32269 100644
--- a/diffsims/tests/test_library/test_structure_library.py
+++ b/diffsims/tests/test_library/test_structure_library.py
@@ -21,20 +21,24 @@
from diffsims.libraries.structure_library import StructureLibrary
-
-def test_constructor():
+def test_from_orientations_method():
identifiers = ['a', 'b']
- # Arbitrary values for tracking
structures = [1, 2]
orientations = [3, 4]
- library = StructureLibrary(identifiers, structures, orientations)
-
+ library = StructureLibrary.from_orientation_lists(identifiers,structures,orientations)
np.testing.assert_equal(library.identifiers, identifiers)
np.testing.assert_equal(library.structures, structures)
np.testing.assert_equal(library.orientations, orientations)
np.testing.assert_equal(library.struct_lib['a'], (1, 3))
np.testing.assert_equal(library.struct_lib['b'], (2, 4))
+def test_from_systems_methods():
+ identifiers = ['a', 'b']
+ structures = [1, 2]
+ systems = ['cubic', 'hexagonal']
+ library = StructureLibrary.from_crystal_systems(identifiers,structures,systems,resolution=2,equal='angle')
+ assert len(library.struct_lib['a'][1]) < len(library.struct_lib['b'][1]) #cubic is less area the hexagonal
+
@pytest.mark.parametrize('identifiers, structures, orientations', [
(['a'], [1, 2], [3, 4]),
diff --git a/diffsims/tests/test_utils/test_sim_utils.py b/diffsims/tests/test_utils/test_sim_utils.py
index ca8c613a..422e95bd 100644
--- a/diffsims/tests/test_utils/test_sim_utils.py
+++ b/diffsims/tests/test_utils/test_sim_utils.py
@@ -23,39 +23,7 @@
from diffsims.utils.sim_utils import get_electron_wavelength, \
get_interaction_constant, get_unique_families, get_kinematical_intensities, \
get_vectorized_list_for_atomic_scattering_factors, get_points_in_sphere, \
- simulate_kinematic_scattering, is_lattice_hexagonal, uvtw_to_uvw, \
- rotation_list_stereographic
-
-
-def create_lattice_structure(a, b, c, alpha, beta, gamma):
- lattice = diffpy.structure.lattice.Lattice(a, b, c, alpha, beta, gamma)
- atom = diffpy.structure.atom.Atom(atype='Si', xyz=[0, 0, 0], lattice=lattice)
- return diffpy.structure.Structure(atoms=[atom], lattice=lattice)
-
-
-def create_structure_cubic():
- return create_lattice_structure(1, 1, 1, 90, 90, 90)
-
-
-def create_structure_hexagonal():
- return create_lattice_structure(1, 1, 1, 90, 90, 120)
-
-
-def create_structure_orthorombic():
- return create_lattice_structure(1, 2, 3, 90, 90, 90)
-
-
-def create_structure_tetragonal():
- return create_lattice_structure(1, 1, 2, 90, 90, 90)
-
-
-def create_structure_trigonal():
- return create_lattice_structure(1, 1, 1, 100, 100, 100)
-
-
-def create_structure_monoclinic():
- return create_lattice_structure(1, 2, 3, 90, 100, 90)
-
+ simulate_kinematic_scattering, is_lattice_hexagonal, uvtw_to_uvw
@pytest.mark.parametrize('accelerating_voltage, wavelength', [
(100, 0.0370143659),
@@ -143,65 +111,3 @@ def test_kinematic_simulator_invalid_illumination():
def test_uvtw_to_uvw(uvtw, uvw):
val = uvtw_to_uvw(uvtw)
np.testing.assert_almost_equal(val, uvw)
-
-
-# Three corners of the rotation lists, for comparison
-structure_cubic_rotations = [
- [0, 0, 0],
- [90, 45, 0],
- [135, 54.73561032, 0]
-]
-
-structure_hexagonal_rotations = [
- [0, 0, 0],
- [90, 90, 0],
- [120, 90, 0]
-]
-
-structure_orthogonal_rotations = [
- [0, 0, 0],
- [90, 90, 0],
- [180, 90, 0]
-]
-
-structure_tetragonal_rotations = [
- [0, 0, 0],
- [90, 90, 0],
- [135, 90, 0]
-]
-
-structure_trigonal_rotations = [
- [0, 0, 0],
- [-28.64458044, 75.45951959, 0],
- [38.93477108, 90, 0]
-]
-
-structure_monoclinic_rotations = [
- [0, 0, 0],
- [0, 90, 0],
- [180, 90, 0]
-]
-
-
-@pytest.mark.parametrize('structure, corner_a, corner_b, corner_c, rotation_list', [
- (create_structure_cubic(), (0, 0, 1), (1, 0, 1), (1, 1, 1), structure_cubic_rotations),
- (create_structure_hexagonal(), (0, 0, 0, 1), (1, 0, -1, 0), (1, 1, -2, 0), structure_hexagonal_rotations),
- (create_structure_orthorombic(), (0, 0, 1), (1, 0, 0), (0, 1, 0), structure_orthogonal_rotations),
- (create_structure_tetragonal(), (0, 0, 1), (1, 0, 0), (1, 1, 0), structure_tetragonal_rotations),
- (create_structure_trigonal(), (0, 0, 0, 1), (0, -1, 1, 0), (1, -1, 0, 0), structure_trigonal_rotations),
- (create_structure_monoclinic(), (0, 0, 1), (0, 1, 0), (0, -1, 0), structure_monoclinic_rotations),
-])
-def test_rotation_list_stereographic(structure, corner_a, corner_b, corner_c, rotation_list):
- val = rotation_list_stereographic(structure, corner_a, corner_b, corner_c, [0], np.deg2rad(10))
- for expected in rotation_list:
- assert any((np.allclose(expected, actual) for actual in val))
-
-
-@pytest.mark.xfail(raises=ValueError)
-@pytest.mark.parametrize('structure, corner_a, corner_b, corner_c, inplane_rotations, resolution, rotation_list', [
- (create_structure_cubic(), (0, 0, 1), (0, 0, 1), (1, 1, 1), [0], np.deg2rad(10), structure_cubic_rotations),
- (create_structure_cubic(), (0, 0, 1), (1, 0, 1), (0, 0, 1), [0], np.deg2rad(10), structure_cubic_rotations)
-])
-def test_rotation_list_stereographic_raises_invalid_corners(
- structure, corner_a, corner_b, corner_c, inplane_rotations, resolution, rotation_list):
- rotation_list_stereographic(structure, corner_a, corner_b, corner_c, inplane_rotations, resolution)
diff --git a/diffsims/utils/sim_utils.py b/diffsims/utils/sim_utils.py
index 5adbd837..b0bc7fd9 100644
--- a/diffsims/utils/sim_utils.py
+++ b/diffsims/utils/sim_utils.py
@@ -372,7 +372,7 @@ def simulate_rotated_structure(diffraction_generator, structure, rotation_matrix
stdbase = structure.lattice.stdbase
stdbase_inverse = np.linalg.inv(stdbase)
rotation_matrix_diffpy = stdbase_inverse @ rotation_matrix @ stdbase
-
+
lattice_rotated = diffpy.structure.lattice.Lattice(
*structure.lattice.abcABG(),
baserot=rotation_matrix_diffpy)
@@ -458,111 +458,3 @@ def uvtw_to_uvw(uvtw):
u, v, w = 2 * u + v, 2 * v + u, w
common_factor = math.gcd(math.gcd(u, v), w)
return tuple((int(x / common_factor)) for x in (u, v, w))
-
-
-def rotation_list_stereographic(structure, corner_a, corner_b, corner_c,
- inplane_rotations, resolution):
- """Generate a rotation list covering the inverse pole figure specified by
- three corners in cartesian coordinates.
-
- Parameters
- ----------
- structure : diffpy.structure.Structure
- Structure for which to calculate the rotation list.
- corner_a, corner_b, corner_c : tuple
- The three corners of the inverse pole figure, each given by a
- three-dimensional coordinate. The coordinate system is given by the
- structure lattice.
- inplane_rotations : list
- List of angles in radians for in-plane rotation of the diffraction
- pattern. This corresponds to the third Euler angle rotation. The
- rotation list will be generated for each of these angles, and combined.
- This should be done automatically, but by including all possible
- rotations in the rotation list, it becomes too large.
-
- To cover all inplane rotations, use e.g. np.linspace(0, 2*np.pi, 360).
- resolution : float
- Angular resolution in radians of the generated rotation list.
-
- Returns
- -------
- rotation_list : numpy.array
- Rotations covering the inverse pole figure given as an array of Euler
- angles in degrees.
- """
- # Convert the crystal directions to cartesian vectors and normalize
- if len(corner_a) == 4:
- corner_a = uvtw_to_uvw(corner_a)
- if len(corner_b) == 4:
- corner_b = uvtw_to_uvw(corner_b)
- if len(corner_c) == 4:
- corner_c = uvtw_to_uvw(corner_c)
-
- lattice = structure.lattice
-
- corner_a = np.dot(corner_a, lattice.stdbase)
- corner_b = np.dot(corner_b, lattice.stdbase)
- corner_c = np.dot(corner_c, lattice.stdbase)
-
- corner_a /= np.linalg.norm(corner_a)
- corner_b /= np.linalg.norm(corner_b)
- corner_c /= np.linalg.norm(corner_c)
-
- angle_a_to_b = get_angle_cartesian(corner_a, corner_b)
- angle_a_to_c = get_angle_cartesian(corner_a, corner_c)
- angle_b_to_c = get_angle_cartesian(corner_b, corner_c)
- axis_a_to_b = np.cross(corner_a, corner_b)
- axis_a_to_c = np.cross(corner_a, corner_c)
-
- # Input validation. The corners have to define a non-degenerate triangle
- if np.count_nonzero(axis_a_to_b) == 0:
- raise ValueError('Directions a and b are parallel')
- if np.count_nonzero(axis_a_to_c) == 0:
- raise ValueError('Directions a and c are parallel')
-
- rotations = []
-
- # Generate a list of theta_count evenly spaced angles theta_b in the range
- # [0, angle_a_to_b] and an equally long list of evenly spaced angles
- # theta_c in the range[0, angle_a_to_c].
- # Ensure that we keep the resolution also along the direction to the corner
- # b or c farthest away from a.
- theta_count = math.ceil(max(angle_a_to_b, angle_a_to_c) / resolution)
- for i, (theta_b, theta_c) in enumerate(
- zip(np.linspace(0, angle_a_to_b, theta_count),
- np.linspace(0, angle_a_to_c, theta_count))):
- # Define the corner local_b at a rotation theta_b from corner_a toward
- # corner_b on the circle surface. Similarly, define the corner local_c
- # at a rotation theta_c from corner_a toward corner_c.
-
- rotation_a_to_b = axangle2mat(axis_a_to_b, theta_b)
- rotation_a_to_c = axangle2mat(axis_a_to_c, theta_c)
- local_b = np.dot(rotation_a_to_b, corner_a)
- local_c = np.dot(rotation_a_to_c, corner_a)
-
- # Then define an axis and a maximum rotation to create a great cicle
- # arc between local_b and local_c. Ensure that this is not a degenerate
- # case where local_b and local_c are coincident.
- angle_local_b_to_c = get_angle_cartesian(local_b, local_c)
- axis_local_b_to_c = np.cross(local_b, local_c)
- if np.count_nonzero(axis_local_b_to_c) == 0:
- # Theta rotation ended at the same position. First position, might
- # be other cases?
- axis_local_b_to_c = corner_a
- axis_local_b_to_c /= np.linalg.norm(axis_local_b_to_c)
-
- # Generate points along the great circle arc with a distance defined by
- # resolution.
- phi_count_local = max(math.ceil(angle_local_b_to_c / resolution), 1)
- for j, phi in enumerate(
- np.linspace(0, angle_local_b_to_c, phi_count_local)):
- rotation_phi = axangle2mat(axis_local_b_to_c, phi)
-
- for k, psi in enumerate(inplane_rotations):
- # Combine the rotations. Order is important. The matrix is
- # applied from the left, and we rotate by theta first toward
- # local_b, then across the triangle toward local_c
- rotation = list(mat2euler(rotation_phi @ rotation_a_to_b, 'rzxz'))
- rotations.append(np.rad2deg([rotation[0], rotation[1], psi]))
-
- return np.unique(rotations, axis=0)