Ejemplo n.º 1
0
def get_fourth_order_displacements(cell,
                                   symmetry,
                                   is_plusminus='auto',
                                   is_diagonal=False):
    # Atoms 1, 2, and 3 are defined as follows:
    #
    # Atom 1: The first displaced atom. Fourth order force constant
    #         between Atoms 1, 2, 3, and 4 is calculated.
    # Atom 2: The second displaced atom. Third order force constant
    #         between Atoms 2, 3, and 4 is calculated.
    # Atom 3: The third displaced atom. Second order force constant
    #         between Atoms 3 and 4 is calculated.
    # Atom 4: Force is mesuared on this atom.

    # Least displacements for third order force constants
    #
    # Data structure
    # [{'number': atom1,
    #   'displacement': [0.00000, 0.007071, 0.007071],
    #   'second_atoms': [ {'number': atom2,
    #                      'displacement': [0.007071, 0.000000, 0.007071],
    #                      'third_atoms': [ {'number': atom3,
    #                                        'displacements':
    #                                       [[-0.007071, 0.000000, -0.007071],
    #                                        ,...]}, {...}, ... ]},

    # Least displacements of first atoms (Atom 1) are searched by
    # using respective site symmetries of the original crystal.
    disps_first = get_least_displacements(symmetry,
                                          is_plusminus=is_plusminus,
                                          is_diagonal=False)

    symprec = symmetry.get_symmetry_tolerance()

    dds = []
    for disp in disps_first:
        atom1 = disp[0]
        disp1 = disp[1:4]
        site_sym = symmetry.get_site_symmetry(atom1)

        dds_atom1 = {'number': atom1, 'direction': disp1, 'second_atoms': []}
        reduced_site_sym = get_reduced_site_symmetry(site_sym, disp1, symprec)
        second_atoms = get_least_orbits(atom1, cell, reduced_site_sym, symprec)

        for atom2 in second_atoms:
            reduced_bond_sym = get_bond_symmetry(reduced_site_sym,
                                                 cell.get_scaled_positions(),
                                                 atom1, atom2, symprec)

            for disp2 in _get_displacements_second(reduced_bond_sym, symprec,
                                                   is_diagonal):
                dds_atom2 = _get_second_displacements(atom2, disp2, cell,
                                                      reduced_bond_sym,
                                                      symprec, is_diagonal)
                dds_atom1['second_atoms'].append(dds_atom2)
        dds.append(dds_atom1)

    write_supercells_with_three_displacements(cell, dds)

    return dds
Ejemplo n.º 2
0
def _get_second_displacements(atom2,
                              disp2,
                              cell,
                              reduced_bond_sym,
                              symprec,
                              is_diagonal):
    positions = cell.get_scaled_positions()
    dds_atom2 = {'number': atom2,
                 'direction': disp2,
                 'third_atoms': []}
    reduced_bond_sym2 = get_reduced_site_symmetry(reduced_bond_sym,
                                                  disp2,
                                                  symprec)
    third_atoms = get_least_orbits(atom2,
                                   cell,
                                   reduced_bond_sym2,
                                   symprec)

    for atom3 in third_atoms:
        reduced_plane_sym = get_bond_symmetry(
            reduced_bond_sym2,
            cell.get_scaled_positions(),
            atom2,
            atom3,
            symprec)
        dds_atom3 = get_next_displacements(atom2,
                                           atom3,
                                           reduced_plane_sym,
                                           positions,
                                           symprec,
                                           is_diagonal)
        dds_atom2['third_atoms'].append(dds_atom3)

    return dds_atom2
Ejemplo n.º 3
0
    def _get_reduced_bond_sym(self, reduced_site_sym, first_atom_num,
                              second_atom_num, disp2):
        bond_sym = get_bond_symmetry(reduced_site_sym, self._positions,
                                     first_atom_num, second_atom_num,
                                     self._symprec)
        direction = np.dot(np.linalg.inv(self._lattice), disp2)
        reduced_bond_sym = get_reduced_site_symmetry(bond_sym, direction,
                                                     self._symprec)

        return reduced_bond_sym
Ejemplo n.º 4
0
def get_constrained_fc2(
    supercell,
    dataset_second_atoms,
    atom1,
    reduced_site_sym,
    translational_symmetry_type,
    is_permutation_symmetry,
    symprec,
):
    """
    dataset_second_atoms: [{'number': 7,
                            'displacement': [],
                            'delta_forces': []}, ...]
    """
    num_atom = supercell.get_number_of_atoms()
    fc2 = np.zeros((num_atom, num_atom, 3, 3), dtype="double")
    atom_list = np.unique([x["number"] for x in dataset_second_atoms])
    for atom2 in atom_list:
        disps2 = []
        sets_of_forces = []
        for disps_second in dataset_second_atoms:
            if atom2 != disps_second["number"]:
                continue
            bond_sym = get_bond_symmetry(reduced_site_sym, supercell.get_scaled_positions(), atom1, atom2, symprec)

            disps2.append(disps_second["displacement"])
            sets_of_forces.append(disps_second["delta_forces"])

        solve_force_constants(fc2, atom2, disps2, sets_of_forces, supercell, bond_sym, symprec)

    # Shift positions according to set atom1 is at origin
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    pos_center = positions[atom1].copy()
    positions -= pos_center
    distribute_force_constants(
        fc2,
        range(num_atom),
        atom_list,
        lattice,
        positions,
        np.array(reduced_site_sym, dtype="intc", order="C"),
        np.zeros((len(reduced_site_sym), 3), dtype="double"),
        symprec,
    )

    if translational_symmetry_type:
        set_translational_invariance(fc2, translational_symmetry_type=translational_symmetry_type)

    if is_permutation_symmetry:
        set_permutation_symmetry(fc2)

    return fc2
Ejemplo n.º 5
0
def get_fourth_order_displacements(cell, symmetry, is_plusminus="auto", is_diagonal=False):
    # Atoms 1, 2, and 3 are defined as follows:
    #
    # Atom 1: The first displaced atom. Fourth order force constant
    #         between Atoms 1, 2, 3, and 4 is calculated.
    # Atom 2: The second displaced atom. Third order force constant
    #         between Atoms 2, 3, and 4 is calculated.
    # Atom 3: The third displaced atom. Second order force constant
    #         between Atoms 3 and 4 is calculated.
    # Atom 4: Force is mesuared on this atom.

    # Least displacements for third order force constants
    #
    # Data structure
    # [{'number': atom1,
    #   'displacement': [0.00000, 0.007071, 0.007071],
    #   'second_atoms': [ {'number': atom2,
    #                      'displacement': [0.007071, 0.000000, 0.007071],
    #                      'third_atoms': [ {'number': atom3,
    #                                        'displacements':
    #                                       [[-0.007071, 0.000000, -0.007071],
    #                                        ,...]}, {...}, ... ]},

    # Least displacements of first atoms (Atom 1) are searched by
    # using respective site symmetries of the original crystal.
    disps_first = get_least_displacements(symmetry, is_plusminus=is_plusminus, is_diagonal=False)

    symprec = symmetry.get_symmetry_tolerance()

    dds = []
    for disp in disps_first:
        atom1 = disp[0]
        disp1 = disp[1:4]
        site_sym = symmetry.get_site_symmetry(atom1)

        dds_atom1 = {"number": atom1, "direction": disp1, "second_atoms": []}
        reduced_site_sym = get_reduced_site_symmetry(site_sym, disp1, symprec)
        second_atoms = get_least_orbits(atom1, cell, reduced_site_sym, symprec)

        for atom2 in second_atoms:
            reduced_bond_sym = get_bond_symmetry(reduced_site_sym, cell.get_scaled_positions(), atom1, atom2, symprec)

            for disp2 in _get_displacements_second(reduced_bond_sym, symprec, is_diagonal):
                dds_atom2 = _get_second_displacements(atom2, disp2, cell, reduced_bond_sym, symprec, is_diagonal)
                dds_atom1["second_atoms"].append(dds_atom2)
        dds.append(dds_atom1)

    write_supercells_with_three_displacements(cell, dds)

    return dds
Ejemplo n.º 6
0
    def _get_reduced_bond_sym(self,
                              reduced_site_sym,
                              first_atom_num,
                              second_atom_num,
                              disp2):
        bond_sym = get_bond_symmetry(
            reduced_site_sym,
            self._positions,
            first_atom_num,
            second_atom_num,
            self._symprec)
        direction = np.dot(np.linalg.inv(self._lattice), disp2)
        reduced_bond_sym = get_reduced_site_symmetry(
            bond_sym, direction, self._symprec)

        return reduced_bond_sym
Ejemplo n.º 7
0
def get_constrained_fc2(supercell, dataset_second_atoms, atom1,
                        reduced_site_sym, translational_symmetry_type,
                        is_permutation_symmetry, symprec):
    """
    dataset_second_atoms: [{'number': 7,
                            'displacement': [],
                            'delta_forces': []}, ...]
    """
    num_atom = supercell.get_number_of_atoms()
    fc2 = np.zeros((num_atom, num_atom, 3, 3), dtype='double')
    atom_list = np.unique([x['number'] for x in dataset_second_atoms])
    atom_list_done = []
    for atom2 in atom_list:
        disps2 = []
        sets_of_forces = []
        for disps_second in dataset_second_atoms:
            if atom2 != disps_second['number']:
                continue
            atom_list_done.append(atom2)
            bond_sym = get_bond_symmetry(reduced_site_sym,
                                         supercell.get_scaled_positions(),
                                         atom1, atom2, symprec)

            disps2.append(disps_second['displacement'])
            sets_of_forces.append(disps_second['delta_forces'])

        solve_force_constants(fc2, atom2, disps2, sets_of_forces, supercell,
                              bond_sym, symprec)

    # Shift positions according to set atom1 is at origin
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    pos_center = positions[atom1].copy()
    positions -= pos_center
    distribute_force_constants(
        fc2, range(num_atom), atom_list_done, lattice, positions,
        np.array(reduced_site_sym, dtype='intc', order='C'),
        np.zeros((len(reduced_site_sym), 3), dtype='double'), symprec)

    if translational_symmetry_type:
        set_translational_invariance(
            fc2, translational_symmetry_type=translational_symmetry_type)

    if is_permutation_symmetry:
        set_permutation_symmetry(fc2)

    return fc2
Ejemplo n.º 8
0
def _get_second_displacements(atom2, disp2, cell, reduced_bond_sym, symprec,
                              is_diagonal):
    positions = cell.get_scaled_positions()
    dds_atom2 = {'number': atom2, 'direction': disp2, 'third_atoms': []}
    reduced_bond_sym2 = get_reduced_site_symmetry(reduced_bond_sym, disp2,
                                                  symprec)
    third_atoms = get_least_orbits(atom2, cell, reduced_bond_sym2, symprec)

    for atom3 in third_atoms:
        reduced_plane_sym = get_bond_symmetry(reduced_bond_sym2,
                                              cell.get_scaled_positions(),
                                              atom2, atom3, symprec)
        dds_atom3 = get_next_displacements(atom2, atom3, reduced_plane_sym,
                                           positions, symprec, is_diagonal)
        dds_atom2['third_atoms'].append(dds_atom3)

    return dds_atom2
Ejemplo n.º 9
0
def _get_constrained_fc3(supercell, displacements, reduced_site_sym,
                         translational_symmetry_type, is_permutation_symmetry,
                         symprec, verbose):
    """
    Two displacements and force constants calculation (e.g. DFPT)

        displacements = {'number': 3,
                         'displacement': [0.01, 0.00, 0.01]
                         'second_atoms': [{'number': 7,
                                           'displacement': [],
                                           'delta_fc2': }]}

    Three displacements and force calculation

        displacements = {'number': 3,
                         'displacement': [0.01, 0.00, 0.01]
                         'second_atoms': [{'number': 7,
                                           'displacement': [],
                                           'third_atoms': ... }]}
           third_atoms is like:
                         'third_atoms': [{'number': 56,
                                          'displacement': [],
                                          'delta_forces': ... }]}
    """
    num_atom = supercell.get_number_of_atoms()
    atom1 = displacements['number']
    disp1 = displacements['displacement']
    delta_fc3 = np.zeros((num_atom, num_atom, num_atom, 3, 3, 3),
                         dtype='double')

    if 'delta_forces' in displacements['second_atoms'][0]:
        fc2_with_one_disp = get_constrained_fc2(
            supercell, displacements['second_atoms'], atom1, reduced_site_sym,
            translational_symmetry_type, is_permutation_symmetry, symprec)

    atom_list = np.unique([x['number'] for x in displacements['second_atoms']])
    for atom2 in atom_list:
        bond_sym = get_bond_symmetry(reduced_site_sym,
                                     supercell.get_scaled_positions(), atom1,
                                     atom2, symprec)
        disps2 = []
        delta_fc2s = []
        for disps_second in displacements['second_atoms']:
            if atom2 != disps_second['number']:
                continue
            disps2.append(disps_second['displacement'])

            if 'delta_fc2' in disps_second:
                delta_fc2s.append(disps_second['delta_fc2'])
            else:
                direction = np.dot(disps_second['displacement'],
                                   np.linalg.inv(supercell.get_cell()))
                reduced_bond_sym = get_reduced_site_symmetry(
                    bond_sym, direction, symprec)

                delta_fc2s.append(
                    get_delta_fc2(disps_second['third_atoms'], atom2,
                                  fc2_with_one_disp, supercell,
                                  reduced_bond_sym,
                                  translational_symmetry_type,
                                  is_permutation_symmetry, symprec))

            if verbose > 1:
                print("Second displacements for fc4[ %d, %d, x, x ]" %
                      (atom1 + 1, atom2 + 1))
                for i, v in enumerate(disps2):
                    print "  [%7.4f %7.4f %7.4f]" % tuple(v)

        solve_fc3(delta_fc3,
                  atom2,
                  supercell,
                  bond_sym,
                  disps2,
                  delta_fc2s,
                  symprec=symprec,
                  verbose=False)

    # Shift positions according to set atom1 is at origin
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    pos_center = positions[atom1].copy()
    positions -= pos_center

    if verbose:
        print "Expanding delta fc3"

    distribute_fc3(delta_fc3,
                   atom_list,
                   lattice,
                   positions,
                   np.array(reduced_site_sym, dtype='intc', order='C'),
                   np.zeros((len(reduced_site_sym), 3), dtype='double'),
                   symprec,
                   verbose=verbose)

    if translational_symmetry_type > 0:
        set_translational_invariance_fc3_per_index(delta_fc3)

    if is_permutation_symmetry:
        set_permutation_symmetry_fc3(delta_fc3)

    return delta_fc3
Ejemplo n.º 10
0
def _get_constrained_fc3(supercell,
                         displacements,
                         reduced_site_sym,
                         is_translational_symmetry,
                         is_permutation_symmetry,
                         symprec,
                         verbose):
    """
    Two displacements and force constants calculation (e.g. DFPT)

        displacements = {'number': 3,
                         'displacement': [0.01, 0.00, 0.01]
                         'second_atoms': [{'number': 7,
                                           'displacement': [],
                                           'delta_fc2': }]}

    Three displacements and force calculation

        displacements = {'number': 3,
                         'displacement': [0.01, 0.00, 0.01]
                         'second_atoms': [{'number': 7,
                                           'displacement': [],
                                           'third_atoms': ... }]}
           third_atoms is like:
                         'third_atoms': [{'number': 56,
                                          'displacement': [],
                                          'delta_forces': ... }]}
    """
    num_atom = supercell.get_number_of_atoms()
    atom1 = displacements['number']
    disp1 = displacements['displacement']
    fc3 = np.zeros((num_atom, num_atom, num_atom, 3, 3, 3), dtype='double')
    atom_list_done = []

    if 'delta_forces' in displacements['second_atoms'][0]:
        fc2_with_one_disp = get_constrained_fc2(supercell,
                                                displacements['second_atoms'],
                                                atom1,
                                                reduced_site_sym,
                                                is_translational_symmetry,
                                                is_permutation_symmetry,
                                                symprec)
    
    atom_list = np.unique([x['number'] for x in displacements['second_atoms']])
    for atom2 in atom_list:
        disps2 = []
        delta_fc2s = []
        for disps_second in displacements['second_atoms']:
            if atom2 != disps_second['number']:
                continue
            atom_list_done.append(atom2)
            bond_sym = get_bond_symmetry(
                reduced_site_sym,
                supercell.get_scaled_positions(),
                atom1,
                atom2,
                symprec)
            disps2.append(disps_second['displacement'])

            if 'delta_fc2' in disps_second:
                delta_fc2s.append(disps_second['delta_fc2'])
            else:
                direction = np.dot(disps_second['displacement'],
                                   np.linalg.inv(supercell.get_cell()))
                reduced_bond_sym = get_reduced_site_symmetry(
                    bond_sym, direction, symprec)

                delta_fc2s.append(get_delta_fc2(
                        disps_second['third_atoms'],
                        atom2,
                        fc2_with_one_disp,
                        supercell,
                        reduced_bond_sym,
                        is_translational_symmetry,
                        is_permutation_symmetry,
                        symprec))
    
            if verbose > 1:
                print ("Second displacements for fc4[ %d, %d, x, x ]" %
                       (atom1 + 1, atom2 + 1))
                for i, v in enumerate(disps2):
                    print "  [%7.4f %7.4f %7.4f]" % tuple(v)

            solve_fc3(fc3,
                      atom2,
                      supercell,
                      bond_sym,
                      disps2,
                      delta_fc2s,
                      symprec=symprec)

    # Shift positions according to set atom1 is at origin
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    pos_center = positions[atom1].copy()
    positions -= pos_center

    if verbose:
        print "(Copying delta fc3...)"
    distribute_fc3(fc3,
                   atom_list_done,
                   lattice,
                   positions,
                   np.intc(reduced_site_sym).copy(),
                   np.zeros((len(reduced_site_sym), 3), dtype='double'),
                   symprec,
                   verbose)

    if is_translational_symmetry:
        set_translational_invariance_fc3_per_index(fc3)

    if is_permutation_symmetry:
        set_permutation_symmetry_fc3(fc3)

    return fc3