def get_properties_from_phonopy(structure, phonopy_input, force_constants): """ Calculate DOS and thermal properties using phonopy (locally) :param structure: Aiida StructureData Object :param phonopy_input: Aiida Parametersdata object containing a dictionary with the data needed to run phonopy: supercells matrix, primitive matrix and q-points mesh. :param force_constants: :return: """ from phonopy.structure.atoms import Atoms as PhonopyAtoms 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) phonopy_input = phonopy_input.get_dict() force_constants = force_constants.get_array('force_constants') phonon = Phonopy(bulk, phonopy_input['supercell'], primitive_matrix=phonopy_input['primitive']) phonon.set_force_constants(force_constants) #Normalization factor primitive to unit cell normalization_factor = phonon.unitcell.get_number_of_atoms( ) / phonon.primitive.get_number_of_atoms() phonon.set_mesh(phonopy_input['mesh'], is_eigenvectors=True, is_mesh_symmetry=False) phonon.set_total_DOS() phonon.set_partial_DOS() # get DOS (normalized to unit cell) total_dos = phonon.get_total_DOS() * normalization_factor partial_dos = phonon.get_partial_DOS() * normalization_factor # Stores DOS data in DB as a workflow result dos = ArrayData() dos.set_array('frequency', total_dos[0]) dos.set_array('total_dos', total_dos[1]) dos.set_array('partial_dos', partial_dos[1]) #THERMAL PROPERTIES (per primtive cell) phonon.set_thermal_properties() t, free_energy, entropy, cv = phonon.get_thermal_properties() # Stores thermal properties (per unit cell) data in DB as a workflow result thermal_properties = ArrayData() thermal_properties.set_array('temperature', t) thermal_properties.set_array('free_energy', free_energy * normalization_factor) thermal_properties.set_array('entropy', entropy * normalization_factor) thermal_properties.set_array('cv', cv * normalization_factor) return {'thermal_properties': thermal_properties, 'dos': dos}
def phonopy_calculation_inline(**kwargs): from phonopy.structure.atoms import Atoms as PhonopyAtoms from phonopy import Phonopy structure = kwargs.pop('structure') phonopy_input = kwargs.pop('phonopy_input').get_dict() force_constants = kwargs.pop('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']) phonon.set_force_constants(force_constants) # Normalization factor primitive to unit cell normalization_factor = phonon.unitcell.get_number_of_atoms( ) / phonon.primitive.get_number_of_atoms() phonon.set_mesh(phonopy_input['mesh'], is_eigenvectors=True, is_mesh_symmetry=False) phonon.set_total_DOS() phonon.set_partial_DOS() # get DOS (normalized to unit cell) total_dos = phonon.get_total_DOS() * normalization_factor partial_dos = phonon.get_partial_DOS() * normalization_factor # Stores DOS data in DB as a workflow result dos = ArrayData() dos.set_array('frequency', total_dos[0]) dos.set_array('total_dos', total_dos[1]) dos.set_array('partial_dos', partial_dos[1]) # THERMAL PROPERTIES (per primtive cell) phonon.set_thermal_properties() t, free_energy, entropy, cv = phonon.get_thermal_properties() # Stores thermal properties (per unit cell) data in DB as a workflow result thermal_properties = ArrayData() thermal_properties.set_array('temperature', t) thermal_properties.set_array('free_energy', free_energy * normalization_factor) thermal_properties.set_array('entropy', entropy * normalization_factor) thermal_properties.set_array('cv', cv * normalization_factor) return {'thermal_properties': thermal_properties, 'dos': dos}
append_band(bands, [0.0, 0.0, 0.0], [0.5, 0.5, 0.5]) phonon.set_band_structure(bands) q_points, distances, frequencies, eigvecs = phonon.get_band_structure() for q, d, freq in zip(q_points, distances, frequencies): print q, d, freq phonon.plot_band_structure().show() # Mesh sampling 20x20x20 phonon.set_mesh([20, 20, 20]) phonon.set_thermal_properties(t_step=10, t_max=1000, t_min=0) # DOS phonon.set_total_DOS(sigma=0.1) for omega, dos in np.array(phonon.get_total_DOS()).T: print "%15.7f%15.7f" % (omega, dos) phonon.plot_total_DOS().show() # Thermal properties for t, free_energy, entropy, cv in np.array(phonon.get_thermal_properties()).T: print ("%12.3f " + "%15.7f" * 3) % ( t, free_energy, entropy, cv ) phonon.plot_thermal_properties().show() # PDOS phonon.set_mesh([10, 10, 10], is_mesh_symmetry=False, is_eigenvectors=True) phonon.set_partial_DOS(tetrahedron_method=True) omegas, pdos = phonon.get_partial_DOS() pdos_indices = [[0], [1]]
append_band(bands, [0.5, 0.0, 0.0], [0.5, 0.5, 0.0]) append_band(bands, [0.5, 0.5, 0.0], [0.0, 0.0, 0.0]) append_band(bands, [0.0, 0.0, 0.0], [0.5, 0.5, 0.5]) phonon.set_band_structure(bands) q_points, distances, frequencies, eigvecs = phonon.get_band_structure() for q, d, freq in zip(q_points, distances, frequencies): print q, d, freq phonon.plot_band_structure().show() # Mesh sampling 20x20x20 phonon.set_mesh([20, 20, 20]) phonon.set_thermal_properties(t_step=10, t_max=1000, t_min=0) # DOS phonon.set_total_DOS(sigma=0.1) for omega, dos in np.array(phonon.get_total_DOS()).T: print "%15.7f%15.7f" % (omega, dos) phonon.plot_total_DOS().show() # Thermal properties for t, free_energy, entropy, cv in np.array(phonon.get_thermal_properties()).T: print("%12.3f " + "%15.7f" * 3) % (t, free_energy, entropy, cv) phonon.plot_thermal_properties().show() # PDOS phonon.set_mesh([10, 10, 10], is_mesh_symmetry=False, is_eigenvectors=True) phonon.set_partial_DOS(tetrahedron_method=True) omegas, pdos = phonon.get_partial_DOS() pdos_indices = [[0], [1]] phonon.plot_partial_DOS(pdos_indices=pdos_indices, legend=pdos_indices).show()
def phonopy_calculation_inline(**kwargs): from phonopy.structure.atoms import Atoms as PhonopyAtoms from phonopy import Phonopy structure = kwargs.pop('structure') phonopy_input = kwargs.pop('phonopy_input').get_dict() force_constants = kwargs.pop('force_constants').get_array( 'force_constants') bands = get_path_using_seekpath(structure) # 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'], symprec=phonopy_input['symmetry_precision']) phonon.set_force_constants(force_constants) try: print('trying born') nac_data = kwargs.pop('nac_data') born = nac_data.get_array('born_charges') epsilon = nac_data.get_array('epsilon') phonon.set_nac_params(get_born_parameters(phonon, born, epsilon)) print('born succeed') except: pass # Normalization factor primitive to unit cell norm_primitive_to_unitcell = phonon.unitcell.get_number_of_atoms( ) / phonon.primitive.get_number_of_atoms() phonon.set_band_structure(bands['ranges']) phonon.set_mesh(phonopy_input['mesh'], is_eigenvectors=True, is_mesh_symmetry=False) phonon.set_total_DOS(tetrahedron_method=True) phonon.set_partial_DOS(tetrahedron_method=True) # get band structure band_structure_phonopy = phonon.get_band_structure() q_points = np.array(band_structure_phonopy[0]) q_path = np.array(band_structure_phonopy[1]) frequencies = np.array(band_structure_phonopy[2]) band_labels = np.array(bands['labels']) # stores band structure band_structure = ArrayData() band_structure.set_array('q_points', q_points) band_structure.set_array('q_path', q_path) band_structure.set_array('frequencies', frequencies) band_structure.set_array('labels', band_labels) # get DOS (normalized to unit cell) total_dos = phonon.get_total_DOS() * norm_primitive_to_unitcell partial_dos = phonon.get_partial_DOS() * norm_primitive_to_unitcell # Stores DOS data in DB as a workflow result dos = ArrayData() dos.set_array('frequency', total_dos[0]) dos.set_array('total_dos', total_dos[1] * norm_primitive_to_unitcell) dos.set_array('partial_dos', partial_dos[1] * norm_primitive_to_unitcell) dos.set_array('partial_symbols', np.array(phonon.primitive.symbols)) # THERMAL PROPERTIES (per primtive cell) phonon.set_thermal_properties() t, free_energy, entropy, cv = phonon.get_thermal_properties() # Stores thermal properties (per mol) data in DB as a workflow result thermal_properties = ArrayData() thermal_properties.set_array('temperature', t) thermal_properties.set_array('free_energy', free_energy * norm_primitive_to_unitcell) thermal_properties.set_array('entropy', entropy * norm_primitive_to_unitcell) thermal_properties.set_array('cv', cv * norm_primitive_to_unitcell) return { 'thermal_properties': thermal_properties, 'dos': dos, 'band_structure': band_structure }
class PhonopyJob(AtomisticParallelMaster): """ Args: project: job_name: """ def __init__(self, project, job_name): super(PhonopyJob, self).__init__(project, job_name) self.__name__ = "PhonopyJob" self.__version__ = "0.0.1" self.input["interaction_range"] = (10.0, "Minimal size of supercell, Ang") self.input["factor"] = ( VaspToTHz, "Frequency unit conversion factor (default for VASP)", ) self.input["displacement"] = (0.01, "atoms displacement, Ang") self.input["dos_mesh"] = (20, "mesh size for DOS calculation") self.phonopy = None self._job_generator = PhonopyJobGenerator(self) self._disable_phonopy_pickle = False s.publication_add(phonopy_publication()) @property def phonopy_pickling_disabled(self): return self._disable_phonopy_pickle @phonopy_pickling_disabled.setter def phonopy_pickling_disabled(self, disable): self._disable_phonopy_pickle = disable @property def _phonopy_unit_cell(self): if self.structure is not None: return atoms_to_phonopy(self.structure) else: return None def _enable_phonopy(self): if self.phonopy is None: if self.structure is not None: self.phonopy = Phonopy( unitcell=self._phonopy_unit_cell, supercell_matrix=self._phonopy_supercell_matrix(), factor=self.input["factor"], ) self.phonopy.generate_displacements( distance=self.input["displacement"]) self.to_hdf() else: raise ValueError( "No reference job/ No reference structure found.") def list_structures(self): if self.structure is not None: self._enable_phonopy() return [struct for _, struct in self._job_generator.parameter_list] else: return [] def _phonopy_supercell_matrix(self): if self.structure is not None: supercell_range = np.ceil( self.input["interaction_range"] / np.array([ np.linalg.norm(vec) for vec in self._phonopy_unit_cell.get_cell() ])) return np.eye(3) * supercell_range else: return np.eye(3) def run_static(self): # Initialise the phonopy object before starting the first calculation. self._enable_phonopy() super(PhonopyJob, self).run_static() def run_if_interactive(self): self._enable_phonopy() super(PhonopyJob, self).run_if_interactive() def to_hdf(self, hdf=None, group_name=None): """ Store the PhonopyJob in an HDF5 file Args: hdf (ProjectHDFio): HDF5 group object - optional group_name (str): HDF5 subgroup name - optional """ super(PhonopyJob, self).to_hdf(hdf=hdf, group_name=group_name) if self.phonopy is not None and not self._disable_phonopy_pickle: with self.project_hdf5.open("output") as hdf5_output: hdf5_output["phonopy_pickeled"] = codecs.encode( pickle.dumps(self.phonopy), "base64").decode() def from_hdf(self, hdf=None, group_name=None): """ Restore the PhonopyJob from an HDF5 file Args: hdf (ProjectHDFio): HDF5 group object - optional group_name (str): HDF5 subgroup name - optional """ super(PhonopyJob, self).from_hdf(hdf=hdf, group_name=group_name) with self.project_hdf5.open("output") as hdf5_output: if "phonopy_pickeled" in hdf5_output.list_nodes(): self.phonopy = pickle.loads( codecs.decode(hdf5_output["phonopy_pickeled"].encode(), "base64")) if "dos_total" in hdf5_output.list_nodes(): self._dos_total = hdf5_output["dos_total"] if "dos_energies" in hdf5_output.list_nodes(): self._dos_energies = hdf5_output["dos_energies"] def collect_output(self): """ Returns: """ if self.server.run_mode.interactive: forces_lst = self.project_hdf5.inspect( self.child_ids[0])["output/generic/forces"] else: forces_lst = [ self.project_hdf5.inspect(job_id)["output/generic/forces"][-1] for job_id in self._get_jobs_sorted() ] self.phonopy.set_forces(forces_lst) self.phonopy.produce_force_constants() self.phonopy.set_mesh(mesh=[self.input["dos_mesh"]] * 3) qpoints, weights, frequencies, eigvecs = self.phonopy.get_mesh() self.phonopy.set_total_DOS() erg, dos = self.phonopy.get_total_DOS() self.to_hdf() with self.project_hdf5.open("output") as hdf5_out: hdf5_out["dos_total"] = dos hdf5_out["dos_energies"] = erg hdf5_out["qpoints"] = qpoints hdf5_out["supercell_matrix"] = self._phonopy_supercell_matrix() hdf5_out[ "displacement_dataset"] = self.phonopy.get_displacement_dataset( ) hdf5_out[ "dynamical_matrix"] = self.phonopy.dynamical_matrix.get_dynamical_matrix( ) hdf5_out["force_constants"] = self.phonopy.force_constants def write_phonopy_force_constants(self, file_name="FORCE_CONSTANTS", cwd=None): """ Args: file_name: cwd: Returns: """ if cwd is not None: file_name = posixpath.join(cwd, file_name) write_FORCE_CONSTANTS(force_constants=self.phonopy.force_constants, filename=file_name) def get_hesse_matrix(self): """ Returns: """ unit_conversion = ( scipy.constants.physical_constants["Hartree energy in eV"][0] / scipy.constants.physical_constants["Bohr radius"][0]**2 * scipy.constants.angstrom**2) force_shape = np.shape(self.phonopy.force_constants) force_reshape = force_shape[0] * force_shape[2] return (np.transpose(self.phonopy.force_constants, (0, 2, 1, 3)).reshape( (force_reshape, force_reshape)) / unit_conversion) def get_thermal_properties(self, t_min=1, t_max=1500, t_step=50, temperatures=None): """ Args: t_min: t_max: t_step: temperatures: Returns: """ self.phonopy.set_thermal_properties(t_step=t_step, t_max=t_max, t_min=t_min, temperatures=temperatures) return thermal(*self.phonopy.get_thermal_properties()) @property def dos_total(self): """ Returns: """ return self["output/dos_total"] @property def dos_energies(self): """ Returns: """ return self["output/dos_energies"] @property def dynamical_matrix(self): """ Returns: """ return np.real_if_close( self.phonopy.get_dynamical_matrix().get_dynamical_matrix()) def dynamical_matrix_at_q(self, q): """ Args: q: Returns: """ return np.real_if_close(self.phonopy.get_dynamical_matrix_at_q(q)) def plot_dos(self, ax=None, *args, **qwargs): """ Args: *args: ax: **qwargs: Returns: """ try: import pylab as plt except ImportError: import matplotlib.pyplot as plt if ax is None: fig, ax = plt.subplots(1, 1) ax.plot(self["output/dos_energies"], self["output/dos_total"], *args, **qwargs) ax.set_xlabel("Frequency [THz]") ax.set_ylabel("DOS") ax.set_title("Phonon DOS vs Energy") return ax
cell = aseAtoms(symbols=sc.get_chemical_symbols(), scaled_positions=sc.get_scaled_positions(), cell=sc.get_cell(), pbc=(1,1,1)) cell = Atoms(cell) cell.set_calculator(pot) forces.append(cell.get_forces()) phonon.set_forces(forces) phonon.produce_force_constants() mesh = [nqx, nqy, nqz] phonon.set_mesh(mesh, is_eigenvectors=True) qpoints, weights, frequencies, eigvecs = phonon.get_mesh() #SHOW DOS STRUCTURE phonon.set_total_DOS(freq_min=0.0, freq_max=12.0, tetrahedron_method=False) phonon.get_total_DOS() phonon.write_total_DOS() phonon.plot_total_DOS().show() #BAND STRUCTURE phonon.set_band_structure(paths, is_eigenvectors=False, is_band_connection=True) phonon.get_band_structure() ph_plot = phonon.plot_band_structure(labels=["G", "N", "P"]) ph_plot.show() #WRITE ANIMATION MODE phonon.write_animation() #TEMPERATURE phonon.set_thermal_properties(t_step=10, t_max=1000, t_min=0) temp_plot = open('temp_plot.dat', 'w') for t, free_energy, entropy, cv in np.array(phonon.get_thermal_properties()).T: print >> temp_plot, ("%12.3f " + "%15.7f" * 3) % ( t, free_energy, entropy, cv )
def get_properties_from_phonopy(**kwargs): """ Calculate DOS and thermal properties using phonopy (locally) :param structure: StructureData Object :param ph_settings: Parametersdata object containing a dictionary with the data needed to run phonopy: supercells matrix, primitive matrix and q-points mesh. :param force_constants: (optional)ForceConstantsData object containing the 2nd order force constants :param force_sets: (optional) ForceSetsData object containing the phonopy force sets :param nac: (optional) ArrayData object from a single point calculation data containing dielectric tensor and Born charges :return: phonon band structure, force constants, thermal properties and DOS """ structure = kwargs.pop('structure') ph_settings = kwargs.pop('ph_settings') bands = kwargs.pop('bands') from phonopy import Phonopy phonon = Phonopy(phonopy_bulk_from_structure(structure), supercell_matrix=ph_settings.dict.supercell, primitive_matrix=ph_settings.dict.primitive, symprec=ph_settings.dict.symmetry_precision) if 'force_constants' in kwargs: force_constants = kwargs.pop('force_constants') phonon.set_force_constants(force_constants.get_data()) else: force_sets = kwargs.pop('force_sets') phonon.set_displacement_dataset(force_sets.get_force_sets()) phonon.produce_force_constants() force_constants = ForceConstantsData(data=phonon.get_force_constants()) if 'nac_data' in kwargs: print('use born charges') nac_data = kwargs.pop('nac_data') primitive = phonon.get_primitive() nac_parameters = nac_data.get_born_parameters_phonopy( primitive_cell=primitive.get_cell()) phonon.set_nac_params(nac_parameters) # Normalization factor primitive to unit cell normalization_factor = phonon.unitcell.get_number_of_atoms( ) / phonon.primitive.get_number_of_atoms() # DOS phonon.set_mesh(ph_settings.dict.mesh, is_eigenvectors=True, is_mesh_symmetry=False) phonon.set_total_DOS(tetrahedron_method=True) phonon.set_partial_DOS(tetrahedron_method=True) total_dos = phonon.get_total_DOS() partial_dos = phonon.get_partial_DOS() dos = PhononDosData( frequencies=total_dos[0], dos=total_dos[1] * normalization_factor, partial_dos=np.array(partial_dos[1]) * normalization_factor, atom_labels=np.array(phonon.primitive.get_chemical_symbols())) # THERMAL PROPERTIES (per primtive cell) phonon.set_thermal_properties() t, free_energy, entropy, cv = phonon.get_thermal_properties() # Stores thermal properties (per unit cell) data in DB as a workflow result thermal_properties = ArrayData() thermal_properties.set_array('temperature', t) thermal_properties.set_array('free_energy', free_energy * normalization_factor) thermal_properties.set_array('entropy', entropy * normalization_factor) thermal_properties.set_array('heat_capacity', cv * normalization_factor) # BAND STRUCTURE phonon.set_band_structure(bands.get_bands()) band_structure = BandStructureData(bands=bands.get_bands(), labels=bands.get_labels(), unitcell=bands.get_unitcell()) band_structure.set_band_structure_phonopy(phonon.get_band_structure()) return { 'thermal_properties': thermal_properties, 'dos': dos, 'band_structure': band_structure, 'force_constants': force_constants }