Пример #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
Пример #2
0
    def _distribute_displacements_and_forces(self, set_of_disps,
                                             sets_of_forces, first_atom_num,
                                             disp1, unique_second_atom_nums):
        site_symmetry = self._symmetry.get_site_symmetry(first_atom_num)
        direction = np.dot(np.linalg.inv(self._lattice), disp1)
        reduced_site_sym = get_reduced_site_symmetry(site_symmetry, direction,
                                                     self._symprec)
        positions = self._positions.copy() - self._positions[first_atom_num]
        rot_map_syms = get_positions_sent_by_rot_inv(self._lattice, positions,
                                                     reduced_site_sym,
                                                     self._symprec)

        disp_pairs = []
        for second_atom_num in range(self._num_atom):
            if set_of_disps[second_atom_num] is None:
                (sets_of_forces_atom2,
                 set_of_disps_atom2) = self._copy_dataset_2nd(
                     second_atom_num, set_of_disps, sets_of_forces,
                     unique_second_atom_nums, reduced_site_sym, rot_map_syms)
                disp_pairs.append([[disp1, d] for d in set_of_disps_atom2])
                sets_of_forces[second_atom_num] = sets_of_forces_atom2
            else:
                disp_pairs.append([[disp1, d]
                                   for d in set_of_disps[second_atom_num]])

        return disp_pairs, sets_of_forces
Пример #3
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
Пример #4
0
    def _distribute_displacements_and_forces(self,
                                             set_of_disps,
                                             sets_of_forces,
                                             first_atom_num,
                                             disp1,
                                             unique_second_atom_nums):
        site_symmetry = self._symmetry.get_site_symmetry(first_atom_num)
        direction = np.dot(np.linalg.inv(self._lattice), disp1)
        reduced_site_sym = get_reduced_site_symmetry(
            site_symmetry, direction, self._symprec)
        positions = self._positions.copy() - self._positions[first_atom_num]
        rot_map_syms = get_positions_sent_by_rot_inv(positions,
                                                     reduced_site_sym,
                                                     self._symprec)

        disp_pairs = []
        for second_atom_num in range(self._num_atom):
            if set_of_disps[second_atom_num] is None:
                (sets_of_forces_atom2,
                 set_of_disps_atom2) = self._copy_dataset_2nd(
                    second_atom_num,
                    set_of_disps,
                    sets_of_forces,
                    unique_second_atom_nums,
                    reduced_site_sym,
                    rot_map_syms)
                disp_pairs.append(
                    [[disp1, d] for d in set_of_disps_atom2])
                sets_of_forces[second_atom_num] = sets_of_forces_atom2
            else:
                disp_pairs.append(
                    [[disp1, d] for d in set_of_disps[second_atom_num]])

        return disp_pairs, sets_of_forces
Пример #5
0
def _get_fc3_one_atom(fc3, supercell, disp_dataset, fc2, first_atom_num,
                      site_symmetry, translational_symmetry_type,
                      is_permutation_symmetry, symprec, verbose):
    displacements_first = []
    delta_fc2s = []
    for dataset_first_atom in disp_dataset['first_atoms']:
        if first_atom_num != dataset_first_atom['number']:
            continue

        displacements_first.append(dataset_first_atom['displacement'])
        if 'delta_fc2' in dataset_first_atom:
            delta_fc2s.append(dataset_first_atom['delta_fc2'])
        else:
            direction = np.dot(dataset_first_atom['displacement'],
                               np.linalg.inv(supercell.get_cell()))
            reduced_site_sym = get_reduced_site_symmetry(
                site_symmetry, direction, symprec)
            delta_fc2s.append(
                get_delta_fc2(dataset_first_atom['second_atoms'],
                              dataset_first_atom['number'], fc2, supercell,
                              reduced_site_sym, translational_symmetry_type,
                              is_permutation_symmetry, symprec))

    solve_fc3(fc3,
              first_atom_num,
              supercell,
              site_symmetry,
              displacements_first,
              delta_fc2s,
              symprec,
              verbose=verbose)
Пример #6
0
 def _get_reduced_site_sym(self, dataset_1st):
     disp1 = dataset_1st['displacement']
     first_atom_num = dataset_1st['number']
     site_symmetry = self._symmetry.get_site_symmetry(first_atom_num)
     direction = np.dot(np.linalg.inv(self._lattice), disp1)
     reduced_site_sym = get_reduced_site_symmetry(site_symmetry, direction,
                                                  self._symprec)
     return reduced_site_sym
Пример #7
0
def _get_fc4_one_atom(fc4,
                      supercell,
                      disp_dataset,
                      fc3,
                      first_atom_num,
                      site_symmetry,
                      translational_symmetry_type,
                      is_permutation_symmetry,
                      symprec,
                      verbose):
    
    displacements_first = []
    delta_fc3s = []
    for dataset_first_atom in disp_dataset['first_atoms']:
        if first_atom_num != dataset_first_atom['number']:
            continue

        displacements_first.append(dataset_first_atom['displacement'])
        direction = np.dot(dataset_first_atom['displacement'],
                           np.linalg.inv(supercell.get_cell()))
        reduced_site_sym = get_reduced_site_symmetry(
            site_symmetry, direction, symprec)

        if verbose:
            print "Solving fc4[ %d, x, x, x ] with" % (first_atom_num + 1),
            if len(displacements_first) > 1:
                print "displacements:"
            else:
                print "a displacement:"
            for i, v in enumerate(displacements_first):
                print "    [%7.4f %7.4f %7.4f]" % tuple(v)
                sys.stdout.flush()

        delta_fc3s.append(_get_delta_fc3(
                dataset_first_atom,
                fc3,
                supercell,
                reduced_site_sym,
                translational_symmetry_type,
                is_permutation_symmetry,
                symprec,
                verbose))

    _solve_fc4(fc4,
               first_atom_num,
               supercell,
               site_symmetry,
               displacements_first,
               np.array(delta_fc3s, dtype='double', order='C'),
               symprec)

    if verbose > 2:
        print "Site symmetry:"
        for i, v in enumerate(site_symmetry):
            print "  [%2d %2d %2d] #%2d" % tuple(list(v[0])+[i+1])
            print "  [%2d %2d %2d]" % tuple(v[1])
            print "  [%2d %2d %2d]\n" % tuple(v[2])
            sys.stdout.flush()
Пример #8
0
 def _get_reduced_site_sym(self, dataset_1st):
     disp1 = dataset_1st['displacement']
     first_atom_num = dataset_1st['number']
     site_symmetry = self._symmetry.get_site_symmetry(first_atom_num)
     direction = np.dot(np.linalg.inv(self._lattice), disp1)
     reduced_site_sym = get_reduced_site_symmetry(site_symmetry,
                                                  direction,
                                                  self._symprec)
     return reduced_site_sym
Пример #9
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
Пример #10
0
def _get_fc4_one_atom(fc4,
                      supercell,
                      disp_dataset,
                      fc3,
                      first_atom_num,
                      site_symmetry,
                      is_translational_symmetry,
                      is_permutation_symmetry,
                      symprec,
                      verbose):
    
    displacements_first = []
    delta_fc3s = []
    for dataset_first_atom in disp_dataset['first_atoms']:
        if first_atom_num != dataset_first_atom['number']:
            continue

        displacements_first.append(dataset_first_atom['displacement'])
        direction = np.dot(dataset_first_atom['displacement'],
                           np.linalg.inv(supercell.get_cell()))
        reduced_site_sym = get_reduced_site_symmetry(
            site_symmetry, direction, symprec)

        if verbose:
            print ("First displacements for fc4[ %d, x, x, x ]" %
                   (first_atom_num + 1))
            for i, v in enumerate(displacements_first):
                print "  [%7.4f %7.4f %7.4f]" % tuple(v)
                sys.stdout.flush()

        delta_fc3s.append(_get_delta_fc3(
                dataset_first_atom,
                fc3,
                supercell,
                reduced_site_sym,
                is_translational_symmetry,
                is_permutation_symmetry,
                symprec,
                verbose))

    _solve_fc4(fc4,
               first_atom_num,
               supercell,
               site_symmetry,
               displacements_first,
               np.double(delta_fc3s),
               symprec)

    if verbose > 2:
        print "Site symmetry:"
        for i, v in enumerate(site_symmetry):
            print "  [%2d %2d %2d] #%2d" % tuple(list(v[0])+[i+1])
            print "  [%2d %2d %2d]" % tuple(v[1])
            print "  [%2d %2d %2d]\n" % tuple(v[2])
            sys.stdout.flush()
Пример #11
0
def _get_fc3_one_atom(fc3,
                      supercell,
                      disp_dataset,
                      fc2,
                      first_atom_num,
                      site_symmetry,
                      is_translational_symmetry,
                      is_permutation_symmetry,
                      symprec,
                      verbose):
    displacements_first = []
    delta_fc2s = []
    for dataset_first_atom in disp_dataset['first_atoms']:
        if first_atom_num != dataset_first_atom['number']:
            continue
        
        displacements_first.append(dataset_first_atom['displacement'])
        if 'delta_fc2' in dataset_first_atom:
            delta_fc2s.append(dataset_first_atom['delta_fc2'])
        else:
            direction = np.dot(dataset_first_atom['displacement'],
                               np.linalg.inv(supercell.get_cell()))
            reduced_site_sym = get_reduced_site_symmetry(
                site_symmetry, direction, symprec)
            delta_fc2s.append(get_delta_fc2(
                    dataset_first_atom['second_atoms'],
                    dataset_first_atom['number'],
                    fc2,
                    supercell,
                    reduced_site_sym,
                    is_translational_symmetry,
                    is_permutation_symmetry,
                    symprec))

    solve_fc3(fc3,
              first_atom_num,
              supercell,
              site_symmetry,
              displacements_first,
              delta_fc2s,
              symprec)

    if verbose:
        print "Displacements for fc3[ %d, x, x ]" % (first_atom_num + 1)
        for i, v in enumerate(displacements_first):
            print "  [%7.4f %7.4f %7.4f]" % tuple(v)
            sys.stdout.flush()
        if verbose > 2:
            print "Site symmetry:"
            for i, v in enumerate(site_symmetry):
                print "  [%2d %2d %2d] #%2d" % tuple(list(v[0])+[i+1])
                print "  [%2d %2d %2d]" % tuple(v[1])
                print "  [%2d %2d %2d]\n" % tuple(v[2])
                sys.stdout.flush()
Пример #12
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
Пример #13
0
def _get_fc3_done(supercell, disp_dataset, symmetry):
    num_atom = supercell.get_number_of_atoms()
    fc3_done = np.zeros((num_atom, num_atom, num_atom), dtype='byte')
    symprec = symmetry.get_symmetry_tolerance()
    positions = supercell.get_scaled_positions()
    rotations = symmetry.get_symmetry_operations()['rotations']
    translations = symmetry.get_symmetry_operations()['translations']

    atom_mapping = []
    for rot, trans in zip(rotations, translations):
        atom_indices = []
        for rot_pos in (np.dot(positions, rot.T) + trans):
            diff = positions - rot_pos
            diff -= np.rint(diff)
            atom_indices.append(
                np.where((np.abs(diff) < symprec).all(axis=1))[0][0])
        atom_mapping.append(atom_indices)

    for dataset_first_atom in disp_dataset['first_atoms']:
        first_atom_num = dataset_first_atom['number']
        site_symmetry = symmetry.get_site_symmetry(first_atom_num)
        direction = np.dot(dataset_first_atom['displacement'],
                           np.linalg.inv(supercell.get_cell()))
        reduced_site_sym = get_reduced_site_symmetry(
            site_symmetry, direction, symprec)
        least_second_atom_nums = []
        for second_atoms in dataset_first_atom['second_atoms']:
            if second_atoms['included']:
                least_second_atom_nums.append(second_atoms['number'])
        positions_shifted = positions - positions[first_atom_num]
        least_second_atom_nums = np.unique(least_second_atom_nums)

        second_atom_nums = []
        for red_rot in reduced_site_sym:
            for i in least_second_atom_nums:
                second_atom_nums.append(
                    get_atom_by_symmetry(positions_shifted,
                                         red_rot,
                                         np.zeros(3, dtype='double'),
                                         i,
                                         symprec))
        second_atom_nums = np.unique(second_atom_nums)

        for i in range(len(rotations)):
            rotated_atom1 = atom_mapping[i][first_atom_num]
            for j in second_atom_nums:
                fc3_done[rotated_atom1, atom_mapping[i][j]] = 1

    return fc3_done
Пример #14
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
Пример #15
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
Пример #16
0
def _get_fc3_one_atom(fc3,
                      supercell,
                      disp_dataset,
                      fc2,
                      first_atom_num,
                      site_symmetry,
                      translational_symmetry_type,
                      is_permutation_symmetry,
                      symprec,
                      verbose):
    displacements_first = []
    delta_fc2s = []
    for dataset_first_atom in disp_dataset['first_atoms']:
        if first_atom_num != dataset_first_atom['number']:
            continue

        displacements_first.append(dataset_first_atom['displacement'])
        if 'delta_fc2' in dataset_first_atom:
            delta_fc2s.append(dataset_first_atom['delta_fc2'])
        else:
            direction = np.dot(dataset_first_atom['displacement'],
                               np.linalg.inv(supercell.get_cell()))
            reduced_site_sym = get_reduced_site_symmetry(
                site_symmetry, direction, symprec)
            delta_fc2s.append(get_delta_fc2(
                    dataset_first_atom['second_atoms'],
                    dataset_first_atom['number'],
                    fc2,
                    supercell,
                    reduced_site_sym,
                    translational_symmetry_type,
                    is_permutation_symmetry,
                    symprec))

    solve_fc3(fc3,
              first_atom_num,
              supercell,
              site_symmetry,
              displacements_first,
              delta_fc2s,
              symprec,
              verbose=verbose)
Пример #17
0
def _get_fc3_one_atom(fc3, supercell, disp_dataset, fc2, first_atom_num,
                      site_symmetry, translational_symmetry_type,
                      is_permutation_symmetry, symprec, verbose):
    displacements_first = []
    delta_fc2s = []
    for dataset_first_atom in disp_dataset['first_atoms']:
        if first_atom_num != dataset_first_atom['number']:
            continue

        displacements_first.append(dataset_first_atom['displacement'])
        if 'delta_fc2' in dataset_first_atom:
            delta_fc2s.append(dataset_first_atom['delta_fc2'])
        else:
            direction = np.dot(dataset_first_atom['displacement'],
                               np.linalg.inv(supercell.get_cell()))
            reduced_site_sym = get_reduced_site_symmetry(
                site_symmetry, direction, symprec)
            delta_fc2s.append(
                get_delta_fc2(dataset_first_atom['second_atoms'],
                              dataset_first_atom['number'], fc2, supercell,
                              reduced_site_sym, translational_symmetry_type,
                              is_permutation_symmetry, symprec))

    solve_fc3(fc3, first_atom_num, supercell, site_symmetry,
              displacements_first, delta_fc2s, symprec)

    if verbose:
        print "- Displacements for fc3[ %d, x, x ]" % (first_atom_num + 1)
        for i, v in enumerate(displacements_first):
            print "    [%7.4f %7.4f %7.4f]" % tuple(v)
            sys.stdout.flush()
        if verbose > 2:
            print "  Site symmetry:"
            for i, v in enumerate(site_symmetry):
                print "    [%2d %2d %2d] #%2d" % tuple(list(v[0]) + [i + 1])
                print "    [%2d %2d %2d]" % tuple(v[1])
                print "    [%2d %2d %2d]\n" % tuple(v[2])
                sys.stdout.flush()
Пример #18
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
Пример #19
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