Esempio n. 1
0
 def _set_properties(self):
     """
     Set properties.
     """
     cry_lat = CrystalLattice(lattice=self._lattice)
     self._reciprocal_lattice = cry_lat.reciprocal_lattice
     recip_cry_lat = CrystalLattice(lattice=self._reciprocal_lattice)
     self._reciprocal_abc = recip_cry_lat.abc
     self._reciprocal_volume = recip_cry_lat.volume
     try:
         check_hexagonal_lattice(self._lattice)
         self._is_hexagonal = True
     except AssertionError:
         pass
Esempio n. 2
0
 def _test_expansion():
     wyckoff = 'c'
     lattice, _, symbols = ti_cell_wyckoff_c
     shear_strain_ratio = 0.3
     twinmode = '11-21'
     expansion_ratios = np.array([1.1, 0.9, 1.2])
     shear_orig = ShearStructure(
         lattice=lattice,
         symbol=symbols[0],
         shear_strain_ratio=shear_strain_ratio,
         twinmode=twinmode,
         wyckoff=wyckoff,
     )
     shear_expand = ShearStructure(
         lattice=lattice,
         symbol=symbols[0],
         shear_strain_ratio=shear_strain_ratio,
         twinmode=twinmode,
         wyckoff=wyckoff,
     )
     shear_lattices = []
     shear_expand.set_expansion_ratios(expansion_ratios=expansion_ratios)
     for shr in [shear_orig, shear_expand]:
         shr.run(is_primitive=False)
         shear_lattice = shr.get_cell_for_export(
             get_lattice=False, move_atoms_into_unitcell=True)[0]
         shear_lattices.append(shear_lattice)
     shear_lattice_expand = CrystalLattice(
         lattice=shear_lattices[0]).get_expanded_lattice(
             expansion_ratios=expansion_ratios)
     np.testing.assert_allclose(shear_lattice_expand, shear_lattices[1])
Esempio n. 3
0
def get_neighbors(cell: tuple,
                  idx: int,
                  distance_cutoff: float,
                  get_distances: bool = False) -> list:
    """
    Get neighboring atoms from idx th atom.

    Args:
        cell (tuple): cell
        idx (int): index of specific atom
        distance_cutoff (float): distance cutoff
        get_distances (bool): if True, return also distances

    Returns:
        list: List of neighboring atoms. Each data contains
              atom_index in the first element and periorics
              in the remaining elements. If get_distances=True,
              this function also returns distances.
    """
    lattice = CrystalLattice(cell[0])
    periodics = np.floor(distance_cutoff / lattice.abc).astype(int)  # round up

    neighbors = []
    distances = []

    for i, posi in enumerate(cell[1]):
        grids = [[i for i in range(-(x + 1), (x + 2))] for x in periodics]
        for l, m, n in itertools.product(*grids):
            if i == idx and [l, m, n] == [0, 0, 0]:
                continue

            distance = lattice.get_distance(cell[1][idx],
                                            posi + np.array([l, m, n]))
            if distance < distance_cutoff:
                neighbors.append([i, l, m, n])
                distances.append(distance)

    # sort
    sort_idx = np.argsort(distances)
    distances = list(np.array(distances)[sort_idx])
    neighbors = list(np.array(neighbors)[sort_idx])
    neighbors = list(map(tuple, neighbors))

    if get_distances:
        return (neighbors, distances)

    return neighbors
Esempio n. 4
0
    def get_relaxplot(self, start_step:int=1) -> RelaxPlot:
        """
        Get RelaxPlot class object.

        Args:
            start_step: The step number of the first relax in this WorkChain.
                        If you relax 20 steps in the privious RelaxWorkChain,
                        for example, start_step becomes 21.

        Returns:
            RelaxPlot: RelaxPlot class object.
        """
        relax_vasps, static_vasp = self.get_vasp_calculations()
        relax_data = {}
        relax_data['max_force'] = \
                np.array([ relax_vasp.get_max_force()
                               for relax_vasp in relax_vasps ])
        # stress xx yy zz yz zx xy
        relax_data['stress'] = \
                np.array([ relax_vasp.stress.flatten()[[0,4,8,5,6,1]]
                               for relax_vasp in relax_vasps ])
        relax_data['energy'] = \
                np.array([ relax_vasp.energy
                               for relax_vasp in relax_vasps ])
        relax_data['abc'] = \
                np.array([ CrystalLattice(relax_vasp.final_cell[0]).abc
                               for relax_vasp in relax_vasps ])
        relax_data['step_energies_collection'] = \
                [ relax_vasp.step_energies for relax_vasp in relax_vasps ]

        if static_vasp is None:
            static_data = None
        else:
            static_data = {
                    'max_force': static_vasp.get_max_force(),
                    'stress': static_vasp.stress.flatten()[[0,4,8,5,6,1]] ,
                    'energy': static_vasp.energy,
                    'abc': CrystalLattice(static_vasp.initial_cell[0]).abc,
                    }

        relax_plot = RelaxPlot(relax_data=relax_data,
                               static_data=static_data,
                               start_step=start_step)

        return relax_plot
Esempio n. 5
0
 def _set_shear_strain_ratio_Rodney():
     """
     Set shear strain ratio based on Rodney.
     """
     self._set_lattice(shear_strain_ratio=0.)  # initialize
     crylat = CrystalLattice(lattice=self._lattice)
     _, b, c = crylat.abc
     l = b / self._b_replicate * step_range
     burg = self._burg_vec[1]
     s = burg * l / (2 * b * c)
     self._shear_strain_ratio = s
     self._set_lattice(self._shear_strain_ratio)
Esempio n. 6
0
 def _set_shear_strain_ratio_half():
     """
     Set shear strain ratio based on half.
     """
     self._set_lattice(shear_strain_ratio=0.)  # initialize
     crylat = CrystalLattice(lattice=self._lattice)
     _, b, c = crylat.abc
     interval = c / ((self._twinboundary.layers + 1) * 2)
     print(c)
     ratio = interval / c
     self._shear_strain_ratio = ratio
     print(ratio)
     self._set_lattice(ratio)
Esempio n. 7
0
def write_thermal_ellipsoid(cell: tuple,
                            matrices: np.array,
                            temperatures: list,
                            filetype: str = 'CrystalMaker',
                            header: str = ''):
    """
    Write thermal ellipsoid.

    Args:
        cell: (lattice, scaled_positions, symbols).
        matrices: Thermal ellipsoid.
        temperatures: Temperature list.
        filetype: Currently only 'CrystalMaker' is supported.
        header: Header of filename.
    """
    if filetype != 'CrystalMaker':
        raise ValueError("Only filetype='CrystalMaker' is supported.")
    lines = []
    lattice = CrystalLattice(cell[0])
    abc = lattice.abc
    abc_str = ' '.join(map(str, list(abc)))
    angles = lattice.angles
    angles_str = ' '.join(map(str, list(angles)))
    cell_str = "CELL {} {}".format(abc_str, angles_str)
    lines.append(cell_str)
    lines.append("")
    lines.append("ATOM")

    # crystal maker => xx yy zz xy xz yz
    tensor_idx = [[0, 0], [1, 1], [2, 2], [0, 1], [0, 2], [1, 2]]

    for i in range(len(cell[2])):
        frac_str = ' '.join(map(str, list(cell[1][i])))
        lines.append("{} {} {}".format(cell[2][i], cell[2][i] + str(i + 1),
                                       frac_str))
    lines.append("")
    lines.append("UANI")
    for i, temp in enumerate(temperatures):
        temp_lines = deepcopy(lines)
        for j in range(len(cell[2])):
            mat = np.round(matrices[i, j], decimals=4)
            tensor = [str(mat.item(*idx)) for idx in tensor_idx]
            tensor_str = ' '.join(tensor)
            temp_lines.append("{} {}".format(cell[2][j] + str(1 + j),
                                             tensor_str))

        strings = '\n'.join(temp_lines)
        filename = header + "temp{}K.cmtx".format(temp)
        with open(filename, 'w') as f:
            f.write(strings)
Esempio n. 8
0
    def __init__(
        self,
        lattice: np.array,
        symbol: str,
        twinmode: str,
        wyckoff: str = 'c',
    ):
        """
        Setup.

        Args:
            lattice: Lattice.
            symbol: Element symbol.
            twinmode: Twin mode.
            wyckoff: No.194 Wycoff letter ('c' or 'd').

        Todo:
            Check it is best to use 'deepcopy'.
        """
        atoms_from_lp = get_hcp_atom_positions(wyckoff)
        symbols = [symbol] * 2
        crylat = CrystalLattice(lattice=lattice)
        check_cell_is_hcp(cell=(lattice, atoms_from_lp, symbols))
        self._hexagonal_lattice = lattice
        self._a, _, self._c = crylat.abc
        self._r = self._c / self._a
        self._symbol = symbol
        self._wyckoff = wyckoff
        self._atoms_from_lattice_points = \
                get_hcp_atom_positions(wyckoff=self._wyckoff)
        self._natoms = 2
        self._twinmode = None
        self._indices = None
        self._set_twinmode(twinmode=twinmode)
        self._xshift = None
        self._yshift = None
        self._expansion_ratios = np.ones(3)
        self._output_structure = \
                {'lattice': self._hexagonal_lattice,
                 'lattice_points': {
                     'white': np.array([0.,0.,0.])},
                 'atoms_from_lattice_points': {
                     'white': self._atoms_from_lattice_points},
                 'symbols': [self._symbol] * 2}
Esempio n. 9
0
 def _set_shear_strain_ratios(self):
     """
     Set shear strain ratios.
     """
     hex_lat = \
         self._aiida_twinboundary_relax.cells['hexagonal'][0]
     crylat = CrystalLattice(hex_lat)
     a, _, c = crylat.abc
     r = c / a
     twinmode = self._aiida_twinboundary_relax.twinboundary_structure.twinmode
     func = get_shear_strain_function(twinmode)
     gamma = func(r)
     conf = self._node.inputs.twinboundary_shear_conf.get_dict()
     if conf['is_ratio']:
         self._shear_strain_ratios = conf['shear_strain']
         self._shear_strain = \
                 [ ratio * gamma for ratio in conf['shear_strain'] ]
     else:
         self._shear_strain = conf['shear_strain']
         self._shear_strain_ratios = \
                 [ s / gamma for s in conf['shear_strain'] ]
Esempio n. 10
0
def check_hexagonal_lattice(lattice: np.array):
    """
    Check input lattice is hexagonal lattice.

    Args:
        lattice: Lattice matrix.

    Raises:
        AssertionError: The angles are not (90, 90, 120).

    Note:
        Check the angles of input lattice are (90, 90, 120).
    """
    hexagonal = CrystalLattice(lattice)
    expected = np.array([90., 90., 120.])
    actual = hexagonal.angles
    err_msg = "The angles of lattice was {}, \
               which does not match [90., 90., 120.]".format(actual)
    np.testing.assert_allclose(
        actual,
        expected,
        err_msg=err_msg,
    )
Esempio n. 11
0
def _get_atomic_environment(cell: tuple, layer_indices: list) -> tuple:
    """
    Get plane coords from lower plane to upper plane.
    Return list of z coordinates of original cell frame.
    Plane coordinates (z coordinates) are fractional.

    Args:
        cell (np.array): (lattice, scaled_positions, symbols).
        layer_indices (list): List of layer indices.

    Returns:
        tuple: (planes, distances, angles)
    """
    lattice = CrystalLattice(cell[0])
    angles = lattice.angles
    np.testing.assert_allclose(
        angles[1:], [90., 90.],
        err_msg="Angles of lattice is {}. "
        "Angle beta and gamma must be 90 degree.".format(angles))
    sine = lattice.sin_angles[0]
    plane_z_coords = []
    distances = []
    previous_z_coord = 0.
    angles = []
    pair_distances = []
    c_norm = np.linalg.norm(cell[0], axis=1)[2]
    for i, indices in enumerate(layer_indices):
        pair_atoms = cell[1][indices, :]
        pair_diff = lattice.get_diff(first_coord=pair_atoms[0],
                                     second_coord=pair_atoms[1],
                                     is_cartesian=False,
                                     with_periodic=True)
        pair_distance = lattice.get_norm(coord=pair_diff,
                                         is_cartesian=False,
                                         with_periodic=True)
        pair_distances.append(pair_distance)
        lattice_point = lattice.get_midpoint(
            first_coord=pair_atoms[0],
            second_coord=pair_atoms[1],
            with_periodic=True,
        )
        if i == 0:
            if lattice_point[2] > 0.9:
                lattice_point[2] = lattice_point[2] - 1.
        elif i == len(layer_indices) - 1:
            if lattice_point[2] < 0.1:
                lattice_point[2] = lattice_point[2] + 1.
        plane_z_coord = c_norm * lattice_point[2] * sine
        plane_z_coords.append(plane_z_coord)

        if i > 0:
            d = plane_z_coord - previous_z_coord
            distances.append(d)
            previous_z_coord = plane_z_coord

    # # angles
        diff = lattice.get_diff(
            first_coord=pair_atoms[0],
            second_coord=pair_atoms[1],
            is_cartesian=False,
            with_periodic=True,
        )
        diff_cart = np.dot(lattice.lattice.T, diff)
        cos = diff_cart[1] / np.linalg.norm(diff_cart)
        angle = np.arccos(cos) * 180 / np.pi % 180
        angles.append(angle)
    angles = np.array(angles)
    angles = np.where(angles > 90., angles - 180, angles)
    angles = np.abs(angles)
    distances.append(lattice.abc[2] * sine - plane_z_coords[-1])

    return (list(plane_z_coords), list(distances), list(angles),
            pair_distances)
Esempio n. 12
0
def write_crystal_maker(
    modulation,
    multiply: float = 1.,
    color_sets=[1, 0, 0],
    dirname='.',
    origin_shift=[0, 0, 0],
    is_minus=False,
):
    import os
    from twinpy.structure.lattice import CrystalLattice
    import itertools

    base_cell = get_cell_from_phonopy_structure(
        modulation._modulation._primitive)
    super_cell = \
        get_cell_from_phonopy_structure(modulation._modulation._supercell)
    supercell_mat = modulation._modulation._supercell.supercell_matrix.diagonal(
    )
    for j, disp in enumerate(modulation._displacements):
        filename = os.path.join(dirname, '%d.cmtx' % j)
        cell = super_cell

        lines = []
        lattice = CrystalLattice(cell[0])
        abc = lattice.abc
        abc_str = ' '.join(map(str, list(abc)))
        angles = lattice.angles
        angles_str = ' '.join(map(str, list(angles)))
        cell_str = "CELL {} {}".format(abc_str, angles_str)
        lines.append(cell_str)
        lines.append("")
        cell_range = [0, 1, 0, 1, 0, 1]
        cell_range_str = ' '.join(map(str, cell_range))
        lines.append("XYZR %s" % cell_range_str)
        lines.append("")
        lines.append("ATOM")
        lines.append("")

        for i in range(len(cell[2])):
            frac_str = ' '.join(
                map(str, list((cell[1][i] + np.array(origin_shift)) % 1)))
            lines.append("{} {} {}".format(cell[2][i], cell[2][i] + str(i + 1),
                                           frac_str))
        lines.append("")
        lines.append("! Atom vectors")
        lines.append("AVEC")

        color_str = ' '.join(map(str, list(color_sets)))

        norms = []
        for i in range(len(cell[2])):
            amplitude = modulation._phonon_modes[j][2]
            frac_str = ' '.join(
                map(str, list((cell[1][i] + np.array(origin_shift)) % 1)))
            egn = np.linalg.norm(disp[i].real)
            eigen_str = ' '.join(
                map(str, list(np.round(disp[i].real / egn, decimals=6))))
            norm = np.linalg.norm(disp[i].real) * multiply
            norms.append(norm)
            norm_str = str(norm)
            # 1 0 0 => red, 1 => vector style
            lines.append("{} {} {} {} {}  1".format(cell[2][i] + str(i + 1),
                                                    frac_str, eigen_str,
                                                    norm_str, color_str))

            strings = '\n'.join(lines)
        print("Max norm: {}".format(max(norms)))

        with open(filename, 'w') as f:
            f.write(strings)
Esempio n. 13
0
    def __init__(
        self,
        lattice: np.array,
        twinmode: str,
        wyckoff: str,
    ):
        """
        Get twin indices of input twinmode.
        Twinmode must be '10-11', '10-12', '11-21' or '11-22'.

        Args:
            lattice: Hexagonal lattice matrix.
            twinmode: Currently supported \
                            '10-11', '10-12', '11-22' and '11-21'.
            wyckoff: Wyckoff letter, 'c' or 'd'.

        Returns:
            dict: Twin indices.

        Note:
            You can find customs how to set the four indices
            in the paper 'DEFORMATION TWINNING' by Christian (1995).
            Abstruct is as bellow

              1. Vector m normal to shear plane,
                 eta1 and eta2 form right hand system.
              2. The angle between eta1 and eta2 are abtuse.
              3. The angle between eta1 and k2 are acute.
              4. The angle between eta2 and k1 are acute.
                 Additional rule:
              5. K1 plane depends on wyckoff 'c' or 'd'
                 because in the case of {10-12}, either (10-12) or (-1012)
                 is chosen based on which plane are nearer to the neighbor
                 atoms

            In this algorithm, indices are set in order of

              a. k1    condition(5)
              b. eta2  condition(4)
              c. eta1  condition(2)
              d. k2    condition(3)
              e. m     condition(1)

        Todo:
            _twin_indices_orig is a little bit
            different from the ones 1981. Yoo especially 'S'.
        """
        check_hexagonal_lattice(lattice)
        check_supported_twinmode(twinmode)
        self._lattice = lattice
        self._crylat = CrystalLattice(self._lattice)
        self._twinmode = twinmode
        self._layers = get_number_of_layers(twinmode)
        self._atom_num_per_layer = get_number_of_atoms_per_layer(twinmode)
        self._wyckoff = wyckoff
        self._indices_Yoo = self._get_indices_Yoo()
        self._indices = deepcopy(self._indices_Yoo)
        self._set_K1()
        self._set_k1_k2()
        self._reset_indices()
        self._set_shear_plane()
Esempio n. 14
0
class TwinIndices():
    """
    Deals with twin indices.
    """
    def __init__(
        self,
        lattice: np.array,
        twinmode: str,
        wyckoff: str,
    ):
        """
        Get twin indices of input twinmode.
        Twinmode must be '10-11', '10-12', '11-21' or '11-22'.

        Args:
            lattice: Hexagonal lattice matrix.
            twinmode: Currently supported \
                            '10-11', '10-12', '11-22' and '11-21'.
            wyckoff: Wyckoff letter, 'c' or 'd'.

        Returns:
            dict: Twin indices.

        Note:
            You can find customs how to set the four indices
            in the paper 'DEFORMATION TWINNING' by Christian (1995).
            Abstruct is as bellow

              1. Vector m normal to shear plane,
                 eta1 and eta2 form right hand system.
              2. The angle between eta1 and eta2 are abtuse.
              3. The angle between eta1 and k2 are acute.
              4. The angle between eta2 and k1 are acute.
                 Additional rule:
              5. K1 plane depends on wyckoff 'c' or 'd'
                 because in the case of {10-12}, either (10-12) or (-1012)
                 is chosen based on which plane are nearer to the neighbor
                 atoms

            In this algorithm, indices are set in order of

              a. k1    condition(5)
              b. eta2  condition(4)
              c. eta1  condition(2)
              d. k2    condition(3)
              e. m     condition(1)

        Todo:
            _twin_indices_orig is a little bit
            different from the ones 1981. Yoo especially 'S'.
        """
        check_hexagonal_lattice(lattice)
        check_supported_twinmode(twinmode)
        self._lattice = lattice
        self._crylat = CrystalLattice(self._lattice)
        self._twinmode = twinmode
        self._layers = get_number_of_layers(twinmode)
        self._atom_num_per_layer = get_number_of_atoms_per_layer(twinmode)
        self._wyckoff = wyckoff
        self._indices_Yoo = self._get_indices_Yoo()
        self._indices = deepcopy(self._indices_Yoo)
        self._set_K1()
        self._set_k1_k2()
        self._reset_indices()
        self._set_shear_plane()

    @property
    def lattice(self):
        """
        Lattice matrix.
        """
        return self._lattice

    @property
    def twinmode(self):
        """
        Twinmode.
        """
        return self._twinmode

    @property
    def layers(self):
        """
        Number of layers.
        """
        return self._layers

    @property
    def atom_num_per_layer(self):
        """
        Number of atoms per layer.
        """
        return self._atom_num_per_layer

    @property
    def wyckoff(self):
        """
        Wyckoff.
        """
        return self._wyckoff

    @property
    def indices_Yoo(self):
        """
        Indices Yoo showed.
        """
        return self._indices_Yoo

    @property
    def indices(self):
        """
        Indices.
        """
        return self._indices

    def _get_indices_Yoo(self) -> dict:
        """
        Get specific twinmode indices which are found in Yoo's paper.

        Returns:
            dict: indices by Yoo
        """
        indices_ = get_twin_indices_by_Yoo()[self._twinmode]
        indices = {}
        for plane in ['S', 'K1', 'K2']:
            indices[plane] = HexagonalPlane(lattice=self._lattice,
                                            four=indices_[plane])
        for direction in ['eta1', 'eta2']:
            indices[direction] = HexagonalDirection(lattice=self._lattice,
                                                    four=indices_[direction])
        return indices

    def _set_K1(self):
        """
        Set K1.

        Note:
            There are two candidates for K1 plane.
            One is the K1 plane (defimed as (hkil) plane)
            which is found in Yoo's paper, and
            the other is (-h-k-il) plane.
            The plane which has shorter dictance from nearest atoms
            is set as K1 plane.
            If (-h-k-il) is determined, every other planes and directions
            are fixed by multiplied (-1, -1, -1, 1).
        """
        arr = np.array([-1, -1, -1, 1])
        atoms = get_hcp_atom_positions(wyckoff=self.wyckoff)
        K1_1 = self._indices['K1']
        K1_2 = deepcopy(K1_1)
        K1_2.reset_indices(four=K1_2.four * arr)
        if K1_1.get_distance_from_plane(atoms[0]) > \
               K1_2.get_distance_from_plane(atoms[0]):
            for key in ['S', 'K1', 'K2', 'eta1', 'eta2']:
                self._indices[key].reset_indices(four=self._indices[key].four *
                                                 arr)

    def _set_k1_k2(self):
        """
        Set k1 and k2.
        """
        self._indices['k1'] = \
                self._indices['K1'].get_direction_normal_to_plane(
                        normalize=False)
        self._indices['k2'] = \
                self._indices['K2'].get_direction_normal_to_plane(
                        normalize=False)

    def _reset_indices(self):
        """
        Reset indices.

        Raises:
            AssertionError: k1 is not orthogonal to eta1
            AssertionError: k2 is not orthogonal to eta2

        Note:
            conditions are as bellow

            - if the angle between k1 and eta2 is obtuse, eta2 -> -eta2
            - if the angle between eta1 and eta2 is acute, eta1 -> -eta1
            - if the angle between eta1 and k2 is obtuse, k2 -> -k2
            - check k1 is orthogonal to eta1
            - check k2 is orthogonal to eta2
        """
        # reset eta2
        if self._crylat.dot(self._indices['k1'].three,
                            self._indices['eta2'].three) < 0:
            self._indices['eta2'].inverse()

        # reset eta1
        if self._crylat.dot(self._indices['eta1'].three,
                            self._indices['eta2'].three) > 0:
            self._indices['eta1'].inverse()

        # reset K2
        if self._crylat.dot(self._indices['eta1'].three,
                            self._indices['k2'].three) < 0:
            self._indices['K2'].inverse()
            self._indices['k2'].inverse()

        # check k1 is orthogonal to eta1
        np.testing.assert_allclose(actual=self._crylat.dot(
            self._indices['k1'].three, self._indices['eta1'].three),
                                   desired=0,
                                   atol=1e-6,
                                   err_msg="k1 is not orthogonal to eta1")

        # check k2 is orthogonal to eta2
        np.testing.assert_allclose(actual=self._crylat.dot(
            self._indices['k2'].three, self._indices['eta2'].three),
                                   desired=0,
                                   atol=1e-6,
                                   err_msg="k2 is not orthogonal to eta2")

    def _set_shear_plane(self):
        """
        Set shear plane.

        Raises:
            RuntimeError: Could not find shear plane.

        Note:
            Set shear plane which fulfill the following conditions
            from six candidates
            ((hkil), (hikl), (khil), (kihl), (ihkl), (ikhl)).
        """
        S_four = self._indices['S'].four
        perms = map(list, permutations((0, 1, 2)))
        trial_S_fours = [[S_four[i] for i in lst + [3]] for lst in perms]
        normal_directions = ['k1', 'k2', 'eta1', 'eta2']
        flag = 1
        for trial_S_four in trial_S_fours:
            trial_S = HexagonalPlane(self._lattice,
                                     four=np.array(trial_S_four, dtype='intc'))
            trial_m = trial_S.get_direction_normal_to_plane(normalize=False)
            dots = [
                self._crylat.dot(trial_m.three, self._indices[direction].three)
                for direction in normal_directions
            ]
            if np.allclose(np.array(dots), np.zeros(4), atol=1e-4):
                flag = 0
                break
        if flag == 1:
            raise RuntimeError("could not find shear plane")

        triple_product = \
                np.dot(trial_m.get_cartesian(),
                       np.cross(self._indices['eta1'].get_cartesian(),
                                self._indices['eta2'].get_cartesian()))
        if triple_product < 0:
            trial_S.inverse()
            trial_m.inverse()
        self._indices['S'] = trial_S
        self._indices['m'] = trial_m

    def get_supercell_matrix_for_parent(self) -> np.array:
        """
        Get supercell matrix for creating parent matrix.

        Returns:
            np.array: Sueprcell matrix.

        Note:
            Create lattice basis with integerized m, eta1 and eta2.
        """
        tf1 = np.array(get_ratio(self._indices['m'].three))
        tf2 = np.array(get_ratio(self._indices['eta1'].three))
        tf3 = np.array(get_ratio(self._indices['eta2'].three))
        supercell_matrix = np.vstack([tf1, tf2, tf3]).T

        return supercell_matrix

    def get_shear_strain_function(self):
        """
        Get shear strain function.
        """
        return get_shear_strain_function(self._twinmode)
Esempio n. 15
0
def get_structure_diff(cells: list,
                       base_index: int = 0,
                       include_base: bool = True) -> dict:
    """
    Get structure diff with first cell in cells.

    Args:
        cells: List of cells.
        base_index: Base cell index.
        include_base: If True, include base cell in output dict.

    Returns:
        dict: Containing 'lattice_diffs', 'frac_posi_diffs',
              'cart_posi_diffs' and 'cart_norm_diffs'.

    Note:
        Return diff compared with base cell.
        ex. lattice_diffs[i] = ith_lattice - base_lattice.
        The value 'frac_posi_diffs' are the difference between two
        fractional coordinates which is not consider lattice change,
        which can be defined as 'shuffle'.
        The value 'cart_posi_diffs' are the difference between two
        cartesian coordinates which is automatically consider lattice
        periodicity.
    """
    cart_posis = [
        np.dot(cells[i][0].T, cells[i][1].T).T for i in range(len(cells))
    ]
    base_lat, base_frac_posi, _ = cells[base_index]
    base_cart_posi = cart_posis[base_index]
    lattice_diffs = [cell[0] - base_lat for cell in cells]
    _frac_posi_diffs = [
        np.round(cell[1] - base_frac_posi, decimals=8) for cell in cells
    ]
    frac_posi_diffs = [
        np.where(diff > 0.5, diff - 1, diff) for diff in _frac_posi_diffs
    ]

    cart_posi_diffs = []
    for cell, cart_posi in zip(cells, cart_posis):
        lattice = CrystalLattice(lattice=cell[0])
        diff = lattice.get_diff(first_coords=base_cart_posi,
                                second_coords=cart_posi,
                                is_cartesian=True,
                                with_periodic=True)
        cart_posi_diffs.append(np.dot(lattice.lattice.T, diff.T).T)

    cart_norm_diffs = [
        np.linalg.norm(cart_posi_diff, axis=1)
        for cart_posi_diff in cart_posi_diffs
    ]

    if not include_base:
        del lattice_diffs[base_index]
        del frac_posi_diffs[base_index]
        del cart_posi_diffs[base_index]
        del cart_norm_diffs[base_index]

    return {
        'lattice_diffs': np.array(lattice_diffs),
        'frac_posi_diffs': np.array(frac_posi_diffs),
        'cart_posi_diffs': np.array(cart_posi_diffs),
        'cart_norm_diffs': np.array(cart_norm_diffs),
    }
Esempio n. 16
0
def test_lattice(ti_cell_wyckoff_c):
    """
    Check Lattice.

    Todo:
        Write test for 'get_diff' and get_midpoint
        after refactering.
    """
    def _test_reciprocal_lattice(crylat):
        _direct_lattice = crylat.lattice
        _recip_lattice_expected = crylat.reciprocal_lattice

        recip_bases = []
        for i in range(3):
            j = (i + 1) % 3
            k = (i + 2) % 3
            recip_bases.append(
                np.cross(_direct_lattice[j], _direct_lattice[k])
                / crylat.volume)
        _recip_lattice = np.array(recip_bases)
        np.testing.assert_allclose(_recip_lattice, _recip_lattice_expected)

    def _test_abc_angles_cos_angles_dot(crylat):
        """
        check dot
        """
        v1 = np.array([1. ,0., 0.])
        v2 = np.array([0. ,1., 0.])
        _abc = crylat.abc
        _cos_angles = crylat.cos_angles
        _inner_product = crylat.dot(first_coord=v1,
                                    second_coord=v2,
                                    is_cartesian=False)
        _inner_product_expected = \
                _abc[0] * _abc[1] * _cos_angles[2]
        np.testing.assert_allclose(_inner_product, _inner_product_expected)

    def _test_convert_coordinate(crylat):
        """
        check convert_fractional_to_cartesian
        check convert_cartesian_to_fractional
        """
        a, _, c = crylat.abc
        v1_frac = np.array([0., 0., 0.5])
        v2_frac = np.array([[0., 0., 0.5],
                            [1., 0., 0. ]])
        v1_cart_expected = np.array([0., 0., c/2])
        v2_cart_expected = np.array([[0., 0., c/2],
                                     [a,  0.,  0.]])
        _v1_cart = crylat.convert_fractional_to_cartesian(frac_coords=v1_frac)
        _v2_cart = crylat.convert_fractional_to_cartesian(frac_coords=v2_frac)
        _v1_frac = crylat.convert_cartesian_to_fractional(cart_coords=_v1_cart)
        _v2_frac = crylat.convert_cartesian_to_fractional(cart_coords=_v2_cart)
        np.testing.assert_allclose(_v1_cart, v1_cart_expected)
        np.testing.assert_allclose(_v2_cart, v2_cart_expected)
        np.testing.assert_allclose(_v1_frac, v1_frac)
        np.testing.assert_allclose(_v2_frac, v2_frac)

    def _test_get_norm(crylat):
        _a_norm_expected = crylat.abc[0]
        _a_frac = np.array([1., 0., 0.])
        _a_cart = np.array([_a_norm_expected,0.,0.])
        _a_norm_from_frac = crylat.get_norm(coord=_a_frac,
                                            is_cartesian=False,
                                            with_periodic=False)
        _a_norm_from_cart = crylat.get_norm(coord=_a_cart,
                                            is_cartesian=True,
                                            with_periodic=False)
        np.testing.assert_allclose(_a_norm_from_frac, _a_norm_expected)
        np.testing.assert_allclose(_a_norm_from_cart, _a_norm_expected)

    def _test_expanded_lattice(crylat):
        _dim = np.array([2,3,4])
        _sup_lat = crylat.get_expanded_lattice(expansion_ratios=_dim)
        _sup_lat_expected = crylat.lattice.copy()
        for i in range(3):
            _sup_lat_expected[i] *= _dim[i]
        np.testing.assert_allclose(_sup_lat, _sup_lat_expected)

    hex_lattice = ti_cell_wyckoff_c[0]
    hex_crylat = CrystalLattice(lattice=hex_lattice)

    _test_reciprocal_lattice(crylat=hex_crylat)
    _test_abc_angles_cos_angles_dot(crylat=hex_crylat)
    _test_convert_coordinate(crylat=hex_crylat)
    _test_get_norm(crylat=hex_crylat)
    _test_expanded_lattice(crylat=hex_crylat)
Esempio n. 17
0
def plot_nearest_atomic_distance_of_twinboundary(
        lattice: np.array,
        symbol: str,
        twinmode: str,
        layers: int,
        wyckoff: str = 'c',
        delta: float = 0.,
        twintype: int = 1,
        xshift: float = 0.,
        yshift: float = 0.,
        shear_strain_ratio: float = 0.,
        expansion_ratios: np.array = np.ones(3),
        make_tb_flat: bool = True,
):
    """
    Show nearest atomic distance of twinboundary
    by changing xshift and yshift.

    Args:
        lattice: Lattice matrix.
        symbol: Element symbol.
        twinmode: Twinmode.
        layers: The number of layers.
        wyckoff: No.194 Wycoff position ('c' or 'd').
        delta: Additional interval both sites of twin boundary.
        twintype: Twintype, choose from 1 and 2.
        shear_strain_ratio (float): Shear twinboundary ratio.
        expansion_ratios: Expansion ratios.
        make_tb_flat: If True, atoms on the twin boundary plane are
                      projected to twin boundary.
    """
    import matplotlib.pyplot as plt
    from twinpy.structure.bonding import get_nearest_atomic_distance
    from twinpy.structure.lattice import CrystalLattice

    tb = TwinBoundaryStructure(lattice=lattice,
                               symbol=symbol,
                               twinmode=twinmode,
                               twintype=twintype,
                               wyckoff=wyckoff)
    tb.set_expansion_ratios(expansion_ratios)

    x = np.arange(0, 1.025, 0.025)
    y = np.arange(0, 1.025, 0.025)

    X, Y = np.meshgrid(x, y)
    shape = X.shape
    Z = np.zeros(shape)

    for i in range(shape[0]):
        for j in range(shape[1]):
            tb.run(layers=layers,
                   delta=delta,
                   xshift=X[i, j],
                   yshift=Y[i, j],
                   shear_strain_ratio=shear_strain_ratio,
                   make_tb_flat=make_tb_flat)
            cell = tb.get_cell_for_export()
            Z[i, j] = get_nearest_atomic_distance(cell)

    a, b, _ = CrystalLattice(lattice=cell[0]).abc
    fig = plt.figure(figsize=(4, 4 * b / a))
    cont = plt.contour(X, Y, Z, 5, vmin=0, vmax=4, colors=['black'])
    cont.clabel(fmt='%1.1f')

    plt.xlabel('xshift')
    plt.ylabel('yshift')

    plt.pcolormesh(X, Y, Z, cmap='cool')
    pp = plt.colorbar(orientation="vertical")
    pp.set_label("Nearest Atomic Distance")

    plt.show()