Пример #1
0
def get_displaced_structures(pmg_structure,
                             atom_disp=0.01,
                             supercell_matrix=None,
                             yaml_fname=None,
                             **kwargs):
    r"""
    Generate a set of symmetrically inequivalent displaced structures for
    phonon calculations.

    Args:
        pmg_structure (Structure): A pymatgen structure object.
        atom_disp (float): Atomic displacement. Default is 0.01 $\\AA$.
        supercell_matrix (3x3 array): Scaling matrix for supercell.
        yaml_fname (string): If not None, it represents the full path to
            the outputting displacement yaml file, e.g. disp.yaml.
        **kwargs: Parameters used in Phonopy.generate_displacement method.

    Return:
        A list of symmetrically inequivalent structures with displacements, in
        which the first element is the perfect supercell structure.
    """

    is_plusminus = kwargs.get("is_plusminus", "auto")
    is_diagonal = kwargs.get("is_diagonal", True)
    is_trigonal = kwargs.get("is_trigonal", False)

    ph_structure = get_phonopy_structure(pmg_structure)

    if supercell_matrix is None:
        supercell_matrix = np.eye(3) * np.array((1, 1, 1))

    phonon = Phonopy(unitcell=ph_structure, supercell_matrix=supercell_matrix)
    phonon.generate_displacements(
        distance=atom_disp,
        is_plusminus=is_plusminus,
        is_diagonal=is_diagonal,
        is_trigonal=is_trigonal,
    )

    if yaml_fname is not None:
        displacements = phonon.get_displacements()
        write_disp_yaml(
            displacements=displacements,
            supercell=phonon.get_supercell(),
            filename=yaml_fname,
        )

    # Supercell structures with displacement
    disp_supercells = phonon.get_supercells_with_displacements()
    # Perfect supercell structure
    init_supercell = phonon.get_supercell()
    # Structure list to be returned
    structure_list = [get_pmg_structure(init_supercell)]

    for c in disp_supercells:
        if c is not None:
            structure_list.append(get_pmg_structure(c))

    return structure_list
Пример #2
0
def get_displaced_structures(pmg_structure, atom_disp=0.01,
                             supercell_matrix=None, yaml_fname=None, **kwargs):
    """
    Generate a set of symmetrically inequivalent displaced structures for
    phonon calculations.

    Args:
        pmg_structure (Structure): A pymatgen structure object.
        atom_disp (float): Atomic displacement. Default is 0.01 $\\AA$.
        supercell_matrix (3x3 array): Scaling matrix for supercell.
        yaml_fname (string): If not None, it represents the full path to
            the outputting displacement yaml file, e.g. disp.yaml.
        **kwargs: Parameters used in Phonopy.generate_displacement method.

    Return:
        A list of symmetrically inequivalent structures with displacements, in
        which the first element is the perfect supercell structure.
    """

    is_plusminus = kwargs.get("is_plusminus", "auto")
    is_diagonal = kwargs.get("is_diagonal", True)
    is_trigonal = kwargs.get("is_trigonal", False)

    ph_structure = get_phonopy_structure(pmg_structure)

    if supercell_matrix is None:
        supercell_matrix = np.eye(3) * np.array((1, 1, 1))

    phonon = Phonopy(unitcell=ph_structure, supercell_matrix=supercell_matrix)
    phonon.generate_displacements(distance=atom_disp,
                                  is_plusminus=is_plusminus,
                                  is_diagonal=is_diagonal,
                                  is_trigonal=is_trigonal)

    if yaml_fname is not None:
        displacements = phonon.get_displacements()
        directions = phonon.get_displacement_directions()
        write_disp_yaml(displacements=displacements,
                        supercell=phonon.get_supercell(),
                        directions=directions, filename=yaml_fname)

    # Supercell structures with displacement
    disp_supercells = phonon.get_supercells_with_displacements()
    # Perfect supercell structure
    init_supercell = phonon.get_supercell()
    # Structure list to be returned
    structure_list = [get_pmg_structure(init_supercell)]

    for c in disp_supercells:
        if c is not None:
            structure_list.append(get_pmg_structure(c))

    return structure_list
Пример #3
0
def get_data_from_dir(directory, i_volume):

    data_sets = file_IO.parse_FORCE_SETS(
        filename=directory + '/phonon-{0:02d}/FORCE_SETS'.format(i_volume))

    yaml_file = open(
        directory + '/phonon-{0:02d}/phonon.yaml'.format(i_volume), 'r')
    data = yaml.load_all(yaml_file).next()

    unit_cell = PhonopyAtoms(
        symbols=[item['symbol'] for item in data['points']],
        scaled_positions=[item['coordinates'] for item in data['points']],
        cell=data['lattice'])

    phonon = Phonopy(unit_cell, data['supercell_matrix'])

    phonon.set_displacement_dataset(data_sets)
    phonon.produce_force_constants()

    force_constants = phonon.get_force_constants()

    supercell = phonon.get_supercell()

    volume = unit_cell.get_volume()
    energy = data['electric_total_energy']

    return supercell, volume, energy, force_constants, data['supercell_matrix']
Пример #4
0
 def _get_phonon(self, cell):
     phonon = Phonopy(cell,
                      np.diag([2, 2, 2]),
                      primitive_matrix=[[0, 0.5, 0.5],
                                        [0.5, 0, 0.5],
                                        [0.5, 0.5, 0]])
     force_sets = parse_FORCE_SETS(filename=os.path.join(data_dir,"FORCE_SETS_moment"))
     phonon.set_displacement_dataset(force_sets)
     phonon.produce_force_constants()
     supercell = phonon.get_supercell()
     born_elems = {'Na': [[1.08703, 0, 0],
                          [0, 1.08703, 0],
                          [0, 0, 1.08703]],
                   'Cl': [[-1.08672, 0, 0],
                          [0, -1.08672, 0],
                          [0, 0, -1.08672]]}
     born = [born_elems[s] for s in ['Na', 'Cl']]
     epsilon = [[2.43533967, 0, 0],
                [0, 2.43533967, 0],
                [0, 0, 2.43533967]]
     factors = 14.400
     phonon.set_nac_params({'born': born,
                            'factor': factors,
                            'dielectric': epsilon})
     return phonon
Пример #5
0
 def _get_phonon(self, cell):
     phonon = Phonopy(cell,
                      np.diag([2, 2, 2]),
                      primitive_matrix=[[0, 0.5, 0.5],
                                        [0.5, 0, 0.5],
                                        [0.5, 0.5, 0]])
     force_sets = parse_FORCE_SETS(filename="FORCE_SETS_moment")
     phonon.set_displacement_dataset(force_sets)
     phonon.produce_force_constants()
     supercell = phonon.get_supercell()
     born_elems = {'Na': [[1.08703, 0, 0],
                          [0, 1.08703, 0],
                          [0, 0, 1.08703]],
                   'Cl': [[-1.08672, 0, 0],
                          [0, -1.08672, 0],
                          [0, 0, -1.08672]]}
     born = [born_elems[s] for s in ['Na', 'Cl']]
     epsilon = [[2.43533967, 0, 0],
                [0, 2.43533967, 0],
                [0, 0, 2.43533967]]
     factors = 14.400
     phonon.set_nac_params({'born': born,
                            'factor': factors,
                            'dielectric': epsilon})
     return phonon
Пример #6
0
def phonon_dos(fcp_file):
    if 'fcc2x2x2' in fcp_file:
        prim = read(ref_fcc_conv2x2x2)
    else:
        prim = read(ref_fcc)
    fcp = ForceConstantPotential.read(fcp_file)
    mesh = [33, 33, 33]

    atoms_phonopy = PhonopyAtoms(symbols=prim.get_chemical_symbols(),
                                 scaled_positions=prim.get_scaled_positions(),
                                 cell=prim.cell)

    phonopy = Phonopy(atoms_phonopy,
                      supercell_matrix=5 * np.eye(3),
                      primitive_matrix=None)

    supercell = phonopy.get_supercell()
    supercell = Atoms(cell=supercell.cell,
                      numbers=supercell.numbers,
                      pbc=True,
                      scaled_positions=supercell.get_scaled_positions())
    fcs = fcp.get_force_constants(supercell)

    phonopy.set_force_constants(fcs.get_fc_array(order=2))
    phonopy.set_mesh(mesh, is_eigenvectors=True, is_mesh_symmetry=False)
    phonopy.run_total_dos()
    phonopy.plot_total_DOS()
    plt.savefig("phononDOS.png", dpi=200)

    Nq = 51
    G2X = get_band(np.array([0, 0, 0]), np.array([0.5, 0.5, 0]), Nq)
    X2K2G = get_band(np.array([0.5, 0.5, 1.0]), np.array([0, 0, 0]), Nq)
    G2L = get_band(np.array([0, 0, 0]), np.array([0.5, 0.5, 0.5]), Nq)
    bands = [G2X, X2K2G, G2L]

    phonopy.set_band_structure(bands)
    phonopy.plot_band_structure()
    xticks = plt.gca().get_xticks()
    xticks = [x * hbar * 1e15 for x in xticks]  # Convert THz to meV
    # plt.gca().set_xticks(xticks)
    plt.gca().set_xlabel("Frequency (THz)")
    plt.savefig("phononBand.png", dpi=200)
    phonopy.run_thermal_properties(t_step=10, t_max=800, t_min=100)
    tp_dict = phonopy.get_thermal_properties_dict()
    temperatures = tp_dict['temperatures']
    free_energy = tp_dict['free_energy']

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(temperatures, free_energy)

    plt.show()
    def get_rand_FCM(self, asum=15, force=10):
        """
        Generate a symmeterized force constant matrix from an unsymmeterized matrix
        that has no unstable modes and also obeys the acoustic sum rule through an
        iterative procedure

        Args:
            force (float): maximum force constant
            asum (int): number of iterations to attempt to obey the acoustic sum
                rule

        Return:
            NxNx3x3 np.array representing the force constant matrix

        """

        numsites = len(self.structure.sites)
        structure = pymatgen.io.phonopy.get_phonopy_structure(self.structure)
        pnstruc = Phonopy(structure, np.eye(3), np.eye(3))

        dyn = self.get_unstable_FCM(force)
        dyn = self.get_stable_FCM(dyn)

        dyn = np.reshape(dyn, (numsites, 3, numsites, 3)).swapaxes(1, 2)

        dynmass = np.zeros([len(self.structure), len(self.structure), 3, 3])
        masses = []
        for j in range(numsites):
            masses.append(self.structure.sites[j].specie.atomic_mass)
        dynmass = np.zeros([numsites, numsites, 3, 3])
        for m in range(numsites):
            for n in range(numsites):
                dynmass[m][n] = dyn[m][n] * np.sqrt(masses[m]) * np.sqrt(
                    masses[n])

        supercell = pnstruc.get_supercell()
        primitive = pnstruc.get_primitive()

        converter = dyntofc.DynmatToForceConstants(primitive, supercell)

        dyn = np.reshape(np.swapaxes(dynmass, 1, 2),
                         (numsites * 3, numsites * 3))

        converter.set_dynamical_matrices(dynmat=[dyn])

        converter.run()
        fc = converter.get_force_constants()

        return fc
Пример #8
0
def phonopy_commensurate_shifts_inline(**kwargs):
    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy import Phonopy
    from phonopy.harmonic.dynmat_to_fc import get_commensurate_points, DynmatToForceConstants

    structure = kwargs.pop('structure')
    phonopy_input = kwargs.pop('phonopy_input').get_dict()
    force_constants = kwargs.pop('force_constants').get_array('force_constants')
    r_force_constants = kwargs.pop('r_force_constants').get_array('force_constants')


    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'],
                     distance=phonopy_input['distance'])

    primitive = phonon.get_primitive()
    supercell = phonon.get_supercell()


    phonon.set_force_constants(force_constants)

    dynmat2fc = DynmatToForceConstants(primitive, supercell)
    com_points = dynmat2fc.get_commensurate_points()

    phonon.set_qpoints_phonon(com_points,
                              is_eigenvectors=True)
    frequencies_h = phonon.get_qpoints_phonon()[0]


    phonon.set_force_constants(r_force_constants)

    phonon.set_qpoints_phonon(com_points,
                              is_eigenvectors=True)
    frequencies_r = phonon.get_qpoints_phonon()[0]

    shifts = frequencies_r - frequencies_h

    # Stores DOS data in DB as a workflow result
    commensurate = ArrayData()
    commensurate.set_array('qpoints', com_points)
    commensurate.set_array('shifts', shifts)

    return {'commensurate': commensurate}
Пример #9
0
def get_commensurate(structure, ph_settings):
    from phonopy import Phonopy
    from phonopy.harmonic.dynmat_to_fc import DynmatToForceConstants
    from aiida_phonopy.workchains.phonon import phonopy_bulk_from_structure

    phonon = Phonopy(phonopy_bulk_from_structure(structure),
                     ph_settings.dict.supercell,
                     primitive_matrix=ph_settings.dict.primitive,
                     symprec=ph_settings.dict.symmetry_precision)

    primitive = phonon.get_primitive()
    supercell = phonon.get_supercell()

    dynmat2fc = DynmatToForceConstants(primitive, supercell)
    commensurate = dynmat2fc.get_commensurate_points()

    return dynmat2fc, commensurate
Пример #10
0
 def _get_phonon(self):
     cell = read_vasp(os.path.join(data_dir, "../POSCAR_NaCl"))
     phonon = Phonopy(cell, np.diag([2, 2, 2]), primitive_matrix=[[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]])
     filename = os.path.join(data_dir, "FORCE_SETS_NaCl")
     force_sets = parse_FORCE_SETS(filename=filename)
     phonon.set_displacement_dataset(force_sets)
     phonon.produce_force_constants()
     supercell = phonon.get_supercell()
     born_elems = {
         "Na": [[1.08703, 0, 0], [0, 1.08703, 0], [0, 0, 1.08703]],
         "Cl": [[-1.08672, 0, 0], [0, -1.08672, 0], [0, 0, -1.08672]],
     }
     born = [born_elems[s] for s in ["Na", "Cl"]]
     epsilon = [[2.43533967, 0, 0], [0, 2.43533967, 0], [0, 0, 2.43533967]]
     factors = 14.400
     phonon.set_nac_params({"born": born, "factor": factors, "dielectric": epsilon})
     return phonon
Пример #11
0
 def _get_phonon(self, cell):
     phonon = Phonopy(cell, np.diag([1, 1, 1]))
     force_sets = parse_FORCE_SETS(
         filename=os.path.join(data_dir, "FORCE_SETS"))
     phonon.dataset = force_sets
     phonon.produce_force_constants()
     supercell = phonon.get_supercell()
     born_elems = {
         'Na': [[1.08703, 0, 0], [0, 1.08703, 0], [0, 0, 1.08703]],
         'Cl': [[-1.08672, 0, 0], [0, -1.08672, 0], [0, 0, -1.08672]]
     }
     born = [born_elems[s] for s in supercell.get_chemical_symbols()]
     epsilon = [[2.43533967, 0, 0], [0, 2.43533967, 0], [0, 0, 2.43533967]]
     factors = 14.400
     phonon.set_nac_params({
         'born': born,
         'factor': factors,
         'dielectric': epsilon
     })
     return phonon
Пример #12
0
 def _get_phonon(self, cell):
     phonon = Phonopy(cell, np.diag([1, 1, 1]))
     force_sets = parse_FORCE_SETS(
         filename=os.path.join(data_dir, "FORCE_SETS"))
     phonon.dataset = force_sets
     phonon.produce_force_constants()
     supercell = phonon.get_supercell()
     born_elems = {'Na': [[1.08703, 0, 0],
                          [0, 1.08703, 0],
                          [0, 0, 1.08703]],
                   'Cl': [[-1.08672, 0, 0],
                          [0, -1.08672, 0],
                          [0, 0, -1.08672]]}
     born = [born_elems[s]
             for s in supercell.get_chemical_symbols()]
     epsilon = [[2.43533967, 0, 0],
                [0, 2.43533967, 0],
                [0, 0, 2.43533967]]
     factors = 14.400
     phonon.set_nac_params({'born': born,
                            'factor': factors,
                            'dielectric': epsilon})
     return phonon
Пример #13
0
def get_commensurate_points(structure, phonopy_input):

    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy.harmonic.dynmat_to_fc import DynmatToForceConstants
    from phonopy import Phonopy

    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'],
                     distance=phonopy_input['distance'],
                     symprec=phonopy_input['symmetry_precision'])

    primitive = phonon.get_primitive()
    supercell = phonon.get_supercell()

    dynmat2fc = DynmatToForceConstants(primitive, supercell)
    com_points = dynmat2fc.get_commensurate_points()

    return com_points
Пример #14
0
class PhononBase(TaskElement):
    """PhononBase class

    This is an interface to phonopy.

    """

    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 distance=None,
                 displace_plusminus='auto',
                 displace_diagonal=False,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 is_cell_relaxed=False,
                 stop_condition=None,
                 traverse=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._distance = distance
        self._displace_plusminus = displace_plusminus
        self._displace_diagonal = displace_diagonal
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._is_cell_relaxed = is_cell_relaxed
        self._stop_condition = stop_condition
        self._traverse = traverse

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._space_group = None
        self._cell = None
        self._phonon = None # Phonopy object
        self._phonon_tasks = None # Phonopy object

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._phonon_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def get_space_group(self):
        return self._space_group
        
    def set_status(self):
        if self._stage == 0:
            task = self._tasks[0]
            if task.done():
                self._space_group = task.get_space_group()
                status = task.get_status()
                if status == "done":
                    if not self._evaluate_stop_condition():
                        self._status = "next"
                else:
                    self._status = status
        else:
            done = True
            terminate = True
            for task in self._tasks:
                done &= task.done()
                terminate &= (task.get_status() == "terminate")
                
            if done:
                if terminate:
                    self._status = "terminate"
                else:
                    self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print "set_job has to be executed."
            raise

        self._overwrite_settings()

        if self._is_cell_relaxed:
            self._phonon_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def done(self):
        return (self._status == "terminate" or
                self._status == "done" or
                self._status == "max_iteration" or
                self._status == "low_symmetry" or
                self._status == "next")

    def next(self):
        if self._stage == 0:
            if self._status == "next":
                self._energy = self._tasks[0].get_energy()
                num_atom = len(self._tasks[0].get_cell().get_symbols())
                self._comment = self._space_group['international_standard']
                self._comment += "\\n%f/%d" % (self._energy, num_atom)
                self._set_stage1()
                return self._tasks
            elif (self._status == "terminate" and self._traverse == "restart"):
                self._traverse = False
                self._set_stage0()
                return self._tasks
                
        else: # task 1..n: displaced supercells
            if self._status == "next":
                self._status = "done"
                forces = []
                for task in self._tasks:
                    forces.append(task.get_properties()['forces'][-1])
                self._phonon.produce_force_constants(forces)
                write_FORCE_SETS(self._phonon.get_displacement_dataset())
                self._tasks = []
            elif self._status == "terminate" and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._phonon_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
                
        self._write_yaml()
            
        raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._phonon_tasks = [task]
        self._tasks = [task]
        
    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()
        self._phonon_tasks += self._tasks

    def _evaluate_stop_condition(self):
        if self._stop_condition:
            if "symmetry_operations" in self._stop_condition:
                num_ops = len(self._space_group['rotations'])
                if (num_ops <
                    self._stop_condition['symmetry_operations']):
                    self._status = "low_symmetry"
                    return True
                    
        return False
        
    def _set_phonon(self):
        cell = self.get_cell()
        phonopy_cell = cell2atoms(cell)
        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               primitive_matrix=self._primitive_matrix,
                               is_auto_displacements=False,
                               dynamical_matrix_decimals=14,
                               force_constants_decimals=14)
        self._phonon.generate_displacements(
            distance=self._distance,
            is_plusminus=self._displace_plusminus,
            is_diagonal=self._displace_diagonal)
        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, "POSCAR-unitcell")
        write_disp_yaml(displacements, supercell)

    def _write_yaml(self):
        w = open("%s.yaml" % self._directory, 'w')
        w.write("supercell_matrix:\n")
        for row in self._supercell_matrix:
            w.write("- [ %3d, %3d, %3d ]\n" % tuple(row))
        w.write("primitive_matrix:\n")
        for row in self._primitive_matrix:
            w.write("- [ %6.3f, %6.3f, %6.3f ]\n" % tuple(row))
        w.write("distance: %f\n" % self._distance)
        
        if self._phonon_tasks[0]:
            if self._lattice_tolerance is not None:
                w.write("lattice_tolerance: %f\n" % self._lattice_tolerance)
            if self._stress_tolerance is not None:
                w.write("stress_tolerance: %f\n" % self._stress_tolerance)
                w.write("pressure_target: %f\n" % self._pressure_target)
            w.write("force_tolerance: %f\n" % self._force_tolerance)
            if self._max_increase is None:
                w.write("max_increase: unset\n")
            else:
                w.write("max_increase: %f\n" % self._max_increase)
            w.write("max_iteration: %d\n" % self._max_iteration)
            w.write("min_iteration: %d\n" % self._min_iteration)
            w.write("iteration: %d\n" % self._phonon_tasks[0].get_stage())
            if self._energy:
                w.write("electric_total_energy: %20.10f\n" % self._energy)
                
        w.write("status: %s\n" % self._status)
        w.write("tasks:\n")
        for task in self._phonon_tasks:
            if task and task.get_status():
                w.write("- name:   %s\n" % task.get_name())
                w.write("  status: %s\n" % task.get_status())
        w.close()
Пример #15
0
def phonopy_run(phonon, single=True, filename='FORCE_SETS'):
    """Run the phonon calculations, using PhonoPy.
    
    The force constants are then stored in the Phonon ASE object.
          
    input:
    
      phonon: ASE Phonon object with Atoms and Calculator
      single: when True, the forces are computed only for a single step, and then
              exit. This allows to split the loop in independent iterations. When
              calling again the 'run' method, already computed steps are ignored,
              missing steps are completed, until no more are needed. When set to
              False, all steps are done in a row.
    
    output:
    
      True when a calculation step was performed, False otherwise or no more is needed.
      nb_of_iterations: the number of steps remaining

    """

    from phonopy import Phonopy
    from phonopy.structure.atoms import Atoms as PAtoms
    from phonopy.structure.atoms import PhonopyAtoms
    import phonopy.file_IO as file_IO

    # we first look if an existing phonon pickle exists. This is the case if we
    # are running with iterative calls while return value is True. The first call
    # will then create the objects, which are subsequently updated until False.

    # Set calculator if provided
    # assert phonon.calc is not None, "Provide calculator in Phonon __init__ method"

    # Atoms in the supercell -- repeated in the lattice vector directions
    # beginning with the last
    supercell = phonon.atoms * phonon.N_c

    # create a PhonopyAtoms object
    cell = PhonopyAtoms(phonon.atoms.get_chemical_symbols(),
                        positions=phonon.atoms.get_positions(),
                        cell=phonon.atoms.get_cell(),
                        magmoms=None)

    # is there an existing PhonoPy calculation ?
    # using factor=6.46541380e-2=VaspToeV
    if os.path.exists('FORCE_SETS'):
        phonpy = Phonopy(cell,
                         numpy.diag(phonon.N_c),
                         primitive_matrix=None,
                         dynamical_matrix_decimals=None,
                         force_constants_decimals=None,
                         symprec=1e-05,
                         is_symmetry=True,
                         use_lapack_solver=False,
                         log_level=1)
        force_sets = file_IO.parse_FORCE_SETS(filename='FORCE_SETS')
        phonpy.set_displacement_dataset(force_sets)
        # inactivate magmoms in supercell as some calculators do not provide that
        phonpy._supercell.magmoms = None
        phonpy.produce_force_constants(calculate_full_force_constants=False)
    else:
        # create a PhonoPy Phonon object.
        phonpy = Phonopy(cell, numpy.diag(phonon.N_c))
        # generate displacements (minimal set)
        phonpy.generate_displacements(distance=0.01)
        # iterative call for all displacements
        set_of_forces, flag, nb_of_iterations = phonopy_run_calculate(
            phonon, phonpy, supercell, single)

        if flag is True:
            return nb_of_iterations  # some more work is required

        sys.stdout.write('[ASE/Phonopy] Computing force constants\n')
        # use symmetry to derive forces in equivalent displacements
        phonpy.produce_force_constants(forces=set_of_forces)

        # generate disp.yaml and FORCE_SETS (for later use)
        displacements = phonpy.get_displacements()
        directions = phonpy.get_displacement_directions()
        file_IO.write_disp_yaml(displacements,
                                phonpy.get_supercell(),
                                directions=directions)
        file_IO.write_FORCE_SETS(phonpy.get_displacement_dataset())

    # store as additional data in atoms 'info'
    phonon.atoms.info["phonopy"] = phonpy

    # save the PhonoPy object
    fid = opencew("phonopy.pkl")
    if fid is not None and rank == 0:
        print("[ASE/Phonopy] Writing %s" % "phonopy.pkl")
        pickle.dump(phonpy, fid, protocol=2)
        fid.close()

    # transfer results to the ASE phonon object
    # Number of atoms (primitive cell)
    natoms = len(phonon.indices)
    # Number of unit cells (supercell)
    N = numpy.prod(phonon.N_c)

    # Phonopy: force_constants size is [N*natoms,N*natoms,3,3]
    # Phi[i,j,a,b] with [i,j = atom in supercell] and [a,b=xyz]
    force_constants = phonpy.get_force_constants()
    # the atoms [i] which are moved are in the first cell of the supercell, i.e.Ni=0
    # the forces are then stored for all atoms [Nj,j] as [3,3] matrices

    # we compute the sum on all supercells, which all contain n atoms.
    C_N = numpy.zeros((N, 3 * natoms, 3 * natoms), dtype=complex)
    Ni = 0
    for Nj in range(N):
        for ni in range(natoms):
            Nni = ni
            for nj in range(natoms):
                # compute Nn indices
                Nnj = Nj * natoms + nj
                # get fc 3x3 matrix
                C_N[Nj, (3 * ni):(3 * ni + 3),
                    (3 * nj):(3 * nj + 3)] += force_constants[Nni][Nnj]

    # convert to ASE storage
    # ASE: phonon.C_N size is be [N, 3*natoms, 3*natoms]
    # Phi[i,j] = Phi[j,i]
    phonon.C_N = C_N

    # fill dynamical matrix (mass prefactor)
    phonon.D_N = phonon.C_N.copy()

    # Add mass prefactor
    m_a = phonon.atoms.get_masses()
    phonon.m_inv_x = numpy.repeat(m_a[phonon.indices]**-0.5, 3)
    M_inv = numpy.outer(phonon.m_inv_x, phonon.m_inv_x)
    for D in phonon.D_N:
        D *= M_inv

    return 0  # nothing left to do
Пример #16
0
def get_phonon_tb(
    # phonopy_atoms=[],
    atoms=[],
    fc=[],
    out_file="phonopyTB_hr.dat",
    distance_to_A=1.0,
    scell=np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]),
    factor=VaspToTHz,
    symprec=1e-05,
    displacement_distance=0.01,
):
    """Generate phonon TB Hamiltonia, along with WannierHamn."""
    # Forked from Wannier-tools
    unitcell = atoms.phonopy_converter()
    # unitcell = phonopy_atoms
    prim_mat = np.array(PhonopyInputs(atoms).prim_axis().split("=")[1].split(),
                        dtype="float").reshape(3, 3)
    # print("cell", unitcell.cell)
    num_atom = unitcell.get_number_of_atoms()
    num_satom = determinant(scell) * num_atom
    if fc.shape[0] != num_satom:
        print("Check Force constant matrix.")
    phonon = Phonopy(
        unitcell,
        scell,
        primitive_matrix=prim_mat,
        factor=factor,
        dynamical_matrix_decimals=None,
        force_constants_decimals=None,
        symprec=symprec,
        is_symmetry=True,
        use_lapack_solver=False,
        log_level=1,
    )

    supercell = phonon.get_supercell()
    primitive = phonon.get_primitive()
    # Set force constants
    phonon.set_force_constants(fc)
    phonon._set_dynamical_matrix()
    dmat = phonon._dynamical_matrix
    # rescale fcmat by THZ**2
    fcmat = dmat._force_constants * factor**2  # FORCE_CONSTANTS
    # fcmat = dmat._force_constants * factor ** 2  # FORCE_CONSTANTS
    smallest_vectors = dmat._smallest_vectors
    # mass = dmat._mass
    mass = dmat._pcell.get_masses()
    print("mass=", mass)
    multi = dmat._multiplicity
    reduced_bases = get_reduced_bases(supercell.get_cell(), symprec)
    positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases))
    # for pos in positions: pos -= np.rint(pos)
    relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive.get_cell()))
    super_pos = np.zeros((num_satom, 3), dtype=np.float64)
    for i in range(num_satom):
        super_pos[i] = np.dot(positions[i], relative_scale)
    p2s_map = dmat._p2s_map = primitive.get_primitive_to_supercell_map()
    s2p_map = dmat._s2p_map = primitive.get_supercell_to_primitive_map()
    num_satom = supercell.get_number_of_atoms()
    num_patom = primitive.get_number_of_atoms()
    get_phonon_hr(
        fcmat,
        smallest_vectors,
        mass,
        multi,
        super_pos,
        p2s_map,
        s2p_map,
        num_satom,
        num_patom,
        out_file,
    )
    print("phonopy_TB.dat generated! ")
Пример #17
0
def calculate_phonon(atoms,
                     calc=None,
                     forces_set_file=None,
                     ndim=np.eye(3),
                     primitive_matrix=np.eye(3),
                     distance=0.01,
                     factor=VaspToTHz,
                     is_plusminus='auto',
                     is_symmetry=True,
                     symprec=1e-5,
                     func=None,
                     prepare_initial_wavecar=False,
                     skip=None,
                     restart=True,
                     parallel=True,
                     sc_mag=None,
                     **func_args):
    """
    """
    if 'magmoms' in atoms.arrays or 'initial_magmoms' in atoms.arrays:
        is_mag = True
    else:
        is_mag = False
    print("is_mag: ", is_mag)
    # 1. get displacements and supercells
    if calc is not None:
        atoms.set_calculator(calc)
    # bulk = PhonopyAtoms(atoms=atoms)
    if is_mag:
        bulk = PhonopyAtoms(
            symbols=atoms.get_chemical_symbols(),
            scaled_positions=atoms.get_scaled_positions(),
            cell=atoms.get_cell(),
            magmoms=atoms.arrays['initial_magmoms'],
        )
    else:
        bulk = PhonopyAtoms(symbols=atoms.get_chemical_symbols(),
                            scaled_positions=atoms.get_scaled_positions(),
                            cell=atoms.get_cell())

    phonon = Phonopy(bulk,
                     ndim,
                     primitive_matrix=primitive_matrix,
                     factor=factor,
                     symprec=symprec)
    phonon.generate_displacements(distance=distance, is_plusminus=is_plusminus)
    disps = phonon.get_displacements()
    for d in disps:
        print(("[phonopy] %d %s" % (d[0], d[1:])))
    supercell0 = phonon.get_supercell()
    supercells = phonon.get_supercells_with_displacements()
    #write_supercells_with_displacements(supercell0, supercells)
    write_disp_yaml(disps, supercell0)

    # 2. calculated forces.
    if forces_set_file is not None:
        symmetry = phonon.get_symmetry()
        set_of_forces = parse_FORCE_SETS(
            is_translational_invariance=False,
            filename=forces_set_file)  # ['first_atoms']
        # set_of_forces=np.array(set_of_forces)
        #set_of_forces=[np.asarray(f) for f in set_of_forces]
        phonon.set_displacement_dataset(set_of_forces)
        phonon.produce_force_constants()
    else:
        # initialize set of forces
        if restart and os.path.exists('forces_set.pickle'):
            try:
                with open("forces_set.pickle", 'rb') as myfile:
                    set_of_forces = pickle.load(myfile)
                iskip = len(set_of_forces) - 1
            except:
                set_of_forces = []
                iskip = -1
        else:
            set_of_forces = []
            iskip = -1

        if prepare_initial_wavecar and skip is None:
            scell = supercell0
            cell = Atoms(symbols=scell.get_chemical_symbols(),
                         scaled_positions=scell.get_scaled_positions(),
                         cell=scell.get_cell(),
                         pbc=True)
            if is_mag:
                cell.set_initial_magnetic_moments(sc_mag)
            write('Supercell.cif', cell)
            mcalc = copy.deepcopy(calc)
            mcalc.set(lwave=True, lcharg=True)
            cell.set_calculator(mcalc)
            dir_name = "SUPERCELL0"
            cur_dir = os.getcwd()
            if not os.path.exists(dir_name):
                os.mkdir(dir_name)
            os.chdir(dir_name)
            mcalc.scf_calculation(cell)
            os.chdir(cur_dir)

        def calc_force(iscell):
            scell = supercells[iscell]
            cell = Atoms(symbols=scell.get_chemical_symbols(),
                         scaled_positions=scell.get_scaled_positions(),
                         cell=scell.get_cell(),
                         pbc=True)
            if is_mag:
                cell.set_initial_magnetic_moments(sc_mag)
            cell.set_calculator(copy.deepcopy(calc))
            dir_name = "PHON_CELL%s" % iscell
            cur_dir = os.getcwd()
            if not os.path.exists(dir_name):
                os.mkdir(dir_name)
            if prepare_initial_wavecar:
                os.system('ln -s %s %s' %
                          (os.path.abspath("SUPERCELL0/WAVECAR"),
                           os.path.join(dir_name, 'WAVECAR')))

            os.chdir(dir_name)
            forces = cell.get_forces()
            print("[Phonopy] Forces: %s" % forces)
            # Do something other than calculating the forces with func.
            # func: func(atoms, calc, func_args)
            if func is not None:
                func(cell, calc, **func_args)
            os.chdir(cur_dir)
            drift_force = forces.sum(axis=0)
            print("[Phonopy] Drift force:", "%11.5f" * 3 % tuple(drift_force))
            # Simple translational invariance
            for force in forces:
                force -= drift_force / forces.shape[0]
            return forces

        if parallel:
            p = Pool()
            set_of_forces = p.map(calc_force,
                                  list(range(iskip, len(supercells))))
        else:
            for iscell, scell in enumerate(supercells):
                if iscell > iskip:
                    fs = calc_force(iscell)
                    set_of_forces.append(fs)
                    with open("forces_set.pickle", 'wb') as myfile:
                        pickle.dump(set_of_forces, myfile)

        phonon.produce_force_constants(forces=np.array(set_of_forces))
    force_constants = phonon.get_force_constants()
    write_FORCE_CONSTANTS(force_constants, filename='FORCE_CONSTANTS')
    #print("[Phonopy] Phonon frequencies at Gamma:")
    # for i, freq in enumerate(phonon.get_frequencies((0, 0, 0))):
    #    print(("[Phonopy] %3d: %10.5f THz" % (i + 1, freq)))  # THz
    #    print(("[Phonopy] %3d: %10.5f cm-1" % (i + 1, freq * 33.35)))  #cm-1
    with open('phonon.pickle', 'wb') as myfile:
        pickle.dump(phonon, myfile)
    phonon.save(settings={'force_constants': True})
    return phonon
Пример #18
0
def calculate_phonon(atoms,
                     calc,
                     ndim=np.eye(3),
                     primitive_matrix=np.eye(3),
                     distance=0.01,
                     factor=VaspToTHz,
                     is_symmetry=True,
                     symprec=1e-5,
                     func=None,
                     **func_args):
    """
    """
    if 'magmoms' in atoms.arrays:
        is_mag = True
    else:
        is_mag = False
    # 1. get displacements and supercells
    atoms.set_calculator(calc)
    # bulk = PhonopyAtoms(atoms=atoms)
    if is_mag:
        bulk = PhonopyAtoms(
            symbols=atoms.get_chemical_symbols(),
            scaled_positions=atoms.get_scaled_positions(),
            cell=atoms.get_cell(),
            magmoms=atoms.arrays['magmoms'],
        )
    else:
        bulk = PhonopyAtoms(symbols=atoms.get_chemical_symbols(),
                            scaled_positions=atoms.get_scaled_positions(),
                            cell=atoms.get_cell())

    phonon = Phonopy(bulk,
                     ndim,
                     primitive_matrix=primitive_matrix,
                     factor=factor,
                     symprec=symprec)
    phonon.generate_displacements(distance=distance)
    disps = phonon.get_displacements()
    for d in disps:
        print("[phonopy] %d %s" % (d[0], d[1:]))
    supercell0 = phonon.get_supercell()
    supercells = phonon.get_supercells_with_displacements()
    write_supercells_with_displacements(supercell0, supercells)
    write_disp_yaml(disps, supercell0)

    # 2. calculated forces.
    set_of_forces = []
    for iscell, scell in enumerate(supercells):
        cell = Atoms(symbols=scell.get_chemical_symbols(),
                     scaled_positions=scell.get_scaled_positions(),
                     cell=scell.get_cell(),
                     pbc=True)
        if is_mag:
            cell.set_initial_magnetic_moments(
                atoms.get_initial_magnetic_moments())
        cell.set_calculator(calc)
        dir_name = "PHON_CELL%s" % iscell
        cur_dir = os.getcwd()
        if not os.path.exists(dir_name):
            os.mkdir(dir_name)
        os.chdir(dir_name)
        forces = cell.get_forces()
        #print "[Phonopy] Forces: %s" % forces
        # Do something other than calculating the forces with func.
        # func: func(atoms, calc, func_args)
        if func is not None:
            func(cell, calc, **func_args)
        os.chdir(cur_dir)
        drift_force = forces.sum(axis=0)
        #print "[Phonopy] Drift force:", "%11.5f" * 3 % tuple(drift_force)
        # Simple translational invariance
        for force in forces:
            force -= drift_force / forces.shape[0]
        set_of_forces.append(forces)

    # Phonopy post-process
    phonon.produce_force_constants(forces=set_of_forces)
    force_constants = phonon.get_force_constants()
    write_FORCE_CONSTANTS(force_constants, filename='FORCE_CONSTANTS')
    print('')
    print("[Phonopy] Phonon frequencies at Gamma:")
    for i, freq in enumerate(phonon.get_frequencies((0, 0, 0))):
        print("[Phonopy] %3d: %10.5f THz" % (i + 1, freq))  # THz
        print("[Phonopy] %3d: %10.5f cm-1" % (i + 1, freq * 33.35))  #cm-1
    return phonon
Пример #19
0
class PhononBase(TaskElement):
    """PhononBase class

    This is an interface to phonopy.

    """
    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 distance=None,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 traverse=False,
                 is_cell_relaxed=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._distance = distance
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._traverse = traverse
        self._is_cell_relaxed = is_cell_relaxed

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._cell = None
        self._phonon = None  # Phonopy object

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._phonon_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def set_status(self):
        done = True
        terminate = False
        for task in self._tasks:
            done &= task.done()
            if task.get_status() == "terminate":
                terminate = True
        if done:
            if terminate:
                self._status = "terminate"
            else:
                self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print "set_job has to be executed."
            raise

        self._overwrite_settings()

        if self._is_cell_relaxed:
            self._phonon_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def end(self):
        pass

    def done(self):
        return ("terminate" in self._status or "done" in self._status
                or "next" in self._status)

    def next(self):
        if self._stage == 0:
            if "next" in self._status:
                self._energy = self._tasks[0].get_energy()
                self._comment = "%s\\n%f" % (self._tasks[0].get_space_group(
                )['international_standard'], self._energy)
                self._set_stage1()
                return self._tasks
            elif "terminate" in self._status and self._traverse == "restart":
                self._traverse = False
                self._set_stage0()
                return self._tasks
            else:
                raise StopIteration
        else:  # task 1..n: displaced supercells
            if "next" in self._status:
                self._status = "done"
                forces = []
                for task in self._phonon_tasks[1:]:
                    forces.append(task.get_properties()['forces'][-1])
                self._write_FORCE_SETS(forces)
                self._phonon.set_post_process(self._primitive_matrix,
                                              forces,
                                              force_constants_decimals=14)
                self._tasks = []
                raise StopIteration
            elif "terminate" in self._status and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()[1:]
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._phonon_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
            else:
                raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._phonon_tasks = [task]
        self._tasks = [task]

    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()[1:]
        self._phonon_tasks += self._tasks

    def _set_phonon(self):
        cell = self.get_cell()
        phonopy_cell = Atoms(cell=cell.get_lattice().T,
                             scaled_positions=cell.get_points().T,
                             symbols=cell.get_symbols())

        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               is_auto_displacements=False)
        self._phonon.generate_displacements(distance=self._distance,
                                            is_diagonal=False)

        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, "POSCAR-unitcell")
        write_disp_yaml(displacements, supercell)

    def _write_FORCE_SETS(self, forces):
        displacements = [[x[0], x[1:4]]
                         for x in self._phonon.get_displacements()]
        natom = self._phonon.get_supercell().get_number_of_atoms()
        write_FORCE_SETS("FORCE_SETS",
                         natom,
                         displacements,
                         forces,
                         verbose=False)

    def _write_yaml(self):
        w = open("%s.yaml" % self._directory, 'w')
        if self._phonon_tasks[0]:
            if self._lattice_tolerance is not None:
                w.write("lattice_tolerance: %f\n" % self._lattice_tolerance)
            if self._stress_tolerance is not None:
                w.write("stress_tolerance: %f\n" % self._stress_tolerance)
                w.write("pressure_target: %f\n" % self._pressure_target)
            w.write("force_tolerance: %f\n" % self._force_tolerance)
            w.write("max_increase: %f\n" % self._max_increase)
            w.write("max_iteration: %d\n" % self._max_iteration)
            w.write("min_iteration: %d\n" % self._min_iteration)
            w.write("supercell_matrix:\n")
            for row in self._supercell_matrix:
                w.write("- [ %3d, %3d, %3d ]\n" % tuple(row))
            w.write("primitive_matrix:\n")
            for row in self._primitive_matrix:
                w.write("- [ %6.3f, %6.3f, %6.3f ]\n" % tuple(row))
            w.write("distance: %f\n" % self._distance)
            w.write("iteration: %d\n" % self._phonon_tasks[0].get_stage())
            if self._energy:
                w.write("electric_total_energy: %20.10f\n" % self._energy)
        w.write("status: %s\n" % self._status)
        w.write("tasks:\n")
        for task in self._phonon_tasks:
            if task and task.get_status():
                w.write("- name:   %s\n" % task.get_name())
                w.write("  status: %s\n" % task.get_status())
        w.close()
Пример #20
0
    NNN,
    # primitive_matrix = [[0.5,0.5,0],[0,0.5,0.5],[0.5,0,0.5]],
    primitive_matrix=primitive_matrix,
    nac_params=nac_params,
    factor=factor,
    is_symmetry=is_symmetry,
)
phonon.generate_displacements(
    distance=delta,
    is_plusminus=is_plusminus,
)

pho_disp = phonon.get_supercells_with_displacements()

vasp.write_supercells_with_displacements(
    phonon.get_supercell(),
    pho_disp,
)

######### get new phonon object ##########
#
import ss_phonopy as ssp
phonon = ssp.calc_phonon(
    calc,
    phonon,
    acoustic_sum_rule=acou_sum_rule,
    rot_sum_rule=rot_sum_rule,
    r_cut=r_cut,
    # F_0_correction=True,
    # verbose=True,
    # ase_calc=ase_calc,
Пример #21
0
    else:
        file_exists("FORCE_SETS", log_level)

phonon = Phonopy(unitcell,
                 settings.get_supercell_matrix(),
                 primitive_matrix=settings.get_primitive_matrix(),
                 factor=factor,
                 is_auto_displacements=False,
                 dynamical_matrix_decimals=settings.get_dm_decimals(),
                 force_constants_decimals=settings.get_fc_decimals(),
                 symprec=options.symprec,
                 is_symmetry=settings.get_is_symmetry(),
                 use_lapack_solver=settings.get_lapack_solver(),
                 log_level=log_level)

supercell = phonon.get_supercell()
primitive = phonon.get_primitive()

# Set atomic masses of primitive cell
if settings.get_masses() is not None:
    phonon.set_masses(settings.get_masses())

# Print cells
if log_level > 1:
    print_cells(phonon, unitcell_filename)

# Set force constants
if settings.get_is_force_constants() == 'read':
    phonon.set_force_constants(fc)

# Impose cutoff radius on force constants
Пример #22
0
def get_phonon_distrib_alist(
    prim_cell,
    NNN,
    T,
    seed_range,
    calc,
    cp_files=None,
    plus_minus=True,
    delta=0.01,
    ):
    """
    prim_cell (str)
        ASE readable primitive unitcell structure file.
    NNN (list of int, shape: (3,3))
        Supercell matrix used to calculate force constants.
    T (float)
        Temperature in Kelvin unit.
    seed_range (range or list of int)
        Seeds for random number generation.
    calc (str, choices: ('lmp', 'vasp'))
        Calculator for force calculation.
    cp_files (list of str)
        List of input files for force calculation.
    plus_minus (bool)
        Option handed to ASE function.
    delta (float)
        Displacement in Angstrom for finite displacement method.
    """

    # Main
    from ase.io import read, write
    atoms = read(prim_cell)
    from phonopy import Phonopy
    phonon = Phonopy(
        atoms,
        NNN,
        )
    phonon.generate_displacements(
        delta,
        )
    pho_super = phonon.get_supercell()
    pho_disp  = phonon.get_supercells_with_displacements()
    from phonopy.interface import vasp
    vasp.write_supercells_with_displacements(
        pho_super,
        pho_disp,
        )
    import ss_phonopy as ssp
    phonon = ssp.calc_phonon(
        calc,
        phonon,
        cp_files=cp_files,
        )
    masses = pho_super.masses
    job_name = 'eig_x{}{}{}_d{:5.3f}_sym{}'.format(NNN[0][0], NNN[1][1], NNN[2][2], delta, phonon._is_symmetry)
    try:
        e_s = np.load('{}.npz'.format(job_name))
    except:
        print('Failed to load {}.npz file. Start to solve eigen problem.'.format(job_name))
        eigen_set = get_eigen_set(
            phonon.get_force_constants(),
            masses,
            )
        np.savez('{}.npz'.format(job_name), w2=eigen_set[0], D=eigen_set[1])
    else:
        print('Successfully loaded {}.npz file!'.format(job_name))
        eigen_set = (e_s['w2'], e_s['D'])

    from ase.md.velocitydistribution import phonon_harmonics
    from ase import Atoms, units
    alist = []
    for i in seed_range:
        d_ac, v_ac = phonon_harmonics(
            None,
            masses,
            T *units.kB,
            eigen_set=eigen_set,
            # rng=np.random.rand,
            seed=i,
            quantum=True,
            plus_minus=plus_minus,
            # return_eigensolution=False,
            # failfast=True,
            )
        new_super = Atoms(
            cell       = pho_super.get_cell(),
            symbols    = pho_super.get_chemical_symbols(),
            positions  = pho_super.get_positions() + d_ac,
            velocities = v_ac,
            pbc        = True,
            )
        alist.append(new_super)
    return(alist)
Пример #23
0
def phonopy_merge(**kwargs):
    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy import Phonopy
    from phonopy.units import VaspToTHz
    from phonopy.harmonic.dynmat_to_fc import get_commensurate_points, DynmatToForceConstants

    structure = kwargs.pop('structure')
    phonopy_input = kwargs.pop('phonopy_input').get_dict()

    harmonic = kwargs.pop('harmonic')
    renormalized = kwargs.pop('renormalized')

    eigenvectors = harmonic.get_array('eigenvectors')
    frequencies = harmonic.get_array('frequencies')
    shifts = renormalized.get_array('shifts')


    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'],
                     distance=phonopy_input['distance'])

    primitive = phonon.get_primitive()
    supercell = phonon.get_supercell()



    total_frequencies = frequencies + shifts

    dynmat2fc = DynmatToForceConstants(primitive, supercell)
    dynmat2fc.set_dynamical_matrices(total_frequencies / VaspToTHz, eigenvectors)
    dynmat2fc.run()

    total_force_constants = dynmat2fc.get_force_constants()

    # Stores DOS data in DB as a workflow result
    total_data = ArrayData()
    total_data.set_array('force_constants', total_force_constants)

    return {'final_results': total_data}



    # Start script here

    # Workflow phonon (at given volume)
    wf = load_workflow(431)
    parameters = wf.get_parameters()
    results = wf.get_results()

    inline_params = {'structure': results['final_structure'],
                     'phonopy_input': parameters['phonopy_input'],
                     'force_constants': results['force_constants']}

    harmonic = phonopy_commensurate_inline(**inline_params)



    # At reference volume (at T = 0)
    wf = load_workflow(432)
    parameters = wf.get_parameters()
    results_r = wf.get_results()
    results_h = wf.get_results()


    inline_params = {'structure': results_h['final_structure'],
                     'phonopy_input': parameters['phonopy_input'],
                     'force_constants': results_h['force_constants'],
                     'r_force_constants': results_r['r_force_constants']}


    renormalized = phonopy_commensurate_shifts_inline(**inline_params)





    inline_params = {'structure': results_h['final_structure'],
                     'phonopy_input': parameters['phonopy_input'],
                     'harmonic': harmonic,
                     'renormalized': renormalized}

    total = phonopy_merge(**inline_params)

    print total

    inline_params = {'structure': results_h['final_structure'],
                     'phonopy_input': parameters['phonopy_input'],
                     'force_constants': total['force_constants']}

    results = phonopy_calculation_inline(**inline_params)[1]

    band = results['band_structure']


    # Phonon Band structure plot
    plot_data(results['band_structure'])
Пример #24
0
class PhononBase(TaskElement, PhononYaml):
    """PhononBase class

    This is an interface to phonopy.

    """

    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 nac=False,
                 distance=None,
                 displace_plusminus='auto',
                 displace_diagonal=False,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 is_cell_relaxed=False,
                 max_num_atoms=None,
                 stop_condition=None,
                 symmetry_tolerance=None,
                 traverse=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        if self._supercell_matrix is None:
            self._primitive_matrix = np.eye(3, dtype='double')
        else:
            self._primitive_matrix = primitive_matrix
        self._nac = nac
        self._distance = distance
        self._displace_plusminus = displace_plusminus
        self._displace_diagonal = displace_diagonal
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._is_cell_relaxed = is_cell_relaxed
        self._max_num_atoms = max_num_atoms
        self._stop_condition = stop_condition
        self._symmetry_tolerance = symmetry_tolerance
        self._traverse = traverse

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._born = None
        self._epsilon = None

        self._space_group = None
        self._cell = None
        self._phonon = None # Phonopy object
        self._all_tasks = None

        self._try_collect_forces = True

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._all_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def get_space_group(self):
        return self._space_group

    def set_status(self):
        if self._stage == 0:
            task = self._tasks[0]
            if task.done():
                self._space_group = task.get_space_group()
                status = task.get_status()
                if status == "done":
                    if not self._evaluate_stop_condition():
                        self._status = "next"
                else:
                    self._status = status
        else:
            done = True
            terminate = False
            for i, task in enumerate(self._tasks):
                done &= task.done()
                if (task.get_status() == "terminate" or
                    task.get_status() == "max_iteration"):
                    terminate = True
            if done:
                if terminate:
                    self._status = "terminate"
                else:
                    self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print("set_job has to be executed.")
            raise RuntimeError

        if self._is_cell_relaxed:
            self._all_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def done(self):
        return (self._status == "terminate" or
                self._status == "done" or
                self._status == "max_iteration" or
                self._status == "low_symmetry" or
                self._status == "force_collection_failure" or
                self._status == "next")

    def __next__(self):
        return self.next()

    def next(self):
        if self._stage == 0:
            if self._status == "next":
                self._energy = self._tasks[0].get_energy()
                num_atom = len(self._tasks[0].get_cell().get_symbols())
                self._comment = self._space_group['international']
                self._comment += "\\n%f/%d" % (self._energy, num_atom)
                self._set_stage1()
                return self._tasks
            elif (self._status == "terminate" and self._traverse == "restart"):
                self._traverse = False
                self._set_stage0()
                return self._tasks

        elif self._stage == 1: # task 1..n: displaced supercells
            if self._status == "next":
                if self._collect_forces():
                    if self._nac:
                        self._set_stage2()
                        return self._tasks
                    else:
                        self._status = "done"
                else:
                    if self._try_collect_forces:
                        self._status = "displacements"
                        self._log += ("Collection of forces failed. "
                                      "Try once more.\n")
                        self._try_collect_forces = False
                        raise StopIteration
                    else:
                        self._status = "force_collection_failure"
            elif self._status == "terminate" and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._all_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
        elif self._stage == 2:
            if self._status == "next":
                self._status = "done"
                self._set_born_and_epsilon()
            elif self._status == "terminate" and self._traverse == "restart":
                self._traverse = False
                self._all_tasks.pop()
                self._set_stage2()
        else:
            pass

        self._tasks = []
        self._write_yaml()
        raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._all_tasks = [task]
        self._tasks = [task]

    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()
        self._all_tasks += self._tasks

    def _set_stage2(self):
        self._stage = 2
        self._status = "nac"
        if self._nac == "relax":
            nac_task = self._get_nac_task(is_cell_relaxed=False)
        else:
            nac_task = self._get_nac_task()
        self._tasks = [nac_task]
        self._all_tasks += self._tasks

    def _collect_forces(self):
        forces = []
        for task in self._tasks:
            forces.append(task.get_properties()['forces'][-1])
        if self._phonon.produce_force_constants(forces=forces):
            write_FORCE_SETS(self._phonon.get_displacement_dataset())
            return True
        else:
            # This can be due to delay of writting file to file system.
            return False

    def _set_born_and_epsilon(self):
        nac_task = self._tasks[0]
        born = nac_task.get_born_effective_charge()
        epsilon = nac_task.get_dielectric_constant()

        indep_atoms = self._phonon.get_symmetry().get_independent_atoms()
        supercell = self._phonon.get_supercell()
        s2u = supercell.get_supercell_to_unitcell_map()
        u2u = supercell.get_unitcell_to_unitcell_map()
        indep_atoms_u = [u2u[i] for i in s2u[indep_atoms]]

        if born is not None and epsilon is not None:
            self._born = born
            self._epsilon = epsilon
            header = "# epsilon and Z* of atoms "
            header += ' '.join(["%d" % (n + 1) for n in indep_atoms_u])
            lines = [header]
            lines.append(("%13.8f" * 9) % tuple(epsilon.flatten()))
            for z in born[indep_atoms_u]:
                lines.append(("%13.8f" * 9) % tuple(z.flatten()))
            with open("BORN", 'w') as w:
                w.write('\n'.join(lines))

    def _evaluate_stop_condition(self):
        if self._stop_condition:
            if "symmetry_operations" in self._stop_condition:
                num_ops = len(self._space_group['rotations'])
                if (num_ops <
                    self._stop_condition['symmetry_operations']):
                    self._status = "low_symmetry"
                    return True

        return False

    def _set_phonon(self):
        if self._supercell_matrix is None:
            cell = sort_cell_by_symbols(
                get_crystallographic_cell(self.get_cell()))
            self._supercell_matrix = estimate_supercell_matrix(
                cell,
                max_num_atoms=self._max_num_atoms)
        else:
            cell = self.get_cell()

        phonopy_cell = cell2atoms(cell)
        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               primitive_matrix=self._primitive_matrix,
                               dynamical_matrix_decimals=14,
                               force_constants_decimals=14,
                               symprec=self._symmetry_tolerance)
        self._phonon.generate_displacements(
            distance=self._distance,
            is_plusminus=self._displace_plusminus,
            is_diagonal=self._displace_diagonal)
        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, filename="POSCAR-unitcell")
        write_poscar_yaml(cell, filename="POSCAR-unitcell.yaml")
        write_disp_yaml(displacements, supercell)

    def get_yaml_lines(self):
        lines = TaskElement.get_yaml_lines(self)
        if self._is_cell_relaxed:
            cell = self._cell
        else:
            cell = self.get_cell()
        lines += self._get_phonon_yaml_lines(cell)
        if self._all_tasks[0] is not None:
            if self._energy:
                lines.append("electric_total_energy: %20.10f" % self._energy)

        return lines
Пример #25
0
        band.append(np.array(q_start) +
                    (np.array(q_end) - np.array(q_start)) / 50 * i)
    bands.append(band)

bulk = read_vasp("POSCAR")
phonon = Phonopy(bulk,
                 [[2, 0, 0],
                  [0, 2, 0],
                  [0, 0, 2]],
                 primitive_matrix=[[0, 0.5, 0.5],
                                   [0.5, 0, 0.5],
                                   [0.5, 0.5, 0]],
                 is_auto_displacements=False)

primitive = phonon.get_primitive()
supercell = phonon.get_supercell()
dynmat2fc = DynmatToForceConstants(primitive, supercell)
com_points = dynmat2fc.get_commensurate_points()

print "Commensurate points"
for i, q in enumerate(com_points):
    print i + 1, q

force_sets = parse_FORCE_SETS()
phonon.set_displacement_dataset(force_sets)
phonon.produce_force_constants()
phonon.set_qpoints_phonon(com_points,
                          is_eigenvectors=True)
frequencies, eigenvectors = phonon.get_qpoints_phonon()
dynmat2fc.set_dynamical_matrices(frequencies / VaspToTHz, eigenvectors)
dynmat2fc.run()
Пример #26
0
class PhononFromModel(object):
    """
    This class uses frozen phonon method to calculate the phonon dispersion curves and thermodynamic
    properties of a structure.
    The steps are as follows:
        1. Displaced structures are obtained from pristine structure via phonopy.
        2. The forces of each displaced structures are calculated by model
        3. The forces are passed to phonopy object and the force constant are produced
        4. Phonon is calculated once the force constant matrix is available.

    Args:
        model (model object): a model object that has a method "calculate_forces" that takes in a list of
            structures and return a list of N*3 forces, where N are the number of atoms in each structures
        structure (pymatgen structure): a pristine pymatgen structure
        atom_disp (float): small displacements in Angstrom

    """

    def __init__(self, model=None, structure=None, atom_disp=0.015, **kwargs):
        self.model = model
        self.structure = structure
        self.atom_disp = atom_disp
        self.qpoints, self.vertices = get_qpoints_and_vertices(self.structure)
        is_plusminus = kwargs.get('is_plusminus', True)
        is_diagonal = kwargs.get('is_diagonal', True)
        is_trigonal = kwargs.get('is_diagonal', False)
        supercell_matrix = kwargs.get('is_diagonal', None)
        ph_structure = get_phonopy_structure(self.structure)
        if supercell_matrix is None:
            supercell_matrix = np.eye(3) * np.array((1, 1, 1))
        self.phonon = Phonopy(unitcell=ph_structure, supercell_matrix=supercell_matrix)
        self.phonon.generate_displacements(distance=self.atom_disp,
                                      is_plusminus=is_plusminus,
                                      is_diagonal=is_diagonal,
                                      is_trigonal=is_trigonal)

        disp_supercells = self.phonon.get_supercells_with_displacements()
        # Perfect supercell structure
        init_supercell = self.phonon.get_supercell()
        # Structure list to be returned
        self.structure_list = [get_pmg_structure(init_supercell)]

        for c in disp_supercells:
            if c is not None:
                self.structure_list.append(get_pmg_structure(c))

        forces = self.model.calculate_forces(self.structure_list)
        self.phonon.set_forces(forces[1:])
        self.phonon.produce_force_constants()
        logging.info("Force constant produced") 

    def get_thermo_properties(self, mesh=[8, 8, 8], t_step=10, t_max=3000, t_min=0):
        self.phonon.set_mesh(mesh=mesh)
        self.phonon.set_thermal_properties(t_step=t_step,
                                           t_max=t_max,
                                           t_min=t_min)
        plt = self.phonon.plot_thermal_properties()
        return plt

    def get_bs_plot(self, points_per_line=50, figsize=(6, 4), ylim=[-1, 5]):
        bands = []
        bands = append_bands(bands, self.qpoints, points_per_line)
        self.phonon.set_band_structure(bands)
        q_points, self.distances, self.frequencies, eigvecs = self.phonon.get_band_structure()

        special_points = self.phonon._band_structure._special_points
        distance = self.phonon._band_structure._distance

        plt.figure(figsize=figsize)
        for j, (d, f) in enumerate(zip(self.distances, self.frequencies)):
            for i, freqs in enumerate(f.T):
                if i == 0 and j == 0:
                    plt.plot(d, freqs, "b-", lw=1)
                else:
                    plt.plot(d, freqs, "b-", lw=1)
        for sp in special_points:
            plt.axvline(x=sp, linestyle=':', linewidth=1, color='k')
        plt.axhline(y=0, linestyle=':', linewidth=1, color='k')

        plt.xticks(special_points, ["$\mathrm{%s}$" % i for i in self.vertices])
        plt.xlabel("Wave vector")
        plt.ylabel("Frequency (THz)")
        plt.xlim(0, distance)
        plt.ylim(ylim)
        plt.yticks(list(range(ylim[0], ylim[-1]+1)))
        plt.tight_layout()
        return plt
Пример #27
0
def abinit_to_phonopy(anaddbnc,
                      supercell_matrix,
                      symmetrize_tensors=False,
                      output_dir_path=None,
                      prefix_outfiles="",
                      symprec=1e-5,
                      set_masses=False):
    """
    Converts the interatomic force constants(IFC), born effective charges(BEC) and dielectric
    tensor obtained from anaddb to the phonopy format. Optionally writes the
    standard phonopy files to a selected directory: FORCE_CONSTANTS, BORN (if BECs are available)
    POSCAR of the unit cell, POSCAR of the supercell.

    The conversion is performed taking the IFC in the Wigner–Seitz supercell with weights
    as produced by anaddb and reorganizes them in a standard supercell multiple of the
    unit cell. Operations are vectorized using numpy. This may lead to the allocation of
    large arrays in case of very large supercells.

    Performs a check to verify if the two codes identify the same symmetries and it gives a
    warning in case of failure. Mismatching symmetries may lead to incorrect conversions.

    Args:
        anaddbnc: an instance of AnaddbNcFile. Should contain the output of the IFC analysis,
            the BEC and the dielectric tensor.
        supercell_matrix: the supercell matrix used for phonopy. Any choice is acceptable, however
            the best agreement between the abinit and phonopy results is obtained if this is set to
            a diagonal matrix with on the diagonal the ngqpt used to generate the anaddb.nc.
        symmetrize_tensors: if True the tensors will be symmetrized in the Phonopy object and
            in the output files. This will apply to IFC, BEC and dielectric tensor.
        output_dir_path: a path to a directory where the phonopy files will be created
        prefix_outfiles: a string that will be added as a prefix to the name of the written files
        symprec: distance tolerance in Cartesian coordinates to find crystal symmetry in phonopy.
            It might be that the value should be tuned so that it leads to the the same symmetries
            as in the abinit calculation.
        set_masses: if True the atomic masses used by abinit will be added to the PhonopyAtoms
            and will be present in the returned Phonopy object. This should improve compatibility
            among abinit and phonopy results if frequencies needs to be calculated.

    Returns:
        An instance of a Phonopy object that contains the IFC, BEC and dieletric tensor data.
    """

    ifc = anaddbnc.ifc
    nac_params = None
    becs = None
    epsinf = None
    if anaddbnc.becs is not None and anaddbnc.epsinf is not None:
        becs = anaddbnc.becs.values
        epsinf = anaddbnc.epsinf

        # according to the phonopy website 14.399652 is not the coefficient for abinit
        # probably it relies on the other conventions in the output.
        nac_params = {"born": becs, "dielectric": epsinf, "factor": 14.399652}

    s = anaddbnc.structure

    phon_at = get_phonopy_structure(s)
    if set_masses:
        phon_at.masses = [anaddbnc.amu[n] for n in phon_at.numbers]

    # use phonopy to get the proper supercell given by the primitive and the matrix
    # and convert it to pymatgen
    phonon = Phonopy(phon_at,
                     supercell_matrix,
                     primitive_matrix=np.eye(3),
                     nac_params=nac_params,
                     symprec=symprec)
    phon_supercell = phonon.get_supercell()
    supercell = get_pmg_structure(phon_supercell)

    abi_hall_num = s.abi_spacegroup.get_spglib_hall_number()
    spglib_hall_num = phonon.symmetry.dataset["hall_number"]
    if abi_hall_num != spglib_hall_num:
        warnings.warn(
            "The hall number obtained based on the DDB symmetries differs "
            f"from the one calculated with spglib: {abi_hall_num} versus "
            f"{spglib_hall_num}. The conversion may be incorrect. Try changing symprec."
        )

    # convert to phonopy units
    at_cart = ifc.atoms_cart_coord * abu.Bohr_Ang
    ifccc = ifc.ifc_cart_coord * abu.Ha_eV / abu.Bohr_Ang**2
    weights = ifc.ifc_weights
    latt = supercell.lattice

    ifcph = np.zeros((len(s), len(supercell), 3, 3))

    # loop over the atoms in the primitive cell
    # other operations are vectorized using numpy arrays. Some array may require large allocations
    for i, (site, c_list, w_list) in enumerate(zip(s, at_cart, weights)):

        ind_w = np.where(w_list > 0)
        ifccc_loc = ifccc[i, ind_w[0]]

        w_list = w_list[ind_w]
        c_list = c_list[ind_w]

        # align the coordinates of the first atom in the list (the site under consideration)
        # with the site in the primitive cell.
        c_list = c_list - c_list[0] + site.coords

        # convert to fractional coordinates as needed by the Lattice to get the distances
        f_list = latt.get_fractional_coords(c_list)
        sc_fcoords = supercell.frac_coords

        # construct the list of sites of the supercell that are closer to sites in
        # the primitive cell
        dist_and_img = [
            latt.get_distance_and_image(f_list[0], fc) for fc in sc_fcoords
        ]
        # the function gives the translation of the image, but it should be applied to the coordinates.
        # Only the positions are needed
        nearest_sc_fcoords = [
            fc + trasl for (_, trasl), fc in zip(dist_and_img, sc_fcoords)
        ]

        # divide by the corresponding weights. Elements with weights 0 were discarded above
        ifccc_loc = np.transpose(ifccc_loc, (0, 2, 1)) / w_list[:, None, None]

        # create an array with all the possible pairs
        # instantiating this array seems slow but seems still faster than the required loops
        coord_pairs = np.array(
            list(itertools.product(nearest_sc_fcoords, f_list)))

        # find the pairs that match between the coordinates of the modified supercell and the f_list
        ind_match = np.where(
            np.abs(coord_pairs[:, 0] -
                   coord_pairs[:, 1]).sum(axis=1) < 1e-6)[0]
        # set the ifc for phonopy in the final array corresponding to the matching indices.
        n_points_f_list = len(f_list)
        ifcph[i, ind_match // n_points_f_list] = ifccc_loc[ind_match %
                                                           n_points_f_list]

    phonon.set_force_constants(ifcph)
    if symmetrize_tensors:
        phonon.symmetrize_force_constants()

    if output_dir_path:
        makedirs_p(output_dir_path)

        fc_filepath = os.path.join(output_dir_path,
                                   prefix_outfiles + "FORCE_CONSTANTS")
        write_FORCE_CONSTANTS(phonon.get_force_constants(), fc_filepath)

        if becs is not None and epsinf is not None:
            born_filepath = os.path.join(output_dir_path,
                                         prefix_outfiles + "BORN")
            write_BORN(phon_at,
                       borns=becs,
                       epsilon=epsinf,
                       filename=born_filepath,
                       symmetrize_tensors=symmetrize_tensors)

        poscar_filepath = os.path.join(output_dir_path,
                                       prefix_outfiles + "POSCAR")
        poscar = Poscar(s)
        poscar.write_file(poscar_filepath, significant_figures=15)

        supercell_filepath = os.path.join(output_dir_path,
                                          prefix_outfiles + "supercell_POSCAR")
        superce_poscar = Poscar(supercell)
        superce_poscar.write_file(supercell_filepath, significant_figures=15)

    return phonon
Пример #28
0
class PhononBase(TaskElement):
    """PhononBase class

    This is an interface to phonopy.

    """

    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 distance=None,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 traverse=False,
                 is_cell_relaxed=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._distance = distance
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._traverse = traverse
        self._is_cell_relaxed = is_cell_relaxed

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._cell = None
        self._phonon = None # Phonopy object

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._phonon_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def set_status(self):
        done = True
        terminate = False
        for task in self._tasks:
            done &= task.done()
            if task.get_status() == "terminate":
                terminate = True
        if done:
            if terminate:
                self._status = "terminate"
            else:
                self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print "set_job has to be executed."
            raise

        self._overwrite_settings()

        if self._is_cell_relaxed:
            self._phonon_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def end(self):
        pass

    def done(self):
        return ("terminate" in self._status or 
                "done" in self._status or
                "next" in self._status)

    def next(self):
        if self._stage == 0:
            if "next" in self._status:
                self._energy = self._tasks[0].get_energy()
                self._comment = "%s\\n%f" % (
                    self._tasks[0].get_space_group()['international_standard'],
                    self._energy)
                self._set_stage1()
                return self._tasks
            elif "terminate" in self._status and self._traverse == "restart":
                self._traverse = False
                self._set_stage0()
                return self._tasks
            else:
                raise StopIteration
        else: # task 1..n: displaced supercells
            if "next" in self._status:
                self._status = "done"
                forces = []
                for task in self._phonon_tasks[1:]:
                    forces.append(task.get_properties()['forces'][-1])
                self._write_FORCE_SETS(forces)
                self._phonon.set_post_process(self._primitive_matrix,
                                              forces,
                                              force_constants_decimals=14)
                self._tasks = []
                raise StopIteration
            elif "terminate" in self._status and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()[1:]
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._phonon_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
            else:
                raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._phonon_tasks = [task]
        self._tasks = [task]
        
    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()[1:]
        self._phonon_tasks += self._tasks

    def _set_phonon(self):
        cell = self.get_cell()
        phonopy_cell = Atoms(
            cell=cell.get_lattice().T,
            scaled_positions=cell.get_points().T,
            symbols=cell.get_symbols())
        
        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               is_auto_displacements=False)
        self._phonon.generate_displacements(distance=self._distance,
                                            is_diagonal=False)

        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, "POSCAR-unitcell")
        write_disp_yaml(displacements, supercell)

    def _write_FORCE_SETS(self, forces):
        displacements = [[x[0], x[1:4]]
                         for x in self._phonon.get_displacements()]
        natom = self._phonon.get_supercell().get_number_of_atoms()
        write_FORCE_SETS("FORCE_SETS",
                         natom,
                         displacements,
                         forces,
                         verbose=False)

    def _write_yaml(self):
        w = open("%s.yaml" % self._directory, 'w')
        if self._phonon_tasks[0]:
            if self._lattice_tolerance is not None:
                w.write("lattice_tolerance: %f\n" % self._lattice_tolerance)
            if self._stress_tolerance is not None:
                w.write("stress_tolerance: %f\n" % self._stress_tolerance)
                w.write("pressure_target: %f\n" % self._pressure_target)
            w.write("force_tolerance: %f\n" % self._force_tolerance)
            w.write("max_increase: %f\n" % self._max_increase)
            w.write("max_iteration: %d\n" % self._max_iteration)
            w.write("min_iteration: %d\n" % self._min_iteration)
            w.write("supercell_matrix:\n")
            for row in self._supercell_matrix:
                w.write("- [ %3d, %3d, %3d ]\n" % tuple(row))
            w.write("primitive_matrix:\n")
            for row in self._primitive_matrix:
                w.write("- [ %6.3f, %6.3f, %6.3f ]\n" % tuple(row))
            w.write("distance: %f\n" % self._distance)
            w.write("iteration: %d\n" % self._phonon_tasks[0].get_stage())
            if self._energy:
                w.write("electric_total_energy: %20.10f\n" % self._energy)
        w.write("status: %s\n" % self._status)
        w.write("tasks:\n")
        for task in self._phonon_tasks:
            if task and task.get_status():
                w.write("- name:   %s\n" % task.get_name())
                w.write("  status: %s\n" % task.get_status())
        w.close()
Пример #29
0
def BuildForceConstants(lattice_vectors, atom_types, atom_pos, q_pts, freqs, eigs, sc_dim, freq_units = 'thz', atom_mass = None, file_path = r"FORCE_CONSTANTS"):
    """
    Use the Phonopy API to take a set of frequencies and eigenvectors, construct a dynamical matrix, transform to a set of force constants, and write out a Phonopy FORCE_CONSTANTS file.

    Args:
        lattice_vectors -- 3x3 matrix containing the lattice vectors
        atom_types -- list of atomic symbols
        atom_pos -- list of atomic positions ** in fractional coordinates **
        q_pts -- list of q-point coordinates
        freqs -- n_q sets of Frequencies
        eigs -- n_q sets of eigenvectors
        sc_dim -- (equivalent) supercell dimension for preparing force constants
        freq_units -- units of freqs ('thz' or 'inv_cm' -- default: 'thz')
        atom_mass -- (optional) list of atomic masses (default: taken from Phonopy internal database)
        file_path -- path to FORCE_CONSTANTS file to write (default: FORCE_CONSTANTS)
    """

    # Check input.

    _CheckStructure(lattice_vectors, atom_types, atom_pos, atom_mass)

    for param in q_pts, freqs, eigs, sc_dim:
        assert param is not None

    dim_1, dim_2 = np.shape(q_pts)

    assert dim_1 > 0 and dim_2 == 3

    n_at = len(atom_types)

    n_q = dim_1
    n_b = 3 * n_at

    dim_1, dim_2 = np.shape(freqs)

    assert dim_1 == n_q and dim_2 == n_b

    dim_1, dim_2, dim_3, dim_4 = np.shape(eigs)

    assert dim_1 == n_q and dim_2 == n_b and dim_3 == n_at and dim_4 == 3

    dim_1, = np.shape(sc_dim)

    assert dim_1 == 3

    # Obtain a frequency conversion factor to "VASP units".

    freq_conv_factor = None

    if freq_units == 'thz':
        freq_conv_factor = VaspToTHz
    elif freq_units == 'inv_cm':
        freq_conv_factor = VaspToCm

    if freq_conv_factor is None:
        raise Exception("Error: Unknown freq_units '{0}'.".format(freq_units))

    # Create a Phonopy-format structure.

    structure = PhonopyAtoms(
        symbols = atom_types, masses = atom_mass, scaled_positions = atom_pos, cell = lattice_vectors
        )

    # Convert supercell expansion to a supercell matrix.

    dim_1, dim_2, dim_3 = sc_dim

    if dim_1 != dim_2 != dim_2 != 1:
        warnings.warn("The dynamical matrix -> force constants transform has only been tested at the Gamma point; please report issues to the developer.", RuntimeWarning)

    sc_matrix = [[dim_1, 0, 0], [0, dim_2, 0], [0, 0, dim_3]]

    # Use the main Phonopy object to obtain the primitive cell and supercell.

    calculator = Phonopy(structure, sc_matrix)

    primitive = calculator.get_primitive();
    supercell = calculator.get_supercell();

    # Use the DynmatToForceConstants object to convert frequencies/eigenvectors -> dynamical matrices -> force constants.

    dynmat_to_fc = DynmatToForceConstants(primitive, supercell)

    commensurate_points = dynmat_to_fc.get_commensurate_points()

    # If an input code does not use crystal symmetry or outputs data at all q-points in a sampling mesh, data may be provided for more q-points than there are commensurate points.
    # However, for most codes this would be an odd situation -> issue a warning.

    if len(commensurate_points) != n_q:
        warnings.warn("The number of entries in the q_pts list does not equal the number of commensurate points expected for the supplied supercell matrix.", RuntimeWarning)

    # Map commensurate points in Phonopy setup to q-points in input data.

    map_indices = []

    for qx_1, qy_1, qz_1 in commensurate_points:
        map_index = None

        for i, (qx_2, qy_2, qz_2) in enumerate(q_pts):
            if math.fabs(qx_2 - qx_1) < _SymPrec and math.fabs(qy_2 - qy_1) < _SymPrec and math.fabs(qz_2 - qz_1) < _SymPrec:
                map_index = i
                break

        if map_index is None:
            raise Exception("Error: Expected q = ({0: >6.3f}, {1: >6.3f}, {2: >6.3f}) in the q_pts list (this may be a bug; please report to the developer).".format(qx_1, qy_1, qz_1))

        # Sanity check.

        assert map_index not in map_indices

        map_indices.append(map_index)

    # Arrange the frequencies and eigenvectors to the layout required by Phonopy.

    freq_sets, eig_sets = [], []

    for index in map_indices:
        freq_sets.append(
            [freq / freq_conv_factor for freq in freqs[index]]
            )

        eig = eigs[index]

        # Eigenvectors need to be a 3Nx3N matrix in the format:
        # 1_x -> [ m_1, ..., m_3N ]
        # 1_y -> [ m_1, ..., m_3N ]
        # ...
        # N_z -> [ m_1, ..., m_3N ]

        eig_rows = []

        for i in range(0, n_at):
            for j in range(0, 3):
                eig_row = []

                for k in range(0, n_b):
                    eig_row.append(eig[k][i][j])

                eig_rows.append(eig_row)

        eig_sets.append(eig_rows)

    freq_sets = np.array(freq_sets, dtype = np.float64)
    eig_sets = np.array(eig_sets, dtype = np.complex128)

    # Use the DynmatToForceConstants object to build the dynamical matrices, reverse transform to the force constants, and write a Phonopy FORCE_CONSTANTS file.

    dynmat_to_fc.set_dynamical_matrices(freq_sets, eig_sets)

    dynmat_to_fc.run()

    write_FORCE_CONSTANTS(
        dynmat_to_fc.get_force_constants(), filename = file_path
        )