Exemple #1
0
 def test_multiplicity(self, nickel_phase, silicon_carbide_phase):
     assert np.allclose(
         ReciprocalLatticePoint.from_min_dspacing(
             phase=nickel_phase, min_dspacing=1
         ).multiplicity,
         # fmt: off
         np.array([
             8, 24, 24, 24, 12, 24, 48, 48, 24, 24, 48, 24, 24, 24, 6, 8, 24,
             24, 12, 24, 48, 24, 24, 24,  6,  8, 24, 12, 24, 24,  6,  8, 12, 6
         ])
         # fmt: on
     )
     assert np.allclose(
         ReciprocalLatticePoint.from_min_dspacing(
             phase=silicon_carbide_phase, min_dspacing=1
         ).multiplicity,
         # fmt: off
         np.array([
             12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
             12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 6,
             6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
             12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12,
             12, 12, 12, 12, 12, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1,
             1, 1, 1, 1, 1, 1
         ])
         # fmt: on
     )
Exemple #2
0
 def test_init_from_min_dspacing(self, ferrite_phase, min_dspacing, desired_size):
     assert (
         ReciprocalLatticePoint.from_min_dspacing(
             phase=ferrite_phase, min_dspacing=min_dspacing
         ).size
         == desired_size
     )
Exemple #3
0
 def test_gspacing_dspacing_scattering_parameter(self, ferrite_phase):
     rlp = ReciprocalLatticePoint.from_min_dspacing(
         phase=ferrite_phase, min_dspacing=2
     )
     # fmt: off
     assert np.allclose(
         rlp.gspacing,
         np.array([
             1.2084778, 1.04657248, 0.98671799, 0.85452285, 0.78006907, 0.69771498,
             0.604238, 0.493359, 0.34885749
         ])
     )
     assert np.allclose(
         rlp.dspacing,
         np.array([
             0.82748727, 0.9555, 1.01346079, 1.17024372, 1.28193777, 1.43325,
             1.65497455, 2.02692159, 2.8665
         ])
     )
     assert np.allclose(
         rlp.scattering_parameter,
         np.array([
             0.6042389, 0.52328624, 0.493359, 0.42726142, 0.39003453, 0.34885749,
             0.30211945, 0.2466795, 0.17442875
         ])
     )
Exemple #4
0
 def test_get_hkl(self, silicon_carbide_phase):
     rlp = ReciprocalLatticePoint.from_min_dspacing(
         silicon_carbide_phase, min_dspacing=3
     )
     assert np.allclose(rlp.h, [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0])
     assert np.allclose(rlp.k, [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0])
     assert np.allclose(rlp.l, [4, 3, 2, 1, 0, 4, 3, 2, 0, 4, 3, 2])
Exemple #5
0
 def test_repr(self, ferrite_phase):
     rlp = ReciprocalLatticePoint.from_min_dspacing(ferrite_phase, min_dspacing=2)
     assert repr(rlp) == (
         f"ReciprocalLatticePoint (9,)\n"
         f"Phase: ferrite (m-3m)\n"
         "[[2 2 2]\n [2 2 1]\n [2 2 0]\n [2 1 1]\n [2 1 0]\n [2 0 0]\n [1 1 1]\n"
         " [1 1 0]\n [1 0 0]]"
     )
Exemple #6
0
    def test_get_item(self, ferrite_phase):
        rlp = ReciprocalLatticePoint.from_min_dspacing(
            phase=ferrite_phase, min_dspacing=1.5
        )
        rlp.calculate_structure_factor()
        rlp.calculate_theta(voltage=20e3)

        assert rlp[0].size == 1
        assert rlp[:2].size == 2
        assert np.allclose(rlp[5:7].hkl.data, rlp.hkl[5:7].data)

        assert np.allclose(rlp[10:13].structure_factor, rlp.structure_factor[10:13])
        assert np.allclose(rlp[20:23].theta, rlp.theta[20:23])

        assert rlp.phase.space_group.number == rlp[0].phase.space_group.number
        assert rlp.phase.point_group.name == rlp[10:15].phase.point_group.name
        assert np.allclose(
            rlp.phase.structure.lattice.abcABG(),
            rlp[20:23].phase.structure.lattice.abcABG(),
        )
Exemple #7
0
 def test_allowed_raises(self, silicon_carbide_phase):
     with pytest.raises(NotImplementedError):
         _ = ReciprocalLatticePoint.from_min_dspacing(
             phase=silicon_carbide_phase, min_dspacing=1
         ).allowed
Exemple #8
0
    def geometrical_simulation(
        self,
        reciprocal_lattice_point: Optional[ReciprocalLatticePoint] = None
    ) -> GeometricalEBSDSimulation:
        """Project a set of Kikuchi bands and zone axes onto the
        detector, one set for each rotation of the unit cell.

        The zone axes are calculated from the Kikuchi bands.

        Parameters
        ----------
        reciprocal_lattice_point
            Crystal planes to project onto the detector. If None, and
            the generator has a phase with a unit cell with a point
            group, a set of planes with minimum distance of 1 Å and
            their symmetrically equivalent planes are used.

        Returns
        -------
        GeometricalEBSDSimulation

        Examples
        --------
        >>> from diffsims.crystallography import ReciprocalLatticePoint
        >>> simgen
        EBSDSimulationGenerator (1,)
        EBSDDetector (60, 60), px_size 1 um, binning 1, tilt 0, pc
        (0.5, 0.5, 0.5)
        <name: . space group: None. point group: None. proper point
        group: None. color: tab:blue>
        Rotation (1,)
        >>> sim1 = simgen.geometrical_simulation()
        >>> sim1.bands.size
        94
        >>> rlp = ReciprocalLatticePoint(
        ...     phase=simgen.phase, hkl=[[1, 1, 1], [2, 0, 0]]
        ... )
        >>> sim2 = simgen.geometrical_simulation()
        >>> sim2.bands.size
        13
        """
        rlp = reciprocal_lattice_point
        if rlp is None and (hasattr(self.phase.point_group, "name") and
                            hasattr(self.phase.structure.lattice, "abcABG")):
            rlp = ReciprocalLatticePoint.from_min_dspacing(self.phase,
                                                           min_dspacing=1)
            rlp = rlp[rlp.allowed].symmetrise()
        elif rlp is None:
            raise ValueError("A ReciprocalLatticePoint object must be passed")
        self._rlp_phase_is_compatible(rlp)

        # Unit cell parameters (called more than once)
        phase = rlp.phase
        hkl = rlp._hkldata

        # Get number of navigation dimensions and navigation axes
        # indices
        n_nav_dims = self.navigation_dimension
        navigation_axes = (1, 2)[:n_nav_dims]

        # Get Kikuchi band coordinates for all bands in all patterns
        # U_Kstar, transformation from detector frame D to reciprocal
        # crystal lattice frame Kstar.
        # Output shape is (3, n, 3) or (3, ny, nx, 3)
        det2recip = detector2reciprocal_lattice(
            sample_tilt=self.detector.sample_tilt,
            detector_tilt=self.detector.tilt,
            lattice=phase.structure.lattice,
            rotation=self.rotations,
        )
        # Output shape is (nhkl, n, 3) or (nhkl, ny, nx, 3)
        hkl_detector = np.tensordot(hkl, det2recip, axes=(1, 0))
        if n_nav_dims == 0:
            hkl_detector = hkl_detector.squeeze()
        # Get bands that are in some pattern
        hkl_is_upper, hkl_in_a_pattern = _get_coordinates_in_upper_hemisphere(
            z_coordinates=hkl_detector[..., 2],
            navigation_axes=navigation_axes)
        hkl = hkl[hkl_in_a_pattern, ...]
        hkl_in_pattern = hkl_is_upper[hkl_in_a_pattern, ...].T
        # Get coordinates in the proper shape
        hkl_detector = np.moveaxis(hkl_detector[hkl_in_a_pattern],
                                   source=0,
                                   destination=n_nav_dims)
        # And store it all
        bands = KikuchiBand(
            phase=phase,
            hkl=hkl,
            hkl_detector=hkl_detector,
            in_pattern=hkl_in_pattern,
            gnomonic_radius=self.detector.r_max,
        )

        # Get zone axes coordinates from Kikuchi bands
        uvw = _get_uvw_from_hkl(hkl=hkl)
        det2direct = detector2direct_lattice(
            sample_tilt=self.detector.sample_tilt,
            detector_tilt=self.detector.tilt,
            lattice=self.phase.structure.lattice,
            rotation=self.rotations,
        )
        uvw_detector = np.tensordot(uvw, det2direct, axes=(1, 0))
        if n_nav_dims == 0:
            uvw_detector = uvw_detector.squeeze()
        uvw_is_upper, uvw_in_a_pattern = _get_coordinates_in_upper_hemisphere(
            z_coordinates=uvw_detector[..., 2],
            navigation_axes=navigation_axes)
        uvw = uvw[uvw_in_a_pattern, ...]
        uvw_in_pattern = uvw_is_upper[uvw_in_a_pattern, ...].T
        uvw_detector = np.moveaxis(uvw_detector[uvw_in_a_pattern],
                                   source=0,
                                   destination=n_nav_dims)
        zone_axes = ZoneAxis(
            phase=phase,
            uvw=uvw,
            uvw_detector=uvw_detector,
            in_pattern=uvw_in_pattern,
            gnomonic_radius=self.detector.r_max,
        )

        return GeometricalEBSDSimulation(
            detector=self.detector,
            rotations=self.rotations,
            bands=bands,
            zone_axes=zone_axes,
        )
Exemple #9
0
    def geometrical_simulation(
        self,
        reciprocal_lattice_point: Optional[ReciprocalLatticePoint] = None,
    ) -> GeometricalEBSDSimulation:
        """Project a set of center positions of Kikuchi bands on the
        detector, one set for each rotation of the unit cell.

        Parameters
        ----------
        reciprocal_lattice_point :
            Crystal planes to project onto the detector. If None, and
            the generator has a phase with a unit cell with a point
            group, a set of planes with minimum distance of 1 Å and
            their symmetrically equivalent planes are used.

        Returns
        -------
        GeometricalEBSDSimulation

        Examples
        --------
        >>> from diffsims.crystallography import ReciprocalLatticePoint
        >>> simgen
        EBSDSimulationGenerator (1,)
        EBSDDetector (60, 60), px_size 1 um, binning 1, tilt 0, pc
        (0.5, 0.5, 0.5)
        <name: . space group: None. point group: None. proper point
        group: None. color: tab:blue>
        Rotation (1,)
        >>> sim1 = simgen.geometrical_simulation()
        >>> sim1.bands.size
        94
        >>> rlp = ReciprocalLatticePoint(
        ...     phase=simgen.phase, hkl=[[1, 1, 1], [2, 0, 0]]
        ... )
        >>> sim2 = simgen.geometrical_simulation()
        >>> sim2.bands.size
        13
        """
        rlp = reciprocal_lattice_point
        if rlp is None and (hasattr(self.phase.point_group, "name") and
                            hasattr(self.phase.structure.lattice, "abcABG")):
            rlp = ReciprocalLatticePoint.from_min_dspacing(self.phase,
                                                           min_dspacing=1)
            rlp = rlp[rlp.allowed].symmetrise()
        elif rlp is None:
            raise ValueError("A ReciprocalLatticePoint object must be passed")
        self._rlp_phase_is_compatible(rlp)

        # Unit cell parameters (called more than once)
        phase = rlp.phase
        hkl = rlp._hkldata

        # Get Kikuchi band coordinates for all bands in all patterns
        # U_Kstar, transformation from detector frame D to reciprocal crystal
        # lattice frame Kstar
        # TODO: Possible bottleneck due to large dot products! Room for
        #  lots of improvements with dask.
        # Output shape is (3, n, 3) or (3, ny, nx, 3)
        det2recip = detector2reciprocal_lattice(
            sample_tilt=self.detector.sample_tilt,
            detector_tilt=self.detector.tilt,
            lattice=phase.structure.lattice,
            rotation=self.rotations,
        )
        # Output shape is (nhkl, n, 3) or (nhkl, ny, nx, 3)
        band_coordinates = np.tensordot(hkl, det2recip, axes=(1, 0))

        # Determine whether a band is visible in a pattern
        upper_hemisphere = band_coordinates[..., 2] > 0
        nav_dim = self.navigation_dimension
        navigation_axes = (1, 2)[:nav_dim]
        is_in_some_pattern = np.sum(upper_hemisphere,
                                    axis=navigation_axes) != 0

        # Get bands that were in some pattern and their coordinates in the
        # proper shape
        hkl = hkl[is_in_some_pattern, ...]
        hkl_in_pattern = upper_hemisphere[is_in_some_pattern, ...].T
        band_coordinates = np.moveaxis(band_coordinates[is_in_some_pattern],
                                       source=0,
                                       destination=nav_dim)

        # And store it all
        bands = KikuchiBand(
            phase=phase,
            hkl=hkl,
            hkl_detector=band_coordinates,
            in_pattern=hkl_in_pattern,
            gnomonic_radius=self.detector.r_max,
        )

        # Get zone axes coordinates
        # U_K, transformation from detector frame D to direct crystal lattice
        # frame K
        #        det2direct = detector2direct_lattice(
        #            sample_tilt=self.detector.sample_tilt,
        #            detector_tilt=self.detector.tilt,
        #            lattice=phase.structure.lattice,
        #            orientation=self.orientations,
        #        )
        #        hkl_transposed_upper = hkl_transposed[..., upper_hemisphere]
        #        axis_coordinates = det2direct.T.dot(hkl_transposed_upper).T
        #        zone_axes = ZoneAxis(
        #            phase=phase, hkl=upper_hkl, coordinates=axis_coordinates
        #        )

        return GeometricalEBSDSimulation(
            detector=self.detector,
            rotations=self.rotations,
            bands=bands,
            #            zone_axes=zone_axes,
        )