def do_phonons(strt=None, parameters=None, c_size=25): """ Setting up phonopy job using LAMMPS Args: strt: Structure object parameters: LAMMPS input file parameters c_size: cell-size """ p = get_phonopy_atoms(mat=strt) bulk = p dim1 = int((float(c_size) / float(max(abs(strt.lattice.matrix[0]))))) + 1 dim2 = int(float(c_size) / float(max(abs(strt.lattice.matrix[1])))) + 1 dim3 = int(float(c_size) / float(max(abs(strt.lattice.matrix[2])))) + 1 Poscar(strt).write_file("POSCAR") tmp = strt.copy() tmp.make_supercell([dim1, dim2, dim3]) Poscar(tmp).write_file("POSCAR-Super.vasp") phonon = Phonopy(bulk, [[dim1, 0, 0], [0, dim2, 0], [0, 0, dim3]]) # , print("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: print("[Phonopy]", d[0], d[1:]) supercells = phonon.get_supercells_with_displacements() # Force calculations by calculator set_of_forces = [] disp = 0 for scell in supercells: cell = Atoms( symbols=scell.get_chemical_symbols(), scaled_positions=scell.get_scaled_positions(), cell=scell.get_cell(), pbc=True, ) disp = disp + 1 mat = Poscar(AseAtomsAdaptor().get_structure(cell)) mat.comment = str("disp-") + str(disp) parameters["min"] = "skip" parameters["control_file"] = "/users/knc6/in.phonon" # a,b,forces=run_job(mat=mat,parameters={'min':'skip','pair_coeff': '/data/knc6/JARVIS-FF-NEW/ALLOY4/Mishin-Ni-Al-2009.eam.alloy', 'control_file': '/users/knc6/in.phonon', 'pair_style': 'eam/alloy', 'atom_style': 'charge'}) a, b, forces = run_job(mat=mat, parameters=parameters) print("forces=", forces) drift_force = forces.sum(axis=0) print("drift forces=", drift_force) 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) phonon.produce_force_constants(forces=set_of_forces) write_FORCE_CONSTANTS(phonon.get_force_constants(), filename="FORCE_CONSTANTS") print() print("[Phonopy] Phonon frequencies at Gamma:")
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
def get_phonopy_displacements(phonon: phonopy.Phonopy): """ Get displacements as arrays of ``phonopy_atom`` and ``[dx, dy, dz]`` (cartesian). ``phonopy_atom`` is the displaced atom index according to phonopy's supercell ordering convention. Mind that this is different from ASE's convention. """ return tuple( map(list, zip(*[(i, xyz) for (i, *xyz) in phonon.get_displacements()])))
def do_phonons(strt=None,parameters=None): p= get_phonopy_atoms(mat=strt) bulk =p c_size=parameters['phon_size'] dim1=int((float(c_size)/float( max(abs(strt.lattice.matrix[0])))))+1 dim2=int(float(c_size)/float( max(abs(strt.lattice.matrix[1]))))+1 dim3=int(float(c_size)/float( max(abs(strt.lattice.matrix[2]))))+1 Poscar(strt).write_file("POSCAR") tmp=strt.copy() tmp.make_supercell([dim1,dim2,dim3]) Poscar(tmp).write_file("POSCAR-Super.vasp") print ('supercells',dim1,dim2,dim3) phonon = Phonopy(bulk,[[dim1,0,0],[0,dim2,0],[0,0,dim3]]) print ("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: print ("[Phonopy]", d[0], d[1:]) supercells = phonon.get_supercells_with_displacements() # Force calculations by calculator set_of_forces = [] disp=0 for scell in supercells: cell = Atoms(symbols=scell.get_chemical_symbols(), scaled_positions=scell.get_scaled_positions(), cell=scell.get_cell(), pbc=True) disp=disp+1 mat = Poscar(AseAtomsAdaptor().get_structure(cell)) mat.comment=str("disp-")+str(disp) parameters['min']='skip' parameters['control_file']= parameters['phonon_control_file'] #'/users/knc6/in.phonon' #a,b,forces=run_job(mat=mat,parameters={'min':'skip','pair_coeff': '/data/knc6/JARVIS-FF-NEW/ALLOY4/Mishin-Ni-Al-2009.eam.alloy', 'control_file': '/users/knc6/in.phonon', 'pair_style': 'eam/alloy', 'atom_style': 'charge'}) a,b,forces=run_job(mat=mat,parameters=parameters) #print "forces=",forces drift_force = forces.sum(axis=0) #print "drift forces=",drift_force #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) phonon.produce_force_constants(forces=set_of_forces) write_FORCE_CONSTANTS(phonon.get_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
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
def phonopy_pre_process(cell, config_type, supercell_matrix=None): smat = [[3, 0, 0], [0, 3, 0], [0, 0, 3]] phonon = Phonopy(cell, smat) phonon.generate_displacements(distance=0.16) #0.02 print("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: print("[Phonopy] %d %s" % (d[0], d[1:])) return phonon
def build_phonon(self, atoms = None, supercell_matrix = None, primitive_matrix = None, distance = None): if atoms is None: atoms = self.atoms phonon = Phonopy(atoms, supercell_matrix, primitive_matrix = primitive_matrix) phonon.generate_displacements(distance = distance) self.log("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: self.log("[Phonopy] %d %s" % (d[0], d[1:])) self.phonon = phonon
def phonopy_pre_process(cell, disp, config_type, supercell_matrix=None): if config_type == "al": print config_type smat = [[2, 0, 0], [0, 2, 0], [0, 0, 2]] else: smat = [[3, 0, 0], [0, 3, 0], [0, 0, 3]] phonon = Phonopy(cell, smat) phonon.generate_displacements(distance=disp) print("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: print("[Phonopy] %d %s" % (d[0], d[1:])) return phonon
def phonopy_pre_process(cell, supercell_matrix=None): if supercell_matrix is None: smat = [[2,0,0], [0,2,0], [0,0,2]], else: smat = supercell_matrix phonon = Phonopy(cell, smat, primitive_matrix=[[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]]) phonon.generate_displacements(distance=0.03) print("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: print("[Phonopy] %d %s" % (d[0], d[1:])) return phonon
def _get_phononobject_phonopy(self, structure, potential, smat, save_parameters, path, displacement_distance=0.01): cell = get_phonopy_structure(structure) phonon = Phonopy(cell, smat, primitive_matrix=[[1.0, 0.0, 0.0], [0.0, 1, 0.0], [0., 0., 1.0]], factor=VaspToTHz) # displacements phonon.generate_displacements(distance=displacement_distance) print("[Phonopy] Atomic displacements:") disps = phonon.get_displacements() for d in disps: print("[Phonopy] %d %s" % (d[0], d[1:])) supercells = phonon.get_supercells_with_displacements() # Force calculations by calculator set_of_forces = [] for scell in supercells: cell = Atoms(symbols=scell.get_chemical_symbols(), scaled_positions=scell.get_scaled_positions(), cell=scell.get_cell(), pbc=True) cell.set_calculator(potential) # this part is adapted from: https://web.archive.org/web/20200610084959/https://github.com/phonopy/phonopy/blob/develop/example/ase/8Si-phonon.py # Copyright by Atsushi Togo forces = cell.get_forces() drift_force = forces.sum(axis=0) print( ("[Phonopy] Drift force:" + "%11.5f" * 3) % tuple(drift_force)) for force in forces: force -= drift_force / forces.shape[0] set_of_forces.append(forces) phonon.produce_force_constants(forces=set_of_forces) if save_parameters: phonon.save(path) return phonon
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()
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
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()
class PhononFC3Base(TaskElement): """PhononFC3Base class This is an interface to anharmonic phonopy. """ def __init__(self, directory=None, name=None, supercell_matrix=None, primitive_matrix=None, distance=None, is_diagonal=True, check_imaginary=True, cutoff_frequency=None, 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, traverse=False): TaskElement.__init__(self) self._directory = directory if not name: self._name = directory else: self._name = name self._task_type = "anharmonic_phonon" self._supercell_matrix = supercell_matrix self._primitive_matrix = primitive_matrix self._distance = distance self._is_diagonal = is_diagonal self._check_imaginary = check_imaginary self._cutoff_frequency = cutoff_frequency # determine imaginary freq. 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 self._phonon_fc3 = None # Phono3py object self._phonon_fc3_tasks = None def get_phonon(self): return self._phonon def get_phonon_fc3(self): for i, task in enumerate(self._phonon_fc3_tasks[1:]): forces_fc3.append(task.get_properties()['forces'][-1]) disp_dataset = self._phonon_fc3.get_displacement_dataset() self._phonon_fc3.produce_fc3(forces_fc3) return self._phonon_fc3 def get_cell(self): if self._is_cell_relaxed: return self._cell else: return self._phonon_fc3_tasks[0].get_cell() def get_energy(self): """Return energies at geometry optimization steps""" return self._energy def set_status(self): if self._stage == 0: task = self._tasks[0] if task.done(): status = task.get_status() if status == "done": self._status = "next" else: self._status = status else: done = True terminate = False for i, task in enumerate(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 RuntimeError if self._is_cell_relaxed: self._phonon_fc3_tasks = [None] self._set_stage1() else: self._set_stage0() def end(self): pass def done(self): return (self._status == "terminate" or self._status == "done" or self._status == "max_iteration" or self._status == "next" or self._status == "imaginary_mode") def __next__(self): return self.next() 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'], 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 elif self._stage == 1: if "next" in self._status: disp_dataset = self._phonon_fc3.get_displacement_dataset() for disp1, task in zip(disp_dataset['first_atoms'], self._tasks): disp1['forces'] = task.get_properties()['forces'][-1] write_FORCE_SETS(disp_dataset) self._phonon.set_displacement_dataset(disp_dataset) self._phonon.produce_force_constants( calculate_full_force_constants=False) if self._exist_imaginary_mode(): self._status = "imaginary_mode" self._write_yaml() self._tasks = [] raise StopIteration else: self._set_stage2() return self._tasks elif "terminate" in self._status and self._traverse == "restart": self._reset_stage1() return self._tasks else: raise StopIteration elif self._stage == 2: if "next" in self._status: self._status = "done" forces_fc3 = [] for i, task in enumerate(self._phonon_fc3_tasks[1:]): forces_fc3.append(task.get_properties()['forces'][-1]) disp_dataset = self._phonon_fc3.get_displacement_dataset() write_FORCES_FC3(disp_dataset, forces_fc3) self._tasks = [] raise StopIteration elif "terminate" in self._status and self._traverse == "restart": self._reset_stage2() return self._tasks else: raise StopIteration else: # stage2 pass def _set_stage0(self): self._status = "equilibrium" task = self._get_equilibrium_task() self._phonon_fc3_tasks = [task] self._tasks = [task] def _set_stage1(self): self._set_phonon_fc3() if self._check_imaginary: self._stage = 1 self._status = "fc2_displacements" disp_dataset = self._phonon_fc3.get_displacement_dataset() self._tasks = self._get_displacement_tasks( stop=len(disp_dataset['first_atoms'])) self._phonon_fc3_tasks += self._tasks else: self._set_stage2() def _reset_stage1(self): self._traverse = False disp_terminated = [] for i, task in enumerate(self._tasks): if task.get_status() == "terminate": disp_terminated.append(i) disp_dataset = self._phonon_fc3.get_displacement_dataset() tasks = self._get_displacement_tasks( stop=len(disp_dataset['first_atoms'])) self._tasks = [] for i in disp_terminated: self._tasks.append(tasks[i]) self._phonon_fc3_tasks[i + 1] = tasks[i] self._status = "fc2_displacements" def _set_stage2(self): self._stage = 2 self._status = "fc3_displacements" if self._check_imaginary: disp_dataset = self._phonon_fc3.get_displacement_dataset() start_index = len(disp_dataset['first_atoms']) else: start_index = 0 self._tasks = self._get_displacement_tasks(start=start_index) self._phonon_fc3_tasks += self._tasks def _reset_stage2(self): self._traverse = False disp_terminated = [] for i, task in enumerate(self._tasks): if task.get_status() == "terminate": disp_terminated.append(i) if self._check_imaginary: disp_dataset = self._phonon_fc3.get_displacement_dataset() start_index = len(disp_dataset['first_atoms']) else: start_index = 0 tasks = self._get_displacement_tasks(start=start_index) self._tasks = [] for i in disp_terminated: self._tasks.append(tasks[i]) self._phonon_fc3_tasks[i + 1 + start_index] = tasks[i] self._status = "fc3_displacements" def _set_phonon_fc3(self): 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) self._phonon_fc3 = Phono3py(phonopy_cell, self._supercell_matrix, primitive_matrix=self._primitive_matrix) self._phonon_fc3.generate_displacements(distance=self._distance, is_diagonal=self._is_diagonal) supercell = self._phonon_fc3.get_supercell() disp_dataset = self._phonon_fc3.get_displacement_dataset() self._phonon.set_displacement_dataset(disp_dataset) write_poscar(cell, "POSCAR-unitcell") write_disp_yaml(self._phonon.get_displacements(), supercell, directions=self._phonon.get_displacement_directions()) write_disp_fc3_yaml(disp_dataset, supercell) def _exist_imaginary_mode(self): if self._primitive_matrix is None: pmat = np.eye(3) else: pmat = self._primitive_matrix exact_point_matrix = np.dot(np.linalg.inv(self._supercell_matrix), pmat).T max_integer = np.rint(np.amax(np.abs(np.linalg.inv(exact_point_matrix)))) q_points = [] for i in np.arange(-max_integer, max_integer + 1): for j in np.arange(-max_integer, max_integer + 1): for k in np.arange(-max_integer, max_integer + 1): q = np.dot(exact_point_matrix, [i, j, k]) if (-1 < q).all() and (q < 1).all(): q_points.append(q) self._phonon.set_qpoints_phonon(q_points) frequencies = self._phonon.get_qpoints_phonon()[0] if (frequencies < self._cutoff_frequency).any(): self._log = "Stop at phonon calculation due to imaginary modes" return True else: return False def _write_yaml(self): w = open("%s.yaml" % self._directory, 'w') 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("supercell_matrix:\n") for row in self._supercell_matrix: w.write("- [ %3d, %3d, %3d ]\n" % tuple(row)) if self._primitive_matrix is not None: 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_fc3_tasks[0] is not None: w.write("iteration: %d\n" % self._phonon_fc3_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_fc3_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()
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
def phonons(self, atoms=None, lammps_cmd="", enforce_c_size=15.0, parameters={}): """Make Phonon calculation setup.""" from phonopy import Phonopy from phonopy.file_IO import ( # parse_FORCE_CONSTANTS, write_FORCE_CONSTANTS, ) bulk = atoms.phonopy_converter() dim = get_supercell_dims(atoms, enforce_c_size=enforce_c_size) atoms = atoms.make_supercell([dim[0], dim[1], dim[2]]) Poscar(atoms).write_file("POSCAR") atoms = atoms.make_supercell_matrix([dim[0], dim[1], dim[2]]) Poscar(atoms).write_file("POSCAR-Super.vasp") phonon = Phonopy(bulk, [[dim[0], 0, 0], [0, dim[1], 0], [0, 0, dim[2]]]) print("[Phonopy] Atomic displacements1:", bulk) print("[Phonopy] Atomic displacements2:", phonon, dim[0], dim[1], dim[2]) phonon.generate_displacements(distance=0.03) disps = phonon.get_displacements() print("[Phonopy] Atomic displacements3:", disps) for d in disps: print("[Phonopy]", d[0], d[1:]) supercells = phonon.get_supercells_with_displacements() # Force calculations by calculator set_of_forces = [] disp = 0 from ase import Atoms as AseAtoms for scell in supercells: ase_atoms = AseAtoms( symbols=scell.get_chemical_symbols(), scaled_positions=scell.get_scaled_positions(), cell=scell.get_cell(), pbc=True, ) j_atoms = ase_to_atoms(ase_atoms) disp = disp + 1 parameters["control_file"] = "run0.mod" a, b, forces = LammpsJob( atoms=j_atoms, lammps_cmd=lammps_cmd, parameters=parameters, jobname="disp-" + str(disp), ).runjob() print("forces=", forces) drift_force = forces.sum(axis=0) print("drift forces=", drift_force) # Simple translational invariance for force in forces: force -= drift_force / forces.shape[0] set_of_forces.append(forces) phonon.produce_force_constants(forces=set_of_forces) write_FORCE_CONSTANTS(phonon.get_force_constants(), filename="FORCE_CONSTANTS") print() print("[Phonopy] Phonon frequencies at Gamma:")
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
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
(0.75, 0.25, 0.75), (0.75, 0.75, 0.25)] ) bulk.set_cell(np.diag((a, a, a))) calc = GPAW(mode=PW(300), kpts={'size': (4, 4, 4)}, symmetry={'symmorphic': False}) phonon = Phonopy(bulk, [[1,0,0],[0,1,0],[0,0,1]], primitive_matrix=[[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]], distance=0.01) print "[Phonopy] Atomic displacements:" disps = phonon.get_displacements() for d in disps: print "[Phonopy]", d[0], d[1:] supercells = phonon.get_supercells_with_displacements() # Force calculations by calculator set_of_forces = [] for scell in supercells: cell = Atoms(symbols=scell.get_chemical_symbols(), scaled_positions=scell.get_scaled_positions(), cell=scell.get_cell(), pbc=True) cell.set_calculator(calc) forces = cell.get_forces() drift_force = forces.sum(axis=0) print "[Phonopy] Drift force:", "%11.5f"*3 % tuple(drift_force)
scaled_positions=[(0, 0, 0), (0, 0.5, 0.5), (0.5, 0, 0.5), (0.5, 0.5, 0), (0.25, 0.25, 0.25), (0.25, 0.75, 0.75), (0.75, 0.25, 0.75), (0.75, 0.75, 0.25)]) bulk.set_cell(np.diag((a, a, a))) calc = GPAW(mode=PW(300), kpts={'size': (4, 4, 4)}, symmetry={'symmorphic': False}) phonon = Phonopy(bulk, [[1, 0, 0], [0, 1, 0], [0, 0, 1]], primitive_matrix=[[0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]], distance=0.01) print "[Phonopy] Atomic displacements:" disps = phonon.get_displacements() for d in disps: print "[Phonopy]", d[0], d[1:] supercells = phonon.get_supercells_with_displacements() # Force calculations by calculator set_of_forces = [] for scell in supercells: cell = Atoms(symbols=scell.get_chemical_symbols(), scaled_positions=scell.get_scaled_positions(), cell=scell.get_cell(), pbc=True) cell.set_calculator(calc) forces = cell.get_forces() drift_force = forces.sum(axis=0) print "[Phonopy] Drift force:", "%11.5f" * 3 % tuple(drift_force)
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()