Beispiel #1
0
def get_dynamical_matrix(fc2,
                         supercell,
                         primitive,
                         nac_params=None,
                         frequency_scale_factor=None,
                         decimals=None,
                         symprec=1e-5):
    if nac_params is None:
        dm = DynamicalMatrix(
            supercell,
            primitive,
            fc2,
            frequency_scale_factor=frequency_scale_factor,
            decimals=decimals,
            symprec=symprec)
    else:
        dm = DynamicalMatrixNAC(
            supercell,
            primitive,
            fc2,
            frequency_scale_factor=frequency_scale_factor,
            decimals=decimals,
            symprec=symprec)
        dm.set_nac_params(nac_params)
    return dm
Beispiel #2
0
def get_dynamical_matrix(fc2,
                         supercell,
                         primitive,
                         nac_params=None,
                         frequency_scale_factor=None,
                         decimals=None,
                         symprec=1e-5):
    if frequency_scale_factor is None:
        _fc2 = fc2
    else:
        _fc2 = fc2 * frequency_scale_factor ** 2

    if nac_params is None:
        dm = DynamicalMatrix(
            supercell,
            primitive,
            _fc2,
            decimals=decimals,
            symprec=symprec)
    else:
        dm = DynamicalMatrixNAC(
            supercell,
            primitive,
            _fc2,
            decimals=decimals,
            symprec=symprec)
        dm.set_nac_params(nac_params)
    return dm
Beispiel #3
0
    def set_post_process( self,
                          primitive_matrix,
                          set_of_forces=None,
                          force_constants=None,
                          is_nac=False ):
        """
        Set forces to prepare phonon calculations. The order of
        'set_of_forces' has to correspond to that of 'displacements'.

        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

        set_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
             ...                                                   ]
        """

        self.is_nac = is_nac

        if not set_of_forces == None:
            self.set_forces( set_of_forces )
        elif not force_constants == None:
            self.set_force_constants( force_constants )
        elif self.force_constants == None:
            print "In set_post_process, set_of_forces or force_constants"
            print "has to be set."
            sys.exit(1)

        # Primitive cell
        inv_supercell_matrix = np.linalg.inv( self.supercell_matrix )
        self.primitive = Primitive( self.supercell,
                                    np.dot( inv_supercell_matrix, primitive_matrix ),
                                    self.symprec )

        # Dynamical Matrix
        if self.is_nac:
            self.dynamical_matrix = \
                DynamicalMatrixNAC( self.supercell,
                                    self.primitive,
                                    self.force_constants,
                                    symprec=self.symprec )
        else:
            self.dynamical_matrix = \
                DynamicalMatrix( self.supercell,
                                 self.primitive,
                                 self.force_constants,
                                 symprec=self.symprec )
Beispiel #4
0
 def set_dynamical_matrix(self, decimals=None):
     if self._is_nac:
         self._dynamical_matrix = \
             DynamicalMatrixNAC(self._supercell,
                                self._primitive,
                                self._force_constants,
                                decimals=decimals,
                                symprec=self._symprec)
     else:
         self._dynamical_matrix = \
             DynamicalMatrix(self._supercell,
                             self._primitive,
                             self._force_constants,
                             decimals=decimals,
                             symprec=self._symprec)
Beispiel #5
0
 def set_dynamical_matrix(self, decimals=None):
     if self._is_nac:
         self._dynamical_matrix = \
             DynamicalMatrixNAC(self._supercell,
                                self._primitive,
                                self._force_constants,
                                decimals=decimals,
                                symprec=self._symprec)
     else:
         self._dynamical_matrix = \
             DynamicalMatrix(self._supercell,
                             self._primitive,
                             self._force_constants,
                             decimals=decimals,
                             symprec=self._symprec)
Beispiel #6
0
    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
Beispiel #7
0
    def __init__(self,
                 fc2,
                 fc3,
                 supercell,
                 primitive,
                 supercell_extra=None,
                 nac_params=None,
                 nac_q_direction=None,
                 ion_clamped=False,
                 factor=VaspToTHz,
                 symprec=1e-5):
        self._fc2 = fc2
        self._fc3 = fc3
        self._scell = supercell
        if supercell_extra is not None:
            self._scell_extra = supercell_extra
        else:
            self._scell_extra = supercell
        self._pcell = primitive
        self._ion_clamped = ion_clamped
        self._factor = factor
        self._symprec = symprec
        if nac_params is None:
            self._dm = DynamicalMatrix(self._scell_extra,
                                       self._pcell,
                                       self._fc2,
                                       symprec=self._symprec)
        else:
            self._dm = DynamicalMatrixNAC(self._scell_extra,
                                          self._pcell,
                                          self._fc2,
                                          symprec=self._symprec)
            self._dm.set_nac_params(nac_params)
        self._nac_q_direction = nac_q_direction
        self._shortest_vectors, self._multiplicity = get_smallest_vectors(
            self._scell, self._pcell, self._symprec)
        self._shortest_vectors_extra, self._multiplicity_extra = get_smallest_vectors(
            self._scell_extra, self._pcell, self._symprec)

        if self._ion_clamped:
            num_atom_prim = self._pcell.get_number_of_atoms()
            self._X = np.zeros((num_atom_prim, 3, 3, 3), dtype=float)
        else:
            self._X = self._get_X()

        self._dPhidu = self._get_dPhidu()

        self._gruneisen_parameters = None
        self._frequencies = None
        self._qpoints = None
        self._mesh = None
        self._band_paths = None
        self._band_distances = None
        self._run_mode = None
        self._weights = None
Beispiel #8
0
 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)
Beispiel #9
0
    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
Beispiel #10
0
class Phonopy:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 distance=0.01,
                 factor=VaspToTHz,
                 is_auto_displacements=True,
                 symprec=1e-5,
                 is_symmetry=True,
                 log_level=0):
        self._symprec = symprec
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._factor = factor
        self._is_symmetry = is_symmetry
        self._log_level = log_level
        self._supercell = None
        self._set_supercell()
        self._symmetry = None
        self._set_symmetry()

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

        # set_post_process
        self._primitive = None
        self._dynamical_matrix = None
        self._is_nac = False

        # set_force_constants or set_forces
        self._set_of_forces_objects = None
        self._force_constants = None

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = 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_primitive(self):
        return self._primitive

    primitive = property(get_primitive)

    def set_primitive(self, primitive):
        self._primitive = 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 self._symmetry

    symmetry = property(get_symmetry)

    def get_unit_conversion_factor(self):
        return self._factor

    unit_conversion_factor = property(get_unit_conversion_factor)

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

        displacements:
          List of displacements in Cartesian coordinates.
          See 'set_displacements'
        
        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.
                               
        """

        lattice = self._supercell.get_cell()
        self._displacements = []
        self._displacement_directions = \
            get_least_displacements(self._symmetry,
                                    is_plusminus=is_plusminus,
                                    is_diagonal=is_diagonal,
                                    is_trigonal=is_trigonal,
                                    log_level=self._log_level)

        for disp in self._displacement_directions:
            atom_num = disp[0]
            disp_cartesian = np.dot(disp[1:], lattice)
            disp_cartesian *= distance / np.linalg.norm(disp_cartesian)
            self._displacements.append([
                atom_num, disp_cartesian[0], disp_cartesian[1],
                disp_cartesian[2]
            ])

        self._set_supercells_with_displacements()

    def set_displacements(self, displacements):
        """Set displacements manually

        displacemsts: List of disctionaries
           [[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
           
        """

        self._displacements = displacements
        self._set_supercells_with_displacements()

    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):
        return self._supercells_with_displacements

    def set_post_process(self,
                         primitive_matrix=np.eye(3, dtype=float),
                         sets_of_forces=None,
                         set_of_forces_objects=None,
                         force_constants=None,
                         is_nac=False,
                         calculate_full_force_constants=False,
                         force_constants_decimals=None,
                         dynamical_matrix_decimals=None):
        """
        Set forces or force constants to prepare phonon calculations.
        The order of 'sets_of_forces' has to correspond to that of
        'displacements' that should be already stored.

        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

        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
             ...                                                  ]

        set_of_forces_objects:
           [FORCES_object, FORCES_object, FORCES_object, ...]
        """

        self._is_nac = is_nac

        # Primitive cell
        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        self._primitive = Primitive(
            self._supercell, np.dot(inv_supercell_matrix, primitive_matrix),
            self._symprec)

        # Set set of FORCES objects or force constants
        if sets_of_forces is not None:
            self.set_forces(sets_of_forces)
        elif set_of_forces_objects is not None:
            self.set_force_sets(set_of_forces_objects)
        elif force_constants is not None:
            self.set_force_constants(force_constants)

        # Calculate force cosntants from forces (full or symmetry reduced)
        if self._set_of_forces_objects is not None:
            if calculate_full_force_constants:
                self.set_force_constants_from_forces(
                    distributed_atom_list=None,
                    force_constants_decimals=force_constants_decimals)
            else:
                p2s_map = self._primitive.get_primitive_to_supercell_map()
                self.set_force_constants_from_forces(
                    distributed_atom_list=p2s_map,
                    force_constants_decimals=force_constants_decimals)

        if self._force_constants is None:
            print "In set_post_process, sets_of_forces or force_constants"
            print "has to be set."
            return False

        # Dynamical Matrix
        self.set_dynamical_matrix(decimals=dynamical_matrix_decimals)

    def set_nac_params(self, nac_params, method='wang'):
        if self._is_nac:
            self._dynamical_matrix.set_nac_params(nac_params, method)

    def set_dynamical_matrix(self, decimals=None):
        if self._is_nac:
            self._dynamical_matrix = \
                DynamicalMatrixNAC(self._supercell,
                                   self._primitive,
                                   self._force_constants,
                                   decimals=decimals,
                                   symprec=self._symprec)
        else:
            self._dynamical_matrix = \
                DynamicalMatrix(self._supercell,
                                self._primitive,
                                self._force_constants,
                                decimals=decimals,
                                symprec=self._symprec)

    def get_dynamical_matrix(self):
        return self._dynamical_matrix

    dynamical_matrix = property(get_dynamical_matrix)

    def set_forces(self, sets_of_forces):
        forces = []
        for i, disp in enumerate(self._displacements):
            forces.append(Forces(disp[0], disp[1:4], sets_of_forces[i]))
        self._set_of_forces_objects = forces

    def set_force_constants_from_forces(self,
                                        distributed_atom_list=None,
                                        force_constants_decimals=None):
        self._force_constants = get_force_constants(
            self._set_of_forces_objects,
            self._symmetry,
            self._supercell,
            atom_list=distributed_atom_list,
            decimals=force_constants_decimals)

    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, sets_of_forces_objects):
        self._set_of_forces_objects = sets_of_forces_objects

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

    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_dynamical_matrix_at_q(self, q):
        self._dynamical_matrix.set_dynamical_matrix(q)
        return self._dynamical_matrix.get_dynamical_matrix()

    # Frequency at a q-point
    def get_frequencies(self, q):
        """
        Calculate phonon frequencies at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        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

    # Frequency and eigenvector at a q-point
    def get_frequencies_with_eigenvectors(self, q):
        """
        Calculate phonon frequencies and eigenvectors at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        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

        ## This expression may not be supported in old python versions.
        # frequencies = np.array(
        #     [np.sqrt(x) if x > 0 else -np.sqrt(-x) for x in eigvals])
        # return frequencies * self._factor, eigenvectors

    # Band structure
    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):

        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            self._primitive,
            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()

    # Mesh sampling
    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_symmetry=True,
                 is_band_connection=False,
                 is_eigenvectors=False,
                 is_gamma_center=False):

        self._mesh = Mesh(self._dynamical_matrix,
                          self._primitive,
                          mesh,
                          shift=shift,
                          is_time_reversal=is_time_reversal,
                          is_mesh_symmetry=is_symmetry,
                          is_eigenvectors=is_eigenvectors,
                          is_band_connection=is_band_connection,
                          is_gamma_center=is_gamma_center,
                          group_velocity=self._group_velocity,
                          factor=self._factor,
                          symprec=self._symprec)

    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 write_hdf5_mesh(self):
        self._mesh.write_hdf5()

    # Thermal property
    def set_thermal_properties(self,
                               t_step=10,
                               t_max=1000,
                               t_min=0,
                               is_projection=False,
                               cutoff_frequency=None):
        if self._mesh == None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        tp = ThermalProperties(self._mesh.get_frequencies(),
                               weights=self._mesh.get_weights(),
                               eigenvectors=self._mesh.get_eigenvectors(),
                               is_projection=is_projection,
                               cutoff_frequency=cutoff_frequency)
        tp.set_thermal_properties(t_step, t_max, 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)

    # Partial DOS
    def set_partial_DOS(self,
                        sigma=None,
                        omega_min=None,
                        omega_max=None,
                        omega_pitch=None,
                        tetrahedron_method=False):

        if self._mesh == None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)
        if self._mesh.get_eigenvectors() == None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)

        pdos = PartialDos(self._mesh,
                          sigma=sigma,
                          tetrahedron_method=tetrahedron_method)
        pdos.set_draw_area(omega_min, omega_max, omega_pitch)
        pdos.calculate()
        self._pdos = pdos

    def get_partial_DOS(self):
        """
        Retern omegas and partial_dos.
        The first element is omegas and the second is partial_dos.
        
        omegas: [freq1, freq2, ...]
        partial_dos:
          [[elem1-freq1, elem1-freq2, ...],
           [elem2-freq1, elem2-freq2, ...],
           ...]

          where
           elem1: atom1-x compornent
           elem2: atom1-y compornent
           elem3: atom1-z compornent
           elem4: atom2-x compornent
           ...
        """
        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()

    # Total DOS
    def set_total_DOS(self,
                      sigma=None,
                      omega_min=None,
                      omega_max=None,
                      omega_pitch=None,
                      tetrahedron_method=False):

        if self._mesh == 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(omega_min, omega_max, omega_pitch)
        total_dos.calculate()
        self._total_dos = total_dos

    def get_total_DOS(self):
        """
        Retern omegas and total dos.
        The first element is omegas and the second is total dos.
        
        omegas: [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)

    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()

    # Thermal displacement
    def set_thermal_displacements(self,
                                  t_step=10,
                                  t_max=1000,
                                  t_min=0,
                                  direction=None,
                                  cutoff_eigenvalue=None):
        """
        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz^2)

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh == 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_eigenvalue=cutoff_eigenvalue)
        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()
        td.run_mesh()

        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 write_hdf5_thermal_displacements(self):
        self._thermal_displacements.write_hdf5()

    # Thermal displacement matrices
    def set_thermal_displacement_matrices(self,
                                          t_step=10,
                                          t_max=1000,
                                          t_min=0,
                                          cutoff_eigenvalue=None):
        """
        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz^2)

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh == 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_eigenvalue=cutoff_eigenvalue)
        tdm.set_temperature_range(t_min, t_max, t_step)
        # tdm.run()
        tdm.run_mesh()

        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 write_hdf5_thermal_displacement_matrices(self):
        self._thermal_displacement_matrices.write_hdf5()

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

        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz^2)
        """

        td = ThermalDistances(self._mesh.get_frequencies(),
                              self._mesh.get_eigenvectors(),
                              self._supercell,
                              self._primitive,
                              self._mesh.get_qpoints(),
                              symprec=self._symprec,
                              cutoff_eigenvalue=cutoff_eigenvalue)
        td.set_temperature_range(t_min, t_max, t_step)
        # td.run(atom_pairs)
        td.run_mesh(atom_pairs)

        self._thermal_distances = td

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

    def write_hdf5_thermal_distances(self):
        self._thermal_distances.write_hdf5()

    # Q-points mode
    def write_yaml_qpoints(self,
                           q_points,
                           nac_q_direction=None,
                           is_eigenvectors=False,
                           write_dynamical_matrices=False,
                           factor=VaspToTHz):

        write_yaml_qpoints(q_points,
                           self._primitive,
                           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)

    # 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 q_point == None:
            animation = Animation([0, 0, 0],
                                  self._dynamical_matrix,
                                  self._primitive,
                                  shift=shift)
        else:
            animation = Animation(q_point,
                                  self._dynamical_matrix,
                                  self._primitive,
                                  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 == None or amplitude == None or num_div == None:
                print "Parameters are not correctly set for animation."
                sys.exit(1)

            if anime_type == 'arc' or anime_type == 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)

    # Modulation
    def set_modulations(self,
                        dimension,
                        phonon_modes,
                        delta_q=None,
                        derivative_order=None,
                        nac_q_direction=None):
        self._modulation = Modulation(self._dynamical_matrix,
                                      self._primitive,
                                      dimension=dimension,
                                      phonon_modes=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()

    # Characters of irreducible representations
    def set_irreps(self, q, degeneracy_tolerance=1e-4):
        self._irreps = IrReps(self._dynamical_matrix,
                              q,
                              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_points=None, q_length=1e-4):
        self._group_velocity = GroupVelocity(
            self._dynamical_matrix,
            q_points=q_points,
            symmetry=self._symmetry,
            q_length=q_length,
            frequency_factor_to_THz=self._factor)

    def get_group_velocity(self, q_point):
        self._group_velocity.set_q_points([q_point])
        return self._group_velocity.get_group_velocity()[0]

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

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

    def _set_supercells_with_displacements(self):
        supercells = []
        for disp in self._displacements:
            positions = self._supercell.get_positions()
            positions[disp[0]] += disp[1:4]
            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
Beispiel #11
0
class Phonopy:
    def __init__( self,
                  unitcell,
                  supercell_matrix,
                  is_preprocess=True,
                  distance=0.01,
                  symprec=1e-5,
                  factor=VaspToTHz,
                  is_nosym=False,
                  log_level=0 ):
        self.symprec = symprec
        self.unitcell = unitcell
        self.supercell_matrix = supercell_matrix
        self.distance = distance
        self.factor = factor
        self.is_nosym = is_nosym
        self.log_level = log_level
        self.supercell = None
        self.__supercell()
        self.symmetry = None
        self.__symmetry()

        if is_preprocess:
            self.displacements = None
            self.displacement_directions = None
            self.supercells_with_displacements = None
            self.set_displacements()

        # set_post_process
        self.primitive = None
        self.dynamical_matrix = None
        self.is_nac = False

        # set_force_constants or set_forces
        self.force_constants = None

        # set_band_structure
        self.__band_structure = None

        # set_mesh
        self.__mesh = None

        # set_thermal_properties
        self.__thermal_properties = None

        # set_thermal_displacements
        self.__thermal_displacements = None

        # set_partial_DOS
        self.__pdos = None

        # set_total_DOS
        self.__total_dos = None
        
    def __supercell(self):
        self.supercell = get_supercell( self.unitcell,
                                        self.supercell_matrix,
                                        self.symprec )

    def get_supercell( self ):
        return self.supercell

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

    def get_primitive( self ):
        return self.primitive

    def set_primitive( self, primitive ):
        self.primitive = primitive

    def __symmetry(self):
        self.symmetry = Symmetry( self.supercell,
                                  self.symprec,
                                  self.is_nosym )

    def get_symmetry(self):
        return self.symmetry

    def set_displacements( self,
                           is_plusminus='auto',
                           is_diagonal=True ):
        """
        displacements:
          List of displacements in Cartesian coordinates.
          See 'set_special_displacements'
        
        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.
        """

        lattice = self.supercell.get_cell()
        self.displacements = []
        self.displacement_directions = \
            get_least_displacements( self.symmetry, 
                                     is_plusminus=is_plusminus,
                                     is_diagonal=is_diagonal,
                                     log_level=self.log_level )

        for disp in self.displacement_directions:
            atom_num = disp[0]
            disp_cartesian = np.dot(disp[1:], lattice)
            disp_cartesian *= self.distance / np.linalg.norm(disp_cartesian)
            self.displacements.append( [ atom_num,
                                         disp_cartesian[0],
                                         disp_cartesian[1],
                                         disp_cartesian[2] ] )

        self.__supercells_with_displacements()

    def set_special_displacements(self, displacements):
        """
        This method orverwrites displacements that were automatically
        determined in the post-process.

        displacemsts: List of disctionaries
           [[ 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
        """

        self.displacements = displacements
        self.__supercells_with_displacements()

    def get_displacements( self ):
        return self.displacements

    def get_displacement_directions( self ):
        return self.displacement_directions

    def print_displacements(self):
        print "Least displacements:"
        print " Atom       Displacement"
        print " ----------------------------"
        for disp in self.displacements:
            print " %4d  " % disp[0],
            print disp[1:4]

    def __supercells_with_displacements(self):
        supercells = []
        for disp in self.displacements:
            positions = self.supercell.get_positions()
            positions[disp[0]] += disp[1:4]
            supercells.append( Atoms( 
                    numbers = self.supercell.get_atomic_numbers(),
                    masses = self.supercell.get_masses(),
                    positions = positions,
                    cell = self.supercell.get_cell(),
                    pbc = True ) )

        self.supercells_with_displacements = supercells
                        
    def get_supercells_with_displacements(self):
        return self.supercells_with_displacements

    def set_post_process( self,
                          primitive_matrix,
                          set_of_forces=None,
                          force_constants=None,
                          is_nac=False ):
        """
        Set forces to prepare phonon calculations. The order of
        'set_of_forces' has to correspond to that of 'displacements'.

        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

        set_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
             ...                                                   ]
        """

        self.is_nac = is_nac

        if not set_of_forces == None:
            self.set_forces( set_of_forces )
        elif not force_constants == None:
            self.set_force_constants( force_constants )
        elif self.force_constants == None:
            print "In set_post_process, set_of_forces or force_constants"
            print "has to be set."
            sys.exit(1)

        # Primitive cell
        inv_supercell_matrix = np.linalg.inv( self.supercell_matrix )
        self.primitive = Primitive( self.supercell,
                                    np.dot( inv_supercell_matrix, primitive_matrix ),
                                    self.symprec )

        # Dynamical Matrix
        if self.is_nac:
            self.dynamical_matrix = \
                DynamicalMatrixNAC( self.supercell,
                                    self.primitive,
                                    self.force_constants,
                                    symprec=self.symprec )
        else:
            self.dynamical_matrix = \
                DynamicalMatrix( self.supercell,
                                 self.primitive,
                                 self.force_constants,
                                 symprec=self.symprec )

    def set_nac_params( self, nac_params, method='wang' ):
        if self.is_nac:
            self.dynamical_matrix.set_nac_params( nac_params, method )

    def get_dynamical_matrix( self ):
        return self.dynamical_matrix

    def set_forces( self,
                    set_of_forces,
                    is_tensor_symmetry=False ):
        # Forces
        forces = []
        for i, disp in enumerate( self.displacements ):
            forces.append( Forces( disp[0],
                                   disp[1:4],
                                   set_of_forces[i] ) )

        # Force constants
        self.force_constants = get_force_constants( forces,
                                                    self.symmetry,
                                                    self.supercell,
                                                    is_tensor_symmetry )

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

    def symmetrize_force_constants( self, iteration=3 ):
        symmetrize_force_constants( self.force_constants, iteration )
        
    def get_force_constants( self ):
        return self.force_constants

    def get_rotational_condition_of_fc( self ):
        return rotational_invariance( self.force_constants,
                                      self.supercell,
                                      self.primitive,
                                      self.symprec )

    # Frequency at a q-point
    def get_frequencies(self, q):
        """
        Calculate phonon frequency
        
        q: k-vector in reduced coordinates of primitive cell
        """
        self.dynamical_matrix.set_dynamical_matrix(q)
        dm = self.dynamical_matrix.get_dynamical_matrix()
        frequencies = []
        for eig in np.linalg.eigvalsh(dm):
            if eig < 0:
                frequencies.append(-np.sqrt(-eig))
            else:
                frequencies.append(np.sqrt(eig))
            
        return np.array(frequencies) * self.factor

    # Band structure
    def set_band_structure( self,
                            bands,
                            is_eigenvectors=False ):

        self.__band_structure = BandStructure( bands,
                                               self.dynamical_matrix,
                                               self.primitive,
                                               is_eigenvectors=is_eigenvectors,
                                               factor=self.factor )

    def get_band_structure( self ):
        band = self.__band_structure
        return ( band.get_distances(),
                 band.get_qpoints(),
                 band.get_eigenvalues(),
                 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()

    # Mesh sampling
    def set_mesh( self,
                  mesh,
                  shift=None,
                  is_time_reversal=True,
                  is_symmetry=True,
                  is_eigenvectors=False ):

        self.__mesh = Mesh( self.dynamical_matrix,
                            self.primitive,
                            mesh,
                            shift=shift,
                            is_time_reversal=is_time_reversal,
                            is_symmetry=is_symmetry,
                            is_eigenvectors=is_eigenvectors,
                            factor=self.factor,
                            symprec=self.symprec )

    def get_mesh( self ):
        return ( self.__mesh.get_weights(),
                 self.__mesh.get_qpoints(),
                 self.__mesh.get_eigenvalues(),
                 self.__mesh.get_eigenvectors() )

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

    # Thermal property
    def set_thermal_properties( self, t_step=10, t_max=1000, t_min=0,
                                cutoff_eigenvalue=None ):
        if self.__mesh==None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        tp = ThermalProperties( self.__mesh.get_eigenvalues(),
                                weights=self.__mesh.get_weights(),
                                factor=self.factor,
                                cutoff_eigenvalue=cutoff_eigenvalue )
        tp.set_thermal_properties( t_step, t_max, t_min )
        self.__thermal_properties = tp

    def get_thermal_properties( self ):
        temps, fe, entropy, cv = \
            self.__thermal_properties.get_thermal_properties()
        return np.array([ temps, fe, entropy, cv ]).transpose()

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

    def write_yaml_thermal_properties( self ):
        self.__thermal_properties.write_yaml()

    # Partial DOS
    def set_partial_DOS( self,
                         sigma=None,
                         omega_min=None,
                         omega_max=None,
                         omega_pitch=None ):

        if self.__mesh==None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)
        if self.__mesh.get_eigenvectors() == None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)

        pdos = PartialDos( self.__mesh.get_eigenvalues(),
                           self.__mesh.get_weights(),
                           self.__mesh.get_eigenvectors(),
                           factor=self.factor,
                           sigma=sigma )
        pdos.set_draw_area( omega_min,
                            omega_max,
                            omega_pitch )
        pdos.calculate()
        self.__pdos = pdos

    def get_partial_DOS( self ):
        """
        Retern omegas and partial_dos.
        The first element is omegas and the second is partial_dos.
        
        omegas: [ freq1, freq2, ... ]
        partial_dos:
          [[elem1-freq1, elem1-freq2, ... ],
           [elem2-freq1, elem2-freq2, ... ],
           ... ]

          where
           elem1: atom1-x compornent
           elem2: atom1-y compornent
           elem3: atom1-z compornent
           elem4: atom2-x compornent
           ...
        """
        return self.__pdos.get_partial_dos()

    def plot_partial_DOS( self, pdos_indices ):
        return self.__pdos.plot_pdos( pdos_indices )

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

    # Total DOS
    def set_total_DOS( self,
                       sigma=None,
                       omega_min=None,
                       omega_max=None,
                       omega_pitch=None ):

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

        total_dos = TotalDos( self.__mesh.get_eigenvalues(),
                              self.__mesh.get_weights(),
                              factor=self.factor,
                              sigma=sigma )
        total_dos.set_draw_area( omega_min,
                                 omega_max,
                                 omega_pitch )
        total_dos.calculate()
        self.__total_dos = total_dos

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

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

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

    # Thermal displacement
    def set_thermal_displacements( self,
                                   t_step=10,
                                   t_max=1000,
                                   t_min=0,
                                   projector=None,
                                   cutoff_eigenvalue=None ):
        """
        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz)
        """
        if self.__mesh==None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)
        if self.__mesh.get_eigenvectors() == None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)

        td = ThermalDisplacements( self.__mesh.get_eigenvalues(),
                                   self.__mesh.get_eigenvectors(),
                                   self.__mesh.get_weights(),
                                   self.primitive.get_masses(),
                                   factor=self.factor,
                                   cutoff_eigenvalue=cutoff_eigenvalue )
        td.set_temperature_range( t_min, t_max, t_step )
        if not projector==None:
            td.project_eigenvectors( projector, self.primitive.get_cell() )
        td.set_thermal_displacements()
        
        self.__thermal_displacements = td

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

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

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

        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz)
        """

        td = ThermalDistances( self.__mesh.get_eigenvalues(),
                               self.__mesh.get_eigenvectors(),
                               self.__mesh.get_weights(),
                               self.supercell,
                               self.primitive,
                               self.__mesh.get_qpoints(),
                               symprec=self.symprec,
                               factor=self.factor,
                               cutoff_eigenvalue=cutoff_eigenvalue )
        td.set_temperature_range( t_min, t_max, t_step )
        td.set_thermal_distances( atom_pairs )

        self.__thermal_distances = td

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


    # Q-points mode
    def write_yaml_qpoints( self,
                            qpoints,
                            is_eigenvectors=False,
                            factor=VaspToTHz ):
        
        write_yaml_qpoints( qpoints,
                            self.primitive,
                            self.dynamical_matrix,
                            is_eigenvectors=is_eigenvectors,
                            factor=self.factor )

    # Animation
    def write_animation( self,
                         qpoint=None,
                         anime_type='v_sim',
                         band_index=None,
                         amplitude=None,
                         num_div=None,
                         shift=None ):
        if qpoint==None:
            animation = Animation( [0, 0, 0],
                                   self.dynamical_matrix,
                                   self.primitive,
                                   shift=shift )
        else:
            animation = Animation( qpoint,
                                   self.dynamical_matrix,
                                   self.primitive,
                                   shift=shift )
        if anime_type=='v_sim':
            animation.write_v_sim( self.factor )

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

            if anime_type=='arc' or anime_type==None:
                animation.write_arc( band_index,
                                     amplitude,
                                     num_div )
    
            if anime_type=='xyz':
                animation.write_xyz( band_index,
                                     amplitude,
                                     num_div,
                                     self.factor )
    
            if anime_type=='jmol':
                animation.write_xyz_jmol( amplitude=amplitude,
                                          factor=self.factor )
    
            if anime_type=='poscar':
                animation.write_POSCAR( band_index,
                                        amplitude,
                                        num_div )


    def write_modulation( self, setting ):
        write_modulations( self.dynamical_matrix,
                           self.primitive,
                           setting )
Beispiel #12
0
class Phonopy:
    def __init__(self,
                 unitcell,
                 supercell_matrix,
                 distance=0.01,
                 factor=VaspToTHz,
                 is_auto_displacements=True,
                 symprec=1e-5,
                 is_symmetry=True,
                 log_level=0):
        self._symprec = symprec
        self._unitcell = unitcell
        self._supercell_matrix = supercell_matrix
        self._factor = factor
        self._is_symmetry = is_symmetry
        self._log_level = log_level
        self._supercell = None
        self._set_supercell()
        self._symmetry = None
        self._set_symmetry()

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

        # set_post_process
        self._primitive = None
        self._dynamical_matrix = None
        self._is_nac = False

        # set_force_constants or set_forces
        self._set_of_forces_objects = None
        self._force_constants = None

        # set_band_structure
        self._band_structure = None

        # set_mesh
        self._mesh = 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_primitive(self):
        return self._primitive
    primitive = property(get_primitive)

    def set_primitive(self, primitive):
        self._primitive = 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 self._symmetry
    symmetry = property(get_symmetry)

    def get_unit_conversion_factor(self):
        return self._factor
    unit_conversion_factor = property(get_unit_conversion_factor)
    
    def generate_displacements(self,
                               distance=0.01,
                               is_plusminus='auto',
                               is_diagonal=True,
                               is_trigonal=False):
        """Generate displacements automatically

        displacements:
          List of displacements in Cartesian coordinates.
          See 'set_displacements'
        
        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.
                               
        """

        lattice = self._supercell.get_cell()
        self._displacements = []
        self._displacement_directions = \
            get_least_displacements(self._symmetry, 
                                    is_plusminus=is_plusminus,
                                    is_diagonal=is_diagonal,
                                    is_trigonal=is_trigonal,
                                    log_level=self._log_level)

        for disp in self._displacement_directions:
            atom_num = disp[0]
            disp_cartesian = np.dot(disp[1:], lattice)
            disp_cartesian *= distance / np.linalg.norm(disp_cartesian)
            self._displacements.append([atom_num,
                                       disp_cartesian[0],
                                       disp_cartesian[1],
                                       disp_cartesian[2]])

        self._set_supercells_with_displacements()

    def set_displacements(self, displacements):
        """Set displacements manually

        displacemsts: List of disctionaries
           [[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
           
        """

        self._displacements = displacements
        self._set_supercells_with_displacements()

    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):
        return self._supercells_with_displacements

    def set_post_process(self,
                         primitive_matrix=np.eye(3, dtype=float),
                         sets_of_forces=None,
                         set_of_forces_objects=None,
                         force_constants=None,
                         is_nac=False,
                         calculate_full_force_constants=False,
                         force_constants_decimals=None,
                         dynamical_matrix_decimals=None):
        """
        Set forces or force constants to prepare phonon calculations.
        The order of 'sets_of_forces' has to correspond to that of
        'displacements' that should be already stored.

        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

        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
             ...                                                  ]

        set_of_forces_objects:
           [FORCES_object, FORCES_object, FORCES_object, ...]
        """

        self._is_nac = is_nac

        # Primitive cell
        inv_supercell_matrix = np.linalg.inv(self._supercell_matrix)
        self._primitive = Primitive(
            self._supercell,
            np.dot(inv_supercell_matrix, primitive_matrix),
            self._symprec)

        # Set set of FORCES objects or force constants
        if sets_of_forces is not None:
            self.set_forces(sets_of_forces)
        elif set_of_forces_objects is not None:
            self.set_force_sets(set_of_forces_objects)
        elif force_constants is not None:
            self.set_force_constants(force_constants)

        # Calculate force cosntants from forces (full or symmetry reduced)
        if self._set_of_forces_objects is not None:
            if calculate_full_force_constants:
                self.set_force_constants_from_forces(
                    distributed_atom_list=None,
                    force_constants_decimals=force_constants_decimals)
            else:
                p2s_map = self._primitive.get_primitive_to_supercell_map()
                self.set_force_constants_from_forces(
                    distributed_atom_list=p2s_map,
                    force_constants_decimals=force_constants_decimals)

        if self._force_constants is None:
            print "In set_post_process, sets_of_forces or force_constants"
            print "has to be set."
            return False
            
        # Dynamical Matrix
        self.set_dynamical_matrix(decimals=dynamical_matrix_decimals)
        
    def set_nac_params(self, nac_params, method='wang'):
        if self._is_nac:
            self._dynamical_matrix.set_nac_params(nac_params, method)

    def set_dynamical_matrix(self, decimals=None):
        if self._is_nac:
            self._dynamical_matrix = \
                DynamicalMatrixNAC(self._supercell,
                                   self._primitive,
                                   self._force_constants,
                                   decimals=decimals,
                                   symprec=self._symprec)
        else:
            self._dynamical_matrix = \
                DynamicalMatrix(self._supercell,
                                self._primitive,
                                self._force_constants,
                                decimals=decimals,
                                symprec=self._symprec)

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

    def set_forces(self, sets_of_forces):
        forces = []
        for i, disp in enumerate(self._displacements):
            forces.append(Forces(disp[0],
                                 disp[1:4],
                                 sets_of_forces[i]))
        self._set_of_forces_objects = forces

    def set_force_constants_from_forces(self,
                                        distributed_atom_list=None,
                                        force_constants_decimals=None):
        self._force_constants = get_force_constants(
            self._set_of_forces_objects,
            self._symmetry,
            self._supercell,
            atom_list=distributed_atom_list,
            decimals=force_constants_decimals)

    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, sets_of_forces_objects):
        self._set_of_forces_objects = sets_of_forces_objects
        
    def symmetrize_force_constants(self, iteration=3):
        symmetrize_force_constants(self._force_constants, iteration)
        
    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_dynamical_matrix_at_q(self, q):
        self._dynamical_matrix.set_dynamical_matrix(q)
        return self._dynamical_matrix.get_dynamical_matrix()

    # Frequency at a q-point
    def get_frequencies(self, q):
        """
        Calculate phonon frequencies at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        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

    # Frequency and eigenvector at a q-point
    def get_frequencies_with_eigenvectors(self, q):
        """
        Calculate phonon frequencies and eigenvectors at q
        
        q: q-vector in reduced coordinates of primitive cell
        """
        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
                
        ## This expression may not be supported in old python versions.
        # frequencies = np.array(
        #     [np.sqrt(x) if x > 0 else -np.sqrt(-x) for x in eigvals])
        # return frequencies * self._factor, eigenvectors

    # Band structure
    def set_band_structure(self,
                           bands,
                           is_eigenvectors=False,
                           is_band_connection=False):

        self._band_structure = BandStructure(
            bands,
            self._dynamical_matrix,
            self._primitive,
            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()

    # Mesh sampling
    def set_mesh(self,
                 mesh,
                 shift=None,
                 is_time_reversal=True,
                 is_symmetry=True,
                 is_band_connection=False,
                 is_eigenvectors=False,
                 is_gamma_center=False):

        self._mesh = Mesh(self._dynamical_matrix,
                          self._primitive,
                          mesh,
                          shift=shift,
                          is_time_reversal=is_time_reversal,
                          is_mesh_symmetry=is_symmetry,
                          is_eigenvectors=is_eigenvectors,
                          is_band_connection=is_band_connection,
                          is_gamma_center=is_gamma_center,
                          group_velocity=self._group_velocity,
                          factor=self._factor,
                          symprec=self._symprec)

    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 write_hdf5_mesh(self):
        self._mesh.write_hdf5()
    # Thermal property
    def set_thermal_properties(self,
                               t_step=10,
                               t_max=1000,
                               t_min=0,
                               is_projection=False,
                               cutoff_frequency=None):
        if self._mesh==None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)

        tp = ThermalProperties(self._mesh.get_frequencies(),
                               weights=self._mesh.get_weights(),
                               eigenvectors=self._mesh.get_eigenvectors(),
                               is_projection=is_projection,
                               cutoff_frequency=cutoff_frequency)
        tp.set_thermal_properties(t_step, t_max, 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)

    # Partial DOS
    def set_partial_DOS(self,
                        sigma=None,
                        omega_min=None,
                        omega_max=None,
                        omega_pitch=None,
                        tetrahedron_method=False):

        if self._mesh==None:
            print "set_mesh has to be done before set_thermal_properties"
            sys.exit(1)
        if self._mesh.get_eigenvectors() == None:
            print "Eigenvectors have to be calculated."
            sys.exit(1)

        pdos = PartialDos(self._mesh,
                          sigma=sigma,
                          tetrahedron_method=tetrahedron_method)
        pdos.set_draw_area(omega_min,
                           omega_max,
                           omega_pitch)
        pdos.calculate()
        self._pdos = pdos

    def get_partial_DOS(self):
        """
        Retern omegas and partial_dos.
        The first element is omegas and the second is partial_dos.
        
        omegas: [freq1, freq2, ...]
        partial_dos:
          [[elem1-freq1, elem1-freq2, ...],
           [elem2-freq1, elem2-freq2, ...],
           ...]

          where
           elem1: atom1-x compornent
           elem2: atom1-y compornent
           elem3: atom1-z compornent
           elem4: atom2-x compornent
           ...
        """
        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()

    # Total DOS
    def set_total_DOS(self,
                      sigma=None,
                      omega_min=None,
                      omega_max=None,
                      omega_pitch=None,
                      tetrahedron_method=False):

        if self._mesh==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(omega_min,
                                omega_max,
                                omega_pitch)
        total_dos.calculate()
        self._total_dos = total_dos

    def get_total_DOS(self):
        """
        Retern omegas and total dos.
        The first element is omegas and the second is total dos.
        
        omegas: [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)

    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()

    # Thermal displacement
    def set_thermal_displacements(self,
                                  t_step=10,
                                  t_max=1000,
                                  t_min=0,
                                  direction=None,
                                  cutoff_eigenvalue=None):
        """
        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz^2)

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh==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_eigenvalue=cutoff_eigenvalue)
        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()
        td.run_mesh()

        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 write_hdf5_thermal_displacements(self):
        self._thermal_displacements.write_hdf5()

    # Thermal displacement matrices
    def set_thermal_displacement_matrices(self,
                                           t_step=10,
                                           t_max=1000,
                                           t_min=0,
                                           cutoff_eigenvalue=None):
        """
        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz^2)

        direction:
          Projection direction in reduced coordinates
        """
        if self._mesh==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_eigenvalue=cutoff_eigenvalue)
        tdm.set_temperature_range(t_min, t_max, t_step)
        # tdm.run()
        tdm.run_mesh()

        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 write_hdf5_thermal_displacement_matrices(self):
        self._thermal_displacement_matrices.write_hdf5()

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

        cutoff_eigenvalue:
          phonon modes that have frequencies below cutoff_eigenvalue
          are ignored.
          e.g. 0.1 (THz^2)
        """

        td = ThermalDistances(self._mesh.get_frequencies(),
                              self._mesh.get_eigenvectors(),
                              self._supercell,
                              self._primitive,
                              self._mesh.get_qpoints(),
                              symprec=self._symprec,
                              cutoff_eigenvalue=cutoff_eigenvalue)
        td.set_temperature_range(t_min, t_max, t_step)
        # td.run(atom_pairs)
        td.run_mesh(atom_pairs)

        self._thermal_distances = td

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

    def write_hdf5_thermal_distances(self):
        self._thermal_distances.write_hdf5()

    # Q-points mode
    def write_yaml_qpoints(self,
                           q_points,
                           nac_q_direction=None,
                           is_eigenvectors=False,
                           write_dynamical_matrices=False,
                           factor=VaspToTHz):
        
        write_yaml_qpoints(q_points,
                           self._primitive,
                           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)

    # 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 q_point==None:
            animation = Animation([0, 0, 0],
                                  self._dynamical_matrix,
                                  self._primitive,
                                  shift=shift)
        else:
            animation = Animation(q_point,
                                  self._dynamical_matrix,
                                  self._primitive,
                                  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==None or amplitude==None or num_div==None:
                print "Parameters are not correctly set for animation."
                sys.exit(1)

            if anime_type=='arc' or anime_type==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)
                    

    # Modulation
    def set_modulations(self,
                        dimension,
                        phonon_modes,
                        delta_q=None,
                        derivative_order=None,
                        nac_q_direction=None):
        self._modulation = Modulation(self._dynamical_matrix,
                                      self._primitive,
                                      dimension=dimension,
                                      phonon_modes=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()


    # Characters of irreducible representations
    def set_irreps(self, q, degeneracy_tolerance=1e-4):
        self._irreps = IrReps(
            self._dynamical_matrix,
            q,
            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_points=None,
                           q_length=1e-4):
        self._group_velocity = GroupVelocity(
            self._dynamical_matrix,
            q_points=q_points,
            symmetry=self._symmetry,
            q_length=q_length,
            frequency_factor_to_THz=self._factor)

    def get_group_velocity(self, q_point):
        self._group_velocity.set_q_points([q_point])
        return self._group_velocity.get_group_velocity()[0]

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

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

    def _set_supercells_with_displacements(self):
        supercells = []
        for disp in self._displacements:
            positions = self._supercell.get_positions()
            positions[disp[0]] += disp[1:4]
            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