コード例 #1
0
ファイル: vasp.py プロジェクト: Johnson-Wang/phonopy
def get_born_OUTCAR(poscar_filename="POSCAR",
                    outcar_filename="OUTCAR",
                    primitive_axis=np.eye(3),
                    is_symmetry=True,
                    symmetrize_tensors=False):
    cell = read_vasp(poscar_filename)
    primitive = Primitive(cell, primitive_axis)
    p2p = primitive.get_primitive_to_primitive_map()
    symmetry = Symmetry(primitive, is_symmetry=is_symmetry)
    independent_atoms = symmetry.get_independent_atoms()
    prim_lat = primitive.get_cell().T
    outcar = open(outcar_filename)
    
    borns = []
    while True:
        line = outcar.readline()
        if not line:
            break
    
        if "NIONS" in line:
            num_atom = int(line.split()[11])
    
        if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line:
            epsilon = []
            outcar.readline()
            epsilon.append([float(x) for x in outcar.readline().split()])
            epsilon.append([float(x) for x in outcar.readline().split()])
            epsilon.append([float(x) for x in outcar.readline().split()])
    
        if "BORN" in line:
            outcar.readline()
            line = outcar.readline()
            if "ion" in line:
                for i in range(num_atom):
                    born = []
                    born.append([float(x) for x in outcar.readline().split()][1:])
                    born.append([float(x) for x in outcar.readline().split()][1:])
                    born.append([float(x) for x in outcar.readline().split()][1:])
                    outcar.readline()
                    borns.append(born)


    reduced_borns = []
    for p_i, u_i in enumerate(p2p):
        if p_i in independent_atoms:
            if symmetrize_tensors:
                site_sym = [similarity_transformation(prim_lat, rot)
                            for rot in symmetry.get_site_symmetry(p_i)]
                reduced_borns.append(symmetrize_tensor(borns[u_i], site_sym))
            else:
                reduced_borns.append(borns[u_i])
                
    if symmetrize_tensors:
        point_sym = [similarity_transformation(prim_lat, rot)
                     for rot in symmetry.get_pointgroup_operations()]
        epsilon = symmetrize_tensor(epsilon, point_sym)
    else:
        epsilon = np.array(epsilon)

    return np.array(reduced_borns), epsilon
コード例 #2
0
ファイル: frequency_shift.py プロジェクト: Maofei/phonopy
    def __init__(self,
                 fc4,
                 supercell,
                 primitive,
                 mesh,
                 temperatures=None,
                 band_indices=None,
                 frequency_factor_to_THz=VaspToTHz,
                 is_nosym=False,
                 symprec=1e-3,
                 cutoff_frequency=1e-4,
                 log_level=False,
                 lapack_zheev_uplo='L'):
        self._fc4 = fc4
        self._supercell = supercell
        self._primitive = primitive
        self._masses = np.double(self._primitive.get_masses())
        self._mesh = np.intc(mesh)
        if temperatures is None:
            self._temperatures = np.double([0])
        else:
            self._temperatures = np.double(temperatures)
        num_band = primitive.get_number_of_atoms() * 3
        if band_indices is None:
            self._band_indices = np.arange(num_band, dtype='intc')
        else:
            self._band_indices = np.intc(band_indices)
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_nosym = is_nosym
        self._symprec = symprec
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level
        self._lapack_zheev_uplo = lapack_zheev_uplo

        symmetry = Symmetry(primitive, symprec=symprec)
        self._point_group_operations = symmetry.get_pointgroup_operations()

        self._grid_address = None
        self._bz_map = None
        self._set_grid_address()
        
        self._grid_point = None
        self._quartets_at_q = None
        self._weights_at_q = None

        self._phonon_done = None
        self._frequencies = None
        self._eigenvectors = None
        self._dm = None
        self._nac_q_direction = None

        self._frequency_shifts = None
        
        # Unit to THz of Delta
        self._unit_conversion = (EV / Angstrom ** 4 / AMU ** 2
                                 / (2 * np.pi * THz) ** 2
                                 * Hbar * EV / (2 * np.pi * THz) / 8
                                 / np.prod(self._mesh))

        self._allocate_phonon()
コード例 #3
0
ファイル: vasp.py プロジェクト: georgeyumnam/phonopy
def get_born_OUTCAR(
    poscar_filename="POSCAR",
    outcar_filename="OUTCAR",
    primitive_axis=np.eye(3),
    supercell_matrix=np.eye(3, dtype="intc"),
    is_symmetry=True,
    symmetrize_tensors=False,
    symprec=1e-5,
):
    ucell = read_vasp(poscar_filename)
    outcar = open(outcar_filename)

    borns, epsilon = _read_born_and_epsilon(outcar)
    num_atom = len(borns)
    assert num_atom == ucell.get_number_of_atoms()

    if symmetrize_tensors:
        lattice = ucell.get_cell().T
        positions = ucell.get_scaled_positions()
        u_sym = Symmetry(ucell, is_symmetry=is_symmetry, symprec=symprec)
        point_sym = [similarity_transformation(lattice, r) for r in u_sym.get_pointgroup_operations()]
        epsilon = _symmetrize_tensor(epsilon, point_sym)
        borns = _symmetrize_borns(borns, u_sym, lattice, positions, symprec)

    inv_smat = np.linalg.inv(supercell_matrix)
    scell = get_supercell(ucell, supercell_matrix, symprec=symprec)
    pcell = get_primitive(scell, np.dot(inv_smat, primitive_axis), symprec=symprec)
    p2s = np.array(pcell.get_primitive_to_supercell_map(), dtype="intc")
    p_sym = Symmetry(pcell, is_symmetry=is_symmetry, symprec=symprec)
    s_indep_atoms = p2s[p_sym.get_independent_atoms()]
    u2u = scell.get_unitcell_to_unitcell_map()
    u_indep_atoms = [u2u[x] for x in s_indep_atoms]
    reduced_borns = borns[u_indep_atoms].copy()

    return reduced_borns, epsilon
コード例 #4
0
ファイル: frequency_shift.py プロジェクト: FermiSea/phonopy
    def __init__(self,
                 fc4,
                 supercell,
                 primitive,
                 mesh,
                 temperatures=None,
                 band_indices=None,
                 frequency_factor_to_THz=VaspToTHz,
                 is_nosym=False,
                 symprec=1e-3,
                 cutoff_frequency=1e-4,
                 log_level=False,
                 lapack_zheev_uplo='L'):
        self._fc4 = fc4
        self._supercell = supercell
        self._primitive = primitive
        self._masses = np.double(self._primitive.get_masses())
        self._mesh = np.intc(mesh)
        if temperatures is None:
            self._temperatures = np.double([0])
        else:
            self._temperatures = np.double(temperatures)
        num_band = primitive.get_number_of_atoms() * 3
        if band_indices is None:
            self._band_indices = np.arange(num_band, dtype='intc')
        else:
            self._band_indices = np.intc(band_indices)
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_nosym = is_nosym
        self._symprec = symprec
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level
        self._lapack_zheev_uplo = lapack_zheev_uplo

        symmetry = Symmetry(primitive, symprec=symprec)
        self._point_group_operations = symmetry.get_pointgroup_operations()

        self._grid_address = None
        self._bz_map = None
        self._set_grid_address()

        self._grid_point = None
        self._quartets_at_q = None
        self._weights_at_q = None

        self._phonon_done = None
        self._frequencies = None
        self._eigenvectors = None
        self._dm = None
        self._nac_q_direction = None

        self._frequency_shifts = None

        # Unit to THz of Delta
        self._unit_conversion = (EV / Angstrom**4 / AMU**2 /
                                 (2 * np.pi * THz)**2 * Hbar * EV /
                                 (2 * np.pi * THz) / 8 / np.prod(self._mesh))

        self._allocate_phonon()
コード例 #5
0
def get_number_of_triplets(primitive, mesh, grid_point, symprec=1e-5):
    mesh = np.array(mesh, dtype='intc')
    symmetry = Symmetry(primitive, symprec)
    point_group = symmetry.get_pointgroup_operations()
    primitive_lattice = np.linalg.inv(primitive.get_cell())
    triplets_at_q, _, _, _, _, _ = get_triplets_at_q(grid_point, mesh,
                                                     point_group,
                                                     primitive_lattice)

    return len(triplets_at_q)
コード例 #6
0
ファイル: triplets.py プロジェクト: chueter/phonopy
def get_coarse_ir_grid_points(primitive,
                              mesh,
                              mesh_divisors,
                              coarse_mesh_shifts,
                              is_kappa_star=True,
                              symprec=1e-5):
    mesh = np.array(mesh, dtype='intc')

    symmetry = Symmetry(primitive, symprec)
    point_group = symmetry.get_pointgroup_operations()

    if mesh_divisors is None:
        (ir_grid_points,
         ir_grid_weights,
         grid_address,
         grid_mapping_table) = get_ir_grid_points(mesh, point_group)
    else:
        mesh_divs = np.array(mesh_divisors, dtype='intc')
        coarse_mesh = mesh // mesh_divs
        if coarse_mesh_shifts is None:
            coarse_mesh_shifts = [False, False, False]
    
        if not is_kappa_star:
            coarse_grid_address = get_grid_address(coarse_mesh)
            coarse_grid_points = np.arange(np.prod(coarse_mesh), dtype='intc')
            coarse_grid_weights = np.ones(len(coarse_grid_points), dtype='intc')
        else:
            (coarse_ir_grid_points,
             coarse_ir_grid_weights,
             coarse_grid_address,
             coarse_grid_mapping_table) = get_ir_grid_points(
                 coarse_mesh,
                 point_group,
                 mesh_shifts=coarse_mesh_shifts)
        ir_grid_points = from_coarse_to_dense_grid_points(
            mesh,
            mesh_divs,
            coarse_grid_points,
            coarse_grid_address,
            coarse_mesh_shifts=coarse_mesh_shifts)
        grid_address = get_grid_address(mesh)
        ir_grid_weights = ir_grid_weights

    primitive_lattice = np.linalg.inv(primitive.get_cell())
    bz_grid_address, bz_map = spg.relocate_BZ_grid_address(grid_address,
                                                           mesh,
                                                           primitive_lattice)

    return (ir_grid_points,
            ir_grid_weights,
            bz_grid_address,
            grid_mapping_table)
コード例 #7
0
ファイル: triplets.py プロジェクト: kcbhamu/phono3py
def get_coarse_ir_grid_points(primitive,
                              mesh,
                              mesh_divisors,
                              coarse_mesh_shifts,
                              is_kappa_star=True,
                              symprec=1e-5):
    mesh = np.array(mesh, dtype='intc')

    symmetry = Symmetry(primitive, symprec)
    point_group = symmetry.get_pointgroup_operations()

    if mesh_divisors is None:
        (ir_grid_points,
         ir_grid_weights,
         grid_address,
         grid_mapping_table) = get_ir_grid_points(mesh, point_group)
    else:
        mesh_divs = np.array(mesh_divisors, dtype='intc')
        coarse_mesh = mesh // mesh_divs
        if coarse_mesh_shifts is None:
            coarse_mesh_shifts = [False, False, False]

        if not is_kappa_star:
            coarse_grid_address = get_grid_address(coarse_mesh)
            coarse_grid_points = np.arange(np.prod(coarse_mesh), dtype='uintp')
        else:
            (coarse_ir_grid_points,
             coarse_ir_grid_weights,
             coarse_grid_address,
             coarse_grid_mapping_table) = get_ir_grid_points(
                 coarse_mesh,
                 point_group,
                 mesh_shifts=coarse_mesh_shifts)
        ir_grid_points = from_coarse_to_dense_grid_points(
            mesh,
            mesh_divs,
            coarse_grid_points,
            coarse_grid_address,
            coarse_mesh_shifts=coarse_mesh_shifts)
        grid_address = get_grid_address(mesh)
        ir_grid_weights = ir_grid_weights

    reciprocal_lattice = np.linalg.inv(primitive.get_cell())
    bz_grid_address, bz_map = spg.relocate_BZ_grid_address(grid_address,
                                                           mesh,
                                                           reciprocal_lattice,
                                                           is_dense=True)

    return (ir_grid_points,
            ir_grid_weights,
            bz_grid_address,
            grid_mapping_table)
コード例 #8
0
ファイル: triplets.py プロジェクト: georgeyumnam/phonopy
def get_number_of_triplets(primitive,
                           mesh,
                           grid_point,
                           symprec=1e-5):
    mesh = np.array(mesh, dtype='intc')
    symmetry = Symmetry(primitive, symprec)
    point_group = symmetry.get_pointgroup_operations()
    primitive_lattice = np.linalg.inv(primitive.get_cell())
    triplets_at_q, _, _, _, _, _ = get_triplets_at_q(
        grid_point,
        mesh,
        point_group,
        primitive_lattice)

    return len(triplets_at_q)
コード例 #9
0
def get_born_OUTCAR(poscar_filename="POSCAR",
                    outcar_filename="OUTCAR",
                    primitive_matrix=None,
                    supercell_matrix=None,
                    is_symmetry=True,
                    symmetrize_tensors=False,
                    symprec=1e-5):
    if primitive_matrix is None:
        pmat = np.eye(3)
    else:
        pmat = primitive_matrix
    if supercell_matrix is None:
        smat = np.eye(3, dtype='intc')
    else:
        smat = supercell_matrix
    ucell = read_vasp(poscar_filename)
    outcar = open(outcar_filename)

    borns, epsilon = _read_born_and_epsilon(outcar)
    num_atom = len(borns)
    assert num_atom == ucell.get_number_of_atoms()

    if symmetrize_tensors:
        lattice = ucell.get_cell().T
        positions = ucell.get_scaled_positions()
        u_sym = Symmetry(ucell, is_symmetry=is_symmetry, symprec=symprec)
        point_sym = [
            similarity_transformation(lattice, r)
            for r in u_sym.get_pointgroup_operations()
        ]
        epsilon = _symmetrize_tensor(epsilon, point_sym)
        borns = _symmetrize_borns(borns, u_sym, lattice, positions, symprec)

    inv_smat = np.linalg.inv(smat)
    scell = get_supercell(ucell, smat, symprec=symprec)
    pcell = get_primitive(scell, np.dot(inv_smat, pmat), symprec=symprec)
    p2s = np.array(pcell.get_primitive_to_supercell_map(), dtype='intc')
    p_sym = Symmetry(pcell, is_symmetry=is_symmetry, symprec=symprec)
    s_indep_atoms = p2s[p_sym.get_independent_atoms()]
    u2u = scell.get_unitcell_to_unitcell_map()
    u_indep_atoms = [u2u[x] for x in s_indep_atoms]
    reduced_borns = borns[u_indep_atoms].copy()

    return reduced_borns, epsilon, s_indep_atoms
コード例 #10
0
ファイル: triplets.py プロジェクト: georgeyumnam/phonopy
def get_coarse_ir_grid_points(primitive,
                              mesh,
                              mesh_divisors,
                              coarse_mesh_shifts,
                              is_nosym=False,
                              symprec=1e-5):
    if mesh_divisors is None:
        mesh_divs = [1, 1, 1]
    else:
        mesh_divs = mesh_divisors
    mesh = np.array(mesh, dtype='intc')
    mesh_divs = np.array(mesh_divs, dtype='intc')
    coarse_mesh = mesh // mesh_divs
    if coarse_mesh_shifts is None:
        coarse_mesh_shifts = [False, False, False]

    if is_nosym:
        coarse_grid_address = get_grid_address(coarse_mesh)
        coarse_grid_points = np.arange(np.prod(coarse_mesh), dtype='intc')
        coarse_grid_weights = np.ones(len(coarse_grid_points), dtype='intc')
    else:
        symmetry = Symmetry(primitive, symprec)
        (coarse_grid_points,
         coarse_grid_weights,
         coarse_grid_address) = get_ir_grid_points(
             coarse_mesh,
             symmetry.get_pointgroup_operations(),
             mesh_shifts=coarse_mesh_shifts)
    grid_points = from_coarse_to_dense_grid_points(
        mesh,
        mesh_divs,
        coarse_grid_points,
        coarse_grid_address,
        coarse_mesh_shifts=coarse_mesh_shifts)
    grid_address = get_grid_address(mesh)
    primitive_lattice = np.linalg.inv(primitive.get_cell())
    bz_grid_address, _ = spg.relocate_BZ_grid_address(grid_address,
                                                      mesh,
                                                      primitive_lattice)

    return grid_points, coarse_grid_weights, bz_grid_address
コード例 #11
0
def get_coarse_ir_grid_points(primitive,
                              mesh,
                              mesh_divisors,
                              coarse_mesh_shifts,
                              is_nosym=False,
                              symprec=1e-5):
    if mesh_divisors is None:
        mesh_divs = [1, 1, 1]
    else:
        mesh_divs = mesh_divisors
    mesh = np.array(mesh, dtype='intc')
    mesh_divs = np.array(mesh_divs, dtype='intc')
    coarse_mesh = mesh / mesh_divs
    if coarse_mesh_shifts is None:
        coarse_mesh_shifts = [False, False, False]

    if is_nosym:
        coarse_grid_address = get_grid_address(coarse_mesh)
        coarse_grid_points = np.arange(np.prod(coarse_mesh), dtype='intc')
        coarse_grid_weights = np.ones(len(coarse_grid_points), dtype='intc')
    else:
        symmetry = Symmetry(primitive, symprec)
        (coarse_grid_points, coarse_grid_weights,
         coarse_grid_address) = get_ir_grid_points(
             coarse_mesh,
             symmetry.get_pointgroup_operations(),
             mesh_shifts=coarse_mesh_shifts)
    grid_points = from_coarse_to_dense_grid_points(
        mesh,
        mesh_divs,
        coarse_grid_points,
        coarse_grid_address,
        coarse_mesh_shifts=coarse_mesh_shifts)
    grid_address = get_grid_address(mesh)
    primitive_lattice = np.linalg.inv(primitive.get_cell())
    bz_grid_address, _ = spg.relocate_BZ_grid_address(grid_address, mesh,
                                                      primitive_lattice)

    return grid_points, coarse_grid_weights, bz_grid_address
コード例 #12
0
    def set_grid_point(self, grid_point, grid_points2=None, weights2=None):
        "The grid_point is numbered using the bz scheme"
        self._grid_point = grid_point
        if self._grid_address is None:
            primitive_lattice = np.linalg.inv(self._primitive.get_cell())
            self._grid_address, self._bz_map, self._bz_to_pp_map = get_bz_grid_address(
                self._mesh,
                primitive_lattice,
                with_boundary=True,
                is_bz_map_to_pp=True)

        if grid_points2 is not None:
            self._grid_points2 = grid_points2
            self._weights2 = weights2
        elif not self._is_nosym:
            symmetry = Symmetry(self._primitive, symprec=self._symprec)
            qpoint = self._grid_address[grid_point] / np.double(self._mesh)
            mapping, grid_points = spg.get_stabilized_reciprocal_mesh(
                self._mesh,
                symmetry.get_pointgroup_operations(),
                is_shift=np.zeros(3, dtype='intc'),
                is_time_reversal=True,
                qpoints=[qpoint])

            grid_points2 = np.unique(mapping)
            # weight = np.zeros_like(grid_points2)
            # bz_grid_points2 = np.zeros_like(grid_points2)
            # for g, grid in enumerate(grid_points2):
            #     weight[g] = len(np.where(grid == mapping)[0])
            #     bz_grid_points2[g] = np.where(grid == self._bz_to_pp_map)[0][0]
            # self._grid_points2 = bz_grid_points2
            weight_temp = np.bincount(mapping)
            weight = weight_temp[np.nonzero(weight_temp)]
            self._grid_points2 = grid_points2
            self._weights2 = weight
        else:
            self._grid_points2 = np.arange(np.prod(self._mesh))
            self._weights2 = np.ones_like(self._grid_points2, dtype="intc")
コード例 #13
0
ファイル: isotope.py プロジェクト: Johnson-Wang/phonopy
    def set_grid_point(self,
                       grid_point,
                       grid_points2=None,
                       weights2 = None):
        "The grid_point is numbered using the bz scheme"
        self._grid_point = grid_point
        if self._grid_address is None:
            primitive_lattice = np.linalg.inv(self._primitive.get_cell())
            self._grid_address, self._bz_map, self._bz_to_pp_map = get_bz_grid_address(
                self._mesh, primitive_lattice, with_boundary=True, is_bz_map_to_pp=True)

        if grid_points2 is not None:
            self._grid_points2 = grid_points2
            self._weights2 = weights2
        elif not self._is_nosym:
            symmetry = Symmetry(self._primitive, symprec=self._symprec)
            qpoint = self._grid_address[grid_point] / np.double(self._mesh)
            mapping, grid_points = spg.get_stabilized_reciprocal_mesh(self._mesh,
                                                                      symmetry.get_pointgroup_operations(),
                                                                      is_shift=np.zeros(3, dtype='intc'),
                                                                      is_time_reversal=True,
                                                                      qpoints=[qpoint])

            grid_points2 = np.unique(mapping)
            # weight = np.zeros_like(grid_points2)
            # bz_grid_points2 = np.zeros_like(grid_points2)
            # for g, grid in enumerate(grid_points2):
            #     weight[g] = len(np.where(grid == mapping)[0])
            #     bz_grid_points2[g] = np.where(grid == self._bz_to_pp_map)[0][0]
            # self._grid_points2 = bz_grid_points2
            weight_temp = np.bincount(mapping)
            weight = weight_temp[np.nonzero(weight_temp)]
            self._grid_points2 = grid_points2
            self._weights2 = weight
        else:
            self._grid_points2 = np.arange(np.prod(self._mesh))
            self._weights2 = np.ones_like(self._grid_points2, dtype="intc")
コード例 #14
0
ファイル: __init__.py プロジェクト: Johnson-Wang/phonopy
class Phono3py:
    def __init__(self,
                 interaction,
                 mass_variances=None,
                 length=None,
                 adaptive_sigma_step = 0,
                 frequency_factor_to_THz=None,
                 is_nosym=False,
                 symprec=1e-5,
                 log_level=0,
                 is_thm = False, # is tetrahedron method
                 write_tecplot=False):
        self._interaction = interaction
        self._primitive = interaction.get_primitive()
        self._supercell = interaction.get_supercell()
        self._mesh = interaction.get_mesh_numbers()
        self._band_indices = interaction.get_band_indices()
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_nosym = is_nosym
        self._is_symmetry = not is_nosym
        self._symprec = symprec
        self._log_level = log_level
        self._asigma_step=adaptive_sigma_step
        self._step=0
        self._kappa = None
        self._gamma = None
        self._br = None
        self._is_thm = is_thm
        self._write_tecplot=write_tecplot
        self._mass_variances = mass_variances
        self._length=length
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_primitive_symmetry(self):
        return self._primitive_symmetry

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print ("Warning: point group symmetries of supercell and primitive"
                   "cell are different.")

    def set_dynamical_matrix(self,
                             fc2,
                             supercell,
                             primitive,
                             nac_params=None,
                             nac_q_direction=None,
                             frequency_scale_factor=None):
        self._interaction.set_dynamical_matrix(
            fc2,
            supercell,
            primitive,
            nac_params=nac_params,
            frequency_scale_factor=frequency_scale_factor)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)
                           
    def get_imag_self_energy(self,
                             grid_points,
                             frequency_step=1.0,
                             sigmas=[None],
                             temperatures=[0.0],
                             filename=None):
        ise = ImagSelfEnergy(self._interaction, is_thm = self._is_thm)
        for gp in grid_points:
            ise.set_grid_point(gp)
            ise.run_interaction()
            for sigma in sigmas:
                ise.set_sigma(sigma)
                for t in temperatures:
                    ise.set_temperature(t)
                    max_freq = (np.amax(self._interaction.get_phonons()[0]) * 2
                                + sigma * 4)
                    fpoints = np.arange(0, max_freq + frequency_step / 2,
                                        frequency_step)
                    ise.set_fpoints(fpoints)
                    ise.run()
                    gamma = ise.get_imag_self_energy()

                    for i, bi in enumerate(self._band_indices):
                        pos = 0
                        for j in range(i):
                            pos += len(self._band_indices[j])

                        write_damping_functions(
                            gp,
                            bi,
                            self._mesh,
                            fpoints,
                            gamma[:, pos:(pos + len(bi))].sum(axis=1) / len(bi),
                            sigma=sigma,
                            temperature=t,
                            filename=filename)

    def get_matrix_contribution(self,
                                grid_points,
                                frequency_step=1.0,
                                sigmas=[0.1],
                                is_adaptive_sigma=False,
                                filename=None):
        mc = Collision(self._interaction,
                            sigmas=sigmas,
                            is_adaptive_sigma=is_adaptive_sigma,
                            frequencies = self._frequencies,
                            degeneracy=self._degeneracy,
                            write=write_scr,
                            read=read_scr,
                            cutoff_frequency=self._cutfr,
                            cutoff_lifetime=self._cutlt)
        is_sum = False
        if grid_points == None:
            is_sum = True
            if self._is_nosym: # All grid points
                grid_points = np.arange(np.product(self._mesh))
            else: # Automatic sampling
                (grid_points,
                 grid_weights,
                 grid_address) = get_ir_grid_points(
                    self._mesh,
                    self._primitive)
        matrix_contributions = []
        for gp in grid_points:
            print "# grid %d" %gp
            mc.set_grid_point(gp)
            mc.run_interaction()
            matrix_contributions_temp = []
            for sigma in sigmas:
                mc.set_sigma(sigma)
                max_freq = (np.amax(self._interaction.get_phonons()[0]) * 2
                            + sigma * 4)
                fpoints = np.arange(0, max_freq + frequency_step / 2,
                                    frequency_step)
                mc.set_fpoints(fpoints)
                mc.run()
                matrix_contribution = mc.get_imag_self_energy()
                matrix_contributions_temp.append(matrix_contribution)
                if not is_sum:
                    write_matrix_contribution(
                                gp,
                                self._mesh,
                                fpoints,
                                matrix_contribution,
                                sigma=sigma,
                                filename=filename)
            matrix_contributions.append(matrix_contributions_temp)
        matrix_contributions = np.array(matrix_contributions)

        if is_sum:
            for i, sigma in enumerate(sigmas):
                write_matrix_contribution(
                                    None,
                                    self._mesh,
                                    fpoints,
                                    np.sum(matrix_contributions[:,i], axis=0),
                                    sigma=sigma,
                                    filename=filename)

    def get_decay_channels(self,
                           grid_points,
                           sets_of_band_indices,
                           sigmas=[0.2],
                           nu=None,
                           scattering_class=None,
                           read_amplitude=False,
                           temperature=None,
                           filename=None):
        self._interaction.set_is_disperse(True)
        if grid_points==None:
            print "Grid points are not specified."
            return False

        if sets_of_band_indices==None:
            print "Band indices are not specified."
            return False
        self._read_amplitude = read_amplitude
        decay=DecayChannel(self._interaction, nu=nu, scattering_class=scattering_class)
        for gp in grid_points:
            decay.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Decay channel ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            # decay.run_interaction()
            for sigma in sigmas:
                decay.set_sigma(sigma)
                decay.run_interaction()
                for i, t in enumerate(temperature):
                    decay.set_temperature(t)
                    decay.get_decay_channels(filename = filename)


    def get_linewidth(self,
                      grid_points,
                      sigmas=[0.1],
                      temperatures=None,
                      read_amplitude=False,
                      nu=None,
                      scattering_class=None,
                      band_paths=None,
                      filename=None):
        self._interaction.set_is_disperse(True)
        ise = ImagSelfEnergy(self._interaction, nu=nu)
        if temperatures is None:
            temperatures = np.arange(0, 1000.0 + 10.0 / 2.0, 10.0)
        self._temperatures=temperatures
        self._read_amplitude=read_amplitude
        if grid_points is not None:
            self.get_linewidth_at_grid_points(ise,
                                              sigmas,
                                              temperatures,
                                              grid_points,
                                              nu,
                                              scattering_class,
                                              filename)
        elif band_paths is not None:
            self.get_linewidth_at_paths(ise,
                                        sigmas,
                                        temperatures,
                                        band_paths,
                                        nu,
                                        scattering_class,
                                        filename)

    def get_linewidth_at_paths(self,
                               ise,
                               sigmas,
                               temperatures,
                               band_paths,
                               is_nu,
                               scattering_class=None,
                               filename=None):

        if self._is_nosym:
            grid_address, grid_mapping =get_grid_address([x + (x % 2 == 0) for x in self._mesh], is_return_map=True)
        else:
            grids, weights, grid_address, grid_mapping = get_ir_grid_points([x + (x % 2 == 0) for x in self._mesh],
                                                                            self._primitive,
                                                                            is_return_map=True)
        qpoints_address=grid_address / np.array(self._mesh, dtype=float)
        print "Paths in reciprocal reduced coordinates:"
        for sigma in sigmas:
            self._sigma = sigma
            lws_paths=[]
            distances=[]
            frequencies=[]
            new_paths = []
            for path in band_paths:
                print "[%5.2f %5.2f %5.2f] --> [%5.2f %5.2f %5.2f]" % (tuple(path[0]) + tuple(path[-1]))
                (new_path,
                 dists,
                freqs,
                lws)=self.path(path,
                              qpoints_address,
                              grid_mapping,
                              ise,
                              temperatures,
                              scattering_class)
                new_paths.append(new_path)
                distances.append(dists)
                frequencies.append(freqs)
                lws_paths.append(lws)
            self._distances=distances
            self._freqs_on_path=frequencies
            self._lws_on_path=lws_paths

            write_linewidth_band_csv(self._mesh,
                                     new_paths,
                                     distances=self._distances,
                                     lws=self._lws_on_path,
                                     band_indices=self._band_indices,
                                     temperatures=temperatures,
                                     frequencies=self._freqs_on_path,
                                     scattering_class=scattering_class,
                                     nu=is_nu,
                                     filename=(("-s%s"%sigma) if sigma is not None else ""))
            self.plot_lw()

    def plot_lw(self, symbols=None):
        import matplotlib.pyplot as plt
        if symbols:
            from matplotlib import rc
            rc('text', usetex=True)
        distances=np.array(sum(np.array(self._distances).tolist(), []))
        special_point=[0.0] + [d[-1] for d in self._distances]
        lws=np.concatenate(tuple(self._lws_on_path), axis=0)
        for t in np.arange(lws.shape[1]):
            for b in np.arange(lws.shape[2]):
                plt.figure()
                plt.plot(distances, lws[:,t,b])
                plt.ylabel('Linewidth')
                plt.xlabel('Wave vector')
                if symbols and len(symbols)==len(special_point):
                    plt.xticks(special_point, symbols)
                else:
                    plt.xticks(special_point, [''] * len(special_point))
                plt.xlim(0, special_point[-1])
                plt.axhline(y=0, linestyle=':', linewidth=0.5, color='b')
                if len(lws.shape)== 4:
                    plt.legend(["Total","Normal process", "Umklapp process"])
                plt.savefig("linewidth-t%d-b%d.pdf"%(self._temperatures[t],self._band_indices[b]+1))
                plt.show()

    def path(self,
             path,
             qpoints_address,
             grids_mapping,
             ise,
             temperatures,
             scattering_class=None):
        lw_on_path=np.zeros((len(path),len(temperatures), len(self._band_indices)), dtype="double")
        freqs_on_path=np.zeros((len(path), len(self._band_indices)), dtype="double")
        new_path = []
        for p, qpoint in enumerate(path):
            # dist_vector=np.abs(qpoints_address-qpoint)
            distance= np.sqrt(np.sum((qpoints_address-qpoint) ** 2, axis=-1))
            grid=np.argmin(distance)
            ise.set_grid_point(grids_mapping[grid])
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Linewidth ------(%d/%d)"%(p, len(path))
                print "calculated at qpoint", qpoint
                print "and represented by grid: %d (%.7f %.7f %.7f) due to the finite mesh" % (grid, qpoints_address[grid][0], qpoints_address[grid][1], qpoints_address[grid][2])
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            new_path.append(qpoints_address[grid])
            ise.set_sigma(self._sigma)
            ise.run_interaction(scattering_class, self._read_amplitude)
            freqs_on_path[p]=self._interaction._frequencies[grids_mapping[grid]][self._band_indices]
            gamma = np.zeros((len(temperatures),
                              len(self._band_indices)),
                             dtype='double')
            for i, t in enumerate(temperatures):
                ise.set_temperature(t)
                ise.run(scattering_class, is_triplet_symmetry=self._interaction.get_is_symmetrize_fc3_q())
                gamma[i] = ise.get_imag_self_energy()

            for i, bi in enumerate(self._band_indices):
                lw_on_path[p,:,i]=gamma[:, i] * 2
        new_path = np.array(new_path)
        distances=map(lambda x: np.linalg.norm(np.dot(x-new_path[0],
                                                      np.linalg.inv(self._primitive.get_cell().T))),new_path)
        distances=np.array(distances, dtype="double")
        return (new_path, distances, freqs_on_path, lw_on_path)


    def get_linewidth_at_grid_points(self,
                                     ise,
                                     sigmas,
                                     temperatures,
                                     grid_points,
                                     is_nu,
                                     scattering_class,
                                     filename):
        for gp in grid_points:
            ise.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Linewidth ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            for sigma in sigmas:
                ise.set_sigma(sigma)
                ise.run_interaction(scattering_class, self._read_amplitude)
                gamma = np.zeros((len(temperatures),
                                  len(self._band_indices)),
                                 dtype='double')
                if is_nu:
                    gamma_N=np.zeros_like(gamma)
                    gamma_U=np.zeros_like(gamma)
                for i, t in enumerate(temperatures):
                    ise.set_temperature(t)
                    ise.run(scattering_class, is_triplet_symmetry=False)
                    gamma[i] = ise.get_imag_self_energy()
                    if is_nu:
                        gamma_N[i]=ise.get_imag_self_energy_N()
                        gamma_U[i]=ise.get_imag_self_energy_U()

                for i, bi in enumerate(self._band_indices):
                    # pos = 0
                    # for j in range(i):
                    #     pos += len(self._band_indices[j])

                    if not is_nu:
                        write_linewidth(gp,
                                        bi,
                                        temperatures,
                                        gamma[:, i],
                                        self._mesh,
                                        sigma=sigma,
                                        filename=filename)
                    else:
                        write_linewidth(gp,
                                        bi,
                                        temperatures,
                                        gamma[:, i],
                                        self._mesh,
                                        sigma=sigma,
                                        filename=filename,
                                        gamma_N=gamma_N[:, i],
                                        gamma_U=gamma_U[:, i])

    def get_frequency_shift(self,
                            grid_points,
                            epsilon=0.1,
                            temperatures=np.linspace(0,1000,endpoint=True, num=101),
                            filename=None):
        fst = FrequencyShift(self._interaction)
        for gp in grid_points:
            fst.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Frequency shift -o- ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            fst.run_interaction()
            fst.set_epsilon(epsilon)
            delta = np.zeros((len(temperatures),
                              len(self._band_indices)),
                             dtype='double')
            for i, t in enumerate(temperatures):
                fst.set_temperature(t)
                fst.run()
                delta[i] = fst.get_frequency_shift()

            for i, bi in enumerate(self._band_indices):
                pos = 0
                for j in range(i):
                    pos += len(self._band_indices[j])

                write_frequency_shift(gp,
                                      bi,
                                      temperatures,
                                      delta[:, pos:(pos+len(bi))],
                                      self._mesh,
                                      epsilon=epsilon,
                                      filename=filename)

    def get_thermal_conductivity(self,
                                 sigmas=None,
                                 temperatures=None,
                                 grid_points=None,
                                 mesh_divisors=None,
                                 coarse_mesh_shifts=None,
                                 cutoff_lifetime=1e-4,  # in second
                                 diff_kappa = 1e-5,  # relative
                                 nu=None,
                                 no_kappa_stars=False,
                                 gv_delta_q=1e-4,  # for group velocity
                                 write_gamma=False,
                                 read_gamma=False,
                                 kappa_write_step=None,
                                 filename=None):

        br = conductivity_RTA(self._interaction,
                              symmetry=self._primitive_symmetry,
                              sigmas=sigmas,
                              asigma_step= self._asigma_step,
                              temperatures=temperatures,
                              mesh_divisors=mesh_divisors,
                              coarse_mesh_shifts=coarse_mesh_shifts,
                              grid_points=grid_points,
                              cutoff_lifetime=cutoff_lifetime,
                              diff_kappa= diff_kappa,
                              nu=nu,
                              no_kappa_stars=no_kappa_stars,
                              gv_delta_q=gv_delta_q,
                              log_level=self._log_level,
                              write_tecplot = self._write_tecplot,
                              kappa_write_step=kappa_write_step,
                              is_thm=self._is_thm,
                              filename=filename)

        if read_gamma:
            for sigma in sigmas:
                self.read_gamma_at_sigma(sigma)
        br.calculate_kappa(write_gamma=write_gamma)
        mode_kappa = br.get_kappa()
        gamma = br.get_gamma()
        gamma_N=br._gamma_N
        gamma_U=br._gamma_U
        if self._log_level:
            br.print_kappa()
        if grid_points is None:
            temperatures = br.get_temperatures()
            for i, sigma in enumerate(sigmas):
                kappa = mode_kappa[i]
                write_kappa_to_hdf5(gamma[i],
                                    temperatures,
                                    br.get_mesh_numbers(),
                                    frequency=br.get_frequencies(),
                                    group_velocity=br.get_group_velocities(),
                                    heat_capacity=br.get_mode_heat_capacities(),
                                    kappa=kappa,
                                    qpoint=br.get_qpoints(),
                                    weight=br.get_grid_weights(),
                                    mesh_divisors=br.get_mesh_divisors(),
                                    sigma=sigma,
                                    filename=filename,
                                    gnu=(gamma_N[i],gamma_U[i]))
                if self._write_tecplot:
                    for j,temp in enumerate(temperatures):
                        write_kappa_to_tecplot_BZ(np.where(gamma[i,:,j]>1e-8, gamma[i,:,j],0),
                                               temp,
                                               br.get_mesh_numbers(),
                                               bz_q_address=br._bz_grid_address / br.get_mesh_numbers().astype(float),
                                               tetrahedrdons=br._unique_vertices,
                                               bz_to_pp_mapping=br._bz_to_pp_map,
                                               rec_lattice=np.linalg.inv(br._primitive.get_cell()),
                                               spg_indices_mapping=br._irr_index_mapping,
                                               spg_rotation_mapping=br._rot_mappings,
                                               frequency=br.get_frequencies(),
                                               group_velocity=br.get_group_velocities(),
                                               heat_capacity=br.get_mode_heat_capacities()[:,j],
                                               kappa=kappa[:,j],
                                               weight=br.get_grid_weights(),
                                               sigma=sigma,
                                               filename="bz")

        self._kappa = mode_kappa
        self._gamma = gamma
        self._br=br

    def read_gamma_at_sigma(self, sigma):
        br = self._br
        gamma = []
        try:
            properties = read_kappa_from_hdf5(
                br.get_mesh_numbers(),
                mesh_divisors=br.get_mesh_divisors(),
                sigma=sigma,
                filename=br._filename)
            if properties is None:
                raise ValueError
            tbr =  br.get_temperatures()
            ts_pos0, ts_pos1 = np.where(properties['temperature'] == tbr.reshape(-1,1))
            br.set_temperatures(tbr[ts_pos0])
            gamma_at_sigma=properties['gamma'][:,ts_pos1]
            gamma.append(gamma_at_sigma)
            br.broadcast_collision_out(np.double(gamma))
        except ValueError:
            properties = []
            for point in br.get_grid_points():
                property = read_kappa_from_hdf5(
                    br.get_mesh_numbers(),
                    mesh_divisors=br.get_mesh_divisors(),
                    grid_point=point,
                    sigma=sigma,
                    filename=br._filename)
                properties.append(property)
            tbr =  br.get_temperatures()
            ts_pos0,ts_pos1 = np.where(properties[0]['temperature'] == tbr.reshape(-1,1))
            br.set_temperatures(tbr[ts_pos0])
            gamma_at_sigma = np.array([p['gamma'][ts_pos1] for p in properties], dtype="double")
            gamma.append(gamma_at_sigma)
            br.broadcast_collision_out(np.double(gamma))

    def get_kappa_ite(self,
                      sigmas=[0.2],
                      temperatures=None,
                      grid_points=None,
                      max_ite = None,
                      no_kappa_stars=False,
                      diff_kappa = 1e-5, # relative difference
                      write_gamma=False,
                      read_gamma=False,
                      read_col=False,
                      write_col=False,
                      filename="ite"):
        bis=conductivity_ITE(self._interaction, #Iterative Boltzmann solutions
                             symmetry=self._primitive_symmetry,
                             sigmas=sigmas,
                             grid_points = grid_points,
                             temperatures=temperatures,
                             max_ite = max_ite,
                             adaptive_sigma_step = self._asigma_step,
                             no_kappa_stars=no_kappa_stars,
                             diff_kappa= diff_kappa,
                             mass_variances=self._mass_variances,
                             length=self._length,
                             log_level=self._log_level,
                             read_gamma = read_gamma,
                             write_gamma = write_gamma,
                             read_col = read_col,
                             write_col=write_col,
                             filename=filename)
        for s, sigma in enumerate(sigmas):
            write_kappa_to_hdf5(bis._gamma[s],
                        bis._temperatures,
                        bis._mesh,
                        frequency=bis._frequencies,
                        group_velocity=bis._gv,
                        heat_capacity=bis.get_mode_heat_capacities(),
                        kappa=bis._kappa[s],
                        qpoint=bis._qpoints,
                        weight=bis._grid_weights,
                        sigma=sigma,
                        filename="smrt")
        try:
            for bi in bis:
                bi.set_kappa()
                print "After %d iteration(s), the thermal conductivities are recalculated to be (W/mK)"%bi._ite_step
                bi.print_kappa()
        except KeyboardInterrupt:
            print
            print "A keyboard Interruption is captured. The iterations are terminated!"
            print "The kappa is retrieved from the last iterations."
            bis._F = bis._F_prev
        print "Final thermal conductivity (W/mK)"
        for s, sigma in enumerate(sigmas):
            bis.set_equivalent_gamma_at_sigma(s)
            bis.set_kappa_at_sigma(s)
            write_kappa_to_hdf5(bis._gamma[s],
                                bis._temperatures,
                                bis._mesh,
                                frequency=bis._frequencies,
                                group_velocity=bis._gv,
                                heat_capacity=bis.get_mode_heat_capacities(),
                                kappa=bis._kappa[s],
                                qpoint=bis._qpoints,
                                weight=bis._grid_weights,
                                sigma=sigma,
                                filename=bis._filename)
        self._gamma=bis._gamma
        self._kappa=bis._kappa
        bis.print_kappa()
        # bis.print_kappa_rta()

    def get_kappa_dinv(self,
                      sigmas=[0.2],
                      temperatures=None,
                      grid_points=None,
                      no_kappa_stars=False,
                      write_gamma=False,
                      read_gamma=False,
                      read_col=False,
                      write_col=False,
                      filename="dinv"):
        bis=conductivity_DINV(self._interaction, #Iterative Boltzmann solutions
                             symmetry=self._primitive_symmetry,
                             sigmas=sigmas,
                             grid_points = grid_points,
                             temperatures=temperatures,
                             adaptive_sigma_step = self._asigma_step,
                             no_kappa_stars=no_kappa_stars,
                             mass_variances=self._mass_variances,
                             length=self._length,
                             log_level=self._log_level,
                             read_gamma = read_gamma,
                             write_gamma = write_gamma,
                             read_col = read_col,
                             write_col=write_col,
                             filename=filename)

        bis.run()
        bis.set_kappa()

        print "Final thermal conductivity (W/mK)"
        # for s, sigma in enumerate(sigmas):
        #     bis.set_equivalent_gamma_at_sigma(s)
        #     bis.set_kappa_at_sigma(s)
        #     write_kappa_to_hdf5(bis._gamma[s],
        #                         bis._temperatures,
        #                         bis._mesh,
        #                         frequency=bis._frequencies,
        #                         group_velocity=bis._gv,
        #                         heat_capacity=bis.get_mode_heat_capacities(),
        #                         kappa=bis._kappa[s],
        #                         qpoint=bis._qpoints,
        #                         weight=bis._grid_weights,
        #                         sigma=sigma,
        #                         filename=bis._filename)
        self._gamma=bis._gamma
        self._kappa=bis._kappa
        bis.print_kappa()
        # bis.print_kappa_rta()

    def get_kappa_ite_cg(self,
                          sigmas=[0.2],
                          temperatures=None,
                          grid_points=None,
                          max_ite = None,
                          no_kappa_stars=False,
                          diff_kappa = 1e-5, # relative value
                          write_gamma=False,
                          read_gamma=False,
                          read_col=False,
                          write_col=False,
                          filename="ite_cg"):
        bis=conductivity_ITE_CG(self._interaction, #Iterative Boltzmann solutions
                            symmetry=self._primitive_symmetry,
                            sigmas=sigmas,
                            grid_points = grid_points,
                            temperatures=temperatures,
                            max_ite = max_ite,
                            adaptive_sigma_step = self._asigma_step,
                            no_kappa_stars=no_kappa_stars,
                            diff_kappa= diff_kappa,
                            mass_variances=self._mass_variances,
                            length=self._length,
                            log_level=self._log_level,
                            read_gamma = read_gamma,
                            write_gamma = write_gamma,
                            read_col = read_col,
                            write_col=write_col,
                            is_thm=self._is_thm,
                            filename=filename)

        for s, sigma in enumerate(sigmas):
            write_kappa_to_hdf5(bis._gamma[s],
                        bis._temperatures,
                        bis._mesh,
                        frequency=bis._frequencies,
                        group_velocity=bis._gv,
                        heat_capacity=bis.get_mode_heat_capacities(),
                        kappa=bis._kappa[s],
                        qpoint=bis._qpoints,
                        weight=bis._grid_weights,
                        sigma=sigma,
                        filename="smrt")

        try:
            for bi in bis:
                bi.set_kappa()
                print "After %d iteration(s), the thermal conductivities are recalculated to be (W/mK)"%bi._ite_step
                bi.print_kappa()
        except KeyboardInterrupt:
            print
            print "A keyboard Interruption is captured. The iterations are terminated!"
            print "The kappa is retrieved from the last iterations."
            bis._F = bis._F_prev
        print "Final thermal conductivity (W/mK)"
        for s, sigma in enumerate(sigmas):
            bis.set_equivalent_gamma_at_sigma(s)
            bis.set_kappa_at_sigma(s)
            write_kappa_to_hdf5(bis._gamma[s],
                                bis._temperatures,
                                bis._mesh,
                                frequency=bis._frequencies,
                                group_velocity=bis._gv,
                                heat_capacity=bis.get_mode_heat_capacities(),
                                kappa=bis._kappa[s],
                                qpoint=bis._qpoints,
                                weight=bis._grid_weights,
                                sigma=sigma,
                                filename=bis._filename)
        self._gamma=bis._gamma
        self._kappa=bis._kappa
        bis.print_kappa()
コード例 #15
0
class Phono3py:
    def __init__(
            self,
            interaction,
            mass_variances=None,
            length=None,
            adaptive_sigma_step=0,
            frequency_factor_to_THz=None,
            is_nosym=False,
            symprec=1e-5,
            log_level=0,
            is_thm=False,  # is tetrahedron method
            write_tecplot=False):
        self._interaction = interaction
        self._primitive = interaction.get_primitive()
        self._supercell = interaction.get_supercell()
        self._mesh = interaction.get_mesh_numbers()
        self._band_indices = interaction.get_band_indices()
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_nosym = is_nosym
        self._is_symmetry = not is_nosym
        self._symprec = symprec
        self._log_level = log_level
        self._asigma_step = adaptive_sigma_step
        self._step = 0
        self._kappa = None
        self._gamma = None
        self._br = None
        self._is_thm = is_thm
        self._write_tecplot = write_tecplot
        self._mass_variances = mass_variances
        self._length = length
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_primitive_symmetry(self):
        return self._primitive_symmetry

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell, self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive, self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) != len(
                self._primitive_symmetry.get_pointgroup_operations())):
            print(
                "Warning: point group symmetries of supercell and primitive"
                "cell are different.")

    def set_dynamical_matrix(self,
                             fc2,
                             supercell,
                             primitive,
                             nac_params=None,
                             nac_q_direction=None,
                             frequency_scale_factor=None):
        self._interaction.set_dynamical_matrix(
            fc2,
            supercell,
            primitive,
            nac_params=nac_params,
            frequency_scale_factor=frequency_scale_factor)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)

    def get_imag_self_energy(self,
                             grid_points,
                             frequency_step=1.0,
                             sigmas=[None],
                             temperatures=[0.0],
                             filename=None):
        ise = ImagSelfEnergy(self._interaction, is_thm=self._is_thm)
        for gp in grid_points:
            ise.set_grid_point(gp)
            ise.run_interaction()
            for sigma in sigmas:
                ise.set_sigma(sigma)
                for t in temperatures:
                    ise.set_temperature(t)
                    max_freq = (
                        np.amax(self._interaction.get_phonons()[0]) * 2 +
                        sigma * 4)
                    fpoints = np.arange(0, max_freq + frequency_step / 2,
                                        frequency_step)
                    ise.set_fpoints(fpoints)
                    ise.run()
                    gamma = ise.get_imag_self_energy()

                    for i, bi in enumerate(self._band_indices):
                        pos = 0
                        for j in range(i):
                            pos += len(self._band_indices[j])

                        write_damping_functions(
                            gp,
                            bi,
                            self._mesh,
                            fpoints,
                            gamma[:, pos:(pos + len(bi))].sum(axis=1) /
                            len(bi),
                            sigma=sigma,
                            temperature=t,
                            filename=filename)

    def get_matrix_contribution(self,
                                grid_points,
                                frequency_step=1.0,
                                sigmas=[0.1],
                                is_adaptive_sigma=False,
                                filename=None):
        mc = Collision(self._interaction,
                       sigmas=sigmas,
                       is_adaptive_sigma=is_adaptive_sigma,
                       frequencies=self._frequencies,
                       degeneracy=self._degeneracy,
                       write=write_scr,
                       read=read_scr,
                       cutoff_frequency=self._cutfr,
                       cutoff_lifetime=self._cutlt)
        is_sum = False
        if grid_points == None:
            is_sum = True
            if self._is_nosym:  # All grid points
                grid_points = np.arange(np.product(self._mesh))
            else:  # Automatic sampling
                (grid_points, grid_weights,
                 grid_address) = get_ir_grid_points(self._mesh,
                                                    self._primitive)
        matrix_contributions = []
        for gp in grid_points:
            print "# grid %d" % gp
            mc.set_grid_point(gp)
            mc.run_interaction()
            matrix_contributions_temp = []
            for sigma in sigmas:
                mc.set_sigma(sigma)
                max_freq = (np.amax(self._interaction.get_phonons()[0]) * 2 +
                            sigma * 4)
                fpoints = np.arange(0, max_freq + frequency_step / 2,
                                    frequency_step)
                mc.set_fpoints(fpoints)
                mc.run()
                matrix_contribution = mc.get_imag_self_energy()
                matrix_contributions_temp.append(matrix_contribution)
                if not is_sum:
                    write_matrix_contribution(gp,
                                              self._mesh,
                                              fpoints,
                                              matrix_contribution,
                                              sigma=sigma,
                                              filename=filename)
            matrix_contributions.append(matrix_contributions_temp)
        matrix_contributions = np.array(matrix_contributions)

        if is_sum:
            for i, sigma in enumerate(sigmas):
                write_matrix_contribution(None,
                                          self._mesh,
                                          fpoints,
                                          np.sum(matrix_contributions[:, i],
                                                 axis=0),
                                          sigma=sigma,
                                          filename=filename)

    def get_decay_channels(self,
                           grid_points,
                           sets_of_band_indices,
                           sigmas=[0.2],
                           nu=None,
                           scattering_class=None,
                           read_amplitude=False,
                           temperature=None,
                           filename=None):
        self._interaction.set_is_disperse(True)
        if grid_points == None:
            print "Grid points are not specified."
            return False

        if sets_of_band_indices == None:
            print "Band indices are not specified."
            return False
        self._read_amplitude = read_amplitude
        decay = DecayChannel(self._interaction,
                             nu=nu,
                             scattering_class=scattering_class)
        for gp in grid_points:
            decay.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Decay channel ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            # decay.run_interaction()
            for sigma in sigmas:
                decay.set_sigma(sigma)
                decay.run_interaction()
                for i, t in enumerate(temperature):
                    decay.set_temperature(t)
                    decay.get_decay_channels(filename=filename)

    def get_linewidth(self,
                      grid_points,
                      sigmas=[0.1],
                      temperatures=None,
                      read_amplitude=False,
                      nu=None,
                      scattering_class=None,
                      band_paths=None,
                      filename=None):
        self._interaction.set_is_disperse(True)
        ise = ImagSelfEnergy(self._interaction, nu=nu)
        if temperatures is None:
            temperatures = np.arange(0, 1000.0 + 10.0 / 2.0, 10.0)
        self._temperatures = temperatures
        self._read_amplitude = read_amplitude
        if grid_points is not None:
            self.get_linewidth_at_grid_points(ise, sigmas, temperatures,
                                              grid_points, nu,
                                              scattering_class, filename)
        elif band_paths is not None:
            self.get_linewidth_at_paths(ise, sigmas, temperatures, band_paths,
                                        nu, scattering_class, filename)

    def get_linewidth_at_paths(self,
                               ise,
                               sigmas,
                               temperatures,
                               band_paths,
                               is_nu,
                               scattering_class=None,
                               filename=None):

        if self._is_nosym:
            grid_address, grid_mapping = get_grid_address(
                [x + (x % 2 == 0) for x in self._mesh], is_return_map=True)
        else:
            grids, weights, grid_address, grid_mapping = get_ir_grid_points(
                [x + (x % 2 == 0) for x in self._mesh],
                self._primitive,
                is_return_map=True)
        qpoints_address = grid_address / np.array(self._mesh, dtype=float)
        print "Paths in reciprocal reduced coordinates:"
        for sigma in sigmas:
            self._sigma = sigma
            lws_paths = []
            distances = []
            frequencies = []
            new_paths = []
            for path in band_paths:
                print "[%5.2f %5.2f %5.2f] --> [%5.2f %5.2f %5.2f]" % (
                    tuple(path[0]) + tuple(path[-1]))
                (new_path, dists, freqs,
                 lws) = self.path(path, qpoints_address, grid_mapping, ise,
                                  temperatures, scattering_class)
                new_paths.append(new_path)
                distances.append(dists)
                frequencies.append(freqs)
                lws_paths.append(lws)
            self._distances = distances
            self._freqs_on_path = frequencies
            self._lws_on_path = lws_paths

            write_linewidth_band_csv(
                self._mesh,
                new_paths,
                distances=self._distances,
                lws=self._lws_on_path,
                band_indices=self._band_indices,
                temperatures=temperatures,
                frequencies=self._freqs_on_path,
                scattering_class=scattering_class,
                nu=is_nu,
                filename=(("-s%s" % sigma) if sigma is not None else ""))
            self.plot_lw()

    def plot_lw(self, symbols=None):
        import matplotlib.pyplot as plt
        if symbols:
            from matplotlib import rc
            rc('text', usetex=True)
        distances = np.array(sum(np.array(self._distances).tolist(), []))
        special_point = [0.0] + [d[-1] for d in self._distances]
        lws = np.concatenate(tuple(self._lws_on_path), axis=0)
        for t in np.arange(lws.shape[1]):
            for b in np.arange(lws.shape[2]):
                plt.figure()
                plt.plot(distances, lws[:, t, b])
                plt.ylabel('Linewidth')
                plt.xlabel('Wave vector')
                if symbols and len(symbols) == len(special_point):
                    plt.xticks(special_point, symbols)
                else:
                    plt.xticks(special_point, [''] * len(special_point))
                plt.xlim(0, special_point[-1])
                plt.axhline(y=0, linestyle=':', linewidth=0.5, color='b')
                if len(lws.shape) == 4:
                    plt.legend(["Total", "Normal process", "Umklapp process"])
                plt.savefig("linewidth-t%d-b%d.pdf" %
                            (self._temperatures[t], self._band_indices[b] + 1))
                plt.show()

    def path(self,
             path,
             qpoints_address,
             grids_mapping,
             ise,
             temperatures,
             scattering_class=None):
        lw_on_path = np.zeros(
            (len(path), len(temperatures), len(self._band_indices)),
            dtype="double")
        freqs_on_path = np.zeros((len(path), len(self._band_indices)),
                                 dtype="double")
        new_path = []
        for p, qpoint in enumerate(path):
            # dist_vector=np.abs(qpoints_address-qpoint)
            distance = np.sqrt(np.sum((qpoints_address - qpoint)**2, axis=-1))
            grid = np.argmin(distance)
            ise.set_grid_point(grids_mapping[grid])
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Linewidth ------(%d/%d)" % (p, len(path))
                print "calculated at qpoint", qpoint
                print "and represented by grid: %d (%.7f %.7f %.7f) due to the finite mesh" % (
                    grid, qpoints_address[grid][0], qpoints_address[grid][1],
                    qpoints_address[grid][2])
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            new_path.append(qpoints_address[grid])
            ise.set_sigma(self._sigma)
            ise.run_interaction(scattering_class, self._read_amplitude)
            freqs_on_path[p] = self._interaction._frequencies[
                grids_mapping[grid]][self._band_indices]
            gamma = np.zeros((len(temperatures), len(self._band_indices)),
                             dtype='double')
            for i, t in enumerate(temperatures):
                ise.set_temperature(t)
                ise.run(scattering_class,
                        is_triplet_symmetry=self._interaction.
                        get_is_symmetrize_fc3_q())
                gamma[i] = ise.get_imag_self_energy()

            for i, bi in enumerate(self._band_indices):
                lw_on_path[p, :, i] = gamma[:, i] * 2
        new_path = np.array(new_path)
        distances = map(
            lambda x: np.linalg.norm(
                np.dot(x - new_path[0],
                       np.linalg.inv(self._primitive.get_cell().T))), new_path)
        distances = np.array(distances, dtype="double")
        return (new_path, distances, freqs_on_path, lw_on_path)

    def get_linewidth_at_grid_points(self, ise, sigmas, temperatures,
                                     grid_points, is_nu, scattering_class,
                                     filename):
        for gp in grid_points:
            ise.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Linewidth ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            for sigma in sigmas:
                ise.set_sigma(sigma)
                ise.run_interaction(scattering_class, self._read_amplitude)
                gamma = np.zeros((len(temperatures), len(self._band_indices)),
                                 dtype='double')
                if is_nu:
                    gamma_N = np.zeros_like(gamma)
                    gamma_U = np.zeros_like(gamma)
                for i, t in enumerate(temperatures):
                    ise.set_temperature(t)
                    ise.run(scattering_class, is_triplet_symmetry=False)
                    gamma[i] = ise.get_imag_self_energy()
                    if is_nu:
                        gamma_N[i] = ise.get_imag_self_energy_N()
                        gamma_U[i] = ise.get_imag_self_energy_U()

                for i, bi in enumerate(self._band_indices):
                    # pos = 0
                    # for j in range(i):
                    #     pos += len(self._band_indices[j])

                    if not is_nu:
                        write_linewidth(gp,
                                        bi,
                                        temperatures,
                                        gamma[:, i],
                                        self._mesh,
                                        sigma=sigma,
                                        filename=filename)
                    else:
                        write_linewidth(gp,
                                        bi,
                                        temperatures,
                                        gamma[:, i],
                                        self._mesh,
                                        sigma=sigma,
                                        filename=filename,
                                        gamma_N=gamma_N[:, i],
                                        gamma_U=gamma_U[:, i])

    def get_frequency_shift(self,
                            grid_points,
                            epsilon=0.1,
                            temperatures=np.linspace(0,
                                                     1000,
                                                     endpoint=True,
                                                     num=101),
                            filename=None):
        fst = FrequencyShift(self._interaction)
        for gp in grid_points:
            fst.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Frequency shift -o- ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            fst.run_interaction()
            fst.set_epsilon(epsilon)
            delta = np.zeros((len(temperatures), len(self._band_indices)),
                             dtype='double')
            for i, t in enumerate(temperatures):
                fst.set_temperature(t)
                fst.run()
                delta[i] = fst.get_frequency_shift()

            for i, bi in enumerate(self._band_indices):
                pos = 0
                for j in range(i):
                    pos += len(self._band_indices[j])

                write_frequency_shift(gp,
                                      bi,
                                      temperatures,
                                      delta[:, pos:(pos + len(bi))],
                                      self._mesh,
                                      epsilon=epsilon,
                                      filename=filename)

    def get_thermal_conductivity(
            self,
            sigmas=None,
            temperatures=None,
            grid_points=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            cutoff_lifetime=1e-4,  # in second
            diff_kappa=1e-5,  # relative
            nu=None,
            no_kappa_stars=False,
            gv_delta_q=1e-4,  # for group velocity
            write_gamma=False,
            read_gamma=False,
            kappa_write_step=None,
            filename=None):

        br = conductivity_RTA(self._interaction,
                              symmetry=self._primitive_symmetry,
                              sigmas=sigmas,
                              asigma_step=self._asigma_step,
                              temperatures=temperatures,
                              mesh_divisors=mesh_divisors,
                              coarse_mesh_shifts=coarse_mesh_shifts,
                              grid_points=grid_points,
                              cutoff_lifetime=cutoff_lifetime,
                              diff_kappa=diff_kappa,
                              nu=nu,
                              no_kappa_stars=no_kappa_stars,
                              gv_delta_q=gv_delta_q,
                              log_level=self._log_level,
                              write_tecplot=self._write_tecplot,
                              kappa_write_step=kappa_write_step,
                              is_thm=self._is_thm,
                              filename=filename)

        if read_gamma:
            for sigma in sigmas:
                self.read_gamma_at_sigma(sigma)
        br.calculate_kappa(write_gamma=write_gamma)
        mode_kappa = br.get_kappa()
        gamma = br.get_gamma()
        gamma_N = br._gamma_N
        gamma_U = br._gamma_U
        if self._log_level:
            br.print_kappa()
        if grid_points is None:
            temperatures = br.get_temperatures()
            for i, sigma in enumerate(sigmas):
                kappa = mode_kappa[i]
                write_kappa_to_hdf5(
                    gamma[i],
                    temperatures,
                    br.get_mesh_numbers(),
                    frequency=br.get_frequencies(),
                    group_velocity=br.get_group_velocities(),
                    heat_capacity=br.get_mode_heat_capacities(),
                    kappa=kappa,
                    qpoint=br.get_qpoints(),
                    weight=br.get_grid_weights(),
                    mesh_divisors=br.get_mesh_divisors(),
                    sigma=sigma,
                    filename=filename,
                    gnu=(gamma_N[i], gamma_U[i]))
                if self._write_tecplot:
                    for j, temp in enumerate(temperatures):
                        write_kappa_to_tecplot_BZ(
                            np.where(gamma[i, :, j] > 1e-8, gamma[i, :, j], 0),
                            temp,
                            br.get_mesh_numbers(),
                            bz_q_address=br._bz_grid_address /
                            br.get_mesh_numbers().astype(float),
                            tetrahedrdons=br._unique_vertices,
                            bz_to_pp_mapping=br._bz_to_pp_map,
                            rec_lattice=np.linalg.inv(
                                br._primitive.get_cell()),
                            spg_indices_mapping=br._irr_index_mapping,
                            spg_rotation_mapping=br._rot_mappings,
                            frequency=br.get_frequencies(),
                            group_velocity=br.get_group_velocities(),
                            heat_capacity=br.get_mode_heat_capacities()[:, j],
                            kappa=kappa[:, j],
                            weight=br.get_grid_weights(),
                            sigma=sigma,
                            filename="bz")

        self._kappa = mode_kappa
        self._gamma = gamma
        self._br = br

    def read_gamma_at_sigma(self, sigma):
        br = self._br
        gamma = []
        try:
            properties = read_kappa_from_hdf5(
                br.get_mesh_numbers(),
                mesh_divisors=br.get_mesh_divisors(),
                sigma=sigma,
                filename=br._filename)
            if properties is None:
                raise ValueError
            tbr = br.get_temperatures()
            ts_pos0, ts_pos1 = np.where(
                properties['temperature'] == tbr.reshape(-1, 1))
            br.set_temperatures(tbr[ts_pos0])
            gamma_at_sigma = properties['gamma'][:, ts_pos1]
            gamma.append(gamma_at_sigma)
            br.broadcast_collision_out(np.double(gamma))
        except ValueError:
            properties = []
            for point in br.get_grid_points():
                property = read_kappa_from_hdf5(
                    br.get_mesh_numbers(),
                    mesh_divisors=br.get_mesh_divisors(),
                    grid_point=point,
                    sigma=sigma,
                    filename=br._filename)
                properties.append(property)
            tbr = br.get_temperatures()
            ts_pos0, ts_pos1 = np.where(
                properties[0]['temperature'] == tbr.reshape(-1, 1))
            br.set_temperatures(tbr[ts_pos0])
            gamma_at_sigma = np.array(
                [p['gamma'][ts_pos1] for p in properties], dtype="double")
            gamma.append(gamma_at_sigma)
            br.broadcast_collision_out(np.double(gamma))

    def get_kappa_ite(
            self,
            sigmas=[0.2],
            temperatures=None,
            grid_points=None,
            max_ite=None,
            no_kappa_stars=False,
            diff_kappa=1e-5,  # relative difference
            write_gamma=False,
            read_gamma=False,
            read_col=False,
            write_col=False,
            filename="ite"):
        bis = conductivity_ITE(
            self._interaction,  #Iterative Boltzmann solutions
            symmetry=self._primitive_symmetry,
            sigmas=sigmas,
            grid_points=grid_points,
            temperatures=temperatures,
            max_ite=max_ite,
            adaptive_sigma_step=self._asigma_step,
            no_kappa_stars=no_kappa_stars,
            diff_kappa=diff_kappa,
            mass_variances=self._mass_variances,
            length=self._length,
            log_level=self._log_level,
            read_gamma=read_gamma,
            write_gamma=write_gamma,
            read_col=read_col,
            write_col=write_col,
            filename=filename)
        for s, sigma in enumerate(sigmas):
            write_kappa_to_hdf5(bis._gamma[s],
                                bis._temperatures,
                                bis._mesh,
                                frequency=bis._frequencies,
                                group_velocity=bis._gv,
                                heat_capacity=bis.get_mode_heat_capacities(),
                                kappa=bis._kappa[s],
                                qpoint=bis._qpoints,
                                weight=bis._grid_weights,
                                sigma=sigma,
                                filename="smrt")
        try:
            for bi in bis:
                bi.set_kappa()
                print "After %d iteration(s), the thermal conductivities are recalculated to be (W/mK)" % bi._ite_step
                bi.print_kappa()
        except KeyboardInterrupt:
            print
            print "A keyboard Interruption is captured. The iterations are terminated!"
            print "The kappa is retrieved from the last iterations."
            bis._F = bis._F_prev
        print "Final thermal conductivity (W/mK)"
        for s, sigma in enumerate(sigmas):
            bis.set_equivalent_gamma_at_sigma(s)
            bis.set_kappa_at_sigma(s)
            write_kappa_to_hdf5(bis._gamma[s],
                                bis._temperatures,
                                bis._mesh,
                                frequency=bis._frequencies,
                                group_velocity=bis._gv,
                                heat_capacity=bis.get_mode_heat_capacities(),
                                kappa=bis._kappa[s],
                                qpoint=bis._qpoints,
                                weight=bis._grid_weights,
                                sigma=sigma,
                                filename=bis._filename)
        self._gamma = bis._gamma
        self._kappa = bis._kappa
        bis.print_kappa()
        # bis.print_kappa_rta()

    def get_kappa_dinv(self,
                       sigmas=[0.2],
                       temperatures=None,
                       grid_points=None,
                       no_kappa_stars=False,
                       write_gamma=False,
                       read_gamma=False,
                       read_col=False,
                       write_col=False,
                       filename="dinv"):
        bis = conductivity_DINV(
            self._interaction,  #Iterative Boltzmann solutions
            symmetry=self._primitive_symmetry,
            sigmas=sigmas,
            grid_points=grid_points,
            temperatures=temperatures,
            adaptive_sigma_step=self._asigma_step,
            no_kappa_stars=no_kappa_stars,
            mass_variances=self._mass_variances,
            length=self._length,
            log_level=self._log_level,
            read_gamma=read_gamma,
            write_gamma=write_gamma,
            read_col=read_col,
            write_col=write_col,
            filename=filename)

        bis.run()
        bis.set_kappa()

        print "Final thermal conductivity (W/mK)"
        # for s, sigma in enumerate(sigmas):
        #     bis.set_equivalent_gamma_at_sigma(s)
        #     bis.set_kappa_at_sigma(s)
        #     write_kappa_to_hdf5(bis._gamma[s],
        #                         bis._temperatures,
        #                         bis._mesh,
        #                         frequency=bis._frequencies,
        #                         group_velocity=bis._gv,
        #                         heat_capacity=bis.get_mode_heat_capacities(),
        #                         kappa=bis._kappa[s],
        #                         qpoint=bis._qpoints,
        #                         weight=bis._grid_weights,
        #                         sigma=sigma,
        #                         filename=bis._filename)
        self._gamma = bis._gamma
        self._kappa = bis._kappa
        bis.print_kappa()
        # bis.print_kappa_rta()

    def get_kappa_ite_cg(
            self,
            sigmas=[0.2],
            temperatures=None,
            grid_points=None,
            max_ite=None,
            no_kappa_stars=False,
            diff_kappa=1e-5,  # relative value
            write_gamma=False,
            read_gamma=False,
            read_col=False,
            write_col=False,
            filename="ite_cg"):
        bis = conductivity_ITE_CG(
            self._interaction,  #Iterative Boltzmann solutions
            symmetry=self._primitive_symmetry,
            sigmas=sigmas,
            grid_points=grid_points,
            temperatures=temperatures,
            max_ite=max_ite,
            adaptive_sigma_step=self._asigma_step,
            no_kappa_stars=no_kappa_stars,
            diff_kappa=diff_kappa,
            mass_variances=self._mass_variances,
            length=self._length,
            log_level=self._log_level,
            read_gamma=read_gamma,
            write_gamma=write_gamma,
            read_col=read_col,
            write_col=write_col,
            is_thm=self._is_thm,
            filename=filename)

        for s, sigma in enumerate(sigmas):
            write_kappa_to_hdf5(bis._gamma[s],
                                bis._temperatures,
                                bis._mesh,
                                frequency=bis._frequencies,
                                group_velocity=bis._gv,
                                heat_capacity=bis.get_mode_heat_capacities(),
                                kappa=bis._kappa[s],
                                qpoint=bis._qpoints,
                                weight=bis._grid_weights,
                                sigma=sigma,
                                filename="smrt")

        try:
            for bi in bis:
                bi.set_kappa()
                print "After %d iteration(s), the thermal conductivities are recalculated to be (W/mK)" % bi._ite_step
                bi.print_kappa()
        except KeyboardInterrupt:
            print
            print "A keyboard Interruption is captured. The iterations are terminated!"
            print "The kappa is retrieved from the last iterations."
            bis._F = bis._F_prev
        print "Final thermal conductivity (W/mK)"
        for s, sigma in enumerate(sigmas):
            bis.set_equivalent_gamma_at_sigma(s)
            bis.set_kappa_at_sigma(s)
            write_kappa_to_hdf5(bis._gamma[s],
                                bis._temperatures,
                                bis._mesh,
                                frequency=bis._frequencies,
                                group_velocity=bis._gv,
                                heat_capacity=bis.get_mode_heat_capacities(),
                                kappa=bis._kappa[s],
                                qpoint=bis._qpoints,
                                weight=bis._grid_weights,
                                sigma=sigma,
                                filename=bis._filename)
        self._gamma = bis._gamma
        self._kappa = bis._kappa
        bis.print_kappa()
コード例 #16
0
class Phono3py(object):
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 phonon_supercell_matrix=None,
                 masses=None,
                 mesh=None,
                 band_indices=None,
                 sigmas=None,
                 sigma_cutoff=None,
                 cutoff_frequency=1e-4,
                 frequency_factor_to_THz=VaspToTHz,
                 is_symmetry=True,
                 is_mesh_symmetry=True,
                 symmetrize_fc3_q=False,
                 symprec=1e-5,
                 log_level=0,
                 lapack_zheev_uplo='L'):
        if sigmas is None:
            self._sigmas = [None]
        else:
            self._sigmas = sigmas
        self._sigma_cutoff = sigma_cutoff
        self._symprec = symprec
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_symmetry = is_symmetry
        self._is_mesh_symmetry = is_mesh_symmetry
        self._lapack_zheev_uplo =  lapack_zheev_uplo
        self._symmetrize_fc3_q = symmetrize_fc3_q
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._phonon_supercell_matrix = phonon_supercell_matrix # optional
        self._supercell = None
        self._primitive = None
        self._phonon_supercell = None
        self._phonon_primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_phonon_supercell()
        self._build_phonon_primitive_cell()

        if masses is not None:
            self._set_masses(masses)

        # Set supercell, primitive, and phonon supercell symmetries
        self._symmetry = None
        self._primitive_symmetry = None
        self._phonon_supercell_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_phonon_supercell_symmetry()

        # Displacements and supercells
        self._supercells_with_displacements = None
        self._displacement_dataset = None
        self._phonon_displacement_dataset = None
        self._phonon_supercells_with_displacements = None

        # Thermal conductivity
        self._thermal_conductivity = None # conductivity_RTA object

        # Imaginary part of self energy at frequency points
        self._imag_self_energy = None
        self._scattering_event_class = None

        # Linewidth (Imaginary part of self energy x 2) at temperatures
        self._linewidth = None

        self._grid_points = None
        self._frequency_points = None
        self._temperatures = None

        # Other variables
        self._fc2 = None
        self._fc3 = None
        self._nac_params = None

        # Setup interaction
        self._interaction = None
        self._mesh = None
        self._band_indices = None
        self._band_indices_flatten = None
        if mesh is not None:
            self._mesh = np.array(mesh, dtype='intc')
        self.set_band_indices(band_indices)

    def set_band_indices(self, band_indices):
        if band_indices is None:
            num_band = self._primitive.get_number_of_atoms() * 3
            self._band_indices = [np.arange(num_band, dtype='intc')]
        else:
            self._band_indices = band_indices
        self._band_indices_flatten = np.hstack(self._band_indices).astype('intc')

    def set_phph_interaction(self,
                             nac_params=None,
                             nac_q_direction=None,
                             constant_averaged_interaction=None,
                             frequency_scale_factor=None,
                             unit_conversion=None):
        self._nac_params = nac_params
        self._interaction = Interaction(
            self._supercell,
            self._primitive,
            self._mesh,
            self._primitive_symmetry,
            fc3=self._fc3,
            band_indices=self._band_indices_flatten,
            constant_averaged_interaction=constant_averaged_interaction,
            frequency_factor_to_THz=self._frequency_factor_to_THz,
            unit_conversion=unit_conversion,
            cutoff_frequency=self._cutoff_frequency,
            is_mesh_symmetry=self._is_mesh_symmetry,
            symmetrize_fc3_q=self._symmetrize_fc3_q,
            lapack_zheev_uplo=self._lapack_zheev_uplo)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)
        self._interaction.set_dynamical_matrix(
            self._fc2,
            self._phonon_supercell,
            self._phonon_primitive,
            nac_params=self._nac_params,
            frequency_scale_factor=frequency_scale_factor)

    def set_phonon_data(self, frequencies, eigenvectors, grid_address):
        if self._interaction is not None:
            return self._interaction.set_phonon_data(frequencies,
                                                     eigenvectors,
                                                     grid_address)
        else:
            return False

    def write_phonons(self, filename=None):
        if self._interaction is not None:
            grid_address = self._interaction.get_grid_address()
            grid_points = np.arange(len(grid_address), dtype='intc')
            self._interaction.set_phonons(grid_points)
            freqs, eigvecs, _ = self._interaction.get_phonons()
            hdf5_filename = write_phonon_to_hdf5(freqs,
                                                 eigvecs,
                                                 grid_address,
                                                 self._mesh,
                                                 filename=filename)
            return hdf5_filename
        else:
            return False

    def generate_displacements(self,
                               distance=0.03,
                               cutoff_pair_distance=None,
                               is_plusminus='auto',
                               is_diagonal=True):
        direction_dataset = get_third_order_displacements(
            self._supercell,
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal)
        self._displacement_dataset = direction_to_displacement(
            direction_dataset,
            distance,
            self._supercell,
            cutoff_distance=cutoff_pair_distance)

        if self._phonon_supercell_matrix is not None:
            phonon_displacement_directions = get_least_displacements(
                self._phonon_supercell_symmetry,
                is_plusminus=is_plusminus,
                is_diagonal=False)
            self._phonon_displacement_dataset = direction_to_displacement_fc2(
                phonon_displacement_directions,
                distance,
                self._phonon_supercell)

    def produce_fc2(self,
                    forces_fc2,
                    displacement_dataset=None,
                    is_translational_symmetry=False,
                    is_permutation_symmetry=False,
                    translational_symmetry_type=None,
                    use_alm=False):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset

        if use_alm:
            from phono3py.other.alm_wrapper  import get_fc2 as get_fc2_alm
            self._fc2 = get_fc2_alm(self._phonon_supercell,
                                    forces_fc2,
                                    disp_dataset,
                                    self._phonon_supercell_symmetry)
        else:
            for forces, disp1 in zip(forces_fc2, disp_dataset['first_atoms']):
                disp1['forces'] = forces
            self._fc2 = get_fc2(self._phonon_supercell,
                                self._phonon_supercell_symmetry,
                                disp_dataset)
            if is_permutation_symmetry:
                set_permutation_symmetry(self._fc2)
            if is_translational_symmetry:
                tsym_type = 1
            else:
                tsym_type = 0
            if translational_symmetry_type:
                tsym_type = translational_symmetry_type
            if tsym_type:
                set_translational_invariance(
                    self._fc2,
                    translational_symmetry_type=tsym_type)

    def produce_fc3(self,
                    forces_fc3,
                    displacement_dataset=None,
                    cutoff_distance=None, # set fc3 zero
                    is_translational_symmetry=False,
                    is_permutation_symmetry=False,
                    is_permutation_symmetry_fc2=False,
                    translational_symmetry_type=None,
                    use_alm=False):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset

        if use_alm:
            from phono3py.other.alm_wrapper  import get_fc3 as get_fc3_alm
            fc2, fc3 = get_fc3_alm(self._supercell,
                                   forces_fc3,
                                   disp_dataset,
                                   self._symmetry)
        else:
            fc2, fc3 = self._get_fc3(forces_fc3,
                                     disp_dataset,
                                     cutoff_distance,
                                     is_translational_symmetry,
                                     is_permutation_symmetry,
                                     is_permutation_symmetry_fc2,
                                     translational_symmetry_type)

        # Set fc2 and fc3
        self._fc3 = fc3
        if self._fc2 is None:
            self._fc2 = fc2

    def cutoff_fc3_by_zero(self, cutoff_distance, fc3=None):
        if fc3 is None:
            _fc3 = self._fc3
        else:
            _fc3 = fc3
        cutoff_fc3_by_zero(_fc3, # overwritten
                           self._supercell,
                           cutoff_distance,
                           self._symprec)

    def set_permutation_symmetry(self):
        if self._fc2 is not None:
            set_permutation_symmetry(self._fc2)
        if self._fc3 is not None:
            set_permutation_symmetry_fc3(self._fc3)

    def set_translational_invariance(self,
                                     translational_symmetry_type=1):
        if self._fc2 is not None:
            set_translational_invariance(
                self._fc2,
                translational_symmetry_type=translational_symmetry_type)
        if self._fc3 is not None:
            set_translational_invariance_fc3(
                self._fc3,
                translational_symmetry_type=translational_symmetry_type)

    def get_version(self):
        return __version__

    def get_interaction_strength(self):
        return self._interaction

    def get_fc2(self):
        return self._fc2

    def set_fc2(self, fc2):
        self._fc2 = fc2

    def get_fc3(self):
        return self._fc3

    def set_fc3(self, fc3):
        self._fc3 = fc3

    def get_nac_params(self):
        return self._nac_params

    def get_primitive(self):
        return self._primitive

    def get_unitcell(self):
        return self._unitcell

    def get_supercell(self):
        return self._supercell

    def get_phonon_supercell(self):
        return self._phonon_supercell

    def get_phonon_primitive(self):
        return self._phonon_primitive

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_primitive_symmetry(self):
        return self._primitive_symmetry

    def get_phonon_supercell_symmetry(self):
        return self._phonon_supercell_symmetry

    def get_supercell_matrix(self):
        return self._supercell_matrix

    def get_primitive_matrix(self):
        return self._primitive_matrix

    def set_displacement_dataset(self, dataset):
        self._displacement_dataset = dataset

    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_phonon_displacement_dataset(self):
        return self._phonon_displacement_dataset

    def get_supercells_with_displacements(self):
        if self._supercells_with_displacements is None:
            self._build_supercells_with_displacements()
        return self._supercells_with_displacements

    def get_phonon_supercells_with_displacements(self):
        if self._phonon_supercells_with_displacements is None:
            if self._phonon_displacement_dataset is not None:
                self._phonon_supercells_with_displacements = \
                  self._build_phonon_supercells_with_displacements(
                      self._phonon_supercell,
                      self._phonon_displacement_dataset)
        return self._phonon_supercells_with_displacements

    def run_imag_self_energy(self,
                             grid_points,
                             frequency_step=None,
                             num_frequency_points=None,
                             temperatures=None,
                             scattering_event_class=None,
                             write_gamma_detail=False):
        if self._interaction is None:
            self.set_phph_interaction()
        if temperatures is None:
            temperatures = [0.0, 300.0]
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._scattering_event_class = scattering_event_class
        self._imag_self_energy, self._frequency_points = get_imag_self_energy(
            self._interaction,
            grid_points,
            self._sigmas,
            frequency_step=frequency_step,
            num_frequency_points=num_frequency_points,
            temperatures=temperatures,
            scattering_event_class=scattering_event_class,
            write_detail=write_gamma_detail,
            log_level=self._log_level)

    def write_imag_self_energy(self, filename=None):
        write_imag_self_energy(
            self._imag_self_energy,
            self._mesh,
            self._grid_points,
            self._band_indices,
            self._frequency_points,
            self._temperatures,
            self._sigmas,
            scattering_event_class=self._scattering_event_class,
            filename=filename,
            is_mesh_symmetry=self._is_mesh_symmetry)

    def run_linewidth(self,
                      grid_points,
                      temperatures=np.arange(0, 1001, 10, dtype='double'),
                      write_gamma_detail=False):
        if self._interaction is None:
            self.set_phph_interaction()
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._linewidth = get_linewidth(self._interaction,
                                        grid_points,
                                        self._sigmas,
                                        temperatures=temperatures,
                                        write_detail=write_gamma_detail,
                                        log_level=self._log_level)

    def write_linewidth(self, filename=None):
        write_linewidth(self._linewidth,
                        self._band_indices,
                        self._mesh,
                        self._grid_points,
                        self._sigmas,
                        self._temperatures,
                        filename=filename,
                        is_mesh_symmetry=self._is_mesh_symmetry)

    def run_thermal_conductivity(
            self,
            is_LBTE=False,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            is_isotope=False,
            mass_variances=None,
            grid_points=None,
            boundary_mfp=None, # in micrometre
            use_ave_pp=False,
            gamma_unit_conversion=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            is_reducible_collision_matrix=False,
            is_kappa_star=True,
            gv_delta_q=None, # for group velocity
            is_full_pp=False,
            pinv_cutoff=1.0e-8, # for pseudo-inversion of collision matrix
            pinv_solver=0, # solver of pseudo-inversion of collision matrix
            write_gamma=False,
            read_gamma=False,
            is_N_U=False,
            write_kappa=False,
            write_gamma_detail=False,
            write_collision=False,
            read_collision=False,
            write_pp=False,
            read_pp=False,
            write_LBTE_solution=False,
            input_filename=None,
            output_filename=None):
        if self._interaction is None:
            self.set_phph_interaction()
        if is_LBTE:
            self._thermal_conductivity = get_thermal_conductivity_LBTE(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                sigma_cutoff=self._sigma_cutoff,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                is_reducible_collision_matrix=is_reducible_collision_matrix,
                is_kappa_star=is_kappa_star,
                gv_delta_q=gv_delta_q,
                pinv_cutoff=pinv_cutoff,
                pinv_solver=pinv_solver,
                write_collision=write_collision,
                read_collision=read_collision,
                write_kappa=write_kappa,
                write_pp=write_pp,
                read_pp=read_pp,
                write_LBTE_solution=write_LBTE_solution,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)
        else:
            self._thermal_conductivity = get_thermal_conductivity_RTA(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                sigma_cutoff=self._sigma_cutoff,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                use_ave_pp=use_ave_pp,
                gamma_unit_conversion=gamma_unit_conversion,
                mesh_divisors=mesh_divisors,
                coarse_mesh_shifts=coarse_mesh_shifts,
                is_kappa_star=is_kappa_star,
                gv_delta_q=gv_delta_q,
                is_full_pp=is_full_pp,
                write_gamma=write_gamma,
                read_gamma=read_gamma,
                is_N_U=is_N_U,
                write_kappa=write_kappa,
                write_gamma_detail=write_gamma_detail,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)

    def get_thermal_conductivity(self):
        return self._thermal_conductivity

    def get_frequency_shift(self,
                            grid_points,
                            temperatures=np.arange(0, 1001, 10, dtype='double'),
                            output_filename=None):
        if self._interaction is None:
            self.set_phph_interaction()
        if epsilons is None:
            epsilons = [0.1]
        self._grid_points = grid_points
        get_frequency_shift(self._interaction,
                            self._grid_points,
                            self._band_indices,
                            self._sigmas,
                            temperatures,
                            output_filename=output_filename,
                            log_level=self._log_level)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print("Warning: point group symmetries of supercell and primitive"
                  "cell are different.")

    def _search_phonon_supercell_symmetry(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell_symmetry = self._symmetry
        else:
            self._phonon_supercell_symmetry = Symmetry(self._phonon_supercell,
                                                       self._symprec,
                                                       self._is_symmetry)

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """
        self._primitive = self._get_primitive_cell(
            self._supercell, self._supercell_matrix, self._primitive_matrix)

    def _build_phonon_supercell(self):
        """
        phonon_supercell:
          This supercell is used for harmonic phonons (frequencies,
          eigenvectors, group velocities, ...)
        phonon_supercell_matrix:
          Different supercell size can be specified.
        """
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell = self._supercell
        else:
            self._phonon_supercell = get_supercell(
                self._unitcell, self._phonon_supercell_matrix, self._symprec)

    def _build_phonon_primitive_cell(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_primitive = self._primitive
        else:
            self._phonon_primitive = self._get_primitive_cell(
                self._phonon_supercell,
                self._phonon_supercell_matrix,
                self._primitive_matrix)
            if self._primitive is not None:
                if (self._primitive.get_atomic_numbers() !=
                    self._phonon_primitive.get_atomic_numbers()).any():
                    print("********************* Warning *********************")
                    print(" Primitive cells for fc2 and fc3 can be different.")
                    print("********************* Warning *********************")


    def _build_phonon_supercells_with_displacements(self,
                                                    supercell,
                                                    displacement_dataset):
        supercells = []
        magmoms = supercell.get_magnetic_moments()
        masses = supercell.get_masses()
        numbers = supercell.get_atomic_numbers()
        lattice = supercell.get_cell()

        for disp1 in displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            positions = supercell.get_positions()
            positions[disp1['number']] += disp_cart1
            supercells.append(
                Atoms(numbers=numbers,
                      masses=masses,
                      magmoms=magmoms,
                      positions=positions,
                      cell=lattice,
                      pbc=True))

        return supercells

    def _build_supercells_with_displacements(self):
        supercells = []
        magmoms = self._supercell.get_magnetic_moments()
        masses = self._supercell.get_masses()
        numbers = self._supercell.get_atomic_numbers()
        lattice = self._supercell.get_cell()

        supercells = self._build_phonon_supercells_with_displacements(
            self._supercell,
            self._displacement_dataset)

        for disp1 in self._displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            for disp2 in disp1['second_atoms']:
                if 'included' in disp2:
                    included = disp2['included']
                else:
                    included = True
                if included:
                    positions = self._supercell.get_positions()
                    positions[disp1['number']] += disp_cart1
                    positions[disp2['number']] += disp2['displacement']
                    supercells.append(Atoms(numbers=numbers,
                                            masses=masses,
                                            magmoms=magmoms,
                                            positions=positions,
                                            cell=lattice,
                                            pbc=True))
                else:
                    supercells.append(None)

        self._supercells_with_displacements = supercells

    def _get_primitive_cell(self,
                            supercell,
                            supercell_matrix,
                            primitive_matrix):
        inv_supercell_matrix = np.linalg.inv(supercell_matrix)
        if primitive_matrix is None:
            t_mat = inv_supercell_matrix
        else:
            t_mat = np.dot(inv_supercell_matrix, primitive_matrix)

        return get_primitive(supercell, t_mat, self._symprec)

    def _set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[p2p_map[x] for x in
                             self._primitive.get_supercell_to_primitive_map()]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)

        self._phonon_primitive.set_masses(p_masses)
        p2p_map = self._phonon_primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[
            [p2p_map[x] for x in
             self._phonon_primitive.get_supercell_to_primitive_map()]]
        self._phonon_supercell.set_masses(s_masses)

    def _get_fc3(self,
                 forces_fc3,
                 disp_dataset,
                 cutoff_distance,
                 is_translational_symmetry,
                 is_permutation_symmetry,
                 is_permutation_symmetry_fc2,
                 translational_symmetry_type):
        for forces, disp1 in zip(forces_fc3, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        fc2 = get_fc2(self._supercell, self._symmetry, disp_dataset)
        if is_permutation_symmetry_fc2:
            set_permutation_symmetry(fc2)

        if is_translational_symmetry:
            tsym_type = 1
        else:
            tsym_type = 0
        if translational_symmetry_type:
            tsym_type = translational_symmetry_type
        if tsym_type:
            set_translational_invariance(
                fc2,
                translational_symmetry_type=tsym_type)

        count = len(disp_dataset['first_atoms'])
        for disp1 in disp_dataset['first_atoms']:
            for disp2 in disp1['second_atoms']:
                disp2['delta_forces'] = forces_fc3[count] - disp1['forces']
                count += 1
        fc3 = get_fc3(
            self._supercell,
            disp_dataset,
            fc2,
            self._symmetry,
            translational_symmetry_type=tsym_type,
            is_permutation_symmetry=is_permutation_symmetry,
            verbose=self._log_level)

        # Set fc3 elements zero beyond cutoff_distance
        if cutoff_distance:
            if self._log_level:
                print("Cutting-off fc3 by zero (cut-off distance: %f)" %
                      cutoff_distance)
            self.cutoff_fc3_by_zero(cutoff_distance, fc3=fc3)

        return fc2, fc3
コード例 #17
0
ファイル: joint_dos.py プロジェクト: gharib85/phono3py
class JointDos(object):
    def __init__(self,
                 mesh,
                 primitive,
                 supercell,
                 fc2,
                 nac_params=None,
                 nac_q_direction=None,
                 sigma=None,
                 cutoff_frequency=None,
                 frequency_step=None,
                 num_frequency_points=None,
                 temperatures=None,
                 frequency_factor_to_THz=VaspToTHz,
                 frequency_scale_factor=1.0,
                 is_mesh_symmetry=True,
                 symprec=1e-5,
                 filename=None,
                 log_level=False,
                 lapack_zheev_uplo='L'):

        self._grid_point = None
        self._mesh = np.array(mesh, dtype='intc')
        self._primitive = primitive
        self._supercell = supercell
        self._fc2 = fc2
        self._nac_params = nac_params
        self._nac_q_direction = None
        self.set_nac_q_direction(nac_q_direction)
        self._sigma = None
        self.set_sigma(sigma)

        if cutoff_frequency is None:
            self._cutoff_frequency = 0
        else:
            self._cutoff_frequency = cutoff_frequency
        self._frequency_step = frequency_step
        self._num_frequency_points = num_frequency_points
        self._temperatures = temperatures
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._frequency_scale_factor = frequency_scale_factor
        self._is_mesh_symmetry = is_mesh_symmetry
        self._symprec = symprec
        self._filename = filename
        self._log_level = log_level
        self._lapack_zheev_uplo = lapack_zheev_uplo

        self._num_band = self._primitive.get_number_of_atoms() * 3
        self._reciprocal_lattice = np.linalg.inv(self._primitive.get_cell())
        self._init_dynamical_matrix()
        self._symmetry = Symmetry(primitive, symprec)

        self._tetrahedron_method = None
        self._phonon_done = None
        self._frequencies = None
        self._eigenvectors = None

        self._joint_dos = None
        self._frequency_points = None

    def run(self):
        try:
            import phono3py._phono3py as phono3c
            self._run_c()
        except ImportError:
            print("Joint density of states in python is not implemented.")
            return None, None

    @property
    def dynamical_matrix(self):
        return self._dm

    @property
    def joint_dos(self):
        return self._joint_dos

    def get_joint_dos(self):
        warnings.warn("Use attribute, joint_dos", DeprecationWarning)
        return self.joint_dos

    @property
    def frequency_points(self):
        return self._frequency_points

    def get_frequency_points(self):
        warnings.warn("Use attribute, frequency_points", DeprecationWarning)
        return self.frequency_points

    def get_phonons(self):
        return self._frequencies, self._eigenvectors, self._phonon_done

    @property
    def primitive(self):
        return self._primitive

    def get_primitive(self):
        warnings.warn("Use attribute, primitive", DeprecationWarning)
        return self.primitive

    @property
    def mesh_numbers(self):
        return self._mesh

    def get_mesh_numbers(self):
        warnings.warn("Use attribute, mesh_numbers", DeprecationWarning)
        return self.mesh

    def set_nac_q_direction(self, nac_q_direction=None):
        if nac_q_direction is not None:
            self._nac_q_direction = np.array(nac_q_direction, dtype='double')

    def set_sigma(self, sigma):
        if sigma is None:
            self._sigma = None
        else:
            self._sigma = float(sigma)

    def set_grid_point(self, grid_point):
        self._grid_point = grid_point
        self._set_triplets()
        num_grid = np.prod(len(self._grid_address))
        num_band = self._num_band
        if self._phonon_done is None:
            self._phonon_done = np.zeros(num_grid, dtype='byte')
            self._frequencies = np.zeros((num_grid, num_band), dtype='double')
            itemsize = self._frequencies.itemsize
            self._eigenvectors = np.zeros((num_grid, num_band, num_band),
                                          dtype=("c%d" % (itemsize * 2)))

        self._joint_dos = None
        self._frequency_points = None
        self.run_phonon_solver(np.array([grid_point], dtype='uintp'))

    def get_triplets_at_q(self):
        return self._triplets_at_q, self._weights_at_q

    @property
    def grid_address(self):
        return self._grid_address

    def get_grid_address(self):
        warnings.warn("Use attribute, grid_address", DeprecationWarning)
        return self.grid_address

    @property
    def bz_map(self):
        return self._bz_map

    def get_bz_map(self):
        warnings.warn("Use attribute, bz_map", DeprecationWarning)
        return self._bz_map

    def _run_c(self, lang='C'):
        if self._sigma is None:
            if lang == 'C':
                self._run_c_with_g()
            else:
                if self._temperatures is not None:
                    print("JDOS with phonon occupation numbers doesn't work "
                          "in this option.")
                self._run_py_tetrahedron_method()
        else:
            self._run_c_with_g()

    def _run_c_with_g(self):
        self.run_phonon_solver(self._triplets_at_q.ravel())
        max_phonon_freq = np.max(self._frequencies)
        self._frequency_points = get_frequency_points(
            max_phonon_freq=max_phonon_freq,
            sigmas=[
                self._sigma,
            ],
            frequency_points=None,
            frequency_step=self._frequency_step,
            num_frequency_points=self._num_frequency_points)
        num_freq_points = len(self._frequency_points)
        num_mesh = np.prod(self._mesh)

        if self._temperatures is None:
            jdos = np.zeros((num_freq_points, 2), dtype='double')
        else:
            num_temps = len(self._temperatures)
            jdos = np.zeros((num_temps, num_freq_points, 2), dtype='double')
            occ_phonons = []
            for t in self._temperatures:
                freqs = self._frequencies[self._triplets_at_q[:, 1:]]
                occ_phonons.append(
                    np.where(freqs > self._cutoff_frequency,
                             bose_einstein(freqs, t), 0))

        for i, freq_point in enumerate(self._frequency_points):
            g, _ = get_triplets_integration_weights(
                self,
                np.array([freq_point], dtype='double'),
                self._sigma,
                is_collision_matrix=True,
                neighboring_phonons=(i == 0))

            if self._temperatures is None:
                jdos[i, 1] = np.sum(
                    np.tensordot(g[0, :, 0], self._weights_at_q, axes=(0, 0)))
                gx = g[2] - g[0]
                jdos[i, 0] = np.sum(
                    np.tensordot(gx[:, 0], self._weights_at_q, axes=(0, 0)))
            else:
                for j, n in enumerate(occ_phonons):
                    for k, l in list(np.ndindex(g.shape[3:])):
                        jdos[j, i, 1] += np.dot(
                            (n[:, 0, k] + n[:, 1, l] + 1) * g[0, :, 0, k, l],
                            self._weights_at_q)
                        jdos[j, i, 0] += np.dot(
                            (n[:, 0, k] - n[:, 1, l]) * g[1, :, 0, k, l],
                            self._weights_at_q)

        self._joint_dos = jdos / num_mesh

    def _run_py_tetrahedron_method(self):
        thm = TetrahedronMethod(self._reciprocal_lattice, mesh=self._mesh)
        self._vertices = get_tetrahedra_vertices(thm.get_tetrahedra(),
                                                 self._mesh,
                                                 self._triplets_at_q,
                                                 self._grid_address,
                                                 self._bz_map)
        self.run_phonon_solver(self._vertices.ravel())
        f_max = np.max(self._frequencies) * 2
        f_max *= 1.005
        f_min = 0
        self._set_uniform_frequency_points(f_min, f_max)

        num_freq_points = len(self._frequency_points)
        jdos = np.zeros((num_freq_points, 2), dtype='double')
        for vertices, w in zip(self._vertices, self._weights_at_q):
            for i, j in list(np.ndindex(self._num_band, self._num_band)):
                f1 = self._frequencies[vertices[0], i]
                f2 = self._frequencies[vertices[1], j]
                thm.set_tetrahedra_omegas(f1 + f2)
                thm.run(self._frequency_points)
                iw = thm.get_integration_weight()
                jdos[:, 1] += iw * w

                thm.set_tetrahedra_omegas(f1 - f2)
                thm.run(self._frequency_points)
                iw = thm.get_integration_weight()
                jdos[:, 0] += iw * w

                thm.set_tetrahedra_omegas(-f1 + f2)
                thm.run(self._frequency_points)
                iw = thm.get_integration_weight()
                jdos[:, 0] += iw * w

        self._joint_dos = jdos / np.prod(self._mesh)

    def _init_dynamical_matrix(self):
        self._dm = get_dynamical_matrix(
            self._fc2,
            self._supercell,
            self._primitive,
            nac_params=self._nac_params,
            frequency_scale_factor=self._frequency_scale_factor,
            symprec=self._symprec)

    def _set_triplets(self):
        if not self._is_mesh_symmetry:
            if self._log_level:
                print("Triplets at q without considering symmetry")
                sys.stdout.flush()

            (self._triplets_at_q, self._weights_at_q, self._grid_address,
             self._bz_map, map_triplets,
             map_q) = get_nosym_triplets_at_q(self._grid_point,
                                              self._mesh,
                                              self._reciprocal_lattice,
                                              with_bz_map=True)
        else:
            (self._triplets_at_q, self._weights_at_q, self._grid_address,
             self._bz_map, map_triplets, map_q) = get_triplets_at_q(
                 self._grid_point, self._mesh,
                 self._symmetry.get_pointgroup_operations(),
                 self._reciprocal_lattice)

    def run_phonon_solver(self, grid_points):
        run_phonon_solver_c(self._dm, self._frequencies, self._eigenvectors,
                            self._phonon_done, grid_points, self._grid_address,
                            self._mesh, self._frequency_factor_to_THz,
                            self._nac_q_direction, self._lapack_zheev_uplo)

    def set_frequency_points(self, frequency_points):
        self._frequency_points = np.array(frequency_points, dtype='double')
コード例 #18
0
class JointDos:
    def __init__(self,
                 mesh,
                 primitive,
                 supercell,
                 fc2,
                 nac_params=None,
                 nac_q_direction=None,
                 sigma=None,
                 cutoff_frequency=None,
                 frequency_step=None,
                 num_frequency_points=None,
                 temperatures=None,
                 frequency_factor_to_THz=VaspToTHz,
                 frequency_scale_factor=1.0,
                 is_nosym=False,
                 symprec=1e-5,
                 filename=None,
                 log_level=False,
                 lapack_zheev_uplo='L'):

        self._grid_point = None
        self._mesh = np.array(mesh, dtype='intc')
        self._primitive = primitive
        self._supercell = supercell
        self._fc2 = fc2
        self._nac_params = nac_params
        self._nac_q_direction = None
        self.set_nac_q_direction(nac_q_direction)
        self._sigma = None
        self.set_sigma(sigma)

        if cutoff_frequency is None:
            self._cutoff_frequency = 0
        else:
            self._cutoff_frequency = cutoff_frequency
        self._frequency_step = frequency_step
        self._num_frequency_points = num_frequency_points
        self._temperatures = temperatures
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._frequency_scale_factor = frequency_scale_factor
        self._is_nosym = is_nosym
        self._symprec = symprec
        self._filename = filename
        self._log_level = log_level
        self._lapack_zheev_uplo = lapack_zheev_uplo

        self._num_band = self._primitive.get_number_of_atoms() * 3
        self._reciprocal_lattice = np.linalg.inv(self._primitive.get_cell())
        self._set_dynamical_matrix()
        self._symmetry = Symmetry(primitive, symprec)

        self._tetrahedron_method = None
        self._phonon_done = None
        self._frequencies = None
        self._eigenvectors = None
            
        self._joint_dos = None
        self._frequency_points = None

    def run(self):
        try:
            import anharmonic._phono3py as phono3c
            self._run_c()
        except ImportError:
            print "Joint density of states in python is not implemented."
            return None, None

    def get_joint_dos(self):
        return self._joint_dos

    def get_frequency_points(self):
        return self._frequency_points

    def get_phonons(self):
        return self._frequencies, self._eigenvectors, self._phonon_done

    def get_primitive(self):
        return self._primitive

    def get_mesh_numbers(self):
        return self._mesh
        
    def set_nac_q_direction(self, nac_q_direction=None):
        if nac_q_direction is not None:
            self._nac_q_direction = np.array(nac_q_direction, dtype='double')

    def set_sigma(self, sigma):
        if sigma is None:
            self._sigma = None
        else:
            self._sigma = float(sigma)

    def set_grid_point(self, grid_point):
        self._grid_point = grid_point
        self._set_triplets()
        num_grid = np.prod(len(self._grid_address))
        num_band = self._num_band
        if self._phonon_done is None:
            self._phonon_done = np.zeros(num_grid, dtype='byte')
            self._frequencies = np.zeros((num_grid, num_band), dtype='double')
            self._eigenvectors = np.zeros((num_grid, num_band, num_band),
                                          dtype='complex128')
            
        self._joint_dos = None
        self._frequency_points = None
        self.set_phonon(np.array([grid_point], dtype='intc'))

    def get_triplets_at_q(self):
        return self._triplets_at_q, self._weights_at_q
        
    def get_grid_address(self):
        return self._grid_address

    def get_bz_map(self):
        return self._bz_map
    
    def _run_c(self, lang='C'):
        if self._sigma is None:
            if lang == 'C':
                self._run_c_with_g()
            else:
                if self._temperatures is not None:
                    print "JDOS with phonon occupation numbers doesn't work",
                    print "in this option."
                self._run_py_tetrahedron_method()
        else:
            self._run_c_with_g()
            # self._run_smearing_method() is an older and direct implementation.
            # This requies less memory space. self._run_c_with_g can be used
            # for smearing method and can share same code with tetrahedron 
            # method. Therefore maintainance cost of code can be reduced by
            # without using self._run_smearing_method().
                
    def _run_c_with_g(self):
        self.set_phonon(self._triplets_at_q.ravel())
        if self._sigma is None:
            f_max = np.max(self._frequencies) * 2
        else:
            f_max = np.max(self._frequencies) * 2 + self._sigma * 4
        f_max *= 1.005
        f_min = 0
        self._set_frequency_points(f_min, f_max)

        num_freq_points = len(self._frequency_points)
        num_mesh = np.prod(self._mesh)

        if self._temperatures is None:
            jdos = np.zeros((num_freq_points, 2), dtype='double')
        else:
            num_temps = len(self._temperatures)
            jdos = np.zeros((num_temps, num_freq_points, 2), dtype='double')
            occ_phonons = []
            for t in self._temperatures:
                freqs = self._frequencies[self._triplets_at_q[:, 1:]]
                occ_phonons.append(np.where(freqs > self._cutoff_frequency,
                                            occupation(freqs, t), 0))
        
        for i, freq_point in enumerate(self._frequency_points):
            g = get_triplets_integration_weights(
                self,
                np.array([freq_point], dtype='double'),
                self._sigma,
                is_collision_matrix=True,
                neighboring_phonons=(i == 0))

            if self._temperatures is None:
                jdos[i, 0] = np.sum(
                    np.tensordot(g[0, :, 0], self._weights_at_q, axes=(0, 0)))
                gx = g[2] - g[0]
                jdos[i, 1] = np.sum(
                    np.tensordot(gx[:, 0], self._weights_at_q, axes=(0, 0)))
            else:
                for j, n in enumerate(occ_phonons):
                    for k, l in list(np.ndindex(g.shape[3:])):
                        jdos[j, i, 0] += np.dot(
                            (n[:, 0, k] + n[:, 1, l] + 1) *
                            g[0, :, 0, k, l], self._weights_at_q)
                        jdos[j, i, 1] += np.dot((n[:, 0, k] - n[:, 1, l]) *
                                                g[1, :, 0, k, l],
                                                self._weights_at_q)

        self._joint_dos = jdos / num_mesh
    
    def _run_py_tetrahedron_method(self):
        thm = TetrahedronMethod(self._reciprocal_lattice, mesh=self._mesh)
        self._vertices = get_tetrahedra_vertices(
            thm.get_tetrahedra(),
            self._mesh,
            self._triplets_at_q,
            self._grid_address,
            self._bz_map)
        self.set_phonon(self._vertices.ravel())
        f_max = np.max(self._frequencies) * 2
        f_max *= 1.005
        f_min = 0
        self._set_frequency_points(f_min, f_max)

        num_freq_points = len(self._frequency_points)
        jdos = np.zeros((num_freq_points, 2), dtype='double')
        for vertices, w in zip(self._vertices, self._weights_at_q):
            for i, j in list(np.ndindex(self._num_band, self._num_band)):
                f1 = self._frequencies[vertices[0], i]
                f2 = self._frequencies[vertices[1], j]
                thm.set_tetrahedra_omegas(f1 + f2)
                thm.run(self._frequency_points)
                iw = thm.get_integration_weight()
                jdos[:, 0] += iw * w

                thm.set_tetrahedra_omegas(f1 - f2)
                thm.run(self._frequency_points)
                iw = thm.get_integration_weight()
                jdos[:, 1] += iw * w

                thm.set_tetrahedra_omegas(-f1 + f2)
                thm.run(self._frequency_points)
                iw = thm.get_integration_weight()
                jdos[:, 1] += iw * w

        self._joint_dos = jdos / np.prod(self._mesh)

    def _run_smearing_method(self):
        import anharmonic._phono3py as phono3c

        self.set_phonon(self._triplets_at_q.ravel())
        f_max = np.max(self._frequencies) * 2 + self._sigma * 4
        f_min = np.min(self._frequencies) * 2 - self._sigma * 4
        self._set_frequency_points(f_min, f_max)
        jdos = np.zeros((len(self._frequency_points), 2), dtype='double')
        phono3c.joint_dos(jdos,
                          self._frequency_points,
                          self._triplets_at_q,
                          self._weights_at_q,
                          self._frequencies,
                          self._sigma)
        jdos /= np.prod(self._mesh)
        self._joint_dos = jdos
        
    def _set_dynamical_matrix(self):
        self._dm = get_dynamical_matrix(
            self._fc2,
            self._supercell,
            self._primitive,
            nac_params=self._nac_params,
            frequency_scale_factor=self._frequency_scale_factor,
            symprec=self._symprec)
        
    def _set_triplets(self):
        if self._is_nosym:
            if self._log_level:
                print "Triplets at q without considering symmetry"
                sys.stdout.flush()
            
            (self._triplets_at_q,
             self._weights_at_q,
             self._grid_address,
             self._bz_map,
             map_triplets,
             map_q) = get_nosym_triplets_at_q(
                 self._grid_point,
                 self._mesh,
                 self._reciprocal_lattice,
                 with_bz_map=True)
        else:
            (self._triplets_at_q,
             self._weights_at_q,
             self._grid_address,
             self._bz_map,
             map_triplets,
             map_q) = get_triplets_at_q(
                 self._grid_point,
                 self._mesh,
                 self._symmetry.get_pointgroup_operations(),
                 self._reciprocal_lattice)

    def set_phonon(self, grid_points):
        set_phonon_c(self._dm,
                     self._frequencies,
                     self._eigenvectors,
                     self._phonon_done,
                     grid_points,
                     self._grid_address,
                     self._mesh,
                     self._frequency_factor_to_THz,
                     self._nac_q_direction,
                     self._lapack_zheev_uplo)

    def _set_frequency_points(self, f_min, f_max):
        if self._num_frequency_points is None:
            if self._frequency_step is not None:
                self._frequency_points = np.arange(
                    f_min, f_max, self._frequency_step, dtype='double')
            else:
                self._frequency_points = np.array(np.linspace(
                    f_min, f_max, 201), dtype='double')
        else:
            self._frequency_points = np.array(np.linspace(
                f_min, f_max, self._num_frequency_points), dtype='double')
コード例 #19
0
ファイル: __init__.py プロジェクト: arbegla/phonopy
class Phono3py:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 phonon_supercell_matrix=None,
                 mesh=None,
                 band_indices=None,
                 sigmas=[],
                 cutoff_frequency=1e-4,
                 frequency_factor_to_THz=VaspToTHz,
                 is_symmetry=True,
                 is_nosym=False,
                 symmetrize_fc3_q=False,
                 symprec=1e-5,
                 log_level=0,
                 lapack_zheev_uplo='L'):
        self._symprec = symprec
        self._sigmas = sigmas
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_symmetry = is_symmetry
        self._is_nosym = is_nosym
        self._lapack_zheev_uplo =  lapack_zheev_uplo
        self._symmetrize_fc3_q = symmetrize_fc3_q
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._phonon_supercell_matrix = phonon_supercell_matrix # optional
        self._supercell = None
        self._primitive = None
        self._phonon_supercell = None
        self._phonon_primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_phonon_supercell()
        self._build_phonon_primitive_cell()

        # Set supercell, primitive, and phonon supercell symmetries
        self._symmetry = None
        self._primitive_symmetry = None
        self._phonon_supercell_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_phonon_supercell_symmetry()

        # Displacements and supercells
        self._supercells_with_displacements = None
        self._displacement_dataset = None
        self._phonon_displacement_dataset = None
        self._phonon_supercells_with_displacements = None
                
        # Thermal conductivity
        self._thermal_conductivity = None # conductivity_RTA object

        # Imaginary part of self energy at frequency points
        self._imag_self_energy = None

        # Linewidth (Imaginary part of self energy x 2) at temperatures
        self._linewidth = None

        self._grid_points = None
        self._frequency_points = None
        self._temperatures = None

        # Other variables
        self._fc2 = None
        self._fc3 = None
        
        # Setup interaction
        self._interaction = None
        self._mesh = None
        self._band_indices = None
        self._band_indices_flatten = None
        if mesh is not None:
            self._mesh = np.array(mesh, dtype='intc')
        if band_indices is None:
            num_band = self._primitive.get_number_of_atoms() * 3
            self._band_indices = [np.arange(num_band)]
        else:
            self._band_indices = band_indices
        self._band_indices_flatten = np.hstack(self._band_indices).astype('intc')

    def set_phph_interaction(self,
                             nac_params=None,
                             nac_q_direction=None,
                             frequency_scale_factor=None):
        self._interaction = Interaction(
            self._supercell,
            self._primitive,
            self._mesh,
            self._primitive_symmetry,
            fc3=self._fc3,
            band_indices=self._band_indices_flatten,
            frequency_factor_to_THz=self._frequency_factor_to_THz,
            cutoff_frequency=self._cutoff_frequency,
            is_nosym=self._is_nosym,
            symmetrize_fc3_q=self._symmetrize_fc3_q,
            lapack_zheev_uplo=self._lapack_zheev_uplo)
        self._interaction.set_dynamical_matrix(
            self._fc2,
            self._phonon_supercell,
            self._phonon_primitive,
            nac_params=nac_params,
            frequency_scale_factor=frequency_scale_factor)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)

    def generate_displacements(self,
                               distance=0.03,
                               cutoff_pair_distance=None,
                               is_plusminus='auto',
                               is_diagonal=True):
        direction_dataset = get_third_order_displacements(
            self._supercell,
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal)
        self._displacement_dataset = direction_to_displacement(
            direction_dataset,
            distance,
            self._supercell,
            cutoff_distance=cutoff_pair_distance)

        if self._phonon_supercell_matrix is not None:
            phonon_displacement_directions = get_least_displacements(
                self._phonon_supercell_symmetry,
                is_plusminus=is_plusminus,
                is_diagonal=False)
            self._phonon_displacement_dataset = direction_to_displacement_fc2(
                phonon_displacement_directions,
                distance,
                self._phonon_supercell)
            
    def produce_fc2(self,
                    forces_fc2,
                    displacement_dataset=None,
                    is_permutation_symmetry=False,
                    is_translational_symmetry=False):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset
            
        for forces, disp1 in zip(forces_fc2, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        self._fc2 = get_fc2(self._phonon_supercell,
                            self._phonon_supercell_symmetry,
                            disp_dataset)
        if is_permutation_symmetry:
            set_permutation_symmetry(self._fc2)
        if is_translational_symmetry:
            set_translational_invariance(self._fc2)

    def produce_fc3(self,
                    forces_fc3,
                    displacement_dataset=None,
                    cutoff_distance=None, # set fc3 zero
                    is_translational_symmetry=False,
                    is_permutation_symmetry=False):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset
        
        for forces, disp1 in zip(forces_fc3, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        fc2 = get_fc2(self._supercell, self._symmetry, disp_dataset)
        if is_permutation_symmetry:
            set_permutation_symmetry(fc2)
        if is_translational_symmetry:
            set_translational_invariance(fc2)
        
        count = len(disp_dataset['first_atoms'])
        for disp1 in disp_dataset['first_atoms']:
            for disp2 in disp1['second_atoms']:
                disp2['delta_forces'] = forces_fc3[count] - disp1['forces']
                count += 1
        self._fc3 = get_fc3(
            self._supercell,
            disp_dataset,
            fc2,
            self._symmetry,
            is_translational_symmetry=is_translational_symmetry,
            is_permutation_symmetry=is_permutation_symmetry,
            verbose=self._log_level)

        # Set fc3 elements zero beyond cutoff_distance
        if cutoff_distance:
            if self._log_level:
                print ("Cutting-off fc3 by zero (cut-off distance: %f)" %
                       cutoff_distance)
            self.cutoff_fc3_by_zero(cutoff_distance)

        # Set fc2
        if self._fc2 is None:
            self._fc2 = fc2

    def cutoff_fc3_by_zero(self, cutoff_distance):
        cutoff_fc3_by_zero(self._fc3,
                           self._supercell,
                           cutoff_distance,
                           self._symprec)
            
    def set_permutation_symmetry(self):
        if self._fc2 is not None:
            set_permutation_symmetry(self._fc2)
        if self._fc3 is not None:
            set_permutation_symmetry_fc3(self._fc3)

    def set_translational_invariance(self):
        if self._fc2 is not None:
            set_translational_invariance(self._fc2)
        if self._fc3 is not None:
            set_translational_invariance_fc3(self._fc3)
        
    def get_interaction_strength(self):
        return self._interaction
        
    def get_fc2(self):
        return self._fc2

    def set_fc2(self, fc2):
        self._fc2 = fc2

    def get_fc3(self):
        return self._fc3

    def set_fc3(self, fc3):
        self._fc3 = fc3

    def get_primitive(self):
        return self._primitive

    def get_unitcell(self):
        return self._unitcell

    def get_supercell(self):
        return self._supercell

    def get_phonon_supercell(self):
        return self._phonon_supercell

    def get_phonon_primitive(self):
        return self._phonon_primitive

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_primitive_symmetry(self):
        return self._primitive_symmetry

    def get_phonon_supercell_symmetry(self):
        return self._phonon_supercell_symmetry
        
    def set_displacement_dataset(self, dataset):
        self._displacement_dataset = dataset
        
    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_phonon_displacement_dataset(self):
        return self._phonon_displacement_dataset

    def get_supercells_with_displacements(self):
        if self._supercells_with_displacements is None:
            self._build_supercells_with_displacements()
        return self._supercells_with_displacements

    def get_phonon_supercells_with_displacements(self):
        if self._phonon_supercells_with_displacements is None:
            if self._phonon_displacement_dataset is not None:
                self._phonon_supercells_with_displacements = \
                  self._build_phonon_supercells_with_displacements(
                      self._phonon_supercell,
                      self._phonon_displacement_dataset)
        return self._phonon_supercells_with_displacements
        
    def run_imag_self_energy(self,
                             grid_points,
                             frequency_step=0.1,
                             temperatures=[0.0, 300.0]):
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._imag_self_energy, self._frequency_points = get_imag_self_energy(
            self._interaction,
            grid_points,
            self._sigmas,
            frequency_step=frequency_step,
            temperatures=temperatures,
            log_level=self._log_level)
            
    def write_imag_self_energy(self, filename=None):
        write_imag_self_energy(self._imag_self_energy,
                               self._mesh,
                               self._grid_points,
                               self._band_indices,
                               self._frequency_points,
                               self._temperatures,
                               self._sigmas,
                               filename=filename)
        
    def run_linewidth(self,
                      grid_points,
                      temperatures=np.arange(0, 1001, 10, dtype='double')):
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._linewidth = get_linewidth(self._interaction,
                                        grid_points,
                                        self._sigmas,
                                        temperatures=temperatures,
                                        log_level=self._log_level)

    def write_linewidth(self, filename=None):
        write_linewidth(self._linewidth,
                        self._band_indices,
                        self._mesh,
                        self._grid_points,
                        self._sigmas,
                        self._temperatures,
                        filename=filename)

    def run_thermal_conductivity(
            self,
            is_LBTE=True,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            sigmas=[],
            mass_variances=None,
            grid_points=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            cutoff_lifetime=1e-4, # in second
            no_kappa_stars=False,
            gv_delta_q=None, # for group velocity
            write_gamma=False,
            read_gamma=False,
            write_collision=False,
            read_collision=False,
            write_amplitude=False,
            read_amplitude=False,
            input_filename=None,
            output_filename=None):

        if is_LBTE:
            self._thermal_conductivity = get_thermal_conductivity_LBTE(
                    self._interaction,
                    self._primitive_symmetry,
                    temperatures=temperatures,
                    sigmas=self._sigmas,
                    mass_variances=mass_variances,
                    grid_points=grid_points,
                    cutoff_lifetime=cutoff_lifetime,
                    gv_delta_q=gv_delta_q,
                    write_collision=write_collision,
                    read_collision=read_collision,
                    input_filename=input_filename,
                    output_filename=output_filename,
                    log_level=self._log_level)
        else:
            self._thermal_conductivity = get_thermal_conductivity_RTA(
                    self._interaction,
                    self._primitive_symmetry,
                    temperatures=temperatures,
                    sigmas=self._sigmas,
                    mass_variances=mass_variances,
                    grid_points=grid_points,
                    mesh_divisors=mesh_divisors,
                    coarse_mesh_shifts=coarse_mesh_shifts,
                    cutoff_lifetime=cutoff_lifetime,
                    no_kappa_stars=no_kappa_stars,
                    gv_delta_q=gv_delta_q,
                    write_gamma=write_gamma,
                    read_gamma=read_gamma,
                    input_filename=input_filename,
                    output_filename=output_filename,
                    log_level=self._log_level)

    def get_thermal_conductivity(self):
        return self._thermal_conductivity

    def get_frequency_shift(self,
                            grid_points,
                            epsilon=0.1,
                            temperatures=np.arange(0, 1001, 10, dtype='double'),
                            output_filename=None):
        fst = FrequencyShift(self._interaction)
        for gp in grid_points:
            fst.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Frequency shift -o- ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            fst.run_interaction()
            fst.set_epsilon(epsilon)
            delta = np.zeros((len(temperatures),
                              len(self._band_indices_flatten)),
                             dtype='double')
            for i, t in enumerate(temperatures):
                fst.set_temperature(t)
                fst.run()
                delta[i] = fst.get_frequency_shift()

            for i, bi in enumerate(self._band_indices):
                pos = 0
                for j in range(i):
                    pos += len(self._band_indices[j])

                write_frequency_shift(gp,
                                      bi,
                                      temperatures,
                                      delta[:, pos:(pos+len(bi))],
                                      self._mesh,
                                      epsilon=epsilon,
                                      filename=output_filename)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print ("Warning: point group symmetries of supercell and primitive"
                   "cell are different.")
        
    def _search_phonon_supercell_symmetry(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell_symmetry = self._symmetry
        else:
            self._phonon_supercell_symmetry = Symmetry(self._phonon_supercell,
                                                       self._symprec,
                                                       self._is_symmetry)

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """
        self._primitive = self._get_primitive_cell(
            self._supercell, self._supercell_matrix, self._primitive_matrix)

    def _build_phonon_supercell(self):
        """
        phonon_supercell:
          This supercell is used for harmonic phonons (frequencies,
          eigenvectors, group velocities, ...)
        phonon_supercell_matrix:
          Different supercell size can be specified.
        """
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell = self._supercell
        else:
            self._phonon_supercell = get_supercell(
                self._unitcell, self._phonon_supercell_matrix, self._symprec)

    def _build_phonon_primitive_cell(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_primitive = self._primitive
        else:
            self._phonon_primitive = self._get_primitive_cell(
                self._phonon_supercell,
                self._phonon_supercell_matrix,
                self._primitive_matrix)

    def _build_phonon_supercells_with_displacements(self,
                                                    supercell,
                                                    displacement_dataset):
        supercells = []
        magmoms = supercell.get_magnetic_moments()
        masses = supercell.get_masses()
        numbers = supercell.get_atomic_numbers()
        lattice = supercell.get_cell()
        
        for disp1 in displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            positions = supercell.get_positions()
            positions[disp1['number']] += disp_cart1
            supercells.append(
                Atoms(numbers=numbers,
                      masses=masses,
                      magmoms=magmoms,
                      positions=positions,
                      cell=lattice,
                      pbc=True))

        return supercells
            
    def _build_supercells_with_displacements(self):
        supercells = []
        magmoms = self._supercell.get_magnetic_moments()
        masses = self._supercell.get_masses()
        numbers = self._supercell.get_atomic_numbers()
        lattice = self._supercell.get_cell()
        
        supercells = self._build_phonon_supercells_with_displacements(
            self._supercell,
            self._displacement_dataset)
        
        for disp1 in self._displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            for disp2 in disp1['second_atoms']:
                if 'included' in disp2:
                    included = disp2['included']
                else:
                    included = True
                if included:
                    positions = self._supercell.get_positions()
                    positions[disp1['number']] += disp_cart1
                    positions[disp2['number']] += disp2['displacement']
                    supercells.append(Atoms(numbers=numbers,
                                            masses=masses,
                                            magmoms=magmoms,
                                            positions=positions,
                                            cell=lattice,
                                            pbc=True))
                else:
                    supercells.append(None)

        self._supercells_with_displacements = supercells
            
    def _get_primitive_cell(self, supercell, supercell_matrix, primitive_matrix):
        inv_supercell_matrix = np.linalg.inv(supercell_matrix)
        if primitive_matrix is None:
            t_mat = inv_supercell_matrix
        else:
            t_mat = np.dot(inv_supercell_matrix, primitive_matrix)
            
        return get_primitive(supercell, t_mat, self._symprec)
コード例 #20
0
ファイル: triplets_search.py プロジェクト: FermiSea/phonopy
import numpy as np

cell = read_vasp("POSCAR-unitcell")
symmetry = Symmetry(cell, 1e-2)
print symmetry.get_international_table()
reciprocal_lattice = np.linalg.inv(cell.get_cell())
mesh = [7, 7, 7]

print reciprocal_lattice

(triplets_at_q,
 weights_at_q,
 grid_address,
 bz_map,
 triplets_map_at_q,
 ir_map_at_q)= get_triplets_at_q(74,
                                 mesh,
                                 symmetry.get_pointgroup_operations(),
                                 reciprocal_lattice,
                                 stores_triplets_map=True)

for triplet in triplets_at_q:
    sum_q = (grid_address[triplet]).sum(axis=0)
    if (sum_q % mesh != 0).any():
        print "============= Warning =================="
        print triplet
        for tp in triplet:
            print grid_address[tp], np.linalg.norm(np.dot(reciprocal_lattice, grid_address[tp] / mesh))
        print sum_q
        print "============= Warning =================="
コード例 #21
0
ファイル: joint_dos.py プロジェクト: arbegla/phonopy
class JointDos:
    def __init__(self,
                 mesh,
                 primitive,
                 supercell,
                 fc2,
                 nac_params=None,
                 sigma=None,
                 frequency_step=0.1,
                 frequency_factor_to_THz=VaspToTHz,
                 frequency_scale_factor=1.0,
                 is_nosym=False,
                 symprec=1e-5,
                 filename=None,
                 log_level=False,
                 lapack_zheev_uplo='L'):

        self._grid_point = None
        self._mesh = np.array(mesh, dtype='intc')
        self._primitive = primitive
        self._supercell = supercell
        self._fc2 = fc2
        self._nac_params = nac_params
        self.set_sigma(sigma)

        self._frequency_step = frequency_step
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._frequency_scale_factor = frequency_scale_factor
        self._is_nosym = is_nosym
        self._symprec = symprec
        self._filename = filename
        self._log_level = log_level
        self._lapack_zheev_uplo = lapack_zheev_uplo

        self._num_band = self._primitive.get_number_of_atoms() * 3
        self._reciprocal_lattice = np.linalg.inv(self._primitive.get_cell())
        self._set_dynamical_matrix()
        self._symmetry = Symmetry(primitive, symprec)

        self._tetrahedron_method = None
        self._phonon_done = None
        self._frequencies = None
        self._eigenvectors = None
        self._nac_q_direction = None
            
        self._joint_dos = None
        self._frequency_points = None

    def run(self):
        try:
            import anharmonic._phono3py as phono3c
            self._run_c()
        except ImportError:
            print "Joint density of states in python is not implemented."
            return None, None

    def get_joint_dos(self):
        return self._joint_dos

    def get_frequency_points(self):
        return self._frequency_points

    def get_phonons(self):
        return self._frequencies, self._eigenvectors, self._phonon_done
    
    def set_nac_q_direction(self, nac_q_direction=None):
        if nac_q_direction is not None:
            self._nac_q_direction = np.array(nac_q_direction, dtype='double')

    def set_sigma(self, sigma):
        if sigma is None:
            self._sigma = None
        else:
            self._sigma = float(sigma)

    def set_grid_point(self, grid_point):
        self._grid_point = grid_point
        self._set_triplets()
        num_grid = np.prod(len(self._grid_address))
        num_band = self._num_band
        if self._phonon_done is None:
            self._phonon_done = np.zeros(num_grid, dtype='byte')
            self._frequencies = np.zeros((num_grid, num_band), dtype='double')
            self._eigenvectors = np.zeros((num_grid, num_band, num_band),
                                          dtype='complex128')
            
        self._joint_dos = []
        self._frequency_points = []
        self._set_phonon(np.array([grid_point], dtype='intc'))

    def get_grid_address(self):
        return self._grid_address

    def get_triplets_at_q(self):
        return self._triplets_at_q, self._weights_at_q
        
    def _run_c(self, lang='Py'):
        if self._sigma is None:
            self._tetrahedron_method = TetrahedronMethod(
                self._reciprocal_lattice, mesh=self._mesh)
            if lang == 'C':
                self._run_c_tetrahedron_method()
            else:
                self._run_py_tetrahedron_method()
        else:
            self._run_smearing_method()

    def _run_c_tetrahedron_method(self):
        """
        This is not very faster than _run_c_tetrahedron_method and
        use much more memory space. So this function is not set as default.
        """
        import anharmonic._phono3py as phono3c
        thm = self._tetrahedron_method 
        unique_vertices = thm.get_unique_tetrahedra_vertices()
        for i, j in zip((1, 2), (1, -1)):
            neighboring_grid_points = np.zeros(
                len(unique_vertices) * len(self._triplets_at_q), dtype='intc')
            phono3c.neighboring_grid_points(
                neighboring_grid_points,
                self._triplets_at_q[:, i].flatten(),
                j * unique_vertices,
                self._mesh,
                self._grid_address,
                self._bz_map)
            self._set_phonon(np.unique(neighboring_grid_points))

        f_max = np.max(self._frequencies) * 2 + self._frequency_step / 10
        f_min = np.min(self._frequencies) * 2
        frequency_points = np.arange(f_min, f_max, self._frequency_step,
                                     dtype='double')

        num_band = self._num_band
        num_triplets = len(self._triplets_at_q)
        num_freq_points = len(frequency_points)
        g = np.zeros((num_triplets, num_freq_points, num_band, num_band, 2),
                     dtype='double')

        phono3c.triplets_integration_weights(
            g,
            frequency_points,
            thm.get_tetrahedra(),
            self._mesh,
            self._triplets_at_q,
            self._frequencies,
            self._grid_address,
            self._bz_map)

        jdos = np.tensordot(g, self._weights_at_q, axes=([0, 0]))
        jdos = jdos.sum(axis=1).sum(axis=1)[:, 0]
        self._joint_dos = jdos / np.prod(self._mesh)
        self._frequency_points = frequency_points
    
    def _run_py_tetrahedron_method(self):
        self._vertices = get_tetrahedra_vertices(
            self._tetrahedron_method.get_tetrahedra(),
            self._mesh,
            self._triplets_at_q,
            self._grid_address,
            self._bz_map)
        self._set_phonon(self._vertices.ravel())
        thm = self._tetrahedron_method
        f_max = np.max(self._frequencies) * 2 + self._frequency_step / 10
        f_min = np.min(self._frequencies) * 2
        freq_points = np.arange(f_min, f_max, self._frequency_step,
                                dtype='double')
        jdos = np.zeros_like(freq_points)
        for vertices, w in zip(self._vertices, self._weights_at_q):
            for i, j in list(np.ndindex(self._num_band, self._num_band)):
                f1 = self._frequencies[vertices[0], i]
                f2 = self._frequencies[vertices[1], j]
                thm.set_tetrahedra_omegas(f1 + f2)
                thm.run(freq_points)
                iw = thm.get_integration_weight()
                jdos += iw * w

        self._joint_dos = jdos / np.prod(self._mesh)
        self._frequency_points = freq_points

    def _run_smearing_method(self):
        import anharmonic._phono3py as phono3c

        self._set_phonon(self._triplets_at_q.ravel())
        f_max = np.max(self._frequencies) * 2 + self._sigma * 4
        f_min = np.min(self._frequencies) * 2 - self._sigma * 4
        freq_points = np.arange(f_min, f_max, self._frequency_step,
                                dtype='double')
        jdos = np.zeros_like(freq_points)
        phono3c.joint_dos(jdos,
                          freq_points,
                          self._triplets_at_q,
                          self._weights_at_q,
                          self._frequencies,
                          self._sigma)
        jdos /= np.prod(self._mesh)
        self._joint_dos = jdos
        self._frequency_points = freq_points
        
    def _set_dynamical_matrix(self):
        self._dm = get_dynamical_matrix(
            self._fc2,
            self._supercell,
            self._primitive,
            nac_params=self._nac_params,
            frequency_scale_factor=self._frequency_scale_factor,
            symprec=self._symprec)
        
    def _set_triplets(self):
        if self._is_nosym:
            if self._log_level:
                print "Triplets at q without considering symmetry"
                sys.stdout.flush()
            
            (self._triplets_at_q,
             self._weights_at_q,
             self._grid_address,
             self._bz_map) = get_nosym_triplets_at_q(
                 self._grid_point,
                 self._mesh,
                 self._reciprocal_lattice,
                 with_bz_map=True)
        else:
            (self._triplets_at_q,
             self._weights_at_q,
             self._grid_address,
             self._bz_map) = get_triplets_at_q(
                 self._grid_point,
                 self._mesh,
                 self._symmetry.get_pointgroup_operations(),
                 self._reciprocal_lattice)

    def _set_phonon(self, grid_points):
        set_phonon_c(self._dm,
                     self._frequencies,
                     self._eigenvectors,
                     self._phonon_done,
                     grid_points,
                     self._grid_address,
                     self._mesh,
                     self._frequency_factor_to_THz,
                     self._nac_q_direction,
                     self._lapack_zheev_uplo)
コード例 #22
0
class Phonopy(object):
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 nac_params=None,
                 distance=None,
                 factor=VaspToTHz,
                 is_auto_displacements=None,
                 dynamical_matrix_decimals=None,
                 force_constants_decimals=None,
                 symprec=1e-5,
                 is_symmetry=True,
                 use_lapack_solver=False,
                 log_level=0):

        if is_auto_displacements is not None:
            print("Warning: \'is_auto_displacements\' argument is obsolete.")
            if is_auto_displacements is False:
                print("Sets of displacements are not created as default.")
            else:
                print("Use \'generate_displacements\' method explicitly to "
                      "create sets of displacements.")

        if distance is not None:
            print("Warning: \'distance\' keyword argument is obsolete at "
                  "Phonopy instantiation.")
            print("Specify \'distance\' keyword argument when calling "
                  "\'generate_displacements\'")
            print("method (See the Phonopy API document).")

        self._symprec = symprec
        self._factor = factor
        self._is_symmetry = is_symmetry
        self._use_lapack_solver = use_lapack_solver
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = Atoms(atoms=unitcell)
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._supercell = None
        self._primitive = None
        self._build_supercell()
        self._build_primitive_cell()

        # Set supercell and primitive symmetry
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()

        # set_displacements (used only in preprocess)
        self._displacement_dataset = None
        self._displacements = None
        self._displacement_directions = None
        self._supercells_with_displacements = None

        # set_force_constants or set_forces
        self._force_constants = None
        self._force_constants_decimals = force_constants_decimals

        # set_dynamical_matrix
        self._dynamical_matrix = None
        self._nac_params = nac_params
        self._dynamical_matrix_decimals = dynamical_matrix_decimals

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = None

        # set_tetrahedron_method
        self._tetrahedron_method = None

        # set_thermal_properties
        self._thermal_properties = None

        # set_thermal_displacements
        self._thermal_displacements = None

        # set_thermal_displacement_matrices
        self._thermal_displacement_matrices = None

        # set_partial_DOS
        self._pdos = None

        # set_total_DOS
        self._total_dos = None

        # set_modulation
        self._modulation = None

        # set_character_table
        self._irreps = None

        # set_group_velocity
        self._group_velocity = None

    def get_version(self):
        return __version__

    def get_primitive(self):
        return self._primitive
    primitive = property(get_primitive)

    def get_unitcell(self):
        return self._unitcell
    unitcell = property(get_unitcell)

    def get_supercell(self):
        return self._supercell
    supercell = property(get_supercell)

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry
    symmetry = property(get_symmetry)

    def get_primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self._primitive_symmetry

    def get_supercell_matrix(self):
        return self._supercell_matrix

    def get_primitive_matrix(self):
        return self._primitive_matrix

    def get_unit_conversion_factor(self):
        return self._factor
    unit_conversion_factor = property(get_unit_conversion_factor)

    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_displacements(self):
        return self._displacements
    displacements = property(get_displacements)

    def get_displacement_directions(self):
        return self._displacement_directions
    displacement_directions = property(get_displacement_directions)

    def get_supercells_with_displacements(self):
        if self._displacement_dataset is None:
            return None
        else:
            self._build_supercells_with_displacements()
            return self._supercells_with_displacements

    def get_force_constants(self):
        return self._force_constants
    force_constants = property(get_force_constants)

    def get_rotational_condition_of_fc(self):
        return rotational_invariance(self._force_constants,
                                     self._supercell,
                                     self._primitive,
                                     self._symprec)

    def get_nac_params(self):
        return self._nac_params

    def get_dynamical_matrix(self):
        return self._dynamical_matrix
    dynamical_matrix = property(get_dynamical_matrix)

    def set_unitcell(self, unitcell):
        self._unitcell = unitcell
        self._build_supercell()
        self._build_primitive_cell()
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._displacement_dataset = None

    def set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[p2p_map[x] for x in
                             self._primitive.get_supercell_to_primitive_map()]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)
        self._set_dynamical_matrix()

    def set_nac_params(self, nac_params=None):
        self._nac_params = nac_params
        self._set_dynamical_matrix()

    def set_displacement_dataset(self, displacement_dataset):
        """
        displacement_dataset:
           {'natom': number_of_atoms_in_supercell,
            'first_atoms': [
              {'number': atom index of displaced atom,
               'displacement': displacement in Cartesian coordinates,
               'direction': displacement direction with respect to axes
               'forces': forces on atoms in supercell},
              {...}, ...]}
        """
        self._displacement_dataset = displacement_dataset

        self._displacements = []
        self._displacement_directions = []
        for disp in self._displacement_dataset['first_atoms']:
            x = disp['displacement']
            self._displacements.append([disp['number'], x[0], x[1], x[2]])
            if 'direction' in disp:
                y = disp['direction']
                self._displacement_directions.append(
                    [disp['number'], y[0], y[1], y[2]])
        if not self._displacement_directions:
            self._displacement_directions = None

    def set_forces(self, sets_of_forces):
        """
        sets_of_forces:
           [[[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # first supercell
             [[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # second supercell
             ...                                                  ]
        """
        for disp, forces in zip(
                self._displacement_dataset['first_atoms'], sets_of_forces):
            disp['forces'] = forces

    def set_force_constants(self, force_constants):
        self._force_constants = force_constants
        self._set_dynamical_matrix()

    def set_force_constants_zero_with_radius(self, cutoff_radius):
        cutoff_force_constants(self._force_constants,
                               self._supercell,
                               cutoff_radius,
                               symprec=self._symprec)
        self._set_dynamical_matrix()

    def set_dynamical_matrix(self):
        self._set_dynamical_matrix()

    def generate_displacements(self,
                               distance=0.01,
                               is_plusminus='auto',
                               is_diagonal=True,
                               is_trigonal=False):
        """Generate displacements automatically

        displacemsts: List of displacements in Cartesian coordinates.
           [[0, 0.01, 0.00, 0.00], ...]
        where each set of elements is defined by:
           First value:      Atom index in supercell starting with 0
           Second to fourth: Displacement in Cartesian coordinates

        displacement_directions:
          List of directions with respect to axes. This gives only the
          symmetrically non equivalent directions. The format is like:
             [[0, 1, 0, 0],
              [7, 1, 0, 1], ...]
          where each list is defined by:
             First value:      Atom index in supercell starting with 0
             Second to fourth: If the direction is displaced or not ( 1, 0, or -1 )
                               with respect to the axes.

        """
        displacement_directions = get_least_displacements(
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal,
            is_trigonal=is_trigonal,
            log_level=self._log_level)
        displacement_dataset = direction_to_displacement(
            displacement_directions,
            distance,
            self._supercell)
        self.set_displacement_dataset(displacement_dataset)

    def produce_force_constants(self,
                                forces=None,
                                calculate_full_force_constants=True,
                                computation_algorithm="svd"):
        if forces is not None:
            self.set_forces(forces)

        # A primitive check if 'forces' key is in displacement_dataset.
        for disp in self._displacement_dataset['first_atoms']:
            if 'forces' not in disp:
                return False

        if calculate_full_force_constants:
            self._run_force_constants_from_forces(
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)
        else:
            p2s_map = self._primitive.get_primitive_to_supercell_map()
            self._run_force_constants_from_forces(
                distributed_atom_list=p2s_map,
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)

        self._set_dynamical_matrix()

        return True

    def symmetrize_force_constants(self, iteration=3):
        symmetrize_force_constants(self._force_constants, iteration)
        self._set_dynamical_matrix()

    def symmetrize_force_constants_by_space_group(self):
        from phonopy.harmonic.force_constants import (set_tensor_symmetry,
                                                      set_tensor_symmetry_PJ)
        set_tensor_symmetry_PJ(self._force_constants,
                               self._supercell.get_cell().T,
                               self._supercell.get_scaled_positions(),
                               self._symmetry)

        self._set_dynamical_matrix()

    #####################
    # Phonon properties #
    #####################

    # Single q-point
    def get_dynamical_matrix_at_q(self, q):
        self._set_dynamical_matrix()
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return None

        self._dynamical_matrix.set_dynamical_matrix(q)
        return self._dynamical_matrix.get_dynamical_matrix()


    def get_frequencies(self, q):
        """
        Calculate phonon frequencies at q

        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return None

        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        for eig in np.linalg.eigvalsh(dm).real:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor

    def get_frequencies_with_eigenvectors(self, q):
        """
        Calculate phonon frequencies and eigenvectors at q

        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return None

        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        eigvals, eigenvectors = np.linalg.eigh(dm)
        frequencies = []
        for eig in eigvals:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor, eigenvectors

    # Band structure
    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._band_structure = None
            return False

        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            is_eigenvectors=is_eigenvectors,
            is_band_connection=is_band_connection,
            group_velocity=self._group_velocity,
            factor=self._factor)
        return True

    def get_band_structure(self):
        band = self._band_structure
        return (band.get_qpoints(),
                band.get_distances(),
                band.get_frequencies(),
                band.get_eigenvectors())

    def plot_band_structure(self, labels=None):
        import matplotlib.pyplot as plt
        if labels:
            from matplotlib import rc
            rc('text', usetex=True)

        fig, ax = plt.subplots()
        ax.xaxis.set_ticks_position('both')
        ax.yaxis.set_ticks_position('both')
        ax.xaxis.set_tick_params(which='both', direction='in')
        ax.yaxis.set_tick_params(which='both', direction='in')

        self._band_structure.plot(plt, labels=labels)
        return plt

    def write_yaml_band_structure(self,
                                  labels=None,
                                  comment=None,
                                  filename="band.yaml"):
        self._band_structure.write_yaml(labels=labels,
                                        comment=comment,
                                        filename=filename)

    # Sampling mesh
    def run_mesh(self):
        if self._mesh is not None:
            self._mesh.run()

    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_mesh_symmetry=True,
                 is_eigenvectors=False,
                 is_gamma_center=False,
                 run_immediately=True):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._mesh = None
            return False

        self._mesh = Mesh(
            self._dynamical_matrix,
            mesh,
            shift=shift,
            is_time_reversal=is_time_reversal,
            is_mesh_symmetry=is_mesh_symmetry,
            is_eigenvectors=is_eigenvectors,
            is_gamma_center=is_gamma_center,
            group_velocity=self._group_velocity,
            rotations=self._primitive_symmetry.get_pointgroup_operations(),
            factor=self._factor,
            use_lapack_solver=self._use_lapack_solver)
        if run_immediately:
            self._mesh.run()
        return True

    def get_mesh(self):
        if self._mesh is None:
            return None
        else:
            return (self._mesh.get_qpoints(),
                    self._mesh.get_weights(),
                    self._mesh.get_frequencies(),
                    self._mesh.get_eigenvectors())
    
    def get_mesh_grid_info(self):
        if self._mesh is None:
            return None
        else:
            return (self._mesh.get_grid_address(),
                    self._mesh.get_ir_grid_points(),
                    self._mesh.get_grid_mapping_table())

    def write_hdf5_mesh(self):
        self._mesh.write_hdf5()

    def write_yaml_mesh(self):
        self._mesh.write_yaml()

    # Plot band structure and DOS (PDOS) together
    def plot_band_structure_and_dos(self, pdos_indices=None, labels=None):
        import matplotlib.pyplot as plt
        import matplotlib.gridspec as gridspec
        if labels:
            from matplotlib import rc
            rc('text', usetex=True)


        plt.figure(figsize=(10, 6))
        gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
        ax1 = plt.subplot(gs[0, 0])
        ax1.xaxis.set_ticks_position('both')
        ax1.yaxis.set_ticks_position('both')
        ax1.xaxis.set_tick_params(which='both', direction='in')
        ax1.yaxis.set_tick_params(which='both', direction='in')
        self._band_structure.plot(plt, labels=labels)
        ax2 = plt.subplot(gs[0, 1], sharey=ax1)
        ax2.xaxis.set_ticks_position('both')
        ax2.yaxis.set_ticks_position('both')
        ax2.xaxis.set_tick_params(which='both', direction='in')
        ax2.yaxis.set_tick_params(which='both', direction='in')
        plt.subplots_adjust(wspace=0.03)
        plt.setp(ax2.get_yticklabels(), visible=False)

        if pdos_indices is None:
            self._total_dos.plot(plt,
                                 ylabel="",
                                 draw_grid=False,
                                 flip_xy=True)
        else:
            self._pdos.plot(plt,
                            indices=pdos_indices,
                            ylabel="",
                            draw_grid=False,
                            flip_xy=True)

        ax2.set_xlim((0, None))

        return plt

    # DOS
    def set_total_DOS(self,
                      sigma=None,
                      freq_min=None,
                      freq_max=None,
                      freq_pitch=None,
                      tetrahedron_method=False):

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before DOS calculation.")
            self._total_dos = None
            return False

        total_dos = TotalDos(self._mesh,
                             sigma=sigma,
                             tetrahedron_method=tetrahedron_method)
        total_dos.set_draw_area(freq_min, freq_max, freq_pitch)
        total_dos.run()
        self._total_dos = total_dos
        return True

    def get_total_DOS(self):
        """
        Retern frequencies and total dos.
        The first element is freqs and the second is total dos.

        frequencies: [freq1, freq2, ...]
        total_dos: [dos1, dos2, ...]
        """
        return self._total_dos.get_dos()

    def set_Debye_frequency(self, freq_max_fit=None):
        self._total_dos.set_Debye_frequency(
            self._primitive.get_number_of_atoms(),
            freq_max_fit=freq_max_fit)

    def get_Debye_frequency(self):
        return self._total_dos.get_Debye_frequency()

    def plot_total_DOS(self):
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()
        ax.xaxis.set_ticks_position('both')
        ax.yaxis.set_ticks_position('both')
        ax.xaxis.set_tick_params(which='both', direction='in')
        ax.yaxis.set_tick_params(which='both', direction='in')

        self._total_dos.plot(plt, draw_grid=False)

        ax.set_ylim((0, None))

        return plt

    def write_total_DOS(self):
        self._total_dos.write()

    # PDOS
    def set_partial_DOS(self,
                        sigma=None,
                        freq_min=None,
                        freq_max=None,
                        freq_pitch=None,
                        tetrahedron_method=False,
                        direction=None,
                        xyz_projection=False):
        self._pdos = None

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to be called before "
                  "PDOS calculation.")
            return False

        if self._mesh.get_eigenvectors() is None:
            print("Warning: Eigenvectors have to be calculated.")
            return False

        num_grid = np.prod(self._mesh.get_mesh_numbers())
        if num_grid != len(self._mesh.get_ir_grid_points()):
            print("Warning: \'set_mesh\' has to be called with "
                  "is_mesh_symmetry=False.")
            return False

        if direction is not None:
            direction_cart = np.dot(direction, self._primitive.get_cell())
        else:
            direction_cart = None
        self._pdos = PartialDos(self._mesh,
                                sigma=sigma,
                                tetrahedron_method=tetrahedron_method,
                                direction=direction_cart,
                                xyz_projection=xyz_projection)
        self._pdos.set_draw_area(freq_min, freq_max, freq_pitch)
        self._pdos.run()
        return True

    def get_partial_DOS(self):
        """
        Retern frequencies and partial_dos.
        The first element is freqs and the second is partial_dos.

        frequencies: [freq1, freq2, ...]
        partial_dos:
          [[atom1-freq1, atom1-freq2, ...],
           [atom2-freq1, atom2-freq2, ...],
           ...]
        """
        return self._pdos.get_partial_dos()

    def plot_partial_DOS(self, pdos_indices=None, legend=None):
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()
        ax.xaxis.set_ticks_position('both')
        ax.yaxis.set_ticks_position('both')
        ax.xaxis.set_tick_params(which='both', direction='in')
        ax.yaxis.set_tick_params(which='both', direction='in')

        self._pdos.plot(plt,
                        indices=pdos_indices,
                        legend=legend,
                        draw_grid=False)

        ax.set_ylim((0, None))

        return plt

    def write_partial_DOS(self):
        self._pdos.write()

    # Thermal property
    def set_thermal_properties(self,
                               t_step=10,
                               t_max=1000,
                               t_min=0,
                               temperatures=None,
                               is_projection=False,
                               band_indices=None,
                               cutoff_frequency=None,
                               pretend_real=False):
        if self._mesh is None:
            print("Warning: set_mesh has to be done before "
                  "set_thermal_properties")
            return False
        else:
            tp = ThermalProperties(self._mesh.get_frequencies(),
                                   weights=self._mesh.get_weights(),
                                   eigenvectors=self._mesh.get_eigenvectors(),
                                   is_projection=is_projection,
                                   band_indices=band_indices,
                                   cutoff_frequency=cutoff_frequency,
                                   pretend_real=pretend_real)
            if temperatures is None:
                tp.set_temperature_range(t_step=t_step,
                                         t_max=t_max,
                                         t_min=t_min)
            else:
                tp.set_temperatures(temperatures)
            tp.run()
            self._thermal_properties = tp

    def get_thermal_properties(self):
        temps, fe, entropy, cv = \
            self._thermal_properties.get_thermal_properties()
        return temps, fe, entropy, cv

    def plot_thermal_properties(self):
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()
        ax.xaxis.set_ticks_position('both')
        ax.yaxis.set_ticks_position('both')
        ax.xaxis.set_tick_params(which='both', direction='in')
        ax.yaxis.set_tick_params(which='both', direction='in')

        self._thermal_properties.plot(plt)

        temps, _, _, _ = self._thermal_properties.get_thermal_properties()
        ax.set_xlim((0, temps[-1]))

        return plt

    def write_yaml_thermal_properties(self, filename='thermal_properties.yaml'):
        self._thermal_properties.write_yaml(filename=filename)

    # Thermal displacement
    def set_thermal_displacements(self,
                                  t_step=10,
                                  t_max=1000,
                                  t_min=0,
                                  temperatures=None,
                                  direction=None,
                                  cutoff_frequency=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        self._thermal_displacements = None

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before \'set_thermal_displacements\'.")
            return False

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers()

        if self._mesh.get_eigenvectors() is None:
            print("Warning: Eigenvectors have to be calculated.")
            return False

        if np.prod(mesh_nums) != len(eigvecs):
            print("Warning: Sampling mesh must not be symmetrized.")
            return False

        td = ThermalDisplacements(frequencies,
                                  eigvecs,
                                  self._primitive.get_masses(),
                                  cutoff_frequency=cutoff_frequency)
        if temperatures is None:
            td.set_temperature_range(t_min, t_max, t_step)
        else:
            td.set_temperatures(temperatures)
        if direction is not None:
            td.project_eigenvectors(direction, self._primitive.get_cell())
        td.run()

        self._thermal_displacements = td
        return True

    def get_thermal_displacements(self):
        if self._thermal_displacements is not None:
            return self._thermal_displacements.get_thermal_displacements()

    def plot_thermal_displacements(self, is_legend=False):
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()
        ax.xaxis.set_ticks_position('both')
        ax.yaxis.set_ticks_position('both')
        ax.xaxis.set_tick_params(which='both', direction='in')
        ax.yaxis.set_tick_params(which='both', direction='in')

        self._thermal_displacements.plot(plt, is_legend=is_legend)

        temps, _ = self._thermal_displacements.get_thermal_displacements()
        ax.set_xlim((0, temps[-1]))

        return plt

    def write_yaml_thermal_displacements(self):
        self._thermal_displacements.write_yaml()

    # Thermal displacement matrix
    def set_thermal_displacement_matrices(self,
                                          t_step=10,
                                          t_max=1000,
                                          t_min=0,
                                          cutoff_frequency=None,
                                          t_cif=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        self._thermal_displacement_matrices = None

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before \'set_thermal_displacement_matrices\'.")
            return False

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers()

        if self._mesh.get_eigenvectors() is None:
            print("Warning: Eigenvectors have to be calculated.")
            return False

        if np.prod(mesh_nums) != len(eigvecs):
            print("Warning: Sampling mesh must not be symmetrized.")
            return False

        tdm = ThermalDisplacementMatrices(frequencies,
                                          eigvecs,
                                          self._primitive.get_masses(),
                                          cutoff_frequency=cutoff_frequency,
                                          lattice=self._primitive.get_cell().T)
        if t_cif is None:
            tdm.set_temperature_range(t_min, t_max, t_step)
        else:
            tdm.set_temperatures([t_cif])
        tdm.run()

        self._thermal_displacement_matrices = tdm
        return True

    def get_thermal_displacement_matrices(self):
        tdm = self._thermal_displacement_matrices
        if tdm is not None:
            return tdm.get_thermal_displacement_matrices()

    def write_yaml_thermal_displacement_matrices(self):
        self._thermal_displacement_matrices.write_yaml()

    def write_thermal_displacement_matrix_to_cif(self,
                                                 temperature_index):
        self._thermal_displacement_matrices.write_cif(self._primitive,
                                                      temperature_index)

    # Mean square distance between a pair of atoms
    def set_thermal_distances(self,
                              atom_pairs,
                              t_step=10,
                              t_max=1000,
                              t_min=0,
                              cutoff_frequency=None):
        """
        atom_pairs: List of list
          Mean square distances are calculated for the atom_pairs
          e.g. [[1, 2], [1, 4]]

        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.
        """

        td = ThermalDistances(self._mesh.get_frequencies(),
                              self._mesh.get_eigenvectors(),
                              self._supercell,
                              self._primitive,
                              self._mesh.get_qpoints(),
                              cutoff_frequency=cutoff_frequency)
        td.set_temperature_range(t_min, t_max, t_step)
        td.run(atom_pairs)

        self._thermal_distances = td

    def write_yaml_thermal_distances(self):
        self._thermal_distances.write_yaml()

    # Sampling at q-points
    def set_qpoints_phonon(self,
                           q_points,
                           nac_q_direction=None,
                           is_eigenvectors=False,
                           write_dynamical_matrices=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._qpoints_phonon = None
            return False

        self._qpoints_phonon = QpointsPhonon(
            np.reshape(q_points, (-1, 3)),
            self._dynamical_matrix,
            nac_q_direction=nac_q_direction,
            is_eigenvectors=is_eigenvectors,
            group_velocity=self._group_velocity,
            write_dynamical_matrices=write_dynamical_matrices,
            factor=self._factor)
        return True

    def get_qpoints_phonon(self):
        return (self._qpoints_phonon.get_frequencies(),
                self._qpoints_phonon.get_eigenvectors())

    def write_hdf5_qpoints_phonon(self):
        self._qpoints_phonon.write_hdf5()

    def write_yaml_qpoints_phonon(self):
        self._qpoints_phonon.write_yaml()

    # Normal mode animation
    def write_animation(self,
                        q_point=None,
                        anime_type='v_sim',
                        band_index=None,
                        amplitude=None,
                        num_div=None,
                        shift=None,
                        filename=None):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return False

        if q_point is None:
            animation = Animation([0, 0, 0],
                                  self._dynamical_matrix,
                                  shift=shift)
        else:
            animation = Animation(q_point,
                                  self._dynamical_matrix,
                                  shift=shift)
        if anime_type == 'v_sim':
            if amplitude:
                amplitude_ = amplitude
            else:
                amplitude_ = 1.0

            if filename:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor,
                                      filename=filename)
            else:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor)
        if (anime_type == 'arc' or
            anime_type == 'xyz' or
            anime_type == 'jmol' or
            anime_type == 'poscar'):
            if band_index is None or amplitude is None or num_div is None:
                print("Warning: Parameters are not correctly set for "
                      "animation.")
                return False

            if anime_type == 'arc' or anime_type is None:
                if filename:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div,
                                        filename=filename)
                else:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div)

            if anime_type == 'xyz':
                if filename:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor,
                                        filename=filename)
                else:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor)

            if anime_type == 'jmol':
                if filename:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor,
                                             filename=filename)
                else:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor)

            if anime_type == 'poscar':
                if filename:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div,
                                           filename=filename)
                else:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div)

        return True

    # Atomic modulation of normal mode
    def set_modulations(self,
                        dimension,
                        phonon_modes,
                        delta_q=None,
                        derivative_order=None,
                        nac_q_direction=None):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._modulation = None
            return False

        self._modulation = Modulation(self._dynamical_matrix,
                                      dimension,
                                      phonon_modes,
                                      delta_q=delta_q,
                                      derivative_order=derivative_order,
                                      nac_q_direction=nac_q_direction,
                                      factor=self._factor)
        self._modulation.run()
        return True

    def get_modulated_supercells(self):
        """Returns cells with modulations as Atoms objects"""
        return self._modulation.get_modulated_supercells()

    def get_modulations_and_supercell(self):
        """Return modulations and supercell

        (modulations, supercell)

        modulations: Atomic modulations of supercell in Cartesian coordinates
        supercell: Supercell as an Atoms object.

        """
        return self._modulation.get_modulations_and_supercell()

    def write_modulations(self):
        """Create MPOSCAR's"""
        self._modulation.write()

    def write_yaml_modulations(self):
        self._modulation.write_yaml()

    # Irreducible representation
    def set_irreps(self,
                   q,
                   is_little_cogroup=False,
                   nac_q_direction=None,
                   degeneracy_tolerance=1e-4):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._irreps = None
            return None

        self._irreps = IrReps(
            self._dynamical_matrix,
            q,
            is_little_cogroup=is_little_cogroup,
            nac_q_direction=nac_q_direction,
            factor=self._factor,
            symprec=self._symprec,
            degeneracy_tolerance=degeneracy_tolerance,
            log_level=self._log_level)

        return self._irreps.run()

    def get_irreps(self):
        return self._irreps

    def show_irreps(self, show_irreps=False):
        self._irreps.show(show_irreps=show_irreps)

    def write_yaml_irreps(self, show_irreps=False):
        self._irreps.write_yaml(show_irreps=show_irreps)

    # Group velocity
    def set_group_velocity(self, q_length=None):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._group_velocity = None
            return False

        self._group_velocity = GroupVelocity(
            self._dynamical_matrix,
            q_length=q_length,
            symmetry=self._primitive_symmetry,
            frequency_factor_to_THz=self._factor)
        return True

    def get_group_velocity(self):
        return self._group_velocity.get_group_velocity()

    def get_group_velocity_at_q(self, q_point):
        if self._group_velocity is None:
            self.set_group_velocity()
        self._group_velocity.set_q_points([q_point])
        return self._group_velocity.get_group_velocity()[0]

    # Moment
    def set_moment(self,
                   order=1,
                   is_projection=False,
                   freq_min=None,
                   freq_max=None):
        if self._mesh is None:
            print("Warning: set_mesh has to be done before set_moment")
            return False
        else:
            if is_projection:
                if self._mesh.get_eigenvectors() is None:
                    print("Warning: Eigenvectors have to be calculated.")
                    return False
                moment = PhononMoment(
                    self._mesh.get_frequencies(),
                    weights=self._mesh.get_weights(),
                    eigenvectors=self._mesh.get_eigenvectors())
            else:
                moment = PhononMoment(
                    self._mesh.get_frequencies(),
                    weights=self._mesh.get_weights())
            if freq_min is not None or freq_max is not None:
                moment.set_frequency_range(freq_min=freq_min,
                                           freq_max=freq_max)
            moment.run(order=order)
            self._moment = moment.get_moment()
            return True

    def get_moment(self):
        return self._moment

    #################
    # Local methods #
    #################
    def _run_force_constants_from_forces(self,
                                         distributed_atom_list=None,
                                         decimals=None,
                                         computation_algorithm="svd"):
        if self._displacement_dataset is not None:
            self._force_constants = get_fc2(
                self._supercell,
                self._symmetry,
                self._displacement_dataset,
                atom_list=distributed_atom_list,
                decimals=decimals,
                computation_algorithm=computation_algorithm)

    def _set_dynamical_matrix(self):
        self._dynamical_matrix = None

        if (self._supercell is None or self._primitive is None):
            print("Bug: Supercell or primitive is not created.")
            return False
        elif self._force_constants is None:
            print("Warning: Force constants are not prepared.")
            return False
        elif self._primitive.get_masses() is None:
            print("Warning: Atomic masses are not correctly set.")
            return False
        else:
            if self._nac_params is None:
                self._dynamical_matrix = DynamicalMatrix(
                    self._supercell,
                    self._primitive,
                    self._force_constants,
                    decimals=self._dynamical_matrix_decimals,
                    symprec=self._symprec)
            else:
                self._dynamical_matrix = DynamicalMatrixNAC(
                    self._supercell,
                    self._primitive,
                    self._force_constants,
                    nac_params=self._nac_params,
                    decimals=self._dynamical_matrix_decimals,
                    symprec=self._symprec)
            return True

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)

        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print("Warning: Point group symmetries of supercell and primitive"
                  "cell are different.")

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_supercells_with_displacements(self):
        supercells = []
        for disp in self._displacement_dataset['first_atoms']:
            positions = self._supercell.get_positions()
            positions[disp['number']] += disp['displacement']
            supercells.append(Atoms(
                    numbers=self._supercell.get_atomic_numbers(),
                    masses=self._supercell.get_masses(),
                    magmoms=self._supercell.get_magnetic_moments(),
                    positions=positions,
                    cell=self._supercell.get_cell(),
                    pbc=True))

        self._supercells_with_displacements = supercells

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """

        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        if self._primitive_matrix is None:
            trans_mat = inv_supercell_matrix
        else:
            trans_mat = np.dot(inv_supercell_matrix, self._primitive_matrix)
        self._primitive = get_primitive(
            self._supercell, trans_mat, self._symprec)
        num_satom = self._supercell.get_number_of_atoms()
        num_patom = self._primitive.get_number_of_atoms()
        if abs(num_satom * np.linalg.det(trans_mat) - num_patom) < 0.1:
            return True
        else:
            return False
コード例 #23
0
ファイル: api_unfolding.py プロジェクト: yuzie007/ph_unfolder
class PhonopyUnfolding(Phonopy):
    """

    unitcell: before symmetrization
    """
    def __init__(self,
                 unitcell,
                 unitcell_ideal,
                 supercell_matrix,
                 primitive_matrix_ideal,
                 nac_params=None,
                 distance=0.01,
                 factor=VaspToTHz,
                 is_auto_displacements=True,
                 dynamical_matrix_decimals=None,
                 force_constants_decimals=None,
                 star="none",
                 mode="eigenvector",
                 symprec=1e-5,
                 is_symmetry=True,
                 use_lapack_solver=False,
                 log_level=0):
        self._symprec = symprec
        self._distance = distance
        self._factor = factor
        self._is_auto_displacements = is_auto_displacements
        self._is_symmetry = is_symmetry
        self._use_lapack_solver = use_lapack_solver
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._unitcell_ideal = unitcell_ideal
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = None
        self._primitive_matrix_ideal = primitive_matrix_ideal
        self._supercell = None
        self._primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_supercell_ideal()
        self._build_primitive_cell_ideal()

        # Set supercell and primitive symmetry
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_symmetry_ideal()
        self._search_primitive_symmetry_ideal()

        # set_force_constants or set_forces
        self._force_constants = None
        self._force_constants_decimals = force_constants_decimals

        # set_dynamical_matrix
        self._dynamical_matrix = None
        self._nac_params = nac_params
        self._dynamical_matrix_decimals = dynamical_matrix_decimals

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = None

        # set_tetrahedron_method
        self._tetrahedron_method = None

        # set_thermal_properties
        self._thermal_properties = None

        # set_thermal_displacements
        self._thermal_displacements = None

        # set_thermal_displacement_matrices
        self._thermal_displacement_matrices = None

        # set_partial_DOS
        self._pdos = None

        # set_total_DOS
        self._total_dos = None

        # set_modulation
        self._modulation = None

        # set_character_table
        self._irreps = None

        # set_group_velocity
        self._group_velocity = None

        self._star = star
        self._mode = mode

    # Single point
    def run_single_point(self, qpoint, distance):
        SinglePoint(
            qpoint,
            distance,
            dynamical_matrix=self._dynamical_matrix,
            unitcell_ideal=self._unitcell_ideal,
            primitive_matrix_ideal=self._primitive_matrix_ideal,
            factor=self._factor,
            star=self._star,
            mode=self._mode,
            verbose=True)

    # Band structure
    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._band_structure = None
            return False

        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            self._unitcell_ideal,
            self._primitive_matrix_ideal,
            is_eigenvectors=is_eigenvectors,
            is_band_connection=is_band_connection,
            group_velocity=self._group_velocity,
            factor=self._factor,
            star=self._star,
            mode=self._mode,
            verbose=True)
        return True

    # Sampling mesh
    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_mesh_symmetry=True,
                 is_eigenvectors=False,
                 is_gamma_center=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._mesh = None
            return False

        # TODO(ikeda): Check how "rotations" works.
        self._mesh = MeshUnfolding(
            self._dynamical_matrix,
            self._unitcell_ideal,
            self._primitive_matrix_ideal,
            mesh,
            shift=shift,
            is_time_reversal=is_time_reversal,
            is_mesh_symmetry=is_mesh_symmetry,
            is_eigenvectors=is_eigenvectors,
            is_gamma_center=is_gamma_center,
            star=self._star,
            group_velocity=self._group_velocity,
            rotations=self._primitive_symmetry.get_pointgroup_operations(),
            factor=self._factor,
            use_lapack_solver=self._use_lapack_solver,
            mode=self._mode)
        return True

    # DOS
    def set_total_DOS(self,
                      sigma=None,
                      freq_min=None,
                      freq_max=None,
                      freq_pitch=None,
                      tetrahedron_method=False):

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before DOS calculation.")
            self._total_dos = None
            return False

        total_dos = TotalDosUnfolding(
            self._mesh,
            sigma=sigma,
            tetrahedron_method=tetrahedron_method)
        total_dos.set_draw_area(freq_min, freq_max, freq_pitch)
        total_dos.run()
        self._total_dos = total_dos
        return True

    def _set_dynamical_matrix(self):
        self._dynamical_matrix = None

        if self._supercell is None or self._primitive is None:
            print("Bug: Supercell or primitive is not created.")
            return False
        elif self._force_constants is None:
            print("Warning: Force constants are not prepared.")
            return False
        elif self._primitive.get_masses() is None:
            print("Warning: Atomic masses are not correctly set.")
            return False
        else:
            if self._nac_params is None:
                self._dynamical_matrix = DynamicalMatrix(
                    self._supercell,
                    self._primitive,
                    self._force_constants,
                    decimals=self._dynamical_matrix_decimals,
                    symprec=self._symprec)
            else:
                raise ValueError(
                    'Currently NAC is not available for unfolding.')
            return True

    def _search_symmetry_ideal(self):
        self._symmetry = Symmetry(self._supercell_ideal,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry_ideal(self):
        self._primitive_symmetry = Symmetry(self._primitive_ideal,
                                            self._symprec,
                                            self._is_symmetry)

        n0 = len(self._symmetry.get_pointgroup_operations())
        n1 = len(self._primitive_symmetry.get_pointgroup_operations())
        if n0 != n1:
            raise Warning("Point group symmetries of supercell and primitive"
                          "cell are different.")

    def _build_supercell_ideal(self):
        self._supercell_ideal = get_supercell(
            self._unitcell_ideal,
            self._supercell_matrix,
            self._symprec)

    def _build_primitive_cell_ideal(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """

        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        if self._primitive_matrix_ideal is None:
            trans_mat = inv_supercell_matrix
        else:
            trans_mat = np.dot(inv_supercell_matrix, self._primitive_matrix_ideal)
        self._primitive_ideal = get_primitive(
            self._supercell_ideal, trans_mat, self._symprec)
        num_satom = self._supercell_ideal.get_number_of_atoms()
        num_patom = self._primitive_ideal.get_number_of_atoms()
        if abs(num_satom * np.linalg.det(trans_mat) - num_patom) < 0.1:
            return True
        else:
            return False

    def average_masses(self):

        masses = self._unitcell.get_masses()
        masses_average = calculate_average_masses(
            masses, Symmetry(self._unitcell_ideal))
        self._unitcell.set_masses(masses_average)

        self._build_supercell()
        self._build_primitive_cell()

        self._search_symmetry()
        self._search_primitive_symmetry()

    def average_force_constants(self):
        fc_symmetrizer_spg = FCSymmetrizerSPG(
            force_constants=self._force_constants,
            atoms=self._unitcell,
            atoms_ideal=self._unitcell_ideal,
            supercell_matrix=self._supercell_matrix,
        )
        fc_symmetrizer_spg.average_force_constants_spg()
        fc_symmetrizer_spg.write_force_constants_symmetrized()
        fc_average = fc_symmetrizer_spg.get_force_constants_symmetrized()
        self.set_force_constants(fc_average)  # Dynamical matrices are also prepared inside.
コード例 #24
0
ファイル: __init__.py プロジェクト: shanghui/phonopy
class Phonopy:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 nac_params=None,
                 distance=0.01,
                 factor=VaspToTHz,
                 is_auto_displacements=True,
                 dynamical_matrix_decimals=None,
                 force_constants_decimals=None,
                 symprec=1e-5,
                 is_symmetry=True,
                 log_level=0):
        self._symprec = symprec
        self._factor = factor
        self._is_symmetry = is_symmetry
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._supercell = None
        self._primitive = None
        self._build_supercell()
        self._build_primitive_cell()

        # Set supercell and primitive symmetry
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()

        # set_displacements (used only in preprocess)
        self._displacement_dataset = None
        self._displacements = None
        self._displacement_directions = None
        self._supercells_with_displacements = None
        if is_auto_displacements:
            self.generate_displacements(distance=distance)

        # set_force_constants or set_forces
        self._force_constants = None
        self._force_constants_decimals = force_constants_decimals
        
        # set_dynamical_matrix
        self._dynamical_matrix = None
        self._nac_params = nac_params
        self._dynamical_matrix_decimals = dynamical_matrix_decimals

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = None

        # set_tetrahedron_method
        self._tetrahedron_method = None

        # set_thermal_properties
        self._thermal_properties = None

        # set_thermal_displacements
        self._thermal_displacements = None

        # set_thermal_displacement_matrices
        self._thermal_displacement_matrices = None
        
        # set_partial_DOS
        self._pdos = None

        # set_total_DOS
        self._total_dos = None

        # set_modulation
        self._modulation = None

        # set_character_table
        self._irreps = None

        # set_group_velocity
        self._group_velocity = None

    def set_post_process(self,
                         primitive_matrix=None,
                         sets_of_forces=None,
                         displacement_dataset=None,
                         force_constants=None,
                         is_nac=None):
        print 
        print ("********************************** Warning"
               "**********************************")
        print "set_post_process will be obsolete."
        print ("  produce_force_constants is used instead of set_post_process"
               " for producing")
        print ("  force constants from forces.")
        if primitive_matrix is not None:
            print ("  primitive_matrix has to be given at Phonopy::__init__"
                   " object creation.")
        print ("******************************************"
               "**********************************")
        print 

        if primitive_matrix is not None:
            self._primitive_matrix = primitive_matrix
            self._build_primitive_cell()
            self._search_primitive_symmetry()
        
        if sets_of_forces is not None:
            self.set_forces(sets_of_forces)
        elif displacement_dataset is not None:
            self._displacement_dataset = displacement_dataset
        elif force_constants is not None:
            self.set_force_constants(force_constants)
            
        if self._displacement_dataset is not None:
            self.produce_force_constants()

    def set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[p2p_map[x] for x in
                             self._primitive.get_supercell_to_primitive_map()]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)
        
    def get_primitive(self):
        return self._primitive
    primitive = property(get_primitive)

    def get_unitcell(self):
        return self._unitcell
    unitcell = property(get_unitcell)

    def get_supercell(self):
        return self._supercell
    supercell = property(get_supercell)

    def set_supercell(self, supercell):
        self._supercell = supercell

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry
    symmetry = property(get_symmetry)

    def get_primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self._primitive_symmetry

    def get_unit_conversion_factor(self):
        return self._factor
    unit_conversion_factor = property(get_unit_conversion_factor)

    def produce_force_constants(self,
                                forces=None,
                                calculate_full_force_constants=True,
                                computation_algorithm="svd"):
        if forces is not None:
            self.set_forces(forces)
        
        if calculate_full_force_constants:
            self._run_force_constants_from_forces(
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)
        else:
            p2s_map = self._primitive.get_primitive_to_supercell_map()
            self._run_force_constants_from_forces(
                distributed_atom_list=p2s_map,
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)

    def set_nac_params(self, nac_params=None, method=None):
        if method is not None:
            print "set_nac_params:"
            print "  Keyword argument of \"method\" is not more supported."
        self._nac_params = nac_params
        
    def generate_displacements(self,
                               distance=0.01,
                               is_plusminus='auto',
                               is_diagonal=True,
                               is_trigonal=False):
        """Generate displacements automatically

        displacemsts: List of displacements in Cartesian coordinates.
           [[0, 0.01, 0.00, 0.00], ...]
        where each set of elements is defined by:
           First value:      Atom index in supercell starting with 0
           Second to fourth: Displacement in Cartesian coordinates
        
        displacement_directions:
          List of directions with respect to axes. This gives only the
          symmetrically non equivalent directions. The format is like:
             [[0, 1, 0, 0],
              [7, 1, 0, 1], ...]
          where each list is defined by:
             First value:      Atom index in supercell starting with 0
             Second to fourth: If the direction is displaced or not ( 1, 0, or -1 )
                               with respect to the axes.
                               
        """
        displacement_directions = get_least_displacements(
            self._symmetry, 
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal,
            is_trigonal=is_trigonal,
            log_level=self._log_level)
        displacement_dataset = direction_to_displacement(
            displacement_directions,
            distance,
            self._supercell)
        self.set_displacement_dataset(displacement_dataset)

    def set_displacements(self, displacements):
        print 
        print ("********************************** Warning"
               "**********************************")
        print "set_displacements is obsolete. Do nothing."
        print ("******************************************"
               "**********************************")
        print 

    def get_displacements(self):
        return self._displacements
    displacements = property(get_displacements)

    def get_displacement_directions(self):
        return self._displacement_directions
    displacement_directions = property(get_displacement_directions)

    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_supercells_with_displacements(self):
        if self._displacement_dataset is None:
            return None
        else:
            self._build_supercells_with_displacements()
            return self._supercells_with_displacements

    def get_dynamical_matrix(self):
        return self._dynamical_matrix
    dynamical_matrix = property(get_dynamical_matrix)

    def set_forces(self, sets_of_forces):
        """
        sets_of_forces:
           [[[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # first supercell
             [[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # second supercell
             ...                                                  ]
        """
        for disp, forces in zip(
                self._displacement_dataset['first_atoms'], sets_of_forces):
            disp['forces'] = forces

    def set_force_constants_zero_with_radius(self, cutoff_radius):
        cutoff_force_constants(self._force_constants,
                               self._supercell,
                               cutoff_radius,
                               symprec=self._symprec)

    def set_force_constants(self, force_constants):
        self._force_constants = force_constants

    def set_force_sets(self, force_sets):
        print 
        print ("********************************** Warning"
               "**********************************")
        print "set_force_sets will be obsolete."
        print ("   The method name is changed to set_displacement_dataset.")
        print ("******************************************"
               "**********************************")
        print
        self.set_displacement_dataset(force_sets)

    def set_displacement_dataset(self, displacement_dataset):
        """
        displacement_dataset:
           {'natom': number_of_atoms_in_supercell,
            'first_atoms': [
              {'number': atom index of displaced atom,
               'displacement': displacement in Cartesian coordinates,
               'direction': displacement direction with respect to axes
               'forces': forces on atoms in supercell},
              {...}, ...]}
        """
        self._displacement_dataset = displacement_dataset

        self._displacements = []
        self._displacement_directions = []
        for disp in self._displacement_dataset['first_atoms']:
            x = disp['displacement']
            self._displacements.append([disp['number'], x[0], x[1], x[2]])
            if 'direction' in disp:
                y = disp['direction']
                self._displacement_directions.append(
                    [disp['number'], y[0], y[1], y[2]])
        if not self._displacement_directions:
            self._displacement_directions = None
        
    def symmetrize_force_constants(self, iteration=3):
        symmetrize_force_constants(self._force_constants, iteration)

    def symmetrize_force_constants_by_space_group(self):
        rotations = self._symmetry.get_symmetry_operations()['rotations']
        translations = self._symmetry.get_symmetry_operations()['translations']
        set_tensor_symmetry(self._force_constants,
                            self._supercell.get_cell().T,
                            self._supercell.get_scaled_positions(),
                            rotations,
                            translations,
                            self._symprec)
        
    def get_force_constants(self):
        return self._force_constants
    force_constants = property(get_force_constants)

    def get_rotational_condition_of_fc(self):
        return rotational_invariance(self._force_constants,
                                     self._supercell,
                                     self._primitive,
                                     self._symprec)

    def set_dynamical_matrix(self):
        self._set_dynamical_matrix()
        
    def get_dynamical_matrix_at_q(self, q):
        self._set_dynamical_matrix()
        self._dynamical_matrix.set_dynamical_matrix(q)
        return self._dynamical_matrix.get_dynamical_matrix()

    def get_frequencies(self, q):
        """
        Calculate phonon frequencies at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        for eig in np.linalg.eigvalsh(dm).real:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))
            
        return np.array(frequencies) * self._factor

    def get_frequencies_with_eigenvectors(self, q):
        """
        Calculate phonon frequencies and eigenvectors at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        eigvals, eigenvectors = np.linalg.eigh(dm)
        frequencies = []
        for eig in eigvals:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor, eigenvectors

    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):
        self._set_dynamical_matrix()
        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            is_eigenvectors=is_eigenvectors,
            is_band_connection=is_band_connection,
            group_velocity=self._group_velocity,
            factor=self._factor)

    def get_band_structure(self):
        band = self._band_structure
        return (band.get_qpoints(),
                band.get_distances(),                
                band.get_frequencies(),
                band.get_eigenvectors())

    def plot_band_structure(self, symbols=None):
        return self._band_structure.plot_band(symbols)

    def write_yaml_band_structure(self):
        self._band_structure.write_yaml()

    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_mesh_symmetry=True,
                 is_eigenvectors=False,
                 is_gamma_center=False):
        self._set_dynamical_matrix()
        self._mesh = Mesh(
            self._dynamical_matrix,
            mesh,
            shift=shift,
            is_time_reversal=is_time_reversal,
            is_mesh_symmetry=is_mesh_symmetry,
            is_eigenvectors=is_eigenvectors,
            is_gamma_center=is_gamma_center,
            group_velocity=self._group_velocity,
            rotations=self._primitive_symmetry.get_pointgroup_operations(),
            factor=self._factor)

    def get_mesh(self):
        return (self._mesh.get_qpoints(),
                self._mesh.get_weights(),
                self._mesh.get_frequencies(),
                self._mesh.get_eigenvectors())

    def write_yaml_mesh(self):
        self._mesh.write_yaml()

    def set_thermal_properties(self,
                               t_step=10,
                               t_max=1000,
                               t_min=0,
                               is_projection=False,
                               band_indices=None,
                               cutoff_frequency=None):
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            return False
        else:
            tp = ThermalProperties(self._mesh.get_frequencies(),
                                   weights=self._mesh.get_weights(),
                                   eigenvectors=self._mesh.get_eigenvectors(),
                                   is_projection=is_projection,
                                   band_indices=band_indices,
                                   cutoff_frequency=cutoff_frequency)
            tp.set_thermal_properties(t_step=t_step,
                                      t_max=t_max,
                                      t_min=t_min)
            self._thermal_properties = tp

    def get_thermal_properties(self):
        temps, fe, entropy, cv = \
            self._thermal_properties.get_thermal_properties()
        return temps, fe, entropy, cv

    def plot_thermal_properties(self):
        return self._thermal_properties.plot_thermal_properties()

    def write_yaml_thermal_properties(self, filename='thermal_properties.yaml'):
        self._thermal_properties.write_yaml(filename=filename)

    def set_partial_DOS(self,
                        sigma=None,
                        freq_min=None,
                        freq_max=None,
                        freq_pitch=None,
                        tetrahedron_method=False,
                        direction=None):
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)
        if self._mesh.get_eigenvectors() is None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)
        if direction is not None:
            direction_cart = np.dot(direction, self._primitive.get_cell())
        else:
            direction_cart = None
        pdos = PartialDos(self._mesh,
                          sigma=sigma,
                          tetrahedron_method=tetrahedron_method,
                          direction=direction_cart)
        pdos.set_draw_area(freq_min, freq_max, freq_pitch)
        pdos.run()
        self._pdos = pdos

    def get_partial_DOS(self):
        """
        Retern frequencies and partial_dos.
        The first element is freqs and the second is partial_dos.
        
        frequencies: [freq1, freq2, ...]
        partial_dos:
          [[atom1-freq1, atom1-freq2, ...],
           [atom2-freq1, atom2-freq2, ...],
           ...]
        """
        return self._pdos.get_partial_dos()

    def plot_partial_DOS(self, pdos_indices=None, legend=None):
        return self._pdos.plot_pdos(indices=pdos_indices,
                                    legend=legend)

    def write_partial_DOS(self):
        self._pdos.write()

    def set_total_DOS(self,
                      sigma=None,
                      freq_min=None,
                      freq_max=None,
                      freq_pitch=None,
                      tetrahedron_method=False):

        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        total_dos = TotalDos(self._mesh,
                             sigma=sigma,
                             tetrahedron_method=tetrahedron_method)
        total_dos.set_draw_area(freq_min, freq_max, freq_pitch)
        total_dos.run()
        self._total_dos = total_dos

    def get_total_DOS(self):
        """
        Retern frequencies and total dos.
        The first element is freqs and the second is total dos.
        
        frequencies: [freq1, freq2, ...]
        total_dos: [dos1, dos2, ...]
        """
        return self._total_dos.get_dos()

    def set_Debye_frequency(self, freq_max_fit=None):
        self._total_dos.set_Debye_frequency(
            self._primitive.get_number_of_atoms(),
            freq_max_fit=freq_max_fit)

    def get_Debye_frequency(self):
        return self._total_dos.get_Debye_frequency()

    def plot_total_DOS(self):
        return self._total_dos.plot_dos()

    def write_total_DOS(self):
        self._total_dos.write()

    def set_thermal_displacements(self,
                                  t_step=10,
                                  t_max=1000,
                                  t_min=0,
                                  direction=None,
                                  cutoff_frequency=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers() 

        if self._mesh.get_eigenvectors() is None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)
            
        if np.prod(mesh_nums) != len(eigvecs):
            print "Sampling mesh must not be symmetrized."
            sys.exit(1)

        td = ThermalDisplacements(frequencies,
                                  eigvecs,
                                  self._primitive.get_masses(),
                                  cutoff_frequency=cutoff_frequency)
        td.set_temperature_range(t_min, t_max, t_step)
        if direction is not None:
            td.project_eigenvectors(direction, self._primitive.get_cell())
        td.run()
        
        self._thermal_displacements = td

    def get_thermal_displacements(self):
        if self._thermal_displacements is not None:
            return self._thermal_displacements.get_thermal_displacements()
        
    def plot_thermal_displacements(self, is_legend=False):
        return self._thermal_displacements.plot(is_legend)

    def write_yaml_thermal_displacements(self):
        self._thermal_displacements.write_yaml()

    def set_thermal_displacement_matrices(self,
                                           t_step=10,
                                           t_max=1000,
                                           t_min=0,
                                           cutoff_frequency=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers() 

        if self._mesh.get_eigenvectors() is None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)
            
        if np.prod(mesh_nums) != len(eigvecs):
            print "Sampling mesh must not be symmetrized."
            sys.exit(1)

        tdm = ThermalDisplacementMatrices(frequencies,
                                           eigvecs,
                                           self._primitive.get_masses(),
                                           cutoff_frequency=cutoff_frequency)
        tdm.set_temperature_range(t_min, t_max, t_step)
        tdm.run()
        
        self._thermal_displacement_matrices = tdm

    def get_thermal_displacement_matrices(self):
        if self._thermal_displacement_matrices is not None:
            return self._thermal_displacement_matrices.get_thermal_displacement_matrices()
        
    def write_yaml_thermal_displacement_matrices(self):
        self._thermal_displacement_matrices.write_yaml()
        
    def set_thermal_distances(self,
                              atom_pairs,
                              t_step=10,
                              t_max=1000,
                              t_min=0,
                              cutoff_frequency=None):
        """
        atom_pairs: List of list
          Mean square distances are calculated for the atom_pairs
          e.g. [[1, 2], [1, 4]]

        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.
        """

        td = ThermalDistances(self._mesh.get_frequencies(),
                              self._mesh.get_eigenvectors(),
                              self._supercell,
                              self._primitive,
                              self._mesh.get_qpoints(),
                              cutoff_frequency=cutoff_frequency)
        td.set_temperature_range(t_min, t_max, t_step)
        td.run(atom_pairs)

        self._thermal_distances = td

    def write_yaml_thermal_distances(self):
        self._thermal_distances.write_yaml()

    def set_qpoints_phonon(self,
                           q_points,
                           nac_q_direction=None,
                           is_eigenvectors=False,
                           write_dynamical_matrices=False,
                           factor=VaspToTHz):
        self._set_dynamical_matrix()
        self._qpoints_phonon = QpointsPhonon(
            q_points,
            self._dynamical_matrix,
            nac_q_direction=nac_q_direction,
            is_eigenvectors=is_eigenvectors,
            group_velocity=self._group_velocity,
            write_dynamical_matrices=write_dynamical_matrices,
            factor=self._factor)
        
    def get_qpoints_phonon(self):
        return (self._qpoints_phonon.get_frequencies(),
                self._qpoints_phonon.get_eigenvectors())
    
    def write_yaml_qpoints_phonon(self):
        self._qpoints_phonon.write_yaml()

    def write_animation(self,
                        q_point=None,
                        anime_type='v_sim',
                        band_index=None,
                        amplitude=None,
                        num_div=None,
                        shift=None,
                        filename=None):
        self._set_dynamical_matrix()
        if q_point is None:
            animation = Animation([0, 0, 0],
                                  self._dynamical_matrix,
                                  shift=shift)
        else:
            animation = Animation(q_point,
                                  self._dynamical_matrix,
                                  shift=shift)
        if anime_type == 'v_sim':
            if amplitude:
                amplitude_ = amplitude
            else:
                amplitude_ = 1.0

            if filename:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor,
                                      filename=filename)
            else:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor)

            
        if (anime_type == 'arc' or
            anime_type == 'xyz' or
            anime_type == 'jmol' or
            anime_type == 'poscar'):
            if band_index is None or amplitude is None or num_div is None:
                print "Parameters are not correctly set for animation."
                sys.exit(1)

            if anime_type == 'arc' or anime_type is None:
                if filename:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div,
                                        filename=filename)
                else:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div)
    
            if anime_type == 'xyz':
                if filename:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor,
                                        filename=filename)
                else:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor)
    
            if anime_type == 'jmol':
                if filename:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor,
                                             filename=filename)
                else:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor)
    
            if anime_type == 'poscar':
                if filename:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div,
                                           filename=filename)
                else:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div)
                    
    def set_modulations(self,
                        dimension,
                        phonon_modes,
                        delta_q=None,
                        derivative_order=None,
                        nac_q_direction=None):
        self._set_dynamical_matrix()
        self._modulation = Modulation(self._dynamical_matrix,
                                      dimension,
                                      phonon_modes,
                                      delta_q=delta_q,
                                      derivative_order=derivative_order,
                                      nac_q_direction=nac_q_direction,
                                      factor=self._factor)
        self._modulation.run()
                    
    def get_modulations(self):
        """Returns cells with modulations as Atoms objects"""
        return self._modulation.get_modulations()
                
    def get_delta_modulations(self):
        """Return modulations relative to equilibrium supercell

        (modulations, supercell)

        modulations: Atomic modulations of supercell in Cartesian coordinates
        supercell: Supercell as an Atoms object.
        
        """
        return self._modulation.get_delta_modulations()
                
    def write_modulations(self):
        """Create MPOSCAR's"""
        self._modulation.write()
                          
    def write_yaml_modulations(self):
        self._modulation.write_yaml()

    def set_irreps(self,
                   q,
                   is_little_cogroup=False,
                   nac_q_direction=None,
                   degeneracy_tolerance=1e-4):
        self._set_dynamical_matrix()
        self._irreps = IrReps(
            self._dynamical_matrix,
            q,
            is_little_cogroup=is_little_cogroup,
            nac_q_direction=nac_q_direction,
            factor=self._factor,
            symprec=self._symprec,
            degeneracy_tolerance=degeneracy_tolerance,
            log_level=self._log_level)

        return self._irreps.run()

    def get_irreps(self):
        return self._irreps
        
    def show_irreps(self, show_irreps=False):
        self._irreps.show(show_irreps=show_irreps)

    def write_yaml_irreps(self, show_irreps=False):
        self._irreps.write_yaml(show_irreps=show_irreps)

    def set_group_velocity(self, q_length=None):
        self._set_dynamical_matrix()
        self._group_velocity = GroupVelocity(
            self._dynamical_matrix,
            q_length=q_length,
            symmetry=self._primitive_symmetry,
            frequency_factor_to_THz=self._factor)

    def get_group_velocity(self):
        return self._group_velocity.get_group_velocity()
        
    def get_group_velocity_at_q(self, q_point):
        if self._group_velocity is None:
            self.set_group_velocity()
        self._group_velocity.set_q_points([q_point])
        return self._group_velocity.get_group_velocity()[0]

    def _run_force_constants_from_forces(self,
                                         distributed_atom_list=None,
                                         decimals=None,
                                         computation_algorithm="svd"):
        if self._displacement_dataset is not None:
            self._force_constants = get_fc2(
                self._supercell,
                self._symmetry,
                self._displacement_dataset,
                atom_list=distributed_atom_list,
                decimals=decimals,
                computation_algorithm=computation_algorithm)

    def _set_dynamical_matrix(self):
        if self._nac_params is None:
            self._dynamical_matrix = DynamicalMatrix(
                self._supercell,
                self._primitive,
                self._force_constants,
                decimals=self._dynamical_matrix_decimals,
                symprec=self._symprec)
        else:
            self._dynamical_matrix = DynamicalMatrixNAC(
                self._supercell,
                self._primitive,
                self._force_constants,
                nac_params=self._nac_params,
                decimals=self._dynamical_matrix_decimals,
                symprec=self._symprec)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)
        
        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print ("Warning: point group symmetries of supercell and primitive"
                   "cell are different.")

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_supercells_with_displacements(self):
        supercells = []
        for disp in self._displacement_dataset['first_atoms']:
            positions = self._supercell.get_positions()
            positions[disp['number']] += disp['displacement']
            supercells.append(Atoms(
                    numbers=self._supercell.get_atomic_numbers(),
                    masses=self._supercell.get_masses(),
                    magmoms=self._supercell.get_magnetic_moments(),
                    positions=positions,
                    cell=self._supercell.get_cell(),
                    pbc=True))

        self._supercells_with_displacements = supercells

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """

        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        if self._primitive_matrix is None:
            trans_mat = inv_supercell_matrix
        else:
            trans_mat = np.dot(inv_supercell_matrix, self._primitive_matrix)
        self._primitive = get_primitive(
            self._supercell, trans_mat, self._symprec)
        num_satom = self._supercell.get_number_of_atoms()
        num_patom = self._primitive.get_number_of_atoms()
        if abs(num_satom * np.linalg.det(trans_mat) - num_patom) < 0.1:
            return True
        else:
            return False
コード例 #25
0
class Phono3py(object):
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 phonon_supercell_matrix=None,
                 masses=None,
                 mesh=None,
                 band_indices=None,
                 sigmas=None,
                 sigma_cutoff=None,
                 cutoff_frequency=1e-4,
                 frequency_factor_to_THz=VaspToTHz,
                 is_symmetry=True,
                 is_mesh_symmetry=True,
                 symmetrize_fc3q=False,
                 symprec=1e-5,
                 log_level=0,
                 lapack_zheev_uplo='L'):
        if sigmas is None:
            self._sigmas = [None]
        else:
            self._sigmas = sigmas
        self._sigma_cutoff = sigma_cutoff
        self._symprec = symprec
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_symmetry = is_symmetry
        self._is_mesh_symmetry = is_mesh_symmetry
        self._lapack_zheev_uplo = lapack_zheev_uplo
        self._symmetrize_fc3q = symmetrize_fc3q
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        if type(primitive_matrix) is str and primitive_matrix == 'auto':
            self._primitive_matrix = self._guess_primitive_matrix()
        else:
            self._primitive_matrix = primitive_matrix
        self._phonon_supercell_matrix = phonon_supercell_matrix  # optional
        self._supercell = None
        self._primitive = None
        self._phonon_supercell = None
        self._phonon_primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_phonon_supercell()
        self._build_phonon_primitive_cell()

        if masses is not None:
            self._set_masses(masses)

        # Set supercell, primitive, and phonon supercell symmetries
        self._symmetry = None
        self._primitive_symmetry = None
        self._phonon_supercell_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_phonon_supercell_symmetry()

        # Displacements and supercells
        self._supercells_with_displacements = None
        self._displacement_dataset = None
        self._phonon_displacement_dataset = None
        self._phonon_supercells_with_displacements = None

        # Thermal conductivity
        self._thermal_conductivity = None  # conductivity_RTA object

        # Imaginary part of self energy at frequency points
        self._imag_self_energy = None
        self._scattering_event_class = None

        self._grid_points = None
        self._frequency_points = None
        self._temperatures = None

        # Other variables
        self._fc2 = None
        self._fc3 = None
        self._nac_params = None

        # Setup interaction
        self._interaction = None
        self._mesh_numbers = None
        self._band_indices = None
        self._band_indices_flatten = None
        if mesh is not None:
            self._set_mesh_numbers(mesh)
        self.set_band_indices(band_indices)

    def set_band_indices(self, band_indices):
        if band_indices is None:
            num_band = self._primitive.get_number_of_atoms() * 3
            self._band_indices = [np.arange(num_band, dtype='intc')]
        else:
            self._band_indices = band_indices
        self._band_indices_flatten = np.hstack(
            self._band_indices).astype('intc')

    def set_phph_interaction(self,
                             nac_params=None,
                             nac_q_direction=None,
                             constant_averaged_interaction=None,
                             frequency_scale_factor=None,
                             unit_conversion=None,
                             solve_dynamical_matrices=True):
        if self._mesh_numbers is None:
            print("'mesh' has to be set in Phono3py instantiation.")
            raise RuntimeError

        self._nac_params = nac_params
        self._interaction = Interaction(
            self._supercell,
            self._primitive,
            self._mesh_numbers,
            self._primitive_symmetry,
            fc3=self._fc3,
            band_indices=self._band_indices_flatten,
            constant_averaged_interaction=constant_averaged_interaction,
            frequency_factor_to_THz=self._frequency_factor_to_THz,
            frequency_scale_factor=frequency_scale_factor,
            unit_conversion=unit_conversion,
            cutoff_frequency=self._cutoff_frequency,
            is_mesh_symmetry=self._is_mesh_symmetry,
            symmetrize_fc3q=self._symmetrize_fc3q,
            lapack_zheev_uplo=self._lapack_zheev_uplo)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)
        self._interaction.set_dynamical_matrix(
            self._fc2,
            self._phonon_supercell,
            self._phonon_primitive,
            nac_params=self._nac_params,
            solve_dynamical_matrices=solve_dynamical_matrices,
            verbose=self._log_level)

    def set_phonon_data(self, frequencies, eigenvectors, grid_address):
        if self._interaction is not None:
            return self._interaction.set_phonon_data(frequencies,
                                                     eigenvectors,
                                                     grid_address)
        else:
            return False

    def get_phonon_data(self):
        if self._interaction is not None:
            grid_address = self._interaction.get_grid_address()
            freqs, eigvecs, _ = self._interaction.get_phonons()
            return freqs, eigvecs, grid_address
        else:
            msg = "set_phph_interaction has to be done."
            raise RuntimeError(msg)

    def generate_displacements(self,
                               distance=0.03,
                               cutoff_pair_distance=None,
                               is_plusminus='auto',
                               is_diagonal=True):
        direction_dataset = get_third_order_displacements(
            self._supercell,
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal)
        self._displacement_dataset = direction_to_displacement(
            direction_dataset,
            distance,
            self._supercell,
            cutoff_distance=cutoff_pair_distance)

        if self._phonon_supercell_matrix is not None:
            # 'is_diagonal=False' below is made intentionally. For
            # third-order force constants, we need better accuracy,
            # and I expect this choice is better for it, but not very
            # sure.
            # In phono3py, two atoms are displaced for each
            # configuration and the displacements are chosen, first
            # displacement from the perfect supercell, then second
            # displacement, considering symmetry. If I choose
            # is_diagonal=False for the first displacement, the
            # symmetry is less broken and the number of second
            # displacements can be smaller than in the case of
            # is_diagonal=True for the first displacement.  This is
            # done in the call get_least_displacements() in
            # phonon3.displacement_fc3.get_third_order_displacements().
            #
            # The call get_least_displacements() is only for the
            # second order force constants, but 'is_diagonal=False' to
            # be consistent with the above function call, and also for
            # the accuracy when calculating ph-ph interaction
            # strength because displacement directions are better to be
            # close to perpendicular each other to fit force constants.
            #
            # On the discussion of the accuracy, these are just my
            # expectation when I designed phono3py in the early time,
            # and in fact now I guess not very different. If these are
            # little different, then I should not surprise users to
            # change the default behaviour. At this moment, this is
            # open question and we will have more advance and should
            # have better specificy external software on this.
            phonon_displacement_directions = get_least_displacements(
                self._phonon_supercell_symmetry,
                is_plusminus=is_plusminus,
                is_diagonal=False)
            self._phonon_displacement_dataset = directions_to_displacement_dataset(
                phonon_displacement_directions,
                distance,
                self._phonon_supercell)

    def produce_fc2(self,
                    forces_fc2,
                    displacement_dataset=None,
                    symmetrize_fc2=False,
                    is_compact_fc=False,
                    use_alm=False,
                    alm_options=None):
        if displacement_dataset is None:
            if self._phonon_displacement_dataset is None:
                disp_dataset = self._displacement_dataset
            else:
                disp_dataset = self._phonon_displacement_dataset
        else:
            disp_dataset = displacement_dataset

        for forces, disp1 in zip(forces_fc2, disp_dataset['first_atoms']):
            disp1['forces'] = forces

        if is_compact_fc:
            p2s_map = self._phonon_primitive.p2s_map
        else:
            p2s_map = None

        if use_alm:
            from phonopy.interface.alm import get_fc2 as get_fc2_alm
            self._fc2 = get_fc2_alm(self._phonon_supercell,
                                    self._phonon_primitive,
                                    disp_dataset,
                                    atom_list=p2s_map,
                                    alm_options=alm_options,
                                    log_level=self._log_level)
        else:
            self._fc2 = get_fc2(self._phonon_supercell,
                                self._phonon_supercell_symmetry,
                                disp_dataset,
                                atom_list=p2s_map)
            if symmetrize_fc2:
                if is_compact_fc:
                    symmetrize_compact_force_constants(
                        self._fc2, self._phonon_primitive)
                else:
                    symmetrize_force_constants(self._fc2)

    def produce_fc3(self,
                    forces_fc3,
                    displacement_dataset=None,
                    cutoff_distance=None,  # set fc3 zero
                    symmetrize_fc3r=False,
                    is_compact_fc=False,
                    use_alm=False,
                    alm_options=None):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset

        if use_alm:
            from phono3py.other.alm_wrapper import get_fc3 as get_fc3_alm
            fc2, fc3 = get_fc3_alm(self._supercell,
                                   self._primitive,
                                   forces_fc3,
                                   disp_dataset,
                                   self._symmetry,
                                   alm_options=alm_options,
                                   is_compact_fc=is_compact_fc,
                                   log_level=self._log_level)
        else:
            fc2, fc3 = self._get_fc3(forces_fc3,
                                     disp_dataset,
                                     is_compact_fc=is_compact_fc)
            if symmetrize_fc3r:
                if is_compact_fc:
                    set_translational_invariance_compact_fc3(
                        fc3, self._primitive)
                    set_permutation_symmetry_compact_fc3(fc3, self._primitive)
                    if self._fc2 is None:
                        symmetrize_compact_force_constants(fc2,
                                                           self._primitive)
                else:
                    set_translational_invariance_fc3(fc3)
                    set_permutation_symmetry_fc3(fc3)
                    if self._fc2 is None:
                        symmetrize_force_constants(fc2)

        # Set fc2 and fc3
        self._fc3 = fc3

        # Normally self._fc2 is overwritten in produce_fc2
        if self._fc2 is None:
            self._fc2 = fc2

    def cutoff_fc3_by_zero(self, cutoff_distance, fc3=None):
        if fc3 is None:
            _fc3 = self._fc3
        else:
            _fc3 = fc3
        cutoff_fc3_by_zero(_fc3,  # overwritten
                           self._supercell,
                           cutoff_distance,
                           self._symprec)

    def set_permutation_symmetry(self):
        if self._fc2 is not None:
            set_permutation_symmetry(self._fc2)
        if self._fc3 is not None:
            set_permutation_symmetry_fc3(self._fc3)

    def set_translational_invariance(self):
        if self._fc2 is not None:
            set_translational_invariance(self._fc2)
        if self._fc3 is not None:
            set_translational_invariance_fc3(self._fc3)

    @property
    def version(self):
        return __version__

    def get_version(self):
        return self.version

    def get_interaction_strength(self):
        return self._interaction

    def get_fc2(self):
        return self._fc2

    def set_fc2(self, fc2):
        self._fc2 = fc2

    def get_fc3(self):
        return self._fc3

    def set_fc3(self, fc3):
        self._fc3 = fc3

    @property
    def nac_params(self):
        return self._nac_params

    def get_nac_params(self):
        return self.nac_params

    @property
    def primitive(self):
        return self._primitive

    def get_primitive(self):
        return self.primitive

    @property
    def unitcell(self):
        return self._unitcell

    def get_unitcell(self):
        return self.unitcell

    @property
    def supercell(self):
        return self._supercell

    def get_supercell(self):
        return self.supercell

    @property
    def phonon_supercell(self):
        return self._phonon_supercell

    def get_phonon_supercell(self):
        return self.phonon_supercell

    @property
    def phonon_primitive(self):
        return self._phonon_primitive

    def get_phonon_primitive(self):
        return self.phonon_primitive

    @property
    def symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_symmetry(self):
        return self.symmetry

    @property
    def primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self._primitive_symmetry

    def get_primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self.primitive_symmetry

    def get_phonon_supercell_symmetry(self):
        return self._phonon_supercell_symmetry

    @property
    def supercell_matrix(self):
        return self._supercell_matrix

    def get_supercell_matrix(self):
        return self.supercell_matrix

    @property
    def phonon_supercell_matrix(self):
        return self._phonon_supercell_matrix

    def get_phonon_supercell_matrix(self):
        return self.phonon_supercell_matrix

    @property
    def primitive_matrix(self):
        return self._primitive_matrix

    def get_primitive_matrix(self):
        return self.primitive_matrix

    @property
    def unit_conversion_factor(self):
        return self._frequency_factor_to_THz

    def set_displacement_dataset(self, dataset):
        self._displacement_dataset = dataset

    @property
    def displacement_dataset(self):
        return self._displacement_dataset

    def get_displacement_dataset(self):
        return self.displacement_dataset

    def get_phonon_displacement_dataset(self):
        return self._phonon_displacement_dataset

    def get_supercells_with_displacements(self):
        if self._supercells_with_displacements is None:
            self._build_supercells_with_displacements()
        return self._supercells_with_displacements

    def get_phonon_supercells_with_displacements(self):
        if self._phonon_supercells_with_displacements is None:
            if self._phonon_displacement_dataset is not None:
                self._phonon_supercells_with_displacements = \
                  self._build_phonon_supercells_with_displacements(
                      self._phonon_supercell,
                      self._phonon_displacement_dataset)
        return self._phonon_supercells_with_displacements

    @property
    def mesh_numbers(self):
        return self._mesh_numbers

    def run_imag_self_energy(self,
                             grid_points,
                             frequency_step=None,
                             num_frequency_points=None,
                             temperatures=None,
                             scattering_event_class=None,
                             write_gamma_detail=False,
                             output_filename=None):
        if self._interaction is None:
            self.set_phph_interaction()
        if temperatures is None:
            temperatures = [0.0, 300.0]
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._scattering_event_class = scattering_event_class
        self._imag_self_energy, self._frequency_points = get_imag_self_energy(
            self._interaction,
            grid_points,
            self._sigmas,
            frequency_step=frequency_step,
            num_frequency_points=num_frequency_points,
            temperatures=temperatures,
            scattering_event_class=scattering_event_class,
            write_detail=write_gamma_detail,
            output_filename=output_filename,
            log_level=self._log_level)

    def write_imag_self_energy(self, filename=None):
        write_imag_self_energy(
            self._imag_self_energy,
            self._mesh_numbers,
            self._grid_points,
            self._band_indices,
            self._frequency_points,
            self._temperatures,
            self._sigmas,
            scattering_event_class=self._scattering_event_class,
            filename=filename,
            is_mesh_symmetry=self._is_mesh_symmetry)

    def run_thermal_conductivity(
            self,
            is_LBTE=False,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            is_isotope=False,
            mass_variances=None,
            grid_points=None,
            boundary_mfp=None,  # in micrometre
            solve_collective_phonon=False,
            use_ave_pp=False,
            gamma_unit_conversion=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            is_reducible_collision_matrix=False,
            is_kappa_star=True,
            gv_delta_q=None,  # for group velocity
            is_full_pp=False,
            pinv_cutoff=1.0e-8,  # for pseudo-inversion of collision matrix
            pinv_solver=0,  # solver of pseudo-inversion of collision matrix
            write_gamma=False,
            read_gamma=False,
            is_N_U=False,
            write_kappa=False,
            write_gamma_detail=False,
            write_collision=False,
            read_collision=False,
            write_pp=False,
            read_pp=False,
            write_LBTE_solution=False,
            compression=None,
            input_filename=None,
            output_filename=None):
        if self._interaction is None:
            self.set_phph_interaction()
        if is_LBTE:
            self._thermal_conductivity = get_thermal_conductivity_LBTE(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                sigma_cutoff=self._sigma_cutoff,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                solve_collective_phonon=solve_collective_phonon,
                is_reducible_collision_matrix=is_reducible_collision_matrix,
                is_kappa_star=is_kappa_star,
                gv_delta_q=gv_delta_q,
                is_full_pp=is_full_pp,
                pinv_cutoff=pinv_cutoff,
                pinv_solver=pinv_solver,
                write_collision=write_collision,
                read_collision=read_collision,
                write_kappa=write_kappa,
                write_pp=write_pp,
                read_pp=read_pp,
                write_LBTE_solution=write_LBTE_solution,
                compression=compression,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)
        else:
            self._thermal_conductivity = get_thermal_conductivity_RTA(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                sigma_cutoff=self._sigma_cutoff,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                use_ave_pp=use_ave_pp,
                gamma_unit_conversion=gamma_unit_conversion,
                mesh_divisors=mesh_divisors,
                coarse_mesh_shifts=coarse_mesh_shifts,
                is_kappa_star=is_kappa_star,
                gv_delta_q=gv_delta_q,
                is_full_pp=is_full_pp,
                write_gamma=write_gamma,
                read_gamma=read_gamma,
                is_N_U=is_N_U,
                write_kappa=write_kappa,
                write_pp=write_pp,
                read_pp=read_pp,
                write_gamma_detail=write_gamma_detail,
                compression=compression,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)

    def get_thermal_conductivity(self):
        return self._thermal_conductivity

    def get_frequency_shift(
            self,
            grid_points,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            epsilons=None,
            output_filename=None):
        """Frequency shift from lowest order diagram is calculated.

        Args:
            epslins(list of float):
               The value to avoid divergence. When multiple values are given
               frequency shifts for those values are returned.

        """

        if self._interaction is None:
            self.set_phph_interaction()
        if epsilons is None:
            _epsilons = [0.1]
        else:
            _epsilons = epsilons
        self._grid_points = grid_points
        get_frequency_shift(self._interaction,
                            self._grid_points,
                            self._band_indices,
                            _epsilons,
                            temperatures,
                            output_filename=output_filename,
                            log_level=self._log_level)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print("Warning: point group symmetries of supercell and primitive"
                  "cell are different.")

    def _search_phonon_supercell_symmetry(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell_symmetry = self._symmetry
        else:
            self._phonon_supercell_symmetry = Symmetry(self._phonon_supercell,
                                                       self._symprec,
                                                       self._is_symmetry)

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """
        self._primitive = self._get_primitive_cell(
            self._supercell, self._supercell_matrix, self._primitive_matrix)

    def _build_phonon_supercell(self):
        """
        phonon_supercell:
          This supercell is used for harmonic phonons (frequencies,
          eigenvectors, group velocities, ...)
        phonon_supercell_matrix:
          Different supercell size can be specified.
        """
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell = self._supercell
        else:
            self._phonon_supercell = get_supercell(
                self._unitcell, self._phonon_supercell_matrix, self._symprec)

    def _build_phonon_primitive_cell(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_primitive = self._primitive
        else:
            self._phonon_primitive = self._get_primitive_cell(
                self._phonon_supercell,
                self._phonon_supercell_matrix,
                self._primitive_matrix)
            if (self._primitive is not None and
                (self._primitive.get_atomic_numbers() !=
                 self._phonon_primitive.get_atomic_numbers()).any()):
                print(" Primitive cells for fc2 and fc3 can be different.")
                raise RuntimeError

    def _build_phonon_supercells_with_displacements(self,
                                                    supercell,
                                                    displacement_dataset):
        supercells = []
        magmoms = supercell.get_magnetic_moments()
        masses = supercell.get_masses()
        numbers = supercell.get_atomic_numbers()
        lattice = supercell.get_cell()

        for disp1 in displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            positions = supercell.get_positions()
            positions[disp1['number']] += disp_cart1
            supercells.append(
                Atoms(numbers=numbers,
                      masses=masses,
                      magmoms=magmoms,
                      positions=positions,
                      cell=lattice,
                      pbc=True))

        return supercells

    def _build_supercells_with_displacements(self):
        supercells = []
        magmoms = self._supercell.get_magnetic_moments()
        masses = self._supercell.get_masses()
        numbers = self._supercell.get_atomic_numbers()
        lattice = self._supercell.get_cell()

        supercells = self._build_phonon_supercells_with_displacements(
            self._supercell,
            self._displacement_dataset)

        for disp1 in self._displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            for disp2 in disp1['second_atoms']:
                if 'included' in disp2:
                    included = disp2['included']
                else:
                    included = True
                if included:
                    positions = self._supercell.get_positions()
                    positions[disp1['number']] += disp_cart1
                    positions[disp2['number']] += disp2['displacement']
                    supercells.append(Atoms(numbers=numbers,
                                            masses=masses,
                                            magmoms=magmoms,
                                            positions=positions,
                                            cell=lattice,
                                            pbc=True))
                else:
                    supercells.append(None)

        self._supercells_with_displacements = supercells

    def _get_primitive_cell(self,
                            supercell,
                            supercell_matrix,
                            primitive_matrix):
        inv_supercell_matrix = np.linalg.inv(supercell_matrix)
        if primitive_matrix is None:
            t_mat = inv_supercell_matrix
        else:
            t_mat = np.dot(inv_supercell_matrix, primitive_matrix)

        return get_primitive(supercell, t_mat, self._symprec)

    def _guess_primitive_matrix(self):
        return guess_primitive_matrix(self._unitcell, symprec=self._symprec)

    def _set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[p2p_map[x] for x in
                             self._primitive.get_supercell_to_primitive_map()]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)

        self._phonon_primitive.set_masses(p_masses)
        p2p_map = self._phonon_primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[
            [p2p_map[x] for x in
             self._phonon_primitive.get_supercell_to_primitive_map()]]
        self._phonon_supercell.set_masses(s_masses)

    def _set_mesh_numbers(self, mesh):
        _mesh = np.array(mesh)
        mesh_nums = None
        if _mesh.shape:
            if _mesh.shape == (3,):
                mesh_nums = mesh
        elif self._primitive_symmetry is None:
            mesh_nums = length2mesh(mesh, self._primitive.get_cell())
        else:
            rotations = self._primitive_symmetry.get_pointgroup_operations()
            mesh_nums = length2mesh(mesh, self._primitive.get_cell(),
                                    rotations=rotations)
        if mesh_nums is None:
            msg = "mesh has inappropriate type."
            raise TypeError(msg)
        self._mesh_numbers = mesh_nums

    def _get_fc3(self,
                 forces_fc3,
                 disp_dataset,
                 is_compact_fc=False):
        count = 0
        for disp1 in disp_dataset['first_atoms']:
            disp1['forces'] = forces_fc3[count]
            count += 1
        for disp1 in disp_dataset['first_atoms']:
            for disp2 in disp1['second_atoms']:
                disp2['delta_forces'] = forces_fc3[count] - disp1['forces']
                count += 1

        fc2, fc3 = get_fc3(self._supercell,
                           self._primitive,
                           disp_dataset,
                           self._symmetry,
                           is_compact_fc=is_compact_fc,
                           verbose=self._log_level)

        return fc2, fc3
コード例 #26
0
class Phonopy:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 nac_params=None,
                 distance=0.01,
                 factor=VaspToTHz,
                 is_auto_displacements=True,
                 dynamical_matrix_decimals=None,
                 force_constants_decimals=None,
                 symprec=1e-5,
                 is_symmetry=True,
                 log_level=0):
        self._symprec = symprec
        self._factor = factor
        self._is_symmetry = is_symmetry
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._supercell = None
        self._primitive = None
        self._build_supercell()
        self._build_primitive_cell()

        # Set supercell and primitive symmetry
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()

        # set_displacements (used only in preprocess)
        self._displacement_dataset = None
        self._displacements = None
        self._displacement_directions = None
        self._supercells_with_displacements = None
        if is_auto_displacements:
            self.generate_displacements(distance=distance)

        # set_force_constants or set_forces
        self._force_constants = None
        self._force_constants_decimals = force_constants_decimals

        # set_dynamical_matrix
        self._dynamical_matrix = None
        self._nac_params = nac_params
        self._dynamical_matrix_decimals = dynamical_matrix_decimals

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = None

        # set_tetrahedron_method
        self._tetrahedron_method = None

        # set_thermal_properties
        self._thermal_properties = None

        # set_thermal_displacements
        self._thermal_displacements = None

        # set_thermal_displacement_matrices
        self._thermal_displacement_matrices = None

        # set_partial_DOS
        self._pdos = None

        # set_total_DOS
        self._total_dos = None

        # set_modulation
        self._modulation = None

        # set_character_table
        self._irreps = None

        # set_group_velocity
        self._group_velocity = None

    def set_post_process(self,
                         primitive_matrix=None,
                         sets_of_forces=None,
                         displacement_dataset=None,
                         force_constants=None,
                         is_nac=None):
        print
        print(
            "********************************** Warning"
            "**********************************")
        print "set_post_process will be obsolete."
        print(
            "  produce_force_constants is used instead of set_post_process"
            " for producing")
        print("  force constants from forces.")
        if primitive_matrix is not None:
            print(
                "  primitive_matrix has to be given at Phonopy::__init__"
                " object creation.")
        print(
            "******************************************"
            "**********************************")
        print

        if primitive_matrix is not None:
            self._primitive_matrix = primitive_matrix
            self._build_primitive_cell()
            self._search_primitive_symmetry()

        if sets_of_forces is not None:
            self.set_forces(sets_of_forces)
        elif displacement_dataset is not None:
            self._displacement_dataset = displacement_dataset
        elif force_constants is not None:
            self.set_force_constants(force_constants)

        if self._displacement_dataset is not None:
            self.produce_force_constants()

    def set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[
            p2p_map[x]
            for x in self._primitive.get_supercell_to_primitive_map()
        ]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)

    def get_primitive(self):
        return self._primitive

    primitive = property(get_primitive)

    def get_unitcell(self):
        return self._unitcell

    unitcell = property(get_unitcell)

    def get_supercell(self):
        return self._supercell

    supercell = property(get_supercell)

    def set_supercell(self, supercell):
        self._supercell = supercell

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    symmetry = property(get_symmetry)

    def get_primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self._primitive_symmetry

    def get_unit_conversion_factor(self):
        return self._factor

    unit_conversion_factor = property(get_unit_conversion_factor)

    def produce_force_constants(self,
                                forces=None,
                                calculate_full_force_constants=True,
                                computation_algorithm="svd"):
        if forces is not None:
            self.set_forces(forces)

        if calculate_full_force_constants:
            self._run_force_constants_from_forces(
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)
        else:
            p2s_map = self._primitive.get_primitive_to_supercell_map()
            self._run_force_constants_from_forces(
                distributed_atom_list=p2s_map,
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)

    def set_nac_params(self, nac_params=None, method=None):
        if method is not None:
            print "set_nac_params:"
            print "  Keyword argument of \"method\" is not more supported."
        self._nac_params = nac_params

    def generate_displacements(self,
                               distance=0.01,
                               is_plusminus='auto',
                               is_diagonal=True,
                               is_trigonal=False):
        """Generate displacements automatically

        displacemsts: List of displacements in Cartesian coordinates.
           [[0, 0.01, 0.00, 0.00], ...]
        where each set of elements is defined by:
           First value:      Atom index in supercell starting with 0
           Second to fourth: Displacement in Cartesian coordinates
        
        displacement_directions:
          List of directions with respect to axes. This gives only the
          symmetrically non equivalent directions. The format is like:
             [[0, 1, 0, 0],
              [7, 1, 0, 1], ...]
          where each list is defined by:
             First value:      Atom index in supercell starting with 0
             Second to fourth: If the direction is displaced or not ( 1, 0, or -1 )
                               with respect to the axes.
                               
        """
        displacement_directions = get_least_displacements(
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal,
            is_trigonal=is_trigonal,
            log_level=self._log_level)
        displacement_dataset = direction_to_displacement(
            displacement_directions, distance, self._supercell)
        self.set_displacement_dataset(displacement_dataset)

    def set_displacements(self, displacements):
        print
        print(
            "********************************** Warning"
            "**********************************")
        print "set_displacements is obsolete. Do nothing."
        print(
            "******************************************"
            "**********************************")
        print

    def get_displacements(self):
        return self._displacements

    displacements = property(get_displacements)

    def get_displacement_directions(self):
        return self._displacement_directions

    displacement_directions = property(get_displacement_directions)

    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_supercells_with_displacements(self):
        if self._displacement_dataset is None:
            return None
        else:
            self._build_supercells_with_displacements()
            return self._supercells_with_displacements

    def get_dynamical_matrix(self):
        return self._dynamical_matrix

    dynamical_matrix = property(get_dynamical_matrix)

    def set_forces(self, sets_of_forces):
        """
        sets_of_forces:
           [[[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # first supercell
             [[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # second supercell
             ...                                                  ]
        """
        for disp, forces in zip(self._displacement_dataset['first_atoms'],
                                sets_of_forces):
            disp['forces'] = forces

    def set_force_constants_zero_with_radius(self, cutoff_radius):
        cutoff_force_constants(self._force_constants,
                               self._supercell,
                               cutoff_radius,
                               symprec=self._symprec)

    def set_force_constants(self, force_constants):
        self._force_constants = force_constants

    def set_force_sets(self, force_sets):
        print
        print(
            "********************************** Warning"
            "**********************************")
        print "set_force_sets will be obsolete."
        print("   The method name is changed to set_displacement_dataset.")
        print(
            "******************************************"
            "**********************************")
        print
        self.set_displacement_dataset(force_sets)

    def set_displacement_dataset(self, displacement_dataset):
        """
        displacement_dataset:
           {'natom': number_of_atoms_in_supercell,
            'first_atoms': [
              {'number': atom index of displaced atom,
               'displacement': displacement in Cartesian coordinates,
               'direction': displacement direction with respect to axes
               'forces': forces on atoms in supercell},
              {...}, ...]}
        """
        self._displacement_dataset = displacement_dataset

        self._displacements = []
        self._displacement_directions = []
        for disp in self._displacement_dataset['first_atoms']:
            x = disp['displacement']
            self._displacements.append([disp['number'], x[0], x[1], x[2]])
            if 'direction' in disp:
                y = disp['direction']
                self._displacement_directions.append(
                    [disp['number'], y[0], y[1], y[2]])
        if not self._displacement_directions:
            self._displacement_directions = None

    def symmetrize_force_constants(self, iteration=3):
        symmetrize_force_constants(self._force_constants, iteration)

    def symmetrize_force_constants_by_space_group(self):
        rotations = self._symmetry.get_symmetry_operations()['rotations']
        translations = self._symmetry.get_symmetry_operations()['translations']
        set_tensor_symmetry(self._force_constants,
                            self._supercell.get_cell().T,
                            self._supercell.get_scaled_positions(), rotations,
                            translations, self._symprec)

    def get_force_constants(self):
        return self._force_constants

    force_constants = property(get_force_constants)

    def get_rotational_condition_of_fc(self):
        return rotational_invariance(self._force_constants, self._supercell,
                                     self._primitive, self._symprec)

    def set_dynamical_matrix(self):
        self._set_dynamical_matrix()

    def get_dynamical_matrix_at_q(self, q):
        self._set_dynamical_matrix()
        self._dynamical_matrix.set_dynamical_matrix(q)
        return self._dynamical_matrix.get_dynamical_matrix()

    def get_frequencies(self, q):
        """
        Calculate phonon frequencies at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        for eig in np.linalg.eigvalsh(dm).real:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor

    def get_frequencies_with_eigenvectors(self, q):
        """
        Calculate phonon frequencies and eigenvectors at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        eigvals, eigenvectors = np.linalg.eigh(dm)
        frequencies = []
        for eig in eigvals:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor, eigenvectors

    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):
        self._set_dynamical_matrix()
        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            is_eigenvectors=is_eigenvectors,
            is_band_connection=is_band_connection,
            group_velocity=self._group_velocity,
            factor=self._factor)

    def get_band_structure(self):
        band = self._band_structure
        return (band.get_qpoints(), band.get_distances(),
                band.get_frequencies(), band.get_eigenvectors())

    def plot_band_structure(self, symbols=None):
        return self._band_structure.plot_band(symbols)

    def write_yaml_band_structure(self):
        self._band_structure.write_yaml()

    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_mesh_symmetry=True,
                 is_eigenvectors=False,
                 is_gamma_center=False):
        self._set_dynamical_matrix()
        self._mesh = Mesh(
            self._dynamical_matrix,
            mesh,
            shift=shift,
            is_time_reversal=is_time_reversal,
            is_mesh_symmetry=is_mesh_symmetry,
            is_eigenvectors=is_eigenvectors,
            is_gamma_center=is_gamma_center,
            group_velocity=self._group_velocity,
            rotations=self._primitive_symmetry.get_pointgroup_operations(),
            factor=self._factor)

    def get_mesh(self):
        return (self._mesh.get_qpoints(), self._mesh.get_weights(),
                self._mesh.get_frequencies(), self._mesh.get_eigenvectors())

    def write_yaml_mesh(self):
        self._mesh.write_yaml()

    def set_thermal_properties(self,
                               t_step=10,
                               t_max=1000,
                               t_min=0,
                               is_projection=False,
                               band_indices=None,
                               cutoff_frequency=None):
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            return False
        else:
            tp = ThermalProperties(self._mesh.get_frequencies(),
                                   weights=self._mesh.get_weights(),
                                   eigenvectors=self._mesh.get_eigenvectors(),
                                   is_projection=is_projection,
                                   band_indices=band_indices,
                                   cutoff_frequency=cutoff_frequency)
            tp.set_thermal_properties(t_step=t_step, t_max=t_max, t_min=t_min)
            self._thermal_properties = tp

    def get_thermal_properties(self):
        temps, fe, entropy, cv = \
            self._thermal_properties.get_thermal_properties()
        return temps, fe, entropy, cv

    def plot_thermal_properties(self):
        return self._thermal_properties.plot_thermal_properties()

    def write_yaml_thermal_properties(self,
                                      filename='thermal_properties.yaml'):
        self._thermal_properties.write_yaml(filename=filename)

    def set_partial_DOS(self,
                        sigma=None,
                        freq_min=None,
                        freq_max=None,
                        freq_pitch=None,
                        tetrahedron_method=False,
                        direction=None):
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)
        if self._mesh.get_eigenvectors() is None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)
        if direction is not None:
            direction_cart = np.dot(direction, self._primitive.get_cell())
        else:
            direction_cart = None
        pdos = PartialDos(self._mesh,
                          sigma=sigma,
                          tetrahedron_method=tetrahedron_method,
                          direction=direction_cart)
        pdos.set_draw_area(freq_min, freq_max, freq_pitch)
        pdos.run()
        self._pdos = pdos

    def get_partial_DOS(self):
        """
        Retern frequencies and partial_dos.
        The first element is freqs and the second is partial_dos.
        
        frequencies: [freq1, freq2, ...]
        partial_dos:
          [[atom1-freq1, atom1-freq2, ...],
           [atom2-freq1, atom2-freq2, ...],
           ...]
        """
        return self._pdos.get_partial_dos()

    def plot_partial_DOS(self, pdos_indices=None, legend=None):
        return self._pdos.plot_pdos(indices=pdos_indices, legend=legend)

    def write_partial_DOS(self):
        self._pdos.write()

    def set_total_DOS(self,
                      sigma=None,
                      freq_min=None,
                      freq_max=None,
                      freq_pitch=None,
                      tetrahedron_method=False):

        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        total_dos = TotalDos(self._mesh,
                             sigma=sigma,
                             tetrahedron_method=tetrahedron_method)
        total_dos.set_draw_area(freq_min, freq_max, freq_pitch)
        total_dos.run()
        self._total_dos = total_dos

    def get_total_DOS(self):
        """
        Retern frequencies and total dos.
        The first element is freqs and the second is total dos.
        
        frequencies: [freq1, freq2, ...]
        total_dos: [dos1, dos2, ...]
        """
        return self._total_dos.get_dos()

    def set_Debye_frequency(self, freq_max_fit=None):
        self._total_dos.set_Debye_frequency(
            self._primitive.get_number_of_atoms(), freq_max_fit=freq_max_fit)

    def get_Debye_frequency(self):
        return self._total_dos.get_Debye_frequency()

    def plot_total_DOS(self):
        return self._total_dos.plot_dos()

    def write_total_DOS(self):
        self._total_dos.write()

    def set_thermal_displacements(self,
                                  t_step=10,
                                  t_max=1000,
                                  t_min=0,
                                  direction=None,
                                  cutoff_frequency=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers()

        if self._mesh.get_eigenvectors() is None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)

        if np.prod(mesh_nums) != len(eigvecs):
            print "Sampling mesh must not be symmetrized."
            sys.exit(1)

        td = ThermalDisplacements(frequencies,
                                  eigvecs,
                                  self._primitive.get_masses(),
                                  cutoff_frequency=cutoff_frequency)
        td.set_temperature_range(t_min, t_max, t_step)
        if direction is not None:
            td.project_eigenvectors(direction, self._primitive.get_cell())
        td.run()

        self._thermal_displacements = td

    def get_thermal_displacements(self):
        if self._thermal_displacements is not None:
            return self._thermal_displacements.get_thermal_displacements()

    def plot_thermal_displacements(self, is_legend=False):
        return self._thermal_displacements.plot(is_legend)

    def write_yaml_thermal_displacements(self):
        self._thermal_displacements.write_yaml()

    def set_thermal_displacement_matrices(self,
                                          t_step=10,
                                          t_max=1000,
                                          t_min=0,
                                          cutoff_frequency=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh is None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers()

        if self._mesh.get_eigenvectors() is None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)

        if np.prod(mesh_nums) != len(eigvecs):
            print "Sampling mesh must not be symmetrized."
            sys.exit(1)

        tdm = ThermalDisplacementMatrices(frequencies,
                                          eigvecs,
                                          self._primitive.get_masses(),
                                          cutoff_frequency=cutoff_frequency)
        tdm.set_temperature_range(t_min, t_max, t_step)
        tdm.run()

        self._thermal_displacement_matrices = tdm

    def get_thermal_displacement_matrices(self):
        if self._thermal_displacement_matrices is not None:
            return self._thermal_displacement_matrices.get_thermal_displacement_matrices(
            )

    def write_yaml_thermal_displacement_matrices(self):
        self._thermal_displacement_matrices.write_yaml()

    def set_thermal_distances(self,
                              atom_pairs,
                              t_step=10,
                              t_max=1000,
                              t_min=0,
                              cutoff_frequency=None):
        """
        atom_pairs: List of list
          Mean square distances are calculated for the atom_pairs
          e.g. [[1, 2], [1, 4]]

        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.
        """

        td = ThermalDistances(self._mesh.get_frequencies(),
                              self._mesh.get_eigenvectors(),
                              self._supercell,
                              self._primitive,
                              self._mesh.get_qpoints(),
                              cutoff_frequency=cutoff_frequency)
        td.set_temperature_range(t_min, t_max, t_step)
        td.run(atom_pairs)

        self._thermal_distances = td

    def write_yaml_thermal_distances(self):
        self._thermal_distances.write_yaml()

    def set_qpoints_phonon(self,
                           q_points,
                           nac_q_direction=None,
                           is_eigenvectors=False,
                           write_dynamical_matrices=False,
                           factor=VaspToTHz):
        self._set_dynamical_matrix()
        self._qpoints_phonon = QpointsPhonon(
            q_points,
            self._dynamical_matrix,
            nac_q_direction=nac_q_direction,
            is_eigenvectors=is_eigenvectors,
            group_velocity=self._group_velocity,
            write_dynamical_matrices=write_dynamical_matrices,
            factor=self._factor)

    def get_qpoints_phonon(self):
        return (self._qpoints_phonon.get_frequencies(),
                self._qpoints_phonon.get_eigenvectors())

    def write_yaml_qpoints_phonon(self):
        self._qpoints_phonon.write_yaml()

    def write_animation(self,
                        q_point=None,
                        anime_type='v_sim',
                        band_index=None,
                        amplitude=None,
                        num_div=None,
                        shift=None,
                        filename=None):
        self._set_dynamical_matrix()
        if q_point is None:
            animation = Animation([0, 0, 0],
                                  self._dynamical_matrix,
                                  shift=shift)
        else:
            animation = Animation(q_point, self._dynamical_matrix, shift=shift)
        if anime_type == 'v_sim':
            if amplitude:
                amplitude_ = amplitude
            else:
                amplitude_ = 1.0

            if filename:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor,
                                      filename=filename)
            else:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor)

        if (anime_type == 'arc' or anime_type == 'xyz' or anime_type == 'jmol'
                or anime_type == 'poscar'):
            if band_index is None or amplitude is None or num_div is None:
                print "Parameters are not correctly set for animation."
                sys.exit(1)

            if anime_type == 'arc' or anime_type is None:
                if filename:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div,
                                        filename=filename)
                else:
                    animation.write_arc(band_index, amplitude, num_div)

            if anime_type == 'xyz':
                if filename:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor,
                                        filename=filename)
                else:
                    animation.write_xyz(band_index, amplitude, num_div,
                                        self._factor)

            if anime_type == 'jmol':
                if filename:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor,
                                             filename=filename)
                else:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor)

            if anime_type == 'poscar':
                if filename:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div,
                                           filename=filename)
                else:
                    animation.write_POSCAR(band_index, amplitude, num_div)

    def set_modulations(self,
                        dimension,
                        phonon_modes,
                        delta_q=None,
                        derivative_order=None,
                        nac_q_direction=None):
        self._set_dynamical_matrix()
        self._modulation = Modulation(self._dynamical_matrix,
                                      dimension,
                                      phonon_modes,
                                      delta_q=delta_q,
                                      derivative_order=derivative_order,
                                      nac_q_direction=nac_q_direction,
                                      factor=self._factor)
        self._modulation.run()

    def get_modulations(self):
        """Returns cells with modulations as Atoms objects"""
        return self._modulation.get_modulations()

    def get_delta_modulations(self):
        """Return modulations relative to equilibrium supercell

        (modulations, supercell)

        modulations: Atomic modulations of supercell in Cartesian coordinates
        supercell: Supercell as an Atoms object.
        
        """
        return self._modulation.get_delta_modulations()

    def write_modulations(self):
        """Create MPOSCAR's"""
        self._modulation.write()

    def write_yaml_modulations(self):
        self._modulation.write_yaml()

    def set_irreps(self,
                   q,
                   is_little_cogroup=False,
                   nac_q_direction=None,
                   degeneracy_tolerance=1e-4):
        self._set_dynamical_matrix()
        self._irreps = IrReps(self._dynamical_matrix,
                              q,
                              is_little_cogroup=is_little_cogroup,
                              nac_q_direction=nac_q_direction,
                              factor=self._factor,
                              symprec=self._symprec,
                              degeneracy_tolerance=degeneracy_tolerance,
                              log_level=self._log_level)

        return self._irreps.run()

    def get_irreps(self):
        return self._irreps

    def show_irreps(self, show_irreps=False):
        self._irreps.show(show_irreps=show_irreps)

    def write_yaml_irreps(self, show_irreps=False):
        self._irreps.write_yaml(show_irreps=show_irreps)

    def set_group_velocity(self, q_length=None):
        self._set_dynamical_matrix()
        self._group_velocity = GroupVelocity(
            self._dynamical_matrix,
            q_length=q_length,
            symmetry=self._primitive_symmetry,
            frequency_factor_to_THz=self._factor)

    def get_group_velocity(self):
        return self._group_velocity.get_group_velocity()

    def get_group_velocity_at_q(self, q_point):
        if self._group_velocity is None:
            self.set_group_velocity()
        self._group_velocity.set_q_points([q_point])
        return self._group_velocity.get_group_velocity()[0]

    def _run_force_constants_from_forces(self,
                                         distributed_atom_list=None,
                                         decimals=None,
                                         computation_algorithm="svd"):
        if self._displacement_dataset is not None:
            self._force_constants = get_fc2(
                self._supercell,
                self._symmetry,
                self._displacement_dataset,
                atom_list=distributed_atom_list,
                decimals=decimals,
                computation_algorithm=computation_algorithm)

    def _set_dynamical_matrix(self):
        if self._nac_params is None:
            self._dynamical_matrix = DynamicalMatrix(
                self._supercell,
                self._primitive,
                self._force_constants,
                decimals=self._dynamical_matrix_decimals,
                symprec=self._symprec)
        else:
            self._dynamical_matrix = DynamicalMatrixNAC(
                self._supercell,
                self._primitive,
                self._force_constants,
                nac_params=self._nac_params,
                decimals=self._dynamical_matrix_decimals,
                symprec=self._symprec)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell, self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive, self._symprec,
                                            self._is_symmetry)

        if (len(self._symmetry.get_pointgroup_operations()) != len(
                self._primitive_symmetry.get_pointgroup_operations())):
            print(
                "Warning: point group symmetries of supercell and primitive"
                "cell are different.")

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell, self._supercell_matrix,
                                        self._symprec)

    def _build_supercells_with_displacements(self):
        supercells = []
        for disp in self._displacement_dataset['first_atoms']:
            positions = self._supercell.get_positions()
            positions[disp['number']] += disp['displacement']
            supercells.append(
                Atoms(numbers=self._supercell.get_atomic_numbers(),
                      masses=self._supercell.get_masses(),
                      magmoms=self._supercell.get_magnetic_moments(),
                      positions=positions,
                      cell=self._supercell.get_cell(),
                      pbc=True))

        self._supercells_with_displacements = supercells

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """

        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        if self._primitive_matrix is None:
            trans_mat = inv_supercell_matrix
        else:
            trans_mat = np.dot(inv_supercell_matrix, self._primitive_matrix)
        self._primitive = get_primitive(self._supercell, trans_mat,
                                        self._symprec)
        num_satom = self._supercell.get_number_of_atoms()
        num_patom = self._primitive.get_number_of_atoms()
        if abs(num_satom * np.linalg.det(trans_mat) - num_patom) < 0.1:
            return True
        else:
            return False
コード例 #27
0
def get_born_OUTCAR(poscar_filename="POSCAR",
                    outcar_filename="OUTCAR",
                    primitive_axis=np.eye(3),
                    is_symmetry=True,
                    symmetrize_tensors=False):
    cell = read_vasp(poscar_filename)
    primitive = Primitive(cell, primitive_axis)
    p2p = primitive.get_primitive_to_primitive_map()
    symmetry = Symmetry(primitive, is_symmetry=is_symmetry)
    independent_atoms = symmetry.get_independent_atoms()
    prim_lat = primitive.get_cell().T
    outcar = open(outcar_filename)

    borns = []
    while True:
        line = outcar.readline()
        if not line:
            break

        if "NIONS" in line:
            num_atom = int(line.split()[11])

        if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line:
            epsilon = []
            outcar.readline()
            epsilon.append([float(x) for x in outcar.readline().split()])
            epsilon.append([float(x) for x in outcar.readline().split()])
            epsilon.append([float(x) for x in outcar.readline().split()])

        if "BORN" in line:
            outcar.readline()
            line = outcar.readline()
            if "ion" in line:
                for i in range(num_atom):
                    born = []
                    born.append([float(x)
                                 for x in outcar.readline().split()][1:])
                    born.append([float(x)
                                 for x in outcar.readline().split()][1:])
                    born.append([float(x)
                                 for x in outcar.readline().split()][1:])
                    outcar.readline()
                    borns.append(born)

    reduced_borns = []
    for p_i, u_i in enumerate(p2p):
        if p_i in independent_atoms:
            if symmetrize_tensors:
                site_sym = [
                    similarity_transformation(prim_lat, rot)
                    for rot in symmetry.get_site_symmetry(p_i)
                ]
                reduced_borns.append(symmetrize_tensor(borns[u_i], site_sym))
            else:
                reduced_borns.append(borns[u_i])

    if symmetrize_tensors:
        point_sym = [
            similarity_transformation(prim_lat, rot)
            for rot in symmetry.get_pointgroup_operations()
        ]
        epsilon = symmetrize_tensor(epsilon, point_sym)
    else:
        epsilon = np.array(epsilon)

    return np.array(reduced_borns), epsilon
コード例 #28
0
ファイル: __init__.py プロジェクト: georgeyumnam/phonopy
class Phono3py:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 phonon_supercell_matrix=None,
                 masses=None,
                 mesh=None,
                 band_indices=None,
                 sigmas=None,
                 cutoff_frequency=1e-4,
                 frequency_factor_to_THz=VaspToTHz,
                 is_symmetry=True,
                 is_nosym=False,
                 symmetrize_fc3_q=False,
                 symprec=1e-5,
                 log_level=0,
                 lapack_zheev_uplo='L'):
        if sigmas is None:
            sigmas = []
        self._symprec = symprec
        self._sigmas = sigmas
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_symmetry = is_symmetry
        self._is_nosym = is_nosym
        self._lapack_zheev_uplo =  lapack_zheev_uplo
        self._symmetrize_fc3_q = symmetrize_fc3_q
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._phonon_supercell_matrix = phonon_supercell_matrix # optional
        self._supercell = None
        self._primitive = None
        self._phonon_supercell = None
        self._phonon_primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_phonon_supercell()
        self._build_phonon_primitive_cell()

        if masses is not None:
            self._set_masses(masses)

        # Set supercell, primitive, and phonon supercell symmetries
        self._symmetry = None
        self._primitive_symmetry = None
        self._phonon_supercell_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_phonon_supercell_symmetry()

        # Displacements and supercells
        self._supercells_with_displacements = None
        self._displacement_dataset = None
        self._phonon_displacement_dataset = None
        self._phonon_supercells_with_displacements = None
                
        # Thermal conductivity
        self._thermal_conductivity = None # conductivity_RTA object

        # Imaginary part of self energy at frequency points
        self._imag_self_energy = None
        self._scattering_event_class = None

        # Linewidth (Imaginary part of self energy x 2) at temperatures
        self._linewidth = None

        self._grid_points = None
        self._frequency_points = None
        self._temperatures = None

        # Other variables
        self._fc2 = None
        self._fc3 = None
        
        # Setup interaction
        self._interaction = None
        self._mesh = None
        self._band_indices = None
        self._band_indices_flatten = None
        if mesh is not None:
            self._mesh = np.array(mesh, dtype='intc')
        self.set_band_indices(band_indices)

    def set_band_indices(self, band_indices):
        if band_indices is None:
            num_band = self._primitive.get_number_of_atoms() * 3
            self._band_indices = [np.arange(num_band, dtype='intc')]
        else:
            self._band_indices = band_indices
        self._band_indices_flatten = np.hstack(self._band_indices).astype('intc')

    def set_phph_interaction(self,
                             nac_params=None,
                             nac_q_direction=None,
                             constant_averaged_interaction=None,
                             frequency_scale_factor=None,
                             unit_conversion=None):
        self._interaction = Interaction(
            self._supercell,
            self._primitive,
            self._mesh,
            self._primitive_symmetry,
            fc3=self._fc3,
            band_indices=self._band_indices_flatten,
            constant_averaged_interaction=constant_averaged_interaction,
            frequency_factor_to_THz=self._frequency_factor_to_THz,
            unit_conversion=unit_conversion,
            cutoff_frequency=self._cutoff_frequency,
            is_nosym=self._is_nosym,
            symmetrize_fc3_q=self._symmetrize_fc3_q,
            lapack_zheev_uplo=self._lapack_zheev_uplo)
        self._interaction.set_dynamical_matrix(
            self._fc2,
            self._phonon_supercell,
            self._phonon_primitive,
            nac_params=nac_params,
            frequency_scale_factor=frequency_scale_factor)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)

    def generate_displacements(self,
                               distance=0.03,
                               cutoff_pair_distance=None,
                               is_plusminus='auto',
                               is_diagonal=True):
        direction_dataset = get_third_order_displacements(
            self._supercell,
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal)
        self._displacement_dataset = direction_to_displacement(
            direction_dataset,
            distance,
            self._supercell,
            cutoff_distance=cutoff_pair_distance)

        if self._phonon_supercell_matrix is not None:
            phonon_displacement_directions = get_least_displacements(
                self._phonon_supercell_symmetry,
                is_plusminus=is_plusminus,
                is_diagonal=False)
            self._phonon_displacement_dataset = direction_to_displacement_fc2(
                phonon_displacement_directions,
                distance,
                self._phonon_supercell)
            
    def produce_fc2(self,
                    forces_fc2,
                    displacement_dataset=None,
                    is_permutation_symmetry=False,
                    translational_symmetry_type=0):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset
            
        for forces, disp1 in zip(forces_fc2, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        self._fc2 = get_fc2(self._phonon_supercell,
                            self._phonon_supercell_symmetry,
                            disp_dataset)
        if is_permutation_symmetry:
            set_permutation_symmetry(self._fc2)
        if translational_symmetry_type:
            set_translational_invariance(
                self._fc2,
                translational_symmetry_type=translational_symmetry_type)

    def produce_fc3(self,
                    forces_fc3,
                    displacement_dataset=None,
                    cutoff_distance=None, # set fc3 zero
                    translational_symmetry_type=0,
                    is_permutation_symmetry=False,
                    is_permutation_symmetry_fc2=False):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset
        
        for forces, disp1 in zip(forces_fc3, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        fc2 = get_fc2(self._supercell, self._symmetry, disp_dataset)
        if is_permutation_symmetry_fc2:
            set_permutation_symmetry(fc2)
        if translational_symmetry_type:
            set_translational_invariance(
                fc2,
                translational_symmetry_type=translational_symmetry_type)
        
        count = len(disp_dataset['first_atoms'])
        for disp1 in disp_dataset['first_atoms']:
            for disp2 in disp1['second_atoms']:
                disp2['delta_forces'] = forces_fc3[count] - disp1['forces']
                count += 1
        self._fc3 = get_fc3(
            self._supercell,
            disp_dataset,
            fc2,
            self._symmetry,
            translational_symmetry_type=translational_symmetry_type,
            is_permutation_symmetry=is_permutation_symmetry,
            verbose=self._log_level)

        # Set fc3 elements zero beyond cutoff_distance
        if cutoff_distance:
            if self._log_level:
                print("Cutting-off fc3 by zero (cut-off distance: %f)" %
                      cutoff_distance)
            self.cutoff_fc3_by_zero(cutoff_distance)

        # Set fc2
        if self._fc2 is None:
            self._fc2 = fc2

    def cutoff_fc3_by_zero(self, cutoff_distance):
        cutoff_fc3_by_zero(self._fc3,
                           self._supercell,
                           cutoff_distance,
                           self._symprec)
            
    def set_permutation_symmetry(self):
        if self._fc2 is not None:
            set_permutation_symmetry(self._fc2)
        if self._fc3 is not None:
            set_permutation_symmetry_fc3(self._fc3)

    def set_translational_invariance(self,
                                     translational_symmetry_type=1):
        if self._fc2 is not None:
            set_translational_invariance(
                self._fc2,
                translational_symmetry_type=translational_symmetry_type)
        if self._fc3 is not None:
            set_translational_invariance_fc3(
                self._fc3,
                translational_symmetry_type=translational_symmetry_type)
        
    def get_interaction_strength(self):
        return self._interaction
        
    def get_fc2(self):
        return self._fc2

    def set_fc2(self, fc2):
        self._fc2 = fc2

    def get_fc3(self):
        return self._fc3

    def set_fc3(self, fc3):
        self._fc3 = fc3

    def get_primitive(self):
        return self._primitive

    def get_unitcell(self):
        return self._unitcell

    def get_supercell(self):
        return self._supercell

    def get_phonon_supercell(self):
        return self._phonon_supercell

    def get_phonon_primitive(self):
        return self._phonon_primitive

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_primitive_symmetry(self):
        return self._primitive_symmetry

    def get_phonon_supercell_symmetry(self):
        return self._phonon_supercell_symmetry
        
    def set_displacement_dataset(self, dataset):
        self._displacement_dataset = dataset
        
    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_phonon_displacement_dataset(self):
        return self._phonon_displacement_dataset

    def get_supercells_with_displacements(self):
        if self._supercells_with_displacements is None:
            self._build_supercells_with_displacements()
        return self._supercells_with_displacements

    def get_phonon_supercells_with_displacements(self):
        if self._phonon_supercells_with_displacements is None:
            if self._phonon_displacement_dataset is not None:
                self._phonon_supercells_with_displacements = \
                  self._build_phonon_supercells_with_displacements(
                      self._phonon_supercell,
                      self._phonon_displacement_dataset)
        return self._phonon_supercells_with_displacements
        
    def run_imag_self_energy(self,
                             grid_points,
                             frequency_step=None,
                             num_frequency_points=None,
                             temperatures=None,
                             scattering_event_class=None,
                             run_with_g=True,
                             write_details=False):
        if temperatures is None:
            temperatures = [0.0, 300.0]
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._scattering_event_class = scattering_event_class
        self._imag_self_energy, self._frequency_points = get_imag_self_energy(
            self._interaction,
            grid_points,
            self._sigmas,
            frequency_step=frequency_step,
            num_frequency_points=num_frequency_points,
            temperatures=temperatures,
            scattering_event_class=scattering_event_class,
            run_with_g=run_with_g,
            write_details=write_details,
            log_level=self._log_level)
            
    def write_imag_self_energy(self, filename=None):
        write_imag_self_energy(
            self._imag_self_energy,
            self._mesh,
            self._grid_points,
            self._band_indices,
            self._frequency_points,
            self._temperatures,
            self._sigmas,
            scattering_event_class=self._scattering_event_class,
            filename=filename)
        
    def run_linewidth(self,
                      grid_points,
                      temperatures=np.arange(0, 1001, 10, dtype='double'),
                      run_with_g=True,
                      write_details=False):
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._linewidth = get_linewidth(self._interaction,
                                        grid_points,
                                        self._sigmas,
                                        temperatures=temperatures,
                                        run_with_g=run_with_g,
                                        write_details=write_details,
                                        log_level=self._log_level)

    def write_linewidth(self, filename=None):
        write_linewidth(self._linewidth,
                        self._band_indices,
                        self._mesh,
                        self._grid_points,
                        self._sigmas,
                        self._temperatures,
                        filename=filename)

    def run_thermal_conductivity(
            self,
            is_LBTE=True,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            sigmas=None,
            is_isotope=False,
            mass_variances=None,
            grid_points=None,
            boundary_mfp=None, # in micrometre
            use_averaged_pp_interaction=False,
            gamma_unit_conversion=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            is_reducible_collision_matrix=False,
            no_kappa_stars=False,
            gv_delta_q=None, # for group velocity
            run_with_g=True, # integration weights for smearing method, too
            pinv_cutoff=1.0e-8, # for pseudo-inversion of collision matrix
            write_gamma=False,
            read_gamma=False,
            write_collision=False,
            read_collision=False,
            write_amplitude=False,
            read_amplitude=False,
            input_filename=None,
            output_filename=None):

        if sigmas is None:
            sigmas = []
        if is_LBTE:
            self._thermal_conductivity = get_thermal_conductivity_LBTE(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                is_reducible_collision_matrix=is_reducible_collision_matrix,
                no_kappa_stars=no_kappa_stars,
                gv_delta_q=gv_delta_q,
                pinv_cutoff=pinv_cutoff,
                write_collision=write_collision,
                read_collision=read_collision,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)
        else:
            self._thermal_conductivity = get_thermal_conductivity_RTA(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                use_averaged_pp_interaction=use_averaged_pp_interaction,
                gamma_unit_conversion=gamma_unit_conversion,
                mesh_divisors=mesh_divisors,
                coarse_mesh_shifts=coarse_mesh_shifts,
                no_kappa_stars=no_kappa_stars,
                gv_delta_q=gv_delta_q,
                run_with_g=run_with_g,
                write_gamma=write_gamma,
                read_gamma=read_gamma,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)

    def get_thermal_conductivity(self):
        return self._thermal_conductivity

    def get_frequency_shift(self,
                            grid_points,
                            epsilons=None,
                            temperatures=np.arange(0, 1001, 10, dtype='double'),
                            output_filename=None):
        if epsilons is None:
            epsilons = [0.1]
        self._grid_points = grid_points
        get_frequency_shift(self._interaction,
                            self._grid_points,
                            self._band_indices,
                            epsilons,
                            temperatures,
                            output_filename=output_filename,
                            log_level=self._log_level)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print("Warning: point group symmetries of supercell and primitive"
                  "cell are different.")
        
    def _search_phonon_supercell_symmetry(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell_symmetry = self._symmetry
        else:
            self._phonon_supercell_symmetry = Symmetry(self._phonon_supercell,
                                                       self._symprec,
                                                       self._is_symmetry)

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """
        self._primitive = self._get_primitive_cell(
            self._supercell, self._supercell_matrix, self._primitive_matrix)

    def _build_phonon_supercell(self):
        """
        phonon_supercell:
          This supercell is used for harmonic phonons (frequencies,
          eigenvectors, group velocities, ...)
        phonon_supercell_matrix:
          Different supercell size can be specified.
        """
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell = self._supercell
        else:
            self._phonon_supercell = get_supercell(
                self._unitcell, self._phonon_supercell_matrix, self._symprec)

    def _build_phonon_primitive_cell(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_primitive = self._primitive
        else:
            self._phonon_primitive = self._get_primitive_cell(
                self._phonon_supercell,
                self._phonon_supercell_matrix,
                self._primitive_matrix)
            if self._primitive is not None:
                if (self._primitive.get_atomic_numbers() !=
                    self._phonon_primitive.get_atomic_numbers()).any():
                    print("********************* Warning *********************")
                    print(" Primitive cells for fc2 and fc3 can be different.")
                    print("********************* Warning *********************")


    def _build_phonon_supercells_with_displacements(self,
                                                    supercell,
                                                    displacement_dataset):
        supercells = []
        magmoms = supercell.get_magnetic_moments()
        masses = supercell.get_masses()
        numbers = supercell.get_atomic_numbers()
        lattice = supercell.get_cell()
        
        for disp1 in displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            positions = supercell.get_positions()
            positions[disp1['number']] += disp_cart1
            supercells.append(
                Atoms(numbers=numbers,
                      masses=masses,
                      magmoms=magmoms,
                      positions=positions,
                      cell=lattice,
                      pbc=True))

        return supercells
            
    def _build_supercells_with_displacements(self):
        supercells = []
        magmoms = self._supercell.get_magnetic_moments()
        masses = self._supercell.get_masses()
        numbers = self._supercell.get_atomic_numbers()
        lattice = self._supercell.get_cell()
        
        supercells = self._build_phonon_supercells_with_displacements(
            self._supercell,
            self._displacement_dataset)
        
        for disp1 in self._displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            for disp2 in disp1['second_atoms']:
                if 'included' in disp2:
                    included = disp2['included']
                else:
                    included = True
                if included:
                    positions = self._supercell.get_positions()
                    positions[disp1['number']] += disp_cart1
                    positions[disp2['number']] += disp2['displacement']
                    supercells.append(Atoms(numbers=numbers,
                                            masses=masses,
                                            magmoms=magmoms,
                                            positions=positions,
                                            cell=lattice,
                                            pbc=True))
                else:
                    supercells.append(None)

        self._supercells_with_displacements = supercells
            
    def _get_primitive_cell(self, supercell, supercell_matrix, primitive_matrix):
        inv_supercell_matrix = np.linalg.inv(supercell_matrix)
        if primitive_matrix is None:
            t_mat = inv_supercell_matrix
        else:
            t_mat = np.dot(inv_supercell_matrix, primitive_matrix)
            
        return get_primitive(supercell, t_mat, self._symprec)

    def _set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[p2p_map[x] for x in
                             self._primitive.get_supercell_to_primitive_map()]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)

        self._phonon_primitive.set_masses(p_masses)
        p2p_map = self._phonon_primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[
            [p2p_map[x] for x in
             self._phonon_primitive.get_supercell_to_primitive_map()]]
        self._phonon_supercell.set_masses(s_masses)
コード例 #29
0
ファイル: api_unfolding.py プロジェクト: syllzp/upho
class PhonopyUnfolding(Phonopy):
    """

    unitcell: before symmetrization
    """
    def __init__(self,
                 unitcell,
                 unitcell_ideal,
                 supercell_matrix,
                 primitive_matrix_ideal,
                 nac_params=None,
                 distance=0.01,
                 factor=VaspToTHz,
                 is_auto_displacements=True,
                 dynamical_matrix_decimals=None,
                 force_constants_decimals=None,
                 star="none",
                 mode="eigenvector",
                 symprec=1e-5,
                 is_symmetry=True,
                 use_lapack_solver=False,
                 log_level=0):
        self._symprec = symprec
        self._distance = distance
        self._factor = factor
        self._is_auto_displacements = is_auto_displacements
        self._is_symmetry = is_symmetry
        self._use_lapack_solver = use_lapack_solver
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._unitcell_ideal = unitcell_ideal
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = None
        if type(primitive_matrix_ideal) is str and primitive_matrix_ideal == 'auto':
            self._primitive_matrix_ideal = self._guess_primitive_matrix()
        elif primitive_matrix is not None:
            self._primitive_matrix_ideal = np.array(primitive_matrix_ideal,
                                              dtype='double', order='c')
        else:
            self._primitive_matrix = None
        self._supercell = None
        self._primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_supercell_ideal()
        self._build_primitive_cell_ideal()

        # Set supercell and primitive symmetry
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_symmetry_ideal()
        self._search_primitive_symmetry_ideal()

        # set_force_constants or set_forces
        self._force_constants = None
        self._force_constants_decimals = force_constants_decimals

        # set_dynamical_matrix
        self._dynamical_matrix = None
        self._nac_params = nac_params
        self._dynamical_matrix_decimals = dynamical_matrix_decimals

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = None

        # set_tetrahedron_method
        self._tetrahedron_method = None

        # set_thermal_properties
        self._thermal_properties = None

        # set_thermal_displacements
        self._thermal_displacements = None

        # set_thermal_displacement_matrices
        self._thermal_displacement_matrices = None

        # set_partial_DOS
        self._pdos = None

        # set_total_DOS
        self._total_dos = None

        # set_modulation
        self._modulation = None

        # set_character_table
        self._irreps = None

        # set_group_velocity
        self._group_velocity = None

        self._star = star
        self._mode = mode

    # Single point
    def run_single_point(self, qpoint, distance):
        SinglePoint(
            qpoint,
            distance,
            dynamical_matrix=self._dynamical_matrix,
            unitcell_ideal=self._unitcell_ideal,
            primitive_matrix_ideal=self._primitive_matrix_ideal,
            factor=self._factor,
            star=self._star,
            mode=self._mode,
            verbose=True)

    # Band structure
    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._band_structure = None
            return False

        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            self._unitcell_ideal,
            self._primitive_matrix_ideal,
            is_eigenvectors=is_eigenvectors,
            is_band_connection=is_band_connection,
            group_velocity=self._group_velocity,
            factor=self._factor,
            star=self._star,
            mode=self._mode,
            verbose=True)
        return True

    # Sampling mesh
    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_mesh_symmetry=True,
                 is_eigenvectors=False,
                 is_gamma_center=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._mesh = None
            return False

        # TODO(ikeda): Check how "rotations" works.
        self._mesh = MeshUnfolding(
            self._dynamical_matrix,
            self._unitcell_ideal,
            self._primitive_matrix_ideal,
            mesh,
            shift=shift,
            is_time_reversal=is_time_reversal,
            is_mesh_symmetry=is_mesh_symmetry,
            is_eigenvectors=is_eigenvectors,
            is_gamma_center=is_gamma_center,
            star=self._star,
            group_velocity=self._group_velocity,
            rotations=self._primitive_symmetry.get_pointgroup_operations(),
            factor=self._factor,
            use_lapack_solver=self._use_lapack_solver,
            mode=self._mode)
        return True

    # DOS
    def set_total_DOS(self,
                      sigma=None,
                      freq_min=None,
                      freq_max=None,
                      freq_pitch=None,
                      tetrahedron_method=False):

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before DOS calculation.")
            self._total_dos = None
            return False

        total_dos = TotalDosUnfolding(
            self._mesh,
            sigma=sigma,
            tetrahedron_method=tetrahedron_method)
        total_dos.set_draw_area(freq_min, freq_max, freq_pitch)
        total_dos.run()
        self._total_dos = total_dos
        return True

    def _set_dynamical_matrix(self):
        self._dynamical_matrix = None

        if self._supercell is None or self._primitive is None:
            print("Bug: Supercell or primitive is not created.")
            return False
        elif self._force_constants is None:
            print("Warning: Force constants are not prepared.")
            return False
        elif self._primitive.get_masses() is None:
            print("Warning: Atomic masses are not correctly set.")
            return False
        else:
            if self._nac_params is None:
                self._dynamical_matrix = DynamicalMatrix(
                    self._supercell,
                    self._primitive,
                    self._force_constants,
                    decimals=self._dynamical_matrix_decimals)
            else:
                raise ValueError(
                    'Currently NAC is not available for unfolding.')
            return True

    def _search_symmetry_ideal(self):
        self._symmetry = Symmetry(self._supercell_ideal,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry_ideal(self):
        self._primitive_symmetry = Symmetry(self._primitive_ideal,
                                            self._symprec,
                                            self._is_symmetry)

        n0 = len(self._symmetry.get_pointgroup_operations())
        n1 = len(self._primitive_symmetry.get_pointgroup_operations())
        if n0 != n1:
            raise Warning("Point group symmetries of supercell and primitive"
                          "cell are different.")

    def _build_supercell_ideal(self):
        self._supercell_ideal = get_supercell(
            self._unitcell_ideal,
            self._supercell_matrix,
            self._symprec)

    def _build_primitive_cell_ideal(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """

        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        if self._primitive_matrix_ideal is None:
            trans_mat = inv_supercell_matrix
        else:
            trans_mat = np.dot(inv_supercell_matrix, self._primitive_matrix_ideal)
        self._primitive_ideal = get_primitive(
            self._supercell_ideal, trans_mat, self._symprec)
        num_satom = self._supercell_ideal.get_number_of_atoms()
        num_patom = self._primitive_ideal.get_number_of_atoms()
        if abs(num_satom * np.linalg.det(trans_mat) - num_patom) < 0.1:
            return True
        else:
            return False

    def average_masses(self):

        masses = self._unitcell.get_masses()
        masses_average = calculate_average_masses(
            masses, Symmetry(self._unitcell_ideal))
        self._unitcell.set_masses(masses_average)

        self._build_supercell()
        self._build_primitive_cell()

        self._search_symmetry()
        self._search_primitive_symmetry()

    def _guess_primitive_matrix(self):
        return guess_primitive_matrix(self._unitcell_ideal, symprec=self._symprec)

    def average_force_constants(self):
        fc_symmetrizer_spg = FCSymmetrizerSPG(
            force_constants=self._force_constants,
            atoms=self._unitcell,
            atoms_ideal=self._unitcell_ideal,
            supercell_matrix=self._supercell_matrix,
        )
        fc_symmetrizer_spg.average_force_constants_spg()
        fc_symmetrizer_spg.write_force_constants_symmetrized()
        fc_average = fc_symmetrizer_spg.get_force_constants_symmetrized()
        self.set_force_constants(fc_average)  # Dynamical matrices are also prepared inside.
コード例 #30
0
ファイル: vasp.py プロジェクト: arbegla/phonopy
def get_born_OUTCAR(poscar_filename="POSCAR",
                    outcar_filename="OUTCAR",
                    primitive_axis=np.eye(3),
                    supercell_matrix=np.eye(3, dtype='intc'),
                    is_symmetry=True,
                    symmetrize_tensors=False):
    ucell = read_vasp(poscar_filename)
    scell = get_supercell(ucell, supercell_matrix)
    inv_smat = np.linalg.inv(supercell_matrix)
    pcell = get_primitive(scell, np.dot(inv_smat, primitive_axis))
    u_sym = Symmetry(ucell, is_symmetry=is_symmetry)
    p_sym = Symmetry(pcell, is_symmetry=is_symmetry)
    lattice = ucell.get_cell().T
    outcar = open(outcar_filename)
    
    borns = []
    while True:
        line = outcar.readline()
        if not line:
            break
    
        if "NIONS" in line:
            num_atom = int(line.split()[11])
    
        if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line:
            epsilon = []
            outcar.readline()
            epsilon.append([float(x) for x in outcar.readline().split()])
            epsilon.append([float(x) for x in outcar.readline().split()])
            epsilon.append([float(x) for x in outcar.readline().split()])
    
        if "BORN" in line:
            outcar.readline()
            line = outcar.readline()
            if "ion" in line:
                for i in range(num_atom):
                    born = []
                    born.append([float(x)
                                 for x in outcar.readline().split()][1:])
                    born.append([float(x)
                                 for x in outcar.readline().split()][1:])
                    born.append([float(x)
                                 for x in outcar.readline().split()][1:])
                    outcar.readline()
                    borns.append(born)

    borns = np.array(borns, dtype='double')
    epsilon = np.array(epsilon, dtype='double')
    if symmetrize_tensors:
        borns_orig = borns.copy()
        point_sym = [similarity_transformation(lattice, r)
                     for r in u_sym.get_pointgroup_operations()]
        epsilon = symmetrize_tensor(epsilon, point_sym)
        for i in range(num_atom):
            z = borns[i]
            site_sym = [similarity_transformation(lattice, r)
                        for r in u_sym.get_site_symmetry(i)]
            borns[i] = symmetrize_tensor(z, site_sym)

        rotations = u_sym.get_symmetry_operations()['rotations']
        map_atoms = u_sym.get_map_atoms()
        borns_copy = np.zeros_like(borns)
        for i, m_i in enumerate(map_atoms):
            count = 0
            for j, r_j in enumerate(u_sym.get_map_operations()):
                if map_atoms[j] == m_i:
                    count += 1
                    r_cart = similarity_transformation(lattice, rotations[r_j])
                    borns_copy[i] += similarity_transformation(r_cart, borns[j])
            borns_copy[i] /= count

        borns = borns_copy
        sum_born = borns.sum(axis=0) / len(borns)
        borns -= sum_born

        if (np.abs(borns_orig - borns) > 0.1).any():
            sys.stderr.write(
                "Born effective charge symmetrization might go wrong.\n")
        
    p2s = np.array(pcell.get_primitive_to_supercell_map(), dtype='intc')
    s_indep_atoms = p2s[p_sym.get_independent_atoms()]
    u2u = scell.get_unitcell_to_unitcell_map()
    u_indep_atoms = [u2u[x] for x in s_indep_atoms]
    reduced_borns = borns[u_indep_atoms].copy()

    return reduced_borns, epsilon
コード例 #31
0
class Phonopy(object):
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 nac_params=None,
                 distance=None,
                 factor=VaspToTHz,
                 is_auto_displacements=None,
                 dynamical_matrix_decimals=None,
                 force_constants_decimals=None,
                 symprec=1e-5,
                 is_symmetry=True,
                 use_lapack_solver=False,
                 log_level=0):

        if is_auto_displacements is not None:
            print("Warning: \'is_auto_displacements\' argument is obsolete.")
            if is_auto_displacements is False:
                print("Sets of displacements are not created as default.")
            else:
                print("Use \'generate_displacements\' method explicitly to "
                      "create sets of displacements.")

        if distance is not None:
            print("Warning: \'distance\' keyword argument is obsolete at "
                  "Phonopy instantiation.")
            print("Specify \'distance\' keyword argument when calling "
                  "\'generate_displacements\'")
            print("method (See the Phonopy API document).")

        self._symprec = symprec
        self._factor = factor
        self._is_symmetry = is_symmetry
        self._use_lapack_solver = use_lapack_solver
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = Atoms(atoms=unitcell)
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._supercell = None
        self._primitive = None
        self._build_supercell()
        self._build_primitive_cell()

        # Set supercell and primitive symmetry
        self._symmetry = None
        self._primitive_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()

        # set_displacements (used only in preprocess)
        self._displacement_dataset = None
        self._displacements = None
        self._displacement_directions = None
        self._supercells_with_displacements = None

        # set_force_constants or set_forces
        self._force_constants = None
        self._force_constants_decimals = force_constants_decimals

        # set_dynamical_matrix
        self._dynamical_matrix = None
        self._nac_params = nac_params
        self._dynamical_matrix_decimals = dynamical_matrix_decimals

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = None

        # set_tetrahedron_method
        self._tetrahedron_method = None

        # set_thermal_properties
        self._thermal_properties = None

        # set_thermal_displacements
        self._thermal_displacements = None

        # set_thermal_displacement_matrices
        self._thermal_displacement_matrices = None

        # set_partial_DOS
        self._pdos = None

        # set_total_DOS
        self._total_dos = None

        # set_modulation
        self._modulation = None

        # set_character_table
        self._irreps = None

        # set_group_velocity
        self._group_velocity = None

    def get_version(self):
        return __version__

    def get_primitive(self):
        return self._primitive
    primitive = property(get_primitive)

    def get_unitcell(self):
        return self._unitcell
    unitcell = property(get_unitcell)

    def get_supercell(self):
        return self._supercell
    supercell = property(get_supercell)

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry
    symmetry = property(get_symmetry)

    def get_primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self._primitive_symmetry

    def get_supercell_matrix(self):
        return self._supercell_matrix

    def get_primitive_matrix(self):
        return self._primitive_matrix

    def get_unit_conversion_factor(self):
        return self._factor
    unit_conversion_factor = property(get_unit_conversion_factor)

    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_displacements(self):
        return self._displacements
    displacements = property(get_displacements)

    def get_displacement_directions(self):
        return self._displacement_directions
    displacement_directions = property(get_displacement_directions)

    def get_supercells_with_displacements(self):
        if self._displacement_dataset is None:
            return None
        else:
            self._build_supercells_with_displacements()
            return self._supercells_with_displacements

    def get_force_constants(self):
        return self._force_constants
    force_constants = property(get_force_constants)

    def get_rotational_condition_of_fc(self):
        return rotational_invariance(self._force_constants,
                                     self._supercell,
                                     self._primitive,
                                     self._symprec)

    def get_nac_params(self):
        return self._nac_params

    def get_dynamical_matrix(self):
        return self._dynamical_matrix
    dynamical_matrix = property(get_dynamical_matrix)

    def set_unitcell(self, unitcell):
        self._unitcell = unitcell
        self._build_supercell()
        self._build_primitive_cell()
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._displacement_dataset = None

    def set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[p2p_map[x] for x in
                             self._primitive.get_supercell_to_primitive_map()]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)
        self._set_dynamical_matrix()

    def set_nac_params(self, nac_params=None):
        self._nac_params = nac_params
        self._set_dynamical_matrix()

    def set_displacement_dataset(self, displacement_dataset):
        """
        displacement_dataset:
           {'natom': number_of_atoms_in_supercell,
            'first_atoms': [
              {'number': atom index of displaced atom,
               'displacement': displacement in Cartesian coordinates,
               'direction': displacement direction with respect to axes
               'forces': forces on atoms in supercell},
              {...}, ...]}
        """
        self._displacement_dataset = displacement_dataset

        self._displacements = []
        self._displacement_directions = []
        for disp in self._displacement_dataset['first_atoms']:
            x = disp['displacement']
            self._displacements.append([disp['number'], x[0], x[1], x[2]])
            if 'direction' in disp:
                y = disp['direction']
                self._displacement_directions.append(
                    [disp['number'], y[0], y[1], y[2]])
        if not self._displacement_directions:
            self._displacement_directions = None

    def set_forces(self, sets_of_forces):
        """
        sets_of_forces:
           [[[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # first supercell
             [[f_1x, f_1y, f_1z], [f_2x, f_2y, f_2z], ...], # second supercell
             ...                                                  ]
        """
        for disp, forces in zip(
                self._displacement_dataset['first_atoms'], sets_of_forces):
            disp['forces'] = forces

    def set_force_constants(self, force_constants):
        self._force_constants = force_constants
        self._set_dynamical_matrix()

    def set_force_constants_zero_with_radius(self, cutoff_radius):
        cutoff_force_constants(self._force_constants,
                               self._supercell,
                               cutoff_radius,
                               symprec=self._symprec)
        self._set_dynamical_matrix()

    def set_dynamical_matrix(self):
        self._set_dynamical_matrix()

    def generate_displacements(self,
                               distance=0.01,
                               is_plusminus='auto',
                               is_diagonal=True,
                               is_trigonal=False):
        """Generate displacements automatically

        displacemsts: List of displacements in Cartesian coordinates.
           [[0, 0.01, 0.00, 0.00], ...]
        where each set of elements is defined by:
           First value:      Atom index in supercell starting with 0
           Second to fourth: Displacement in Cartesian coordinates

        displacement_directions:
          List of directions with respect to axes. This gives only the
          symmetrically non equivalent directions. The format is like:
             [[0, 1, 0, 0],
              [7, 1, 0, 1], ...]
          where each list is defined by:
             First value:      Atom index in supercell starting with 0
             Second to fourth: If the direction is displaced or not ( 1, 0, or -1 )
                               with respect to the axes.

        """
        displacement_directions = get_least_displacements(
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal,
            is_trigonal=is_trigonal,
            log_level=self._log_level)
        displacement_dataset = direction_to_displacement(
            displacement_directions,
            distance,
            self._supercell)
        self.set_displacement_dataset(displacement_dataset)

    def produce_force_constants(self,
                                forces=None,
                                calculate_full_force_constants=True,
                                computation_algorithm="svd"):
        if forces is not None:
            self.set_forces(forces)

        # A primitive check if 'forces' key is in displacement_dataset.
        for disp in self._displacement_dataset['first_atoms']:
            if 'forces' not in disp:
                return False

        if calculate_full_force_constants:
            self._run_force_constants_from_forces(
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)
        else:
            p2s_map = self._primitive.get_primitive_to_supercell_map()
            self._run_force_constants_from_forces(
                distributed_atom_list=p2s_map,
                decimals=self._force_constants_decimals,
                computation_algorithm=computation_algorithm)

        self._set_dynamical_matrix()

        return True

    def symmetrize_force_constants(self, iteration=3):
        symmetrize_force_constants(self._force_constants, iteration)
        self._set_dynamical_matrix()

    def symmetrize_force_constants_by_space_group(self):
        from phonopy.harmonic.force_constants import (set_tensor_symmetry,
                                                      set_tensor_symmetry_PJ)
        set_tensor_symmetry_PJ(self._force_constants,
                               self._supercell.get_cell().T,
                               self._supercell.get_scaled_positions(),
                               self._symmetry)

        self._set_dynamical_matrix()

    #####################
    # Phonon properties #
    #####################

    # Single q-point
    def get_dynamical_matrix_at_q(self, q):
        self._set_dynamical_matrix()
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return None

        self._dynamical_matrix.set_dynamical_matrix(q)
        return self._dynamical_matrix.get_dynamical_matrix()


    def get_frequencies(self, q):
        """
        Calculate phonon frequencies at q

        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return None

        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        for eig in np.linalg.eigvalsh(dm).real:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor

    def get_frequencies_with_eigenvectors(self, q):
        """
        Calculate phonon frequencies and eigenvectors at q

        q: q-vector in reduced coordinates of primitive cell
        """
        self._set_dynamical_matrix()
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return None

        self._dynamical_matrix.set_dynamical_matrix(q)
        dm = self._dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        eigvals, eigenvectors = np.linalg.eigh(dm)
        frequencies = []
        for eig in eigvals:
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))

        return np.array(frequencies) * self._factor, eigenvectors

    # Band structure
    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._band_structure = None
            return False

        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            is_eigenvectors=is_eigenvectors,
            is_band_connection=is_band_connection,
            group_velocity=self._group_velocity,
            factor=self._factor)
        return True

    def get_band_structure(self):
        band = self._band_structure
        return (band.get_qpoints(),
                band.get_distances(),
                band.get_frequencies(),
                band.get_eigenvectors())

    def plot_band_structure(self, labels=None):
        import matplotlib.pyplot as plt
        if labels:
            from matplotlib import rc
            rc('text', usetex=True)

        self._band_structure.plot(plt, labels=labels)
        return plt

    def write_yaml_band_structure(self,
                                  labels=None,
                                  comment=None,
                                  filename="band.yaml"):
        self._band_structure.write_yaml(labels=labels,
                                        comment=comment,
                                        filename=filename)

    # Sampling mesh
    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_mesh_symmetry=True,
                 is_eigenvectors=False,
                 is_gamma_center=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._mesh = None
            return False

        self._mesh = Mesh(
            self._dynamical_matrix,
            mesh,
            shift=shift,
            is_time_reversal=is_time_reversal,
            is_mesh_symmetry=is_mesh_symmetry,
            is_eigenvectors=is_eigenvectors,
            is_gamma_center=is_gamma_center,
            group_velocity=self._group_velocity,
            rotations=self._primitive_symmetry.get_pointgroup_operations(),
            factor=self._factor,
            use_lapack_solver=self._use_lapack_solver)
        return True

    def get_mesh(self):
        if self._mesh is None:
            return None
        else:
            return (self._mesh.get_qpoints(),
                    self._mesh.get_weights(),
                    self._mesh.get_frequencies(),
                    self._mesh.get_eigenvectors())
    
    def get_mesh_grid_info(self):
        if self._mesh is None:
            return None
        else:
            return (self._mesh.get_grid_address(),
                    self._mesh.get_ir_grid_points(),
                    self._mesh.get_grid_mapping_table())

    def write_hdf5_mesh(self):
        self._mesh.write_hdf5()

    def write_yaml_mesh(self):
        self._mesh.write_yaml()

    # Plot band structure and DOS (PDOS) together
    def plot_band_structure_and_dos(self, pdos_indices=None, labels=None):
        import matplotlib.pyplot as plt
        import matplotlib.gridspec as gridspec
        if labels:
            from matplotlib import rc
            rc('text', usetex=True)

        plt.figure(figsize=(10, 6))
        gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
        ax1 = plt.subplot(gs[0, 0])
        self._band_structure.plot(plt, labels=labels)
        ax2 = plt.subplot(gs[0, 1], sharey=ax1)
        plt.subplots_adjust(wspace=0.03)
        plt.setp(ax2.get_yticklabels(), visible=False)

        if pdos_indices is None:
            self._total_dos.plot(plt,
                                 ylabel="",
                                 draw_grid=False,
                                 flip_xy=True)
        else:
            self._pdos.plot(plt,
                            indices=pdos_indices,
                            ylabel="",
                            draw_grid=False,
                            flip_xy=True)

        return plt

    # DOS
    def set_total_DOS(self,
                      sigma=None,
                      freq_min=None,
                      freq_max=None,
                      freq_pitch=None,
                      tetrahedron_method=False):

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before DOS calculation.")
            self._total_dos = None
            return False

        total_dos = TotalDos(self._mesh,
                             sigma=sigma,
                             tetrahedron_method=tetrahedron_method)
        total_dos.set_draw_area(freq_min, freq_max, freq_pitch)
        total_dos.run()
        self._total_dos = total_dos
        return True

    def get_total_DOS(self):
        """
        Retern frequencies and total dos.
        The first element is freqs and the second is total dos.

        frequencies: [freq1, freq2, ...]
        total_dos: [dos1, dos2, ...]
        """
        return self._total_dos.get_dos()

    def set_Debye_frequency(self, freq_max_fit=None):
        self._total_dos.set_Debye_frequency(
            self._primitive.get_number_of_atoms(),
            freq_max_fit=freq_max_fit)

    def get_Debye_frequency(self):
        return self._total_dos.get_Debye_frequency()

    def plot_total_DOS(self):
        import matplotlib.pyplot as plt
        self._total_dos.plot(plt)
        return plt

    def write_total_DOS(self):
        self._total_dos.write()

    # PDOS
    def set_partial_DOS(self,
                        sigma=None,
                        freq_min=None,
                        freq_max=None,
                        freq_pitch=None,
                        tetrahedron_method=False,
                        direction=None,
                        xyz_projection=False):
        self._pdos = None

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to be called before "
                  "PDOS calculation.")
            return False

        if self._mesh.get_eigenvectors() is None:
            print("Warning: Eigenvectors have to be calculated.")
            return False

        num_grid = np.prod(self._mesh.get_mesh_numbers())
        if num_grid != len(self._mesh.get_ir_grid_points()):
            print("Warning: \'set_mesh\' has to be called with "
                  "is_mesh_symmetry=False.")
            return False

        if direction is not None:
            direction_cart = np.dot(direction, self._primitive.get_cell())
        else:
            direction_cart = None
        self._pdos = PartialDos(self._mesh,
                                sigma=sigma,
                                tetrahedron_method=tetrahedron_method,
                                direction=direction_cart,
                                xyz_projection=xyz_projection)
        self._pdos.set_draw_area(freq_min, freq_max, freq_pitch)
        self._pdos.run()
        return True

    def get_partial_DOS(self):
        """
        Retern frequencies and partial_dos.
        The first element is freqs and the second is partial_dos.

        frequencies: [freq1, freq2, ...]
        partial_dos:
          [[atom1-freq1, atom1-freq2, ...],
           [atom2-freq1, atom2-freq2, ...],
           ...]
        """
        return self._pdos.get_partial_dos()

    def plot_partial_DOS(self, pdos_indices=None, legend=None):
        import matplotlib.pyplot as plt
        self._pdos.plot(plt,
                        indices=pdos_indices,
                        legend=legend)
        return plt

    def write_partial_DOS(self):
        self._pdos.write()

    # Thermal property
    def set_thermal_properties(self,
                               t_step=10,
                               t_max=1000,
                               t_min=0,
                               temperatures=None,
                               is_projection=False,
                               band_indices=None,
                               cutoff_frequency=None):
        if self._mesh is None:
            print("Warning: set_mesh has to be done before "
                  "set_thermal_properties")
            return False
        else:
            tp = ThermalProperties(self._mesh.get_frequencies(),
                                   weights=self._mesh.get_weights(),
                                   eigenvectors=self._mesh.get_eigenvectors(),
                                   is_projection=is_projection,
                                   band_indices=band_indices,
                                   cutoff_frequency=cutoff_frequency)
            if temperatures is None:
                tp.set_temperature_range(t_step=t_step,
                                         t_max=t_max,
                                         t_min=t_min)
            else:
                tp.set_temperatures(temperatures)
            tp.run()
            self._thermal_properties = tp

    def get_thermal_properties(self):
        temps, fe, entropy, cv = \
            self._thermal_properties.get_thermal_properties()
        return temps, fe, entropy, cv

    def plot_thermal_properties(self):
        import matplotlib.pyplot as plt
        self._thermal_properties.plot(plt)
        return plt

    def write_yaml_thermal_properties(self, filename='thermal_properties.yaml'):
        self._thermal_properties.write_yaml(filename=filename)

    # Thermal displacement
    def set_thermal_displacements(self,
                                  t_step=10,
                                  t_max=1000,
                                  t_min=0,
                                  temperatures=None,
                                  direction=None,
                                  cutoff_frequency=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        self._thermal_displacements = None

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before \'set_thermal_displacements\'.")
            return False

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers()

        if self._mesh.get_eigenvectors() is None:
            print("Warning: Eigenvectors have to be calculated.")
            return False

        if np.prod(mesh_nums) != len(eigvecs):
            print("Warning: Sampling mesh must not be symmetrized.")
            return False

        td = ThermalDisplacements(frequencies,
                                  eigvecs,
                                  self._primitive.get_masses(),
                                  cutoff_frequency=cutoff_frequency)
        if temperatures is None:
            td.set_temperature_range(t_min, t_max, t_step)
        else:
            td.set_temperatures(temperatures)
        if direction is not None:
            td.project_eigenvectors(direction, self._primitive.get_cell())
        td.run()

        self._thermal_displacements = td
        return True

    def get_thermal_displacements(self):
        if self._thermal_displacements is not None:
            return self._thermal_displacements.get_thermal_displacements()

    def plot_thermal_displacements(self, is_legend=False):
        import matplotlib.pyplot as plt
        self._thermal_displacements.plot(plt, is_legend=is_legend)
        return plt

    def write_yaml_thermal_displacements(self):
        self._thermal_displacements.write_yaml()

    # Thermal displacement matrix
    def set_thermal_displacement_matrices(self,
                                          t_step=10,
                                          t_max=1000,
                                          t_min=0,
                                          cutoff_frequency=None,
                                          t_cif=None):
        """
        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.

        direction:
          Projection direction in reduced coordinates
        """
        self._thermal_displacement_matrices = None

        if self._mesh is None:
            print("Warning: \'set_mesh\' has to finish correctly "
                  "before \'set_thermal_displacement_matrices\'.")
            return False

        eigvecs = self._mesh.get_eigenvectors()
        frequencies = self._mesh.get_frequencies()
        mesh_nums = self._mesh.get_mesh_numbers()

        if self._mesh.get_eigenvectors() is None:
            print("Warning: Eigenvectors have to be calculated.")
            return False

        if np.prod(mesh_nums) != len(eigvecs):
            print("Warning: Sampling mesh must not be symmetrized.")
            return False

        tdm = ThermalDisplacementMatrices(frequencies,
                                          eigvecs,
                                          self._primitive.get_masses(),
                                          cutoff_frequency=cutoff_frequency,
                                          lattice=self._primitive.get_cell().T)
        if t_cif is None:
            tdm.set_temperature_range(t_min, t_max, t_step)
        else:
            tdm.set_temperatures([t_cif])
        tdm.run()

        self._thermal_displacement_matrices = tdm
        return True

    def get_thermal_displacement_matrices(self):
        tdm = self._thermal_displacement_matrices
        if tdm is not None:
            return tdm.get_thermal_displacement_matrices()

    def write_yaml_thermal_displacement_matrices(self):
        self._thermal_displacement_matrices.write_yaml()

    def write_thermal_displacement_matrix_to_cif(self,
                                                 temperature_index):
        self._thermal_displacement_matrices.write_cif(self._primitive,
                                                      temperature_index)

    # Mean square distance between a pair of atoms
    def set_thermal_distances(self,
                              atom_pairs,
                              t_step=10,
                              t_max=1000,
                              t_min=0,
                              cutoff_frequency=None):
        """
        atom_pairs: List of list
          Mean square distances are calculated for the atom_pairs
          e.g. [[1, 2], [1, 4]]

        cutoff_frequency:
          phonon modes that have frequencies below cutoff_frequency
          are ignored.
        """

        td = ThermalDistances(self._mesh.get_frequencies(),
                              self._mesh.get_eigenvectors(),
                              self._supercell,
                              self._primitive,
                              self._mesh.get_qpoints(),
                              cutoff_frequency=cutoff_frequency)
        td.set_temperature_range(t_min, t_max, t_step)
        td.run(atom_pairs)

        self._thermal_distances = td

    def write_yaml_thermal_distances(self):
        self._thermal_distances.write_yaml()

    # Sampling at q-points
    def set_qpoints_phonon(self,
                           q_points,
                           nac_q_direction=None,
                           is_eigenvectors=False,
                           write_dynamical_matrices=False):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._qpoints_phonon = None
            return False

        self._qpoints_phonon = QpointsPhonon(
            np.reshape(q_points, (-1, 3)),
            self._dynamical_matrix,
            nac_q_direction=nac_q_direction,
            is_eigenvectors=is_eigenvectors,
            group_velocity=self._group_velocity,
            write_dynamical_matrices=write_dynamical_matrices,
            factor=self._factor)
        return True

    def get_qpoints_phonon(self):
        return (self._qpoints_phonon.get_frequencies(),
                self._qpoints_phonon.get_eigenvectors())

    def write_hdf5_qpoints_phonon(self):
        self._qpoints_phonon.write_hdf5()

    def write_yaml_qpoints_phonon(self):
        self._qpoints_phonon.write_yaml()

    # Normal mode animation
    def write_animation(self,
                        q_point=None,
                        anime_type='v_sim',
                        band_index=None,
                        amplitude=None,
                        num_div=None,
                        shift=None,
                        filename=None):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            return False

        if q_point is None:
            animation = Animation([0, 0, 0],
                                  self._dynamical_matrix,
                                  shift=shift)
        else:
            animation = Animation(q_point,
                                  self._dynamical_matrix,
                                  shift=shift)
        if anime_type == 'v_sim':
            if amplitude:
                amplitude_ = amplitude
            else:
                amplitude_ = 1.0

            if filename:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor,
                                      filename=filename)
            else:
                animation.write_v_sim(amplitude=amplitude_,
                                      factor=self._factor)
        if (anime_type == 'arc' or
            anime_type == 'xyz' or
            anime_type == 'jmol' or
            anime_type == 'poscar'):
            if band_index is None or amplitude is None or num_div is None:
                print("Warning: Parameters are not correctly set for "
                      "animation.")
                return False

            if anime_type == 'arc' or anime_type is None:
                if filename:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div,
                                        filename=filename)
                else:
                    animation.write_arc(band_index,
                                        amplitude,
                                        num_div)

            if anime_type == 'xyz':
                if filename:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor,
                                        filename=filename)
                else:
                    animation.write_xyz(band_index,
                                        amplitude,
                                        num_div,
                                        self._factor)

            if anime_type == 'jmol':
                if filename:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor,
                                             filename=filename)
                else:
                    animation.write_xyz_jmol(amplitude=amplitude,
                                             factor=self._factor)

            if anime_type == 'poscar':
                if filename:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div,
                                           filename=filename)
                else:
                    animation.write_POSCAR(band_index,
                                           amplitude,
                                           num_div)

        return True

    # Atomic modulation of normal mode
    def set_modulations(self,
                        dimension,
                        phonon_modes,
                        delta_q=None,
                        derivative_order=None,
                        nac_q_direction=None):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._modulation = None
            return False

        self._modulation = Modulation(self._dynamical_matrix,
                                      dimension,
                                      phonon_modes,
                                      delta_q=delta_q,
                                      derivative_order=derivative_order,
                                      nac_q_direction=nac_q_direction,
                                      factor=self._factor)
        self._modulation.run()
        return True

    def get_modulated_supercells(self):
        """Returns cells with modulations as Atoms objects"""
        return self._modulation.get_modulated_supercells()

    def get_modulations_and_supercell(self):
        """Return modulations and supercell

        (modulations, supercell)

        modulations: Atomic modulations of supercell in Cartesian coordinates
        supercell: Supercell as an Atoms object.

        """
        return self._modulation.get_modulations_and_supercell()

    def write_modulations(self):
        """Create MPOSCAR's"""
        self._modulation.write()

    def write_yaml_modulations(self):
        self._modulation.write_yaml()

    # Irreducible representation
    def set_irreps(self,
                   q,
                   is_little_cogroup=False,
                   nac_q_direction=None,
                   degeneracy_tolerance=1e-4):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._irreps = None
            return None

        self._irreps = IrReps(
            self._dynamical_matrix,
            q,
            is_little_cogroup=is_little_cogroup,
            nac_q_direction=nac_q_direction,
            factor=self._factor,
            symprec=self._symprec,
            degeneracy_tolerance=degeneracy_tolerance,
            log_level=self._log_level)

        return self._irreps.run()

    def get_irreps(self):
        return self._irreps

    def show_irreps(self, show_irreps=False):
        self._irreps.show(show_irreps=show_irreps)

    def write_yaml_irreps(self, show_irreps=False):
        self._irreps.write_yaml(show_irreps=show_irreps)

    # Group velocity
    def set_group_velocity(self, q_length=None):
        if self._dynamical_matrix is None:
            print("Warning: Dynamical matrix has not yet built.")
            self._group_velocity = None
            return False

        self._group_velocity = GroupVelocity(
            self._dynamical_matrix,
            q_length=q_length,
            symmetry=self._primitive_symmetry,
            frequency_factor_to_THz=self._factor)
        return True

    def get_group_velocity(self):
        return self._group_velocity.get_group_velocity()

    def get_group_velocity_at_q(self, q_point):
        if self._group_velocity is None:
            self.set_group_velocity()
        self._group_velocity.set_q_points([q_point])
        return self._group_velocity.get_group_velocity()[0]

    # Moment
    def set_moment(self,
                   order=1,
                   is_projection=False,
                   freq_min=None,
                   freq_max=None):
        if self._mesh is None:
            print("Warning: set_mesh has to be done before set_moment")
            return False
        else:
            if is_projection:
                if self._mesh.get_eigenvectors() is None:
                    print("Warning: Eigenvectors have to be calculated.")
                    return False
                moment = PhononMoment(
                    self._mesh.get_frequencies(),
                    weights=self._mesh.get_weights(),
                    eigenvectors=self._mesh.get_eigenvectors())
            else:
                moment = PhononMoment(
                    self._mesh.get_frequencies(),
                    weights=self._mesh.get_weights())
            if freq_min is not None or freq_max is not None:
                moment.set_frequency_range(freq_min=freq_min,
                                           freq_max=freq_max)
            moment.run(order=order)
            self._moment = moment.get_moment()
            return True

    def get_moment(self):
        return self._moment

    #################
    # Local methods #
    #################
    def _run_force_constants_from_forces(self,
                                         distributed_atom_list=None,
                                         decimals=None,
                                         computation_algorithm="svd"):
        if self._displacement_dataset is not None:
            self._force_constants = get_fc2(
                self._supercell,
                self._symmetry,
                self._displacement_dataset,
                atom_list=distributed_atom_list,
                decimals=decimals,
                computation_algorithm=computation_algorithm)

    def _set_dynamical_matrix(self):
        self._dynamical_matrix = None

        if (self._supercell is None or self._primitive is None):
            print("Bug: Supercell or primitive is not created.")
            return False
        elif self._force_constants is None:
            print("Warning: Force constants are not prepared.")
            return False
        elif self._primitive.get_masses() is None:
            print("Warning: Atomic masses are not correctly set.")
            return False
        else:
            if self._nac_params is None:
                self._dynamical_matrix = DynamicalMatrix(
                    self._supercell,
                    self._primitive,
                    self._force_constants,
                    decimals=self._dynamical_matrix_decimals,
                    symprec=self._symprec)
            else:
                self._dynamical_matrix = DynamicalMatrixNAC(
                    self._supercell,
                    self._primitive,
                    self._force_constants,
                    nac_params=self._nac_params,
                    decimals=self._dynamical_matrix_decimals,
                    symprec=self._symprec)
            return True

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell,
                                  self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive,
                                            self._symprec,
                                            self._is_symmetry)

        if (len(self._symmetry.get_pointgroup_operations()) !=
            len(self._primitive_symmetry.get_pointgroup_operations())):
            print("Warning: Point group symmetries of supercell and primitive"
                  "cell are different.")

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell,
                                        self._supercell_matrix,
                                        self._symprec)

    def _build_supercells_with_displacements(self):
        supercells = []
        for disp in self._displacement_dataset['first_atoms']:
            positions = self._supercell.get_positions()
            positions[disp['number']] += disp['displacement']
            supercells.append(Atoms(
                    numbers=self._supercell.get_atomic_numbers(),
                    masses=self._supercell.get_masses(),
                    magmoms=self._supercell.get_magnetic_moments(),
                    positions=positions,
                    cell=self._supercell.get_cell(),
                    pbc=True))

        self._supercells_with_displacements = supercells

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """

        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        if self._primitive_matrix is None:
            trans_mat = inv_supercell_matrix
        else:
            trans_mat = np.dot(inv_supercell_matrix, self._primitive_matrix)
        self._primitive = get_primitive(
            self._supercell, trans_mat, self._symprec)
        num_satom = self._supercell.get_number_of_atoms()
        num_patom = self._primitive.get_number_of_atoms()
        if abs(num_satom * np.linalg.det(trans_mat) - num_patom) < 0.1:
            return True
        else:
            return False
コード例 #32
0
ファイル: __init__.py プロジェクト: shanghui/phonopy
class Phono3py:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 phonon_supercell_matrix=None,
                 mesh=None,
                 band_indices=None,
                 sigmas=[],
                 cutoff_frequency=1e-4,
                 frequency_factor_to_THz=VaspToTHz,
                 is_symmetry=True,
                 is_nosym=False,
                 symmetrize_fc3_q=False,
                 symprec=1e-5,
                 log_level=0,
                 lapack_zheev_uplo='L'):
        self._symprec = symprec
        self._sigmas = sigmas
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_symmetry = is_symmetry
        self._is_nosym = is_nosym
        self._lapack_zheev_uplo = lapack_zheev_uplo
        self._symmetrize_fc3_q = symmetrize_fc3_q
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._phonon_supercell_matrix = phonon_supercell_matrix  # optional
        self._supercell = None
        self._primitive = None
        self._phonon_supercell = None
        self._phonon_primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_phonon_supercell()
        self._build_phonon_primitive_cell()

        # Set supercell, primitive, and phonon supercell symmetries
        self._symmetry = None
        self._primitive_symmetry = None
        self._phonon_supercell_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_phonon_supercell_symmetry()

        # Displacements and supercells
        self._supercells_with_displacements = None
        self._displacement_dataset = None
        self._phonon_displacement_dataset = None
        self._phonon_supercells_with_displacements = None

        # Thermal conductivity
        self._thermal_conductivity = None  # conductivity_RTA object

        # Imaginary part of self energy at frequency points
        self._imag_self_energy = None
        self._scattering_event_class = None

        # Linewidth (Imaginary part of self energy x 2) at temperatures
        self._linewidth = None

        self._grid_points = None
        self._frequency_points = None
        self._temperatures = None

        # Other variables
        self._fc2 = None
        self._fc3 = None

        # Setup interaction
        self._interaction = None
        self._mesh = None
        self._band_indices = None
        self._band_indices_flatten = None
        if mesh is not None:
            self._mesh = np.array(mesh, dtype='intc')
        if band_indices is None:
            num_band = self._primitive.get_number_of_atoms() * 3
            self._band_indices = [np.arange(num_band)]
        else:
            self._band_indices = band_indices
        self._band_indices_flatten = np.hstack(
            self._band_indices).astype('intc')

    def set_phph_interaction(self,
                             nac_params=None,
                             nac_q_direction=None,
                             use_Peierls_model=False,
                             frequency_scale_factor=None):
        self._interaction = Interaction(
            self._supercell,
            self._primitive,
            self._mesh,
            self._primitive_symmetry,
            fc3=self._fc3,
            band_indices=self._band_indices_flatten,
            use_Peierls_model=use_Peierls_model,
            frequency_factor_to_THz=self._frequency_factor_to_THz,
            cutoff_frequency=self._cutoff_frequency,
            is_nosym=self._is_nosym,
            symmetrize_fc3_q=self._symmetrize_fc3_q,
            lapack_zheev_uplo=self._lapack_zheev_uplo)
        self._interaction.set_dynamical_matrix(
            self._fc2,
            self._phonon_supercell,
            self._phonon_primitive,
            nac_params=nac_params,
            frequency_scale_factor=frequency_scale_factor)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)

    def generate_displacements(self,
                               distance=0.03,
                               cutoff_pair_distance=None,
                               is_plusminus='auto',
                               is_diagonal=True):
        direction_dataset = get_third_order_displacements(
            self._supercell,
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal)
        self._displacement_dataset = direction_to_displacement(
            direction_dataset,
            distance,
            self._supercell,
            cutoff_distance=cutoff_pair_distance)

        if self._phonon_supercell_matrix is not None:
            phonon_displacement_directions = get_least_displacements(
                self._phonon_supercell_symmetry,
                is_plusminus=is_plusminus,
                is_diagonal=False)
            self._phonon_displacement_dataset = direction_to_displacement_fc2(
                phonon_displacement_directions, distance,
                self._phonon_supercell)

    def produce_fc2(self,
                    forces_fc2,
                    displacement_dataset=None,
                    is_permutation_symmetry=False,
                    translational_symmetry_type=0):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset

        for forces, disp1 in zip(forces_fc2, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        self._fc2 = get_fc2(self._phonon_supercell,
                            self._phonon_supercell_symmetry, disp_dataset)
        if is_permutation_symmetry:
            set_permutation_symmetry(self._fc2)
        if translational_symmetry_type:
            set_translational_invariance(
                self._fc2,
                translational_symmetry_type=translational_symmetry_type)

    def produce_fc3(
            self,
            forces_fc3,
            displacement_dataset=None,
            cutoff_distance=None,  # set fc3 zero
            translational_symmetry_type=0,
            is_permutation_symmetry=False):
        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset

        for forces, disp1 in zip(forces_fc3, disp_dataset['first_atoms']):
            disp1['forces'] = forces
        fc2 = get_fc2(self._supercell, self._symmetry, disp_dataset)
        if is_permutation_symmetry:
            set_permutation_symmetry(fc2)
        if translational_symmetry_type:
            set_translational_invariance(
                fc2, translational_symmetry_type=translational_symmetry_type)

        count = len(disp_dataset['first_atoms'])
        for disp1 in disp_dataset['first_atoms']:
            for disp2 in disp1['second_atoms']:
                disp2['delta_forces'] = forces_fc3[count] - disp1['forces']
                count += 1
        self._fc3 = get_fc3(
            self._supercell,
            disp_dataset,
            fc2,
            self._symmetry,
            translational_symmetry_type=translational_symmetry_type,
            is_permutation_symmetry=is_permutation_symmetry,
            verbose=self._log_level)

        # Set fc3 elements zero beyond cutoff_distance
        if cutoff_distance:
            if self._log_level:
                print("Cutting-off fc3 by zero (cut-off distance: %f)" %
                      cutoff_distance)
            self.cutoff_fc3_by_zero(cutoff_distance)

        # Set fc2
        if self._fc2 is None:
            self._fc2 = fc2

    def cutoff_fc3_by_zero(self, cutoff_distance):
        cutoff_fc3_by_zero(self._fc3, self._supercell, cutoff_distance,
                           self._symprec)

    def set_permutation_symmetry(self):
        if self._fc2 is not None:
            set_permutation_symmetry(self._fc2)
        if self._fc3 is not None:
            set_permutation_symmetry_fc3(self._fc3)

    def set_translational_invariance(self, translational_symmetry_type=1):
        if self._fc2 is not None:
            set_translational_invariance(
                self._fc2,
                translational_symmetry_type=translational_symmetry_type)
        if self._fc3 is not None:
            set_translational_invariance_fc3(
                self._fc3,
                translational_symmetry_type=translational_symmetry_type)

    def get_interaction_strength(self):
        return self._interaction

    def get_fc2(self):
        return self._fc2

    def set_fc2(self, fc2):
        self._fc2 = fc2

    def get_fc3(self):
        return self._fc3

    def set_fc3(self, fc3):
        self._fc3 = fc3

    def get_primitive(self):
        return self._primitive

    def get_unitcell(self):
        return self._unitcell

    def get_supercell(self):
        return self._supercell

    def get_phonon_supercell(self):
        return self._phonon_supercell

    def get_phonon_primitive(self):
        return self._phonon_primitive

    def get_symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_primitive_symmetry(self):
        return self._primitive_symmetry

    def get_phonon_supercell_symmetry(self):
        return self._phonon_supercell_symmetry

    def set_displacement_dataset(self, dataset):
        self._displacement_dataset = dataset

    def get_displacement_dataset(self):
        return self._displacement_dataset

    def get_phonon_displacement_dataset(self):
        return self._phonon_displacement_dataset

    def get_supercells_with_displacements(self):
        if self._supercells_with_displacements is None:
            self._build_supercells_with_displacements()
        return self._supercells_with_displacements

    def get_phonon_supercells_with_displacements(self):
        if self._phonon_supercells_with_displacements is None:
            if self._phonon_displacement_dataset is not None:
                self._phonon_supercells_with_displacements = \
                  self._build_phonon_supercells_with_displacements(
                      self._phonon_supercell,
                      self._phonon_displacement_dataset)
        return self._phonon_supercells_with_displacements

    def run_imag_self_energy(self,
                             grid_points,
                             frequency_step=None,
                             num_frequency_points=None,
                             temperatures=[0.0, 300.0],
                             scattering_event_class=None):
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._scattering_event_class = scattering_event_class
        self._imag_self_energy, self._frequency_points = get_imag_self_energy(
            self._interaction,
            grid_points,
            self._sigmas,
            frequency_step=frequency_step,
            num_frequency_points=num_frequency_points,
            temperatures=temperatures,
            scattering_event_class=scattering_event_class,
            log_level=self._log_level)

    def write_imag_self_energy(self, filename=None):
        write_imag_self_energy(
            self._imag_self_energy,
            self._mesh,
            self._grid_points,
            self._band_indices,
            self._frequency_points,
            self._temperatures,
            self._sigmas,
            scattering_event_class=self._scattering_event_class,
            filename=filename)

    def run_linewidth(self,
                      grid_points,
                      temperatures=np.arange(0, 1001, 10, dtype='double')):
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._linewidth = get_linewidth(self._interaction,
                                        grid_points,
                                        self._sigmas,
                                        temperatures=temperatures,
                                        log_level=self._log_level)

    def write_linewidth(self, filename=None):
        write_linewidth(self._linewidth,
                        self._band_indices,
                        self._mesh,
                        self._grid_points,
                        self._sigmas,
                        self._temperatures,
                        filename=filename)

    def run_thermal_conductivity(
            self,
            is_LBTE=True,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            sigmas=[],
            is_isotope=False,
            mass_variances=None,
            grid_points=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            cutoff_mfp=None,  # in micrometre
            is_reducible_collision_matrix=False,
            no_kappa_stars=False,
            gv_delta_q=None,  # for group velocity
            pinv_cutoff=1.0e-8,  # for pseudo-inversion of collision matrix
            write_gamma=False,
            read_gamma=False,
            write_collision=False,
            read_collision=False,
            write_amplitude=False,
            read_amplitude=False,
            input_filename=None,
            output_filename=None):

        if is_LBTE:
            self._thermal_conductivity = get_thermal_conductivity_LBTE(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                cutoff_mfp=cutoff_mfp,
                is_reducible_collision_matrix=is_reducible_collision_matrix,
                no_kappa_stars=no_kappa_stars,
                gv_delta_q=gv_delta_q,
                pinv_cutoff=pinv_cutoff,
                write_collision=write_collision,
                read_collision=read_collision,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)
        else:
            self._thermal_conductivity = get_thermal_conductivity_RTA(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                mesh_divisors=mesh_divisors,
                coarse_mesh_shifts=coarse_mesh_shifts,
                cutoff_mfp=cutoff_mfp,
                no_kappa_stars=no_kappa_stars,
                gv_delta_q=gv_delta_q,
                write_gamma=write_gamma,
                read_gamma=read_gamma,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)

    def get_thermal_conductivity(self):
        return self._thermal_conductivity

    def get_frequency_shift(self,
                            grid_points,
                            epsilon=0.1,
                            temperatures=np.arange(0, 1001, 10,
                                                   dtype='double'),
                            output_filename=None):
        fst = FrequencyShift(self._interaction)
        for gp in grid_points:
            fst.set_grid_point(gp)
            if self._log_level:
                weights = self._interaction.get_triplets_at_q()[1]
                print "------ Frequency shift -o- ------"
                print "Number of ir-triplets:",
                print "%d / %d" % (len(weights), weights.sum())
            fst.run_interaction()
            fst.set_epsilon(epsilon)
            delta = np.zeros(
                (len(temperatures), len(self._band_indices_flatten)),
                dtype='double')
            for i, t in enumerate(temperatures):
                fst.set_temperature(t)
                fst.run()
                delta[i] = fst.get_frequency_shift()

            for i, bi in enumerate(self._band_indices):
                pos = 0
                for j in range(i):
                    pos += len(self._band_indices[j])

                write_frequency_shift(gp,
                                      bi,
                                      temperatures,
                                      delta[:, pos:(pos + len(bi))],
                                      self._mesh,
                                      epsilon=epsilon,
                                      filename=output_filename)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell, self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive, self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) != len(
                self._primitive_symmetry.get_pointgroup_operations())):
            print(
                "Warning: point group symmetries of supercell and primitive"
                "cell are different.")

    def _search_phonon_supercell_symmetry(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell_symmetry = self._symmetry
        else:
            self._phonon_supercell_symmetry = Symmetry(self._phonon_supercell,
                                                       self._symprec,
                                                       self._is_symmetry)

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell, self._supercell_matrix,
                                        self._symprec)

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """
        self._primitive = self._get_primitive_cell(self._supercell,
                                                   self._supercell_matrix,
                                                   self._primitive_matrix)

    def _build_phonon_supercell(self):
        """
        phonon_supercell:
          This supercell is used for harmonic phonons (frequencies,
          eigenvectors, group velocities, ...)
        phonon_supercell_matrix:
          Different supercell size can be specified.
        """
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell = self._supercell
        else:
            self._phonon_supercell = get_supercell(
                self._unitcell, self._phonon_supercell_matrix, self._symprec)

    def _build_phonon_primitive_cell(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_primitive = self._primitive
        else:
            self._phonon_primitive = self._get_primitive_cell(
                self._phonon_supercell, self._phonon_supercell_matrix,
                self._primitive_matrix)

    def _build_phonon_supercells_with_displacements(self, supercell,
                                                    displacement_dataset):
        supercells = []
        magmoms = supercell.get_magnetic_moments()
        masses = supercell.get_masses()
        numbers = supercell.get_atomic_numbers()
        lattice = supercell.get_cell()

        for disp1 in displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            positions = supercell.get_positions()
            positions[disp1['number']] += disp_cart1
            supercells.append(
                Atoms(numbers=numbers,
                      masses=masses,
                      magmoms=magmoms,
                      positions=positions,
                      cell=lattice,
                      pbc=True))

        return supercells

    def _build_supercells_with_displacements(self):
        supercells = []
        magmoms = self._supercell.get_magnetic_moments()
        masses = self._supercell.get_masses()
        numbers = self._supercell.get_atomic_numbers()
        lattice = self._supercell.get_cell()

        supercells = self._build_phonon_supercells_with_displacements(
            self._supercell, self._displacement_dataset)

        for disp1 in self._displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            for disp2 in disp1['second_atoms']:
                if 'included' in disp2:
                    included = disp2['included']
                else:
                    included = True
                if included:
                    positions = self._supercell.get_positions()
                    positions[disp1['number']] += disp_cart1
                    positions[disp2['number']] += disp2['displacement']
                    supercells.append(
                        Atoms(numbers=numbers,
                              masses=masses,
                              magmoms=magmoms,
                              positions=positions,
                              cell=lattice,
                              pbc=True))
                else:
                    supercells.append(None)

        self._supercells_with_displacements = supercells

    def _get_primitive_cell(self, supercell, supercell_matrix,
                            primitive_matrix):
        inv_supercell_matrix = np.linalg.inv(supercell_matrix)
        if primitive_matrix is None:
            t_mat = inv_supercell_matrix
        else:
            t_mat = np.dot(inv_supercell_matrix, primitive_matrix)

        return get_primitive(supercell, t_mat, self._symprec)
コード例 #33
0
class Phono3py(object):
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 primitive_matrix=None,
                 phonon_supercell_matrix=None,
                 masses=None,
                 mesh=None,
                 band_indices=None,
                 sigmas=None,
                 sigma_cutoff=None,
                 cutoff_frequency=1e-4,
                 frequency_factor_to_THz=VaspToTHz,
                 is_symmetry=True,
                 is_mesh_symmetry=True,
                 symmetrize_fc3q=False,
                 symprec=1e-5,
                 log_level=0,
                 lapack_zheev_uplo='L'):
        if sigmas is None:
            self._sigmas = [None]
        else:
            self._sigmas = sigmas
        self._sigma_cutoff = sigma_cutoff
        self._symprec = symprec
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._is_symmetry = is_symmetry
        self._is_mesh_symmetry = is_mesh_symmetry
        self._lapack_zheev_uplo = lapack_zheev_uplo
        self._symmetrize_fc3q = symmetrize_fc3q
        self._cutoff_frequency = cutoff_frequency
        self._log_level = log_level

        # Create supercell and primitive cell
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        if type(primitive_matrix) is str and primitive_matrix == 'auto':
            self._primitive_matrix = self._guess_primitive_matrix()
        else:
            self._primitive_matrix = primitive_matrix
        self._phonon_supercell_matrix = phonon_supercell_matrix  # optional
        self._supercell = None
        self._primitive = None
        self._phonon_supercell = None
        self._phonon_primitive = None
        self._build_supercell()
        self._build_primitive_cell()
        self._build_phonon_supercell()
        self._build_phonon_primitive_cell()

        if masses is not None:
            self._set_masses(masses)

        # Set supercell, primitive, and phonon supercell symmetries
        self._symmetry = None
        self._primitive_symmetry = None
        self._phonon_supercell_symmetry = None
        self._search_symmetry()
        self._search_primitive_symmetry()
        self._search_phonon_supercell_symmetry()

        # Displacements and supercells
        self._supercells_with_displacements = None
        self._displacement_dataset = None
        self._phonon_displacement_dataset = None
        self._phonon_supercells_with_displacements = None

        # Thermal conductivity
        self._thermal_conductivity = None  # conductivity_RTA object

        # Imaginary part of self energy at frequency points
        self._imag_self_energy = None
        self._scattering_event_class = None

        self._grid_points = None
        self._frequency_points = None
        self._temperatures = None

        # Other variables
        self._fc2 = None
        self._fc3 = None
        self._nac_params = None

        # Setup interaction
        self._interaction = None
        self._mesh_numbers = None
        self._band_indices = None
        self._band_indices_flatten = None
        if mesh is not None:
            self._set_mesh_numbers(mesh)
        self.set_band_indices(band_indices)

    @property
    def thermal_conductivity(self):
        return self._thermal_conductivity

    def get_thermal_conductivity(self):
        return self.thermal_conductivity

    @property
    def displacements(self):
        """Return displacements

        Returns
        -------
        displacements : ndarray
            Displacements of all atoms of all supercells in Cartesian
            coordinates.
            shape=(supercells, natom, 3), dtype='double', order='C'

        """

        dataset = self._displacement_dataset

        if 'first_atoms' in dataset:
            num_scells = len(dataset['first_atoms'])
            for disp1 in dataset['first_atoms']:
                num_scells += len(disp1['second_atoms'])
            displacements = np.zeros(
                (num_scells, self._supercells.get_number_of_atoms(), 3),
                dtype='double',
                order='C')
            i = 0
            for disp1 in dataset['first_atoms']:
                displacements[i, disp1['number']] = disp1['displacement']
                i += 1
            for disp1 in dataset['first_atoms']:
                for disp2 in dataset['second_atoms']:
                    displacements[i, disp2['number']] = disp2['displacement']
                    i += 1
        elif 'forces' in dataset or 'displacements' in dataset:
            displacements = dataset['displacements']
        else:
            raise RuntimeError("displacement dataset has wrong format.")

        return displacements

    @displacements.setter
    def displacements(self, displacements):
        """Set displacemens

        Parameters
        ----------
        displacemens : array_like
            Atomic displacements of all atoms of all supercells.
            Only type2 displacement dataset is supported, i.e., displacements
            has to have the array shape of (supercells, natom, 3).
            When displacement dataset is in type1, the type2 dataset is created
            and force information is lost.

        """

        dataset = self._displacement_dataset
        disps = np.array(displacements, dtype='double', order='C')
        natom = self._supercell.get_number_of_atoms()
        if (disps.ndim != 3 or disps.shape[1:] != (natom, 3)):
            raise RuntimeError("Array shape of displacements is incorrect.")

        if 'first_atoms' in dataset:
            dataset = {'displacements': disps}
        elif 'displacements' in dataset or 'forces' in dataset:
            dataset['displacements'] = disps

    @property
    def forces(self):
        dataset = self._displacement_dataset
        if 'forces' in dataset:
            return dataset['forces']
        elif 'first_atoms' in dataset:
            num_scells = len(dataset['first_atoms'])
            for disp1 in dataset['first_atoms']:
                num_scells += len(disp1['second_atoms'])
            forces = np.zeros(
                (num_scells, self._supercells.get_number_of_atoms(), 3),
                dtype='double',
                order='C')
            i = 0
            for disp1 in dataset['first_atoms']:
                forces[i] = disp1['forces']
                i += 1
            for disp1 in dataset['first_atoms']:
                for disp2 in disp1['second_atoms']:
                    forces[i] = disp2['forces']
                    i += 1
            return forces
        else:
            raise RuntimeError("displacement dataset has wrong format.")

    @forces.setter
    def forces(self, forces_fc3):
        """Set forces in displacement dataset.

        Parameters
        ----------
        forces_fc3 : array_like
            A set of atomic forces in displaced supercells. The order of
            displaced supercells has to match with that in displacement
            dataset.
            shape=(displaced supercells, atoms in supercell, 3)

        """

        forces = np.array(forces_fc3, dtype='double', order='C')
        dataset = self._displacement_dataset
        if 'first_atoms' in dataset:
            i = 0
            for disp1 in dataset['first_atoms']:
                disp1['forces'] = forces[i]
                i += 1
            for disp1 in dataset['first_atoms']:
                for disp2 in disp1['second_atoms']:
                    disp2['forces'] = forces[i]
                    i += 1
        elif 'displacements' in dataset or 'forces' in dataset:
            dataset['forces'] = forces

    @property
    def phonon_displacements(self):
        """Return displacements for harmonic phonons

        Returns
        -------
        displacements : ndarray
            Displacements of all atoms of all supercells in Cartesian
            coordinates.
            shape=(supercells, natom, 3), dtype='double', order='C'

        """

        if self._phonon_displacement_dataset is None:
            raise RuntimeError("phonon_displacement_dataset does not exist.")

        dataset = self._phonon_displacement_dataset
        if 'first_atoms' in dataset:
            num_scells = len(dataset['first_atoms'])
            natom = self._phonon_supercells.get_number_of_atoms()
            displacements = np.zeros((num_scells, natom, 3),
                                     dtype='double',
                                     order='C')
            for i, disp1 in enumerate(dataset['first_atoms']):
                displacements[i, disp1['number']] = disp1['displacement']
        elif 'forces' in dataset or 'displacements' in dataset:
            displacements = dataset['displacements']
        else:
            raise RuntimeError("displacement dataset has wrong format.")

        return displacements

    @phonon_displacements.setter
    def phonno_displacements(self, displacements):
        """Set displacemens

        Parameters
        ----------
        displacemens : array_like
            Atomic displacements of all atoms of all supercells.
            Only type2 displacement dataset is supported, i.e., displacements
            has to have the array shape of (supercells, natom, 3).
            When displacement dataset is in type1, the type2 dataset is created
            and force information is lost.

        """

        if self._phonon_displacement_dataset is None:
            raise RuntimeError("phonon_displacement_dataset does not exist.")

        dataset = self._phonon_displacement_dataset
        disps = np.array(displacements, dtype='double', order='C')
        natom = self._phonon_supercell.get_number_of_atoms()
        if (disps.ndim != 3 or disps.shape[1:] != (natom, 3)):
            raise RuntimeError("Array shape of displacements is incorrect.")

        if 'first_atoms' in dataset:
            dataset = {'displacements': disps}
        elif 'displacements' in dataset or 'forces' in dataset:
            dataset['displacements'] = disps

    @property
    def phonon_forces(self):
        if self._phonon_displacement_dataset is None:
            raise RuntimeError("phonon_displacement_dataset does not exist.")

        dataset = self._phonon_displacement_dataset
        if 'forces' in dataset:
            return dataset['forces']
        elif 'first_atoms' in dataset:
            num_scells = len(dataset['first_atoms'])
            forces = np.zeros(
                (num_scells, self._supercells.get_number_of_atoms(), 3),
                dtype='double',
                order='C')
            for i, disp1 in enumerate(dataset['first_atoms']):
                forces[i] = disp1['forces']
            return forces
        else:
            raise RuntimeError("displacement dataset has wrong format.")

    @phonon_forces.setter
    def phonon_forces(self, forces_fc2):
        """Set forces in displacement dataset.

        Parameters
        ----------
        forces_fc2 : array_like
            A set of atomic forces in displaced supercells. The order of
            displaced supercells has to match with that in displacement
            dataset.
            shape=(displaced supercells, atoms in supercell, 3)

        """

        if self._phonon_displacement_dataset is None:
            raise RuntimeError("phonon_displacement_dataset does not exist.")

        forces = np.array(forces_fc2, dtype='double', order='C')
        dataset = self._phonon_displacement_dataset
        if 'first_atoms' in dataset:
            i = 0
            for i, disp1 in enumerate(dataset['first_atoms']):
                disp1['forces'] = forces[i]
                i += 1
        elif 'displacements' in dataset or 'forces' in dataset:
            dataset['forces'] = forces

    @property
    def dataset(self):
        return self._displacement_dataset

    @dataset.setter
    def dataset(self, dataset):
        self._displacement_dataset = dataset

    @property
    def phonon_dataset(self):
        return self._phonon_displacement_dataset

    @phonon_dataset.setter
    def phonon_dataset(self, dataset):
        self._phonon_displacement_dataset = dataset

    @property
    def band_indices(self):
        return self._band_indices

    @band_indices.setter
    def band_indices(self, band_indices):
        if band_indices is None:
            num_band = self._primitive.get_number_of_atoms() * 3
            self._band_indices = [np.arange(num_band, dtype='intc')]
        else:
            self._band_indices = band_indices
        self._band_indices_flatten = np.hstack(
            self._band_indices).astype('intc')

    def set_band_indices(self, band_indices):
        self.band_indices = band_indices

    def set_phph_interaction(self,
                             nac_params=None,
                             nac_q_direction=None,
                             constant_averaged_interaction=None,
                             frequency_scale_factor=None,
                             unit_conversion=None,
                             solve_dynamical_matrices=True):
        if self._mesh_numbers is None:
            print("'mesh' has to be set in Phono3py instantiation.")
            raise RuntimeError

        self._nac_params = nac_params
        self._interaction = Interaction(
            self._supercell,
            self._primitive,
            self._mesh_numbers,
            self._primitive_symmetry,
            fc3=self._fc3,
            band_indices=self._band_indices_flatten,
            constant_averaged_interaction=constant_averaged_interaction,
            frequency_factor_to_THz=self._frequency_factor_to_THz,
            frequency_scale_factor=frequency_scale_factor,
            unit_conversion=unit_conversion,
            cutoff_frequency=self._cutoff_frequency,
            is_mesh_symmetry=self._is_mesh_symmetry,
            symmetrize_fc3q=self._symmetrize_fc3q,
            lapack_zheev_uplo=self._lapack_zheev_uplo)
        self._interaction.set_nac_q_direction(nac_q_direction=nac_q_direction)
        self._interaction.set_dynamical_matrix(
            self._fc2,
            self._phonon_supercell,
            self._phonon_primitive,
            nac_params=self._nac_params,
            solve_dynamical_matrices=solve_dynamical_matrices,
            verbose=self._log_level)

    def set_phonon_data(self, frequencies, eigenvectors, grid_address):
        if self._interaction is not None:
            return self._interaction.set_phonon_data(frequencies, eigenvectors,
                                                     grid_address)
        else:
            return False

    def get_phonon_data(self):
        if self._interaction is not None:
            grid_address = self._interaction.get_grid_address()
            freqs, eigvecs, _ = self._interaction.get_phonons()
            return freqs, eigvecs, grid_address
        else:
            msg = "set_phph_interaction has to be done."
            raise RuntimeError(msg)

    def generate_displacements(self,
                               distance=0.03,
                               cutoff_pair_distance=None,
                               is_plusminus='auto',
                               is_diagonal=True):
        direction_dataset = get_third_order_displacements(
            self._supercell,
            self._symmetry,
            is_plusminus=is_plusminus,
            is_diagonal=is_diagonal)
        self._displacement_dataset = direction_to_displacement(
            direction_dataset,
            distance,
            self._supercell,
            cutoff_distance=cutoff_pair_distance)

        if self._phonon_supercell_matrix is not None:
            # 'is_diagonal=False' below is made intentionally. For
            # third-order force constants, we need better accuracy,
            # and I expect this choice is better for it, but not very
            # sure.
            # In phono3py, two atoms are displaced for each
            # configuration and the displacements are chosen, first
            # displacement from the perfect supercell, then second
            # displacement, considering symmetry. If I choose
            # is_diagonal=False for the first displacement, the
            # symmetry is less broken and the number of second
            # displacements can be smaller than in the case of
            # is_diagonal=True for the first displacement.  This is
            # done in the call get_least_displacements() in
            # phonon3.displacement_fc3.get_third_order_displacements().
            #
            # The call get_least_displacements() is only for the
            # second order force constants, but 'is_diagonal=False' to
            # be consistent with the above function call, and also for
            # the accuracy when calculating ph-ph interaction
            # strength because displacement directions are better to be
            # close to perpendicular each other to fit force constants.
            #
            # On the discussion of the accuracy, these are just my
            # expectation when I designed phono3py in the early time,
            # and in fact now I guess not very different. If these are
            # little different, then I should not surprise users to
            # change the default behaviour. At this moment, this is
            # open question and we will have more advance and should
            # have better specificy external software on this.
            phonon_displacement_directions = get_least_displacements(
                self._phonon_supercell_symmetry,
                is_plusminus=is_plusminus,
                is_diagonal=False)
            self._phonon_displacement_dataset = directions_to_displacement_dataset(
                phonon_displacement_directions, distance,
                self._phonon_supercell)

    def produce_fc2(self,
                    forces_fc2=None,
                    displacement_dataset=None,
                    symmetrize_fc2=False,
                    is_compact_fc=False,
                    fc_calculator=None,
                    fc_calculator_options=None):
        """Calculate fc2 from displacements and forces

        Parameters
        ----------
        forces_fc2 :
            Dummy argument
        displacement_dataset : dict
            Displacements in supercells. There are two types of formats.
            Type 1. Two atomic displacement in each supercell:
                {'natom': number of atoms in supercell,
                 'first_atoms': [
                   {'number': atom index of first displaced atom,
                    'displacement': displacement in Cartesian coordinates,
                    'forces': forces on atoms in supercell,
                    'second_atoms': [
                      {'number': atom index of second displaced atom,
                       'displacement': displacement in Cartesian coordinates},
                       'forces': forces on atoms in supercell,
                      ... ] }, ... ] }
            Type 2. All atomic displacements in each supercell:
                {'displacements': ndarray, dtype='double', order='C',
                                  shape=(supercells, atoms in supercell, 3)
                 'forces': ndarray, dtype='double',, order='C',
                                  shape=(supercells, atoms in supercell, 3)}
            In type 2, displacements and forces can be given by numpy array
            with different shape but that can be reshaped to
            (supercells, natom, 3).
        symmetrize_fc2 : bool
            Only for type 1 displacement_dataset, translational and
            permutation symmetries are applied after creating fc3. This
            symmetrization is not very sophisticated and can break space
            group symmetry, but often useful. If better symmetrization is
            expected, it is recommended to use external force constants
            calculator such as ALM. Default is False.
        is_compact_fc : bool
            fc2 shape is
                False: (supercell, supecell, 3, 3)
                True: (primitive, supecell, 3, 3)
            where 'supercell' and 'primitive' indicate number of atoms in these
            cells. Default is False.
        fc_calculator : str or None
            Force constants calculator given by str.
        fc_calculator_options : dict
            Options for external force constants calculator.

        """

        if displacement_dataset is None:
            if self._phonon_displacement_dataset is None:
                disp_dataset = self._displacement_dataset
            else:
                disp_dataset = self._phonon_displacement_dataset
        else:
            disp_dataset = displacement_dataset

        if forces_fc2 is not None:
            self.phonon_forces = forces_fc2
            msg = ("Forces have to be stored in disp_dataset as written in "
                   "this method's docstring for the type1 dataset.")
            warnings.warn(msg, DeprecationWarning)

        if is_compact_fc:
            p2s_map = self._phonon_primitive.p2s_map
        else:
            p2s_map = None

        if fc_calculator is not None:
            disps, forces = get_displacements_and_forces(disp_dataset)
            self._fc2 = get_fc2(self._phonon_supercell,
                                self._phonon_primitive,
                                disps,
                                forces,
                                fc_calculator=fc_calculator,
                                fc_calculator_options=fc_calculator_options,
                                atom_list=p2s_map,
                                log_level=self._log_level)
        else:
            self._fc2 = get_phonopy_fc2(self._phonon_supercell,
                                        self._phonon_supercell_symmetry,
                                        disp_dataset,
                                        atom_list=p2s_map)
            if symmetrize_fc2:
                if is_compact_fc:
                    symmetrize_compact_force_constants(self._fc2,
                                                       self._phonon_primitive)
                else:
                    symmetrize_force_constants(self._fc2)

    def produce_fc3(
            self,
            forces_fc3=None,
            displacement_dataset=None,
            cutoff_distance=None,  # set fc3 zero
            symmetrize_fc3r=False,
            is_compact_fc=False,
            fc_calculator=None,
            fc_calculator_options=None):
        """Calculate fc3 from displacements and forces

        Parameters
        ----------
        forces_fc3 :
            Dummy argument
        displacement_dataset : dict
            Displacements in supercells. There are two types of formats.
            Type 1. Two atomic displacement in each supercell:
                {'natom': number of atoms in supercell,
                 'first_atoms': [
                   {'number': atom index of first displaced atom,
                    'displacement': displacement in Cartesian coordinates,
                    'forces': forces on atoms in supercell,
                    'second_atoms': [
                      {'number': atom index of second displaced atom,
                       'displacement': displacement in Cartesian coordinates},
                       'forces': forces on atoms in supercell,
                      ... ] }, ... ] }
            Type 2. All atomic displacements in each supercell:
                {'displacements': ndarray, dtype='double', order='C',
                                  shape=(supercells, atoms in supercell, 3)
                 'forces': ndarray, dtype='double',, order='C',
                                  shape=(supercells, atoms in supercell, 3)}
            In type 2, displacements and forces can be given by numpy array
            with different shape but that can be reshaped to
            (supercells, natom, 3).
        cutoff_distance : float
            After creating force constants, fc elements where any pair
            distance in atom triplets larger than cutoff_distance are set zero.
        symmetrize_fc3r : bool
            Only for type 1 displacement_dataset, translational and
            permutation symmetries are applied after creating fc3. This
            symmetrization is not very sophisticated and can break space
            group symmetry, but often useful. If better symmetrization is
            expected, it is recommended to use external force constants
            calculator such as ALM. Default is False.
        is_compact_fc : bool
            fc3 shape is
                False: (supercell, supercell, supecell, 3, 3, 3)
                True: (primitive, supercell, supecell, 3, 3, 3)
            where 'supercell' and 'primitive' indicate number of atoms in these
            cells. Default is False.
        fc_calculator : str or None
            Force constants calculator given by str.
        fc_calculator_options : dict
            Options for external force constants calculator.

        """

        if displacement_dataset is None:
            disp_dataset = self._displacement_dataset
        else:
            disp_dataset = displacement_dataset

        if forces_fc3 is not None:
            self.forces = forces_fc3
            msg = ("Forces have to be stored in disp_dataset as written in "
                   "this method's docstring for the type1 dataset.")
            warnings.warn(msg, DeprecationWarning)

        if fc_calculator is not None:

            from phono3py.other.fc_calculator import (
                get_fc3, get_displacements_and_forces_fc3)
            disps, forces = get_displacements_and_forces_fc3(disp_dataset)
            fc2, fc3 = get_fc3(self._supercell,
                               self._primitive,
                               disps,
                               forces,
                               fc_calculator=fc_calculator,
                               fc_calculator_options=fc_calculator_options,
                               is_compact_fc=is_compact_fc,
                               log_level=self._log_level)
        else:
            fc2, fc3 = get_phono3py_fc3(self._supercell,
                                        self._primitive,
                                        disp_dataset,
                                        self._symmetry,
                                        is_compact_fc=is_compact_fc,
                                        verbose=self._log_level)
            if symmetrize_fc3r:
                if is_compact_fc:
                    set_translational_invariance_compact_fc3(
                        fc3, self._primitive)
                    set_permutation_symmetry_compact_fc3(fc3, self._primitive)
                    if self._fc2 is None:
                        symmetrize_compact_force_constants(
                            fc2, self._primitive)
                else:
                    set_translational_invariance_fc3(fc3)
                    set_permutation_symmetry_fc3(fc3)
                    if self._fc2 is None:
                        symmetrize_force_constants(fc2)

        # Set fc2 and fc3
        self._fc3 = fc3

        # Normally self._fc2 is overwritten in produce_fc2
        if self._fc2 is None:
            self._fc2 = fc2

    def cutoff_fc3_by_zero(self, cutoff_distance, fc3=None):
        if fc3 is None:
            _fc3 = self._fc3
        else:
            _fc3 = fc3
        cutoff_fc3_by_zero(
            _fc3,  # overwritten
            self._supercell,
            cutoff_distance,
            self._symprec)

    def set_permutation_symmetry(self):
        if self._fc2 is not None:
            set_permutation_symmetry(self._fc2)
        if self._fc3 is not None:
            set_permutation_symmetry_fc3(self._fc3)

    def set_translational_invariance(self):
        if self._fc2 is not None:
            set_translational_invariance(self._fc2)
        if self._fc3 is not None:
            set_translational_invariance_fc3(self._fc3)

    @property
    def version(self):
        return __version__

    def get_version(self):
        return self.version

    def get_interaction_strength(self):
        return self._interaction

    @property
    def fc2(self):
        return self._fc2

    def get_fc2(self):
        return self.fc2

    @fc2.setter
    def fc2(self, fc2):
        self._fc2 = fc2

    def set_fc2(self, fc2):
        self.fc2 = fc2

    @property
    def fc3(self):
        return self._fc3

    def get_fc3(self):
        return self.fc3

    @fc3.setter
    def fc3(self, fc3):
        self._fc3 = fc3

    def set_fc3(self, fc3):
        self.fc3 = fc3

    @property
    def nac_params(self):
        return self._nac_params

    def get_nac_params(self):
        return self.nac_params

    @property
    def primitive(self):
        return self._primitive

    def get_primitive(self):
        return self.primitive

    @property
    def unitcell(self):
        return self._unitcell

    def get_unitcell(self):
        return self.unitcell

    @property
    def supercell(self):
        return self._supercell

    def get_supercell(self):
        return self.supercell

    @property
    def phonon_supercell(self):
        return self._phonon_supercell

    def get_phonon_supercell(self):
        return self.phonon_supercell

    @property
    def phonon_primitive(self):
        return self._phonon_primitive

    def get_phonon_primitive(self):
        return self.phonon_primitive

    @property
    def symmetry(self):
        """return symmetry of supercell"""
        return self._symmetry

    def get_symmetry(self):
        return self.symmetry

    @property
    def primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self._primitive_symmetry

    def get_primitive_symmetry(self):
        """return symmetry of primitive cell"""
        return self.primitive_symmetry

    @property
    def phonon_supercell_symmetry(self):
        return self._phonon_supercell_symmetry

    def get_phonon_supercell_symmetry(self):
        return self.phonon_supercell_symmetry

    @property
    def supercell_matrix(self):
        return self._supercell_matrix

    def get_supercell_matrix(self):
        return self.supercell_matrix

    @property
    def phonon_supercell_matrix(self):
        return self._phonon_supercell_matrix

    def get_phonon_supercell_matrix(self):
        return self.phonon_supercell_matrix

    @property
    def primitive_matrix(self):
        return self._primitive_matrix

    def get_primitive_matrix(self):
        return self.primitive_matrix

    @property
    def unit_conversion_factor(self):
        return self._frequency_factor_to_THz

    def set_displacement_dataset(self, dataset):
        self._displacement_dataset = dataset

    @property
    def dataset(self):
        return self._displacement_dataset

    @property
    def displacement_dataset(self):
        return self.dataset

    def get_displacement_dataset(self):
        return self.displacement_dataset

    @property
    def phonon_displacement_dataset(self):
        return self._phonon_displacement_dataset

    def get_phonon_displacement_dataset(self):
        return self.phonon_displacement_dataset

    @property
    def supercells_with_displacements(self):
        if self._supercells_with_displacements is None:
            self._build_supercells_with_displacements()
        return self._supercells_with_displacements

    def get_supercells_with_displacements(self):
        return self.supercells_with_displacements

    @property
    def phonon_supercells_with_displacements(self):
        if self._phonon_supercells_with_displacements is None:
            if self._phonon_displacement_dataset is not None:
                self._phonon_supercells_with_displacements = \
                  self._build_phonon_supercells_with_displacements(
                      self._phonon_supercell,
                      self._phonon_displacement_dataset)
        return self._phonon_supercells_with_displacements

    def get_phonon_supercells_with_displacements(self):
        return self.phonon_supercells_with_displacements

    @property
    def mesh_numbers(self):
        return self._mesh_numbers

    def run_imag_self_energy(self,
                             grid_points,
                             frequency_step=None,
                             num_frequency_points=None,
                             temperatures=None,
                             scattering_event_class=None,
                             write_gamma_detail=False,
                             output_filename=None):
        if self._interaction is None:
            self.set_phph_interaction()
        if temperatures is None:
            temperatures = [0.0, 300.0]
        self._grid_points = grid_points
        self._temperatures = temperatures
        self._scattering_event_class = scattering_event_class
        self._imag_self_energy, self._frequency_points = get_imag_self_energy(
            self._interaction,
            grid_points,
            self._sigmas,
            frequency_step=frequency_step,
            num_frequency_points=num_frequency_points,
            temperatures=temperatures,
            scattering_event_class=scattering_event_class,
            write_detail=write_gamma_detail,
            output_filename=output_filename,
            log_level=self._log_level)

    def write_imag_self_energy(self, filename=None):
        write_imag_self_energy(
            self._imag_self_energy,
            self._mesh_numbers,
            self._grid_points,
            self._band_indices,
            self._frequency_points,
            self._temperatures,
            self._sigmas,
            scattering_event_class=self._scattering_event_class,
            filename=filename,
            is_mesh_symmetry=self._is_mesh_symmetry)

    def run_thermal_conductivity(
            self,
            is_LBTE=False,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            is_isotope=False,
            mass_variances=None,
            grid_points=None,
            boundary_mfp=None,  # in micrometre
            solve_collective_phonon=False,
            use_ave_pp=False,
            gamma_unit_conversion=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            is_reducible_collision_matrix=False,
            is_kappa_star=True,
            gv_delta_q=None,  # for group velocity
            is_full_pp=False,
            pinv_cutoff=1.0e-8,  # for pseudo-inversion of collision matrix
            pinv_solver=0,  # solver of pseudo-inversion of collision matrix
            write_gamma=False,
            read_gamma=False,
            is_N_U=False,
            write_kappa=False,
            write_gamma_detail=False,
            write_collision=False,
            read_collision=False,
            write_pp=False,
            read_pp=False,
            write_LBTE_solution=False,
            compression=None,
            input_filename=None,
            output_filename=None):
        if self._interaction is None:
            self.set_phph_interaction()
        if is_LBTE:
            self._thermal_conductivity = get_thermal_conductivity_LBTE(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                sigma_cutoff=self._sigma_cutoff,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                solve_collective_phonon=solve_collective_phonon,
                is_reducible_collision_matrix=is_reducible_collision_matrix,
                is_kappa_star=is_kappa_star,
                gv_delta_q=gv_delta_q,
                is_full_pp=is_full_pp,
                pinv_cutoff=pinv_cutoff,
                pinv_solver=pinv_solver,
                write_collision=write_collision,
                read_collision=read_collision,
                write_kappa=write_kappa,
                write_pp=write_pp,
                read_pp=read_pp,
                write_LBTE_solution=write_LBTE_solution,
                compression=compression,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)
        else:
            self._thermal_conductivity = get_thermal_conductivity_RTA(
                self._interaction,
                self._primitive_symmetry,
                temperatures=temperatures,
                sigmas=self._sigmas,
                sigma_cutoff=self._sigma_cutoff,
                is_isotope=is_isotope,
                mass_variances=mass_variances,
                grid_points=grid_points,
                boundary_mfp=boundary_mfp,
                use_ave_pp=use_ave_pp,
                gamma_unit_conversion=gamma_unit_conversion,
                mesh_divisors=mesh_divisors,
                coarse_mesh_shifts=coarse_mesh_shifts,
                is_kappa_star=is_kappa_star,
                gv_delta_q=gv_delta_q,
                is_full_pp=is_full_pp,
                write_gamma=write_gamma,
                read_gamma=read_gamma,
                is_N_U=is_N_U,
                write_kappa=write_kappa,
                write_pp=write_pp,
                read_pp=read_pp,
                write_gamma_detail=write_gamma_detail,
                compression=compression,
                input_filename=input_filename,
                output_filename=output_filename,
                log_level=self._log_level)

    def get_frequency_shift(self,
                            grid_points,
                            temperatures=np.arange(0, 1001, 10,
                                                   dtype='double'),
                            epsilons=None,
                            output_filename=None):
        """Frequency shift from lowest order diagram is calculated.

        Args:
            epslins(list of float):
               The value to avoid divergence. When multiple values are given
               frequency shifts for those values are returned.

        """

        if self._interaction is None:
            self.set_phph_interaction()
        if epsilons is None:
            _epsilons = [0.1]
        else:
            _epsilons = epsilons
        self._grid_points = grid_points
        get_frequency_shift(self._interaction,
                            self._grid_points,
                            self._band_indices,
                            _epsilons,
                            temperatures,
                            output_filename=output_filename,
                            log_level=self._log_level)

    def _search_symmetry(self):
        self._symmetry = Symmetry(self._supercell, self._symprec,
                                  self._is_symmetry)

    def _search_primitive_symmetry(self):
        self._primitive_symmetry = Symmetry(self._primitive, self._symprec,
                                            self._is_symmetry)
        if (len(self._symmetry.get_pointgroup_operations()) != len(
                self._primitive_symmetry.get_pointgroup_operations())):
            print("Warning: point group symmetries of supercell and primitive"
                  "cell are different.")

    def _search_phonon_supercell_symmetry(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell_symmetry = self._symmetry
        else:
            self._phonon_supercell_symmetry = Symmetry(self._phonon_supercell,
                                                       self._symprec,
                                                       self._is_symmetry)

    def _build_supercell(self):
        self._supercell = get_supercell(self._unitcell, self._supercell_matrix,
                                        self._symprec)

    def _build_primitive_cell(self):
        """
        primitive_matrix:
          Relative axes of primitive cell to the input unit cell.
          Relative axes to the supercell is calculated by:
             supercell_matrix^-1 * primitive_matrix
          Therefore primitive cell lattice is finally calculated by:
             (supercell_lattice * (supercell_matrix)^-1 * primitive_matrix)^T
        """
        self._primitive = self._get_primitive_cell(self._supercell,
                                                   self._supercell_matrix,
                                                   self._primitive_matrix)

    def _build_phonon_supercell(self):
        """
        phonon_supercell:
          This supercell is used for harmonic phonons (frequencies,
          eigenvectors, group velocities, ...)
        phonon_supercell_matrix:
          Different supercell size can be specified.
        """
        if self._phonon_supercell_matrix is None:
            self._phonon_supercell = self._supercell
        else:
            self._phonon_supercell = get_supercell(
                self._unitcell, self._phonon_supercell_matrix, self._symprec)

    def _build_phonon_primitive_cell(self):
        if self._phonon_supercell_matrix is None:
            self._phonon_primitive = self._primitive
        else:
            self._phonon_primitive = self._get_primitive_cell(
                self._phonon_supercell, self._phonon_supercell_matrix,
                self._primitive_matrix)
            if (self._primitive is not None
                    and (self._primitive.get_atomic_numbers() !=
                         self._phonon_primitive.get_atomic_numbers()).any()):
                print(" Primitive cells for fc2 and fc3 can be different.")
                raise RuntimeError

    def _build_phonon_supercells_with_displacements(self, supercell,
                                                    displacement_dataset):
        supercells = []
        magmoms = supercell.get_magnetic_moments()
        masses = supercell.get_masses()
        numbers = supercell.get_atomic_numbers()
        lattice = supercell.get_cell()

        for disp1 in displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            positions = supercell.get_positions()
            positions[disp1['number']] += disp_cart1
            supercells.append(
                Atoms(numbers=numbers,
                      masses=masses,
                      magmoms=magmoms,
                      positions=positions,
                      cell=lattice,
                      pbc=True))

        return supercells

    def _build_supercells_with_displacements(self):
        supercells = []
        magmoms = self._supercell.get_magnetic_moments()
        masses = self._supercell.get_masses()
        numbers = self._supercell.get_atomic_numbers()
        lattice = self._supercell.get_cell()

        supercells = self._build_phonon_supercells_with_displacements(
            self._supercell, self._displacement_dataset)

        for disp1 in self._displacement_dataset['first_atoms']:
            disp_cart1 = disp1['displacement']
            for disp2 in disp1['second_atoms']:
                if 'included' in disp2:
                    included = disp2['included']
                else:
                    included = True
                if included:
                    positions = self._supercell.get_positions()
                    positions[disp1['number']] += disp_cart1
                    positions[disp2['number']] += disp2['displacement']
                    supercells.append(
                        Atoms(numbers=numbers,
                              masses=masses,
                              magmoms=magmoms,
                              positions=positions,
                              cell=lattice,
                              pbc=True))
                else:
                    supercells.append(None)

        self._supercells_with_displacements = supercells

    def _get_primitive_cell(self, supercell, supercell_matrix,
                            primitive_matrix):
        inv_supercell_matrix = np.linalg.inv(supercell_matrix)
        if primitive_matrix is None:
            t_mat = inv_supercell_matrix
        else:
            t_mat = np.dot(inv_supercell_matrix, primitive_matrix)

        return get_primitive(supercell, t_mat, self._symprec)

    def _guess_primitive_matrix(self):
        return guess_primitive_matrix(self._unitcell, symprec=self._symprec)

    def _set_masses(self, masses):
        p_masses = np.array(masses)
        self._primitive.set_masses(p_masses)
        p2p_map = self._primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[
            p2p_map[x]
            for x in self._primitive.get_supercell_to_primitive_map()
        ]]
        self._supercell.set_masses(s_masses)
        u2s_map = self._supercell.get_unitcell_to_supercell_map()
        u_masses = s_masses[u2s_map]
        self._unitcell.set_masses(u_masses)

        self._phonon_primitive.set_masses(p_masses)
        p2p_map = self._phonon_primitive.get_primitive_to_primitive_map()
        s_masses = p_masses[[
            p2p_map[x]
            for x in self._phonon_primitive.get_supercell_to_primitive_map()
        ]]
        self._phonon_supercell.set_masses(s_masses)

    def _set_mesh_numbers(self, mesh):
        _mesh = np.array(mesh)
        mesh_nums = None
        if _mesh.shape:
            if _mesh.shape == (3, ):
                mesh_nums = mesh
        elif self._primitive_symmetry is None:
            mesh_nums = length2mesh(mesh, self._primitive.get_cell())
        else:
            rotations = self._primitive_symmetry.get_pointgroup_operations()
            mesh_nums = length2mesh(mesh,
                                    self._primitive.get_cell(),
                                    rotations=rotations)
        if mesh_nums is None:
            msg = "mesh has inappropriate type."
            raise TypeError(msg)
        self._mesh_numbers = mesh_nums
コード例 #34
0
class Interaction:
    def __init__(self,
                 fc3,
                 supercell,
                 primitive,
                 mesh,
                 band_indices=None,
                 frequency_factor_to_THz=VaspToTHz,
                 is_nosym=False,
                 symmetrize_fc3_q=False,
                 symprec=1e-3,
                 triplet_cut_super = None,
                 triplet_cut_prim = None,
                 cutoff_frequency=None,
                 cutoff_hfrequency=None,
                 cutoff_delta = None,
                 is_triplets_dispersed=False,
                 is_read_amplitude=False,
                 is_write_amplitude = False,
                 is_triplets_permute=True,
                 lapack_zheev_uplo='L'):
        self._fc3 = fc3
        self._supercell = supercell
        self._primitive = primitive
        self._mesh = np.intc(mesh)
        num_band = primitive.get_number_of_atoms() * 3
        if band_indices is None:
            self._band_indices = np.arange(num_band, dtype='intc')
        else:
            self._band_indices = band_indices.astype("intc")
        self._frequency_factor_to_THz = frequency_factor_to_THz
        self._symprec = symprec
        self._is_tripelts_permute=is_triplets_permute
        natom_super = supercell.get_number_of_atoms()
        natom_prim = primitive.get_number_of_atoms()
        if triplet_cut_super is None:
            self._triplet_cut_super=np.zeros((natom_super, natom_super, natom_super), dtype='bool')
        else:
            self._triplet_cut_super=triplet_cut_super

        if triplet_cut_prim is None:
            self._triplet_cut_prim=np.zeros((natom_prim, natom_prim, natom_prim), dtype='bool')
        else:
            self._triplet_cut_prim=triplet_cut_prim

        if cutoff_delta is None:
            self._cutoff_delta = 1000.0
        else:
            self._cutoff_delta = cutoff_delta

        if cutoff_frequency is None:
            self._cutoff_frequency = 0
        else:
            self._cutoff_frequency = cutoff_frequency

        if cutoff_hfrequency is None:
            self._cutoff_hfrequency = 10000.0 # THz
        elif symmetrize_fc3_q:
            print "Warning: symmetryze_fc3_q and cutoff_hfrequency are not compatible"
            self._cutoff_hfrequency = 10000.0
        else:
            self._cutoff_hfrequency = cutoff_hfrequency
        self._is_nosym = is_nosym
        self._symmetrize_fc3_q = symmetrize_fc3_q
        self._lapack_zheev_uplo = lapack_zheev_uplo
        self._symmetry = Symmetry(primitive, symprec=symprec)
        if self._is_nosym:
            self._point_group_operations = np.array([np.eye(3)],dtype="intc")
            self._kpoint_operations = get_kpoint_group(self._mesh, self._point_group_operations, is_time_reversal=False)
        else:
            self._point_group_operations = self._symmetry.get_pointgroup_operations()
            self._kpoint_operations = get_kpoint_group(self._mesh, self._point_group_operations)

        if self.is_nosym():
            grid_mapping = np.arange(np.prod(self._mesh))
            grid_mapping_rots = np.zeros(len(grid_mapping), dtype="intc")
        else:
            grid_mapping, grid_mapping_rots = get_mappings(self._mesh,
                                        self.get_point_group_operations(),
                                        qpoints=np.array([0,0,0],dtype="double"))

        self._svecs, self._multiplicity = get_smallest_vectors(self._supercell,
                                                                 self._primitive,
                                                                 self._symprec)
        self._grid_mapping = grid_mapping
        self._grid_mapping_rot = grid_mapping_rots

        self._is_read_amplitude = is_read_amplitude
        self._is_write_amplitude = is_write_amplitude
        self._grid_point = None
        self._triplets_at_q = None
        self._weights_at_q = None
        self._grid_address = None
        self._interaction_strength = None
        self._phonon_done = None
        self._frequencies = None
        self._eigenvectors = None
        self._degenerates = None
        self._grid_points = None
        self._dm = None
        self._nac_q_direction = None
        self._triplets = None
        self._triplets_mappings = None
        self._triplets_sequence = None
        self._unique_triplets = None
        self._amplitude_all = None
        self._is_dispersed = is_triplets_dispersed
        self._allocate_phonon()

    def set_is_write_amplitude(self, is_write_amplitude=False):
        self._is_write_amplitude = is_write_amplitude

    def get_is_write_amplitude(self):
        return self._is_write_amplitude

    def set_is_read_amplitude(self, is_read_amplitude=False):
        self._is_read_amplitude = is_read_amplitude

    def get_is_read_amplitude(self):
        return self._is_read_amplitude

    def get_is_dispersed(self):
        return self._is_dispersed

    def get_degeneracy(self):
        return self._degenerates

    def get_amplitude_all(self):
        return self._amplitude_all

    def set_is_disperse(self, is_disperse):
        self._is_dispersed = is_disperse

    def set_is_symmetrize_fc3_q(self, is_symmetrize_fc3q):
        self._symmetrize_fc3_q = is_symmetrize_fc3q

    def get_is_symmetrize_fc3_q(self):
        return self._symmetrize_fc3_q

    def run(self, g_skip=None, lang='C', log_level=0):
        num_band = self._primitive.get_number_of_atoms() * 3
        num_triplets = len(self._triplets_at_q)
        self._interaction_strength = np.zeros(
            (num_triplets, len(self._band_indices), num_band, num_band),
            dtype='double')
        if self._is_dispersed:
            unitrip_indices = self._triplets_uniq_index_at_grid
            mapping = self._triplets_maping_at_grid
            triplets_sequence = self._triplet_sequence_at_grid
            if log_level>0:
                print "Triplets number to be calculated: %d/%d" %(len(unitrip_indices), len(self._interaction_strength))

            if self._is_read_amplitude:
                self._interaction_strength_reduced = \
                    read_amplitude_from_hdf5_at_grid(self._mesh, self._grid_point)
                if self._interaction_strength_reduced is not None:
                    self.set_phonons(lang=lang)
                else:
                    print "Reading amplitude in the disperse mode unsuccessfully. Reverting to writing mode!"
                    self._is_read_amplitude = False
                    self._is_write_amplitude = True

            if not self._is_read_amplitude:
                self._interaction_strength_reduced = np.zeros(
                    (len(self._triplets_uniq_index_at_grid), len(self._band_indices), num_band, num_band),
                    dtype='double')
                self._triplets_at_q_reduced = self._triplets_at_q[unitrip_indices].copy()
                if g_skip is None:
                    g_skip = np.zeros_like(self._interaction_strength_reduced, dtype="bool")


                if lang == 'C':
                    self._run_c(g_skip=g_skip)
                else:
                    self._run_py(g_skip=g_skip)

            import anharmonic._phono3py as phono3c
            if len(self._band_indices) != self._interaction_strength.shape[-1]:
                assert (triplets_sequence[:,0] == 0).all()
            phono3c.interaction_from_reduced(self._interaction_strength,
                                         self._interaction_strength_reduced.astype("double").copy(),
                                         mapping.astype("intc"),
                                         triplets_sequence.astype("byte"))
            #debugging
            # interaction_strength = self._interaction_strength.copy()
            # interaction_strength_reduced = self._interaction_strength_reduced.copy()
            # self._interaction_strength_reduced = np.zeros(
            #         (len(self._triplets_at_q), len(self._band_indices), num_band, num_band),
            #         dtype='double')
            # self._triplets_at_q_reduced = self._triplets_at_q
            # self._run_c()
            # self._interaction_strength = self._interaction_strength_reduced.copy()
            # print np.abs(self._interaction_strength_reduced - interaction_strength).max() / self._interaction_strength_reduced.max(),
            # print np.unravel_index(np.abs(self._interaction_strength_reduced - interaction_strength).argmax(), self._interaction_strength_reduced.shape)

            if self._is_write_amplitude:
                write_amplitude_to_hdf5_at_grid(self._mesh, grid=self._grid_point, amplitude=self._interaction_strength_reduced)


        else:
            if self._is_read_amplitude:
                import anharmonic._phono3py as phono3c
                phono3c.interaction_from_reduced(self._interaction_strength,
                                                 self._amplitude_all,
                                                 self._triplets_mappings[self._i].astype("intc"),
                                                 self._triplets_sequence[self._i].astype("byte"))
                self.set_phonons(lang=lang)
            else:
                map_to_unique, reverse_map = np.unique(self._triplets_mappings[self._i], return_inverse=True)
                undone_num = np.extract(self._triplets_done[map_to_unique]==0, map_to_unique)
                self._triplets_at_q_reduced = self._unique_triplets[undone_num]

                if log_level>0:
                    print "Triplets number to be calculted: %d/%d" %(len(self._triplets_at_q_reduced), len(self._interaction_strength))

                self._interaction_strength_reduced = np.zeros(
                    (len(self._triplets_at_q_reduced), len(self._band_indices), num_band, num_band),
                    dtype='double')
                if g_skip is None:
                    g_skip = np.zeros_like(self._interaction_strength_reduced, dtype="bool")
                if lang == 'C':
                    self._run_c(g_skip=g_skip)
                else:
                    self._run_py(g_skip=g_skip)
                self._amplitude_all[undone_num] = self._interaction_strength_reduced[:]
                import anharmonic._phono3py as phono3c
                phono3c.interaction_from_reduced(self._interaction_strength,
                                                 self._amplitude_all,
                                                 self._triplets_mappings[self._i].astype("intc"),
                                                 self._triplets_sequence[self._i].astype("byte"))
                self._triplets_done[undone_num] = True

        ##Added for my own purpose, please delete it
        self._criteria = 0.55
        self._lcriteria = 0.1
        is_anyq_on_bound = (np.abs(self._grid_address[self._triplets_at_q]) > self._criteria * self._mesh).any(axis=(1,2))
        is_uprocess = np.any(self._grid_address[self._triplets_at_q].sum(axis=1)!=0, axis=1)
        is_anyq_at_center = (np.abs(self._grid_address[self._triplets_at_q]) < self._lcriteria * self._mesh).any(axis=(1,2))
        self._interaction_strength[np.where(np.logical_and(is_uprocess, is_anyq_at_center))] = 0.
        self._interaction_strength[np.where(is_anyq_on_bound)] = 0.

    # @total_time.timeit
    def set_phonons(self, grid_points=None, lang = "C"):
        if lang == "C":
            self._set_phonon_c(grid_points)
        else:
            if grid_points is None:
                for i, grid_triplet in enumerate(self._triplets_at_q):
                    for gp in grid_triplet:
                        self._set_phonon_py(gp)
            else:
                for gp in enumerate(grid_points):
                    self._set_phonon_py(gp)

    def set_phonons_all(self, is_band_connection=True, lang='C', log_level=1):
        if log_level:
            print "calculate phonon frequencies of all phonon mode..."
        grid_points = np.arange(len(self._grid_address))
        if lang == "C":
            self._set_phonon_c(grid_points)
        else:
            for gp in grid_points:
                self._set_phonon_py(gp)
        if is_band_connection:
            self._set_band_connection()

    def _set_band_connection(self):
        nqpoint, nband = self._frequencies.shape
        is_non_degenerate = np.all(self._degenerates == np.arange(nband), axis=1)
        connect_done = np.zeros(nqpoint, dtype='bool')
        start = np.where(is_non_degenerate)[0][0]

        while True:
            connect_done[start] = True
            neighbors = np.argsort(np.sum(np.abs(self._grid_address - self._grid_address[start]), axis=1))
            undone = np.extract(connect_done[neighbors]==False, neighbors)

            if not (len(undone) == 0 or (is_non_degenerate[undone] == False).all()):
                new = np.extract(is_non_degenerate[undone], undone)[0]
                new_neighbors = np.argsort(np.sum(np.abs(self._grid_address - self._grid_address[new]), axis=1))
                new_neighbor_done = np.extract(connect_done[new_neighbors], new_neighbors)[0]
                bo = estimate_band_connection(self._eigenvectors[new_neighbor_done],
                                              self._eigenvectors[new],
                                              np.arange(nband))
                if bo is not None:
                    self._frequencies[new] = (self._frequencies[new])[bo]
                    self._eigenvectors[new] = (self._eigenvectors[new].T)[bo].T
                    # Since all the phonons here are non-degenerate, the step is missed
                start = new

            else:
                break

        for new in undone:
            new_neighbors = np.argsort(np.sum(np.abs(self._grid_address - self._grid_address[new]), axis=1))
            new_neighbor_done = np.extract(connect_done[new_neighbors], new_neighbors)[0]
            deg = [np.where(self._degenerates[new] == j)[0] for j in np.unique(self._degenerates[new])]
            bo = estimate_band_connection(self._eigenvectors[new_neighbor_done],
                                          self._eigenvectors[new],
                                          np.arange(nband),
                                          degenerate_sets=deg)
            if bo is not None:
                self._frequencies[new] = (self._frequencies[new])[bo]
                self._eigenvectors[new] = (self._eigenvectors[new].T)[bo].T
                self._degenerates[new] = (self._degenerates[new])[bo].copy()

    def get_interaction_strength(self):
        return self._interaction_strength

    def get_mesh_numbers(self):
        return self._mesh

    def get_phonons(self):
        return (self._frequencies,
                self._eigenvectors,
                self._phonon_done)

    def get_dynamical_matrix(self):
        return self._dm

    def get_primitive(self):
        return self._primitive

    def get_supercell(self):
        return self._supercell

    def get_point_group_operations(self):
        return self._point_group_operations

    def get_triplets_at_q(self):
        return self._triplets_at_q, self._weights_at_q

    def get_triplets_done(self):
        return self._triplets_done

    def get_triplets_sequence_at_q_disperse(self):
        return self._triplet_sequence_at_grid

    def get_triplets_mapping_at_q_disperse(self):
        return self._triplets_maping_at_grid

    def get_triplets_at_q_nu(self):
        triplet_address = self.get_triplet_address()
        triplets_N=[]
        triplets_U=[]
        for i, t in enumerate(triplet_address):
            if (np.sum(t, axis=0)==0).all():
                triplets_N.append(i)
            else:
                triplets_U.append(i)
        return (triplets_N, triplets_U)
    def get_triplet_address(self):
        return self._triplets_address
    def get_grid_address(self):
        return self._grid_address

    def get_band_indices(self):
        return self._band_indices

    def get_frequency_factor_to_THz(self):
        return self._frequency_factor_to_THz

    def get_lapack_zheev_uplo(self):
        return self._lapack_zheev_uplo

    def is_nosym(self):
        return self._is_nosym

    def get_bz_map(self):
        return self._bz_map

    def get_bz_to_pp_map(self):
        return self._bz_to_pp_map

    def get_grid_mapping(self):
        return self._grid_mapping

    def get_grid_mapping_rot(self):
        return self._grid_mapping_rot

    def get_cutoff_frequency(self):
        return self._cutoff_frequency

    def get_cutoff_hfrequency(self):
        return self._cutoff_hfrequency

    def get_triplets_mapping_at_grid(self):
        if not self._is_dispersed:
            return self._triplets_mappings[self._i]
        else:
            return self._triplets_maping_at_grid

    def get_triplets_sequence_at_grid(self):
        return self._triplets_sequence[self._i]

    @total_time.timeit
    def set_grid_point(self, grid_point, i=None, stores_triplets_map=False):
        if i==None:
            self._grid_point = grid_point
            if self._grid_points is not None:
                self._i = np.where(grid_point == self._grid_points)[0][0]
        else:
            self._i = i
            self._grid_point = self._grid_points[i]
        if self._triplets is not None:
            self._triplets_at_q = self._triplets[self._i]
            self._weights_at_q = self._weights[self._i]
            self._triplets_address = self._grid_address[self._triplets_at_q]
            if self._is_dispersed:
                self._triplets_uniq_index_at_grid = self._unique_triplets[self._i]
                self._triplets_maping_at_grid = self._triplets_mappings[self._i]
                self._triplet_sequence_at_grid = self._triplets_sequence[self._i]
        else:
            reciprocal_lattice = np.linalg.inv(self._primitive.get_cell())
            if self._is_nosym:
                (triplets_at_q,
                 weights_at_q,
                 grid_address,
                 bz_map,
                 triplets_map_at_q,
                 ir_map_at_q) = get_nosym_triplets_at_q(
                     grid_point,
                     self._mesh,
                     reciprocal_lattice,
                     stores_triplets_map=stores_triplets_map)
                if self._is_dispersed:
                    self._triplets_uniq_index_at_grid = np.arange(len(triplets_at_q), dtype="intc")
                    self._triplets_maping_at_grid = np.arange(len(triplets_at_q), dtype="intc")
                    self._triplet_sequence_at_grid = np.arange(3, dtype="intc")[np.newaxis].repeat(len(triplets_at_q))

            else:
                (triples_at_q_crude,
                 weights_at_q,
                 grid_address,
                 grid_map)=\
                    get_triplets_at_q_crude(grid_point, self._mesh, self._point_group_operations)

                (triplets_at_q,
                 weights,
                 bz_grid_address,
                 bz_map)=\
                    get_BZ_triplets_at_q(grid_point, self._mesh, reciprocal_lattice, grid_address, grid_map)

                if self._is_dispersed:
                    (unique_triplet_nums,
                     triplets_mappings,
                     triplet_sequence) = \
                        reduce_triplets_by_permutation_symmetry([triples_at_q_crude],
                                                                self._mesh,
                                                                first_mapping=self._grid_mapping,
                                                                first_rotation=self._kpoint_operations[self._grid_mapping_rot],
                                                                second_mapping=np.array([grid_map]))
                    self._triplets_uniq_index_at_grid = unique_triplet_nums
                    self._triplets_maping_at_grid = triplets_mappings[0]
                    self._triplet_sequence_at_grid = triplet_sequence[0]
            sum_qs = bz_grid_address[triplets_at_q].sum(axis=1)
            resi = sum_qs % self._mesh
            if (resi != 0).any():
                triplets = triplets_at_q[np.where(resi != 0)[0]]
                print "============= Warning =================="
                print triplets
                print sum_qs
                print "============= Warning =================="

            self._triplets_at_q = triplets_at_q
            self._weights_at_q = weights_at_q
            self._ir_map_at_q = grid_map

    def set_grid_points(self, grid_points):
        self._grid_points = grid_points
        reciprocal_lattice = np.linalg.inv(self._primitive.get_cell())
        self._triplets = []
        self._weights = []
        second_mappings = []
        self._triplets_sequence = []
        crude_triplets = []
        total_triplet_num = 0
        # unique triplets at all grid points
        self._unique_triplets = []
        self._triplets_mappings = []
        self._triplets_sequence = []
        for g, grid_point in enumerate(grid_points):
            (triples_at_q_crude,
             weights_at_q,
             grid_address,
             grid_map)=\
                get_triplets_at_q_crude(grid_point, self._mesh, self._point_group_operations)

            (triplets_at_q,
             weights,
             bz_grid_address,
             bz_map)=\
                get_BZ_triplets_at_q(grid_point, self._mesh, reciprocal_lattice, grid_address, grid_map)

            crude_triplets.append(triples_at_q_crude)
            self._triplets.append(triplets_at_q)
            self._weights.append(weights_at_q)
            total_triplet_num += len(triplets_at_q)
            second_mappings.append(grid_map)

            if self._is_dispersed:
                (unique_triplet_nums_grid,
                 triplets_mappings_grid,
                 triplet_sequence_grid) = \
                    reduce_triplets_by_permutation_symmetry([triples_at_q_crude],
                                                            self._mesh,
                                                            first_mapping=self._grid_mapping,
                                                            first_rotation=self._kpoint_operations[self._grid_mapping_rot],
                                                            second_mapping=np.array([grid_map]))
                self._unique_triplets.append(unique_triplet_nums_grid)
                self._triplets_mappings.append(triplets_mappings_grid[0])
                self._triplets_sequence.append(triplet_sequence_grid[0])

        if not self._is_dispersed:
            unique_triplet_num, triplets_mappings, triplet_sequence = reduce_triplets_by_permutation_symmetry(crude_triplets,
                                                    self._mesh,
                                                    first_mapping=self._grid_mapping,
                                                    first_rotation=self._kpoint_operations[self._grid_mapping_rot],
                                                    second_mapping=np.vstack(second_mappings))

            print "Number of total unique triplets after permutation symmetry: %d/ %d" %(len(unique_triplet_num), total_triplet_num)
            self._unique_triplets = np.vstack(self._triplets)[unique_triplet_num]
            self._triplets_done = np.zeros(len(unique_triplet_num), dtype="byte")
            self._triplets_mappings = triplets_mappings #map to the index of the triplets in the unique_triplet_num
            self._second_mappings = second_mappings
            self._triplets_sequence = triplet_sequence
            nband = 3 * self._primitive.get_number_of_atoms()
            try:
                self._amplitude_all = np.zeros((len(self._unique_triplets), nband, nband, nband), dtype="double")
            except MemoryError:
                print "A memory error occurs in allocating the whole interaction strength array"
                print "--disperse is recommended as an alternative method"
                sys.exit(1)
        if self._is_read_amplitude:
            self.read_amplitude_all()

    def read_amplitude_all(self):
        if not self._is_dispersed:
            read_amplitude_from_hdf5_all(self._amplitude_all, self._mesh, self.is_nosym())

    def release_amplitude_all(self):
        del self._amplitude_all
        self._amplitude_all = None

    def set_dynamical_matrix(self,
                             fc2,
                             supercell,
                             primitive,
                             nac_params=None,
                             frequency_scale_factor=None,
                             decimals=None):
        self._dm = get_dynamical_matrix(
            fc2,
            supercell,
            primitive,
            nac_params=nac_params,
            frequency_scale_factor=frequency_scale_factor,
            decimals=decimals,
            symprec=self._symprec)

    def set_nac_q_direction(self, nac_q_direction=None):
        if nac_q_direction is not None:
            self._nac_q_direction = np.double(nac_q_direction)

    def _run_c(self, g_skip=None):
        import anharmonic._phono3py as phono3c
        if g_skip is None:
            g_skip = np.zeros_like(self._interaction_strength_reduced, dtype="bool")
        assert g_skip.shape == self._interaction_strength_reduced.shape
        self._set_phonon_c()
        masses = np.double(self._primitive.get_masses())
        p2s = np.intc(self._primitive.get_primitive_to_supercell_map())
        s2p = np.intc(self._primitive.get_supercell_to_primitive_map())
        atc=np.intc(self._triplet_cut_super) # int type
        atc_prim = np.intc(self._triplet_cut_prim) # int type
        phono3c.interaction(self._interaction_strength_reduced,
                            self._frequencies,
                            self._eigenvectors,
                            self._triplets_at_q_reduced.copy(),
                            self._grid_address,
                            self._mesh,
                            self._fc3,
                            atc,
                            atc_prim,
                            g_skip,
                            self._svecs,
                            self._multiplicity,
                            np.double(masses),
                            p2s,
                            s2p,
                            self._band_indices,
                            self._symmetrize_fc3_q,
                            self._cutoff_frequency,
                            self._cutoff_hfrequency,
                            self._cutoff_delta)
        phono3c.interaction_degeneracy_grid(self._interaction_strength_reduced,
                                            self._degenerates,
                                            self._triplets_at_q_reduced.astype('intc').copy(),
                                            self._band_indices.astype('intc'))
        # from itertools import permutations
        # interaction = np.zeros((6,) + self._interaction_strength_reduced.shape, dtype='double')
        # for i, permute in enumerate(permutations((0,1,2))):
        #     interaction0 = np.zeros_like(self._interaction_strength_reduced)
        #     new = ''.join(np.array(list('ijk'))[list(permute)])
        #     phono3c.interaction(interaction0,
        #                         self._frequencies,
        #                         self._eigenvectors,
        #                         self._triplets_at_q_reduced[:, permute].copy(),
        #                         self._grid_address,
        #                         self._mesh,
        #                         self._fc3,
        #                         atc,
        #                         np.zeros_like(g_skip),
        #                         svecs,
        #                         multiplicity,
        #                         np.double(masses),
        #                         p2s,
        #                         s2p,
        #                         self._band_indices,
        #                         False,
        #                         self._cutoff_frequency,
        #                         self._cutoff_hfrequency,
        #                         self._cutoff_delta)
        #     interaction[i,:] = np.einsum("N%s->Nijk"%new, interaction0)
        # diff = np.abs(interaction - interaction[0])
        # print np.unravel_index(diff.argmax(), diff.shape), diff.max()


    def _set_phonon_c(self, grid_points=None):
        import anharmonic._phono3py as phono3c

        svecs, multiplicity = self._dm.get_shortest_vectors()
        masses = np.double(self._dm.get_primitive().get_masses())
        rec_lattice = np.double(
            np.linalg.inv(self._dm.get_primitive().get_cell())).copy()
        if self._dm.is_nac():
            born = self._dm.get_born_effective_charges()
            nac_factor = self._dm.get_nac_factor()
            dielectric = self._dm.get_dielectric_constant()
        else:
            born = None
            nac_factor = 0
            dielectric = None
        if grid_points == None:
            phono3c.phonon_triplets(self._frequencies,
                                    self._eigenvectors,
                                    self._degenerates,
                                    self._phonon_done,
                                    self._triplets_at_q,
                                    self._grid_address,
                                    self._mesh,
                                    self._dm.get_force_constants(),
                                    svecs,
                                    multiplicity,
                                    masses,
                                    self._dm.get_primitive_to_supercell_map(),
                                    self._dm.get_supercell_to_primitive_map(),
                                    self._frequency_factor_to_THz,
                                    born,
                                    dielectric,
                                    rec_lattice,
                                    self._nac_q_direction,
                                    nac_factor,
                                    self._lapack_zheev_uplo)
        else:
            set_phonon_c(self._dm,
                         self._frequencies,
                         self._eigenvectors,
                         self._degenerates,
                         self._phonon_done,
                         grid_points.astype("intc").copy(),
                         self._grid_address,
                         self._mesh,
                         self._frequency_factor_to_THz,
                         self._nac_q_direction,
                         self._lapack_zheev_uplo)

    def _run_py(self, g_skip=None):
        if g_skip is None:
            g_skip = np.zeros_like(self._interaction_strength_reduced, dtype="bool")
        else:
            assert g_skip.shape == self._interaction_strength_reduced.shape
        r2r = RealToReciprocal(self._fc3,
                               self._supercell,
                               self._primitive,
                               self._mesh,
                               symprec=self._symprec,
                               atom_triplet_cut=self._triplet_cut_super)

        r2n = ReciprocalToNormal(self._primitive,
                                 self._frequencies,
                                 self._eigenvectors,
                                 cutoff_frequency=self._cutoff_frequency,
                                 cutoff_hfrequency=self._cutoff_hfrequency,
                                 cutoff_delta=self._cutoff_delta)

        for i, grid_triplet in enumerate(self._triplets_at_q_reduced):
            print "%d / %d" % (i + 1, len(self._triplets_at_q_reduced))
            r2r.run(self._grid_address[grid_triplet], self._symmetrize_fc3_q)
            fc3_reciprocal = r2r.get_fc3_reciprocal()
            for gp in grid_triplet:
                self._set_phonon_py(gp)
            r2n.run(fc3_reciprocal, grid_triplet, g_skip = g_skip[i])
            self._interaction_strength_reduced[i] = r2n.get_reciprocal_to_normal()

    def _set_phonon_py(self, grid_point):
        set_phonon_py(grid_point,
                      self._phonon_done,
                      self._frequencies,
                      self._eigenvectors,
                      self._degenerates,
                      self._grid_address,
                      self._mesh,
                      self._dm,
                      self._frequency_factor_to_THz,
                      self._lapack_zheev_uplo)

    def _allocate_phonon(self):
        primitive_lattice = np.linalg.inv(self._primitive.get_cell())
        self._grid_address, self._bz_map, self._bz_to_pp_map = get_bz_grid_address(
            self._mesh, primitive_lattice, with_boundary=True, is_bz_map_to_pp=True)
        num_band = self._primitive.get_number_of_atoms() * 3
        num_grid = len(self._grid_address)
        self._phonon_done = np.zeros(num_grid, dtype='byte')
        self._frequencies = np.zeros((num_grid, num_band), dtype='double')
        self._degenerates = np.zeros((num_grid, num_band), dtype="intc")
        self._eigenvectors = np.zeros((num_grid, num_band, num_band),
                                      dtype='complex128')


    def write_amplitude_all(self):
        if self.get_is_write_amplitude():
            if self.get_amplitude_all() is not None:
                write_amplitude_to_hdf5_all(self.get_amplitude_all(),
                                            self._mesh,
                                            is_nosym=self.is_nosym())
            self.set_is_read_amplitude(True)
            self.set_is_write_amplitude(False)