def H(self): """Returns the Hessian matrix extracted from the frozen phonon calculations. """ if self._H is not None: return self._H #Otherwise, we need to calculate it from scratch. This depends on #whether we are using DFPT or frozen phonons. if not self.dfpt: self.calc_forcesets() dim = ' '.join(map(str, self.supercell)) xargs = ["phonopy", '--dim="{}"'.format(dim), "--writefc"] execute(xargs, self.phonodir, venv=True) if not path.isfile(path.join(self.phonodir, "FORCE_CONSTANTS")): msg.err("Cannot convert FORCE_SETS to FORCE_CONSTANTS") msg.err(''.join(xargs["output"])) else: self.calc_fc() with chdir(self.phonodir): result = file_IO.parse_FORCE_CONSTANTS() self._H = unroll_fc(result) self.save_pkl(self._H, self.H_file) return self._H
def _extract_fc_list(self): fc_list = [] for fc_filename in self._fc_filenames: force_constants = parse_FORCE_CONSTANTS(fc_filename) symmetrize_force_constants(force_constants) fc_list.append(force_constants) return fc_list
def __init__(self, force_constants_filename=None, poscar=None, poscar_ideal=None, phonopy_conf=None, is_symmetrized=True): if poscar_ideal is None: poscar_ideal = poscar force_constants = parse_FORCE_CONSTANTS(force_constants_filename) atoms = read_vasp(poscar) atoms_ideal = read_vasp(poscar_ideal) supercell_matrix = read_supercell_matrix(phonopy_conf) # force_constants_analyzer.generate_symmetrized_force_constants( # atoms_symmetry) # force_constants_analyzer.write_force_constants_pair() super(VaspFCAnalyzer, self).__init__( force_constants=force_constants, atoms=atoms, atoms_ideal=atoms_ideal, supercell_matrix=supercell_matrix, is_symmetrized=True) # force_constants_analyzer.check_translational_invariance() self.generate_symmetrized_force_constants() self.write_force_constants_symmetrized()
def _compute_force_constants(phonon, dataset=None, force_constants_filename=None, force_sets_filename=None, calculator=None, fc_calculator=None): natom = phonon.supercell.get_number_of_atoms() _dataset = None if dataset is not None: _dataset = dataset elif force_constants_filename is not None: dot_split = force_constants_filename.split('.') p2s_map = phonon.primitive.p2s_map if len(dot_split) > 1 and dot_split[-1] == 'hdf5': fc = load_helper.read_force_constants_from_hdf5( filename=force_constants_filename, p2s_map=p2s_map, calculator=calculator) else: fc = parse_FORCE_CONSTANTS(filename=force_constants_filename, p2s_map=p2s_map) phonon.set_force_constants(fc) elif force_sets_filename is not None: _dataset = parse_FORCE_SETS(natom=natom, filename=force_sets_filename) elif os.path.isfile("FORCE_SETS"): _dataset = parse_FORCE_SETS(natom=natom) if _dataset is not None: phonon.dataset = _dataset _produce_force_constants(phonon, fc_calculator)
def read_phonopy(sposcar='SPOSCAR', sc_mat=np.eye(3), force_constants=None, disp_yaml=None, force_sets=None): if force_constants is None and (disp_yaml is None or force_sets is None): raise ValueError( "Either FORCE_CONSTANTS or (disp.yaml&FORCE_SETS) file should be provided." ) atoms = read(sposcar) #vesta_view(atoms) primitive_matrix = inv(sc_mat) bulk = PhonopyAtoms(symbols=atoms.get_chemical_symbols(), scaled_positions=atoms.get_scaled_positions(), cell=atoms.get_cell()) phonon = Phonopy( bulk, supercell_matrix=np.eye(3), primitive_matrix=primitive_matrix, #factor=factor, #symprec=symprec ) if disp_yaml is not None: disp = parse_disp_yaml(filename=disp_yaml) phonon.set_displacement_dataset(disp) if force_sets is not None: fc = parse_FORCE_SETS(filename=force_sets) phonon.set_forces(fc) fc = parse_FORCE_CONSTANTS(force_constants) phonon.set_force_constants(fc) return phonon
def __init__(self, force_constants_filename=None, poscar=None, poscar_ideal=None, phonopy_conf=None, is_symmetrized=True): if poscar_ideal is None: poscar_ideal = poscar force_constants = parse_FORCE_CONSTANTS(force_constants_filename) atoms = read_vasp(poscar) atoms_ideal = read_vasp(poscar_ideal) supercell_matrix = read_supercell_matrix(phonopy_conf) # force_constants_analyzer.generate_symmetrized_force_constants( # atoms_symmetry) # force_constants_analyzer.write_force_constants_pair() super(VaspFCAnalyzer, self).__init__(force_constants=force_constants, atoms=atoms, atoms_ideal=atoms_ideal, supercell_matrix=supercell_matrix, is_symmetrized=True) # force_constants_analyzer.check_translational_invariance() self.generate_symmetrized_force_constants() self.write_force_constants_symmetrized()
def _set_force_constants(phonon, force_constants_filename, force_sets_filename, use_alm): natom = phonon.supercell.get_number_of_atoms() if force_constants_filename is not None: dot_split = force_constants_filename.split('.') p2s_map = phonon.primitive.get_primitive_to_supercell_map() if len(dot_split) > 1 and dot_split[-1] == 'hdf5': fc = read_force_constants_hdf5(filename=force_constants_filename, p2s_map=p2s_map) else: fc = parse_FORCE_CONSTANTS(filename=force_constants_filename, p2s_map=p2s_map) phonon.set_force_constants(fc) elif force_sets_filename is not None: force_sets = parse_FORCE_SETS(natom=natom, filename=force_sets_filename) if force_sets: phonon.set_displacement_dataset(force_sets) phonon.produce_force_constants( calculate_full_force_constants=False, use_alm=use_alm) elif os.path.isfile("FORCE_SETS"): force_sets = parse_FORCE_SETS(natom=natom) if force_sets: phonon.set_displacement_dataset(force_sets) phonon.produce_force_constants( calculate_full_force_constants=False, use_alm=use_alm)
def input_files(self, path_POSCAR, path_FORCECONSTANT): bulk = read_vasp(path_POSCAR) self.phonon = Phonopy(bulk, self.super_cell, primitive_matrix=self.primitive_cell) force_constants = file_IO.parse_FORCE_CONSTANTS(path_FORCECONSTANT) self.phonon.set_force_constants(force_constants) return self.phonon
def get_force_constants_from_file(file_name='FORCE_CONSTANTS', fc_supercell=None): # Just a wrapper to phonopy function force_constants = ForceConstants( np.array(parse_FORCE_CONSTANTS(filename=file_name))) if fc_supercell is not None: force_constants.set_supercell(fc_supercell) return force_constants
def setUp(self) -> None: test_path = Path(test_dir) structure_file = test_path / "POSCAR-NaCl" fc_file = test_path / "FORCE_CONSTANTS" self.structure = Structure.from_file(structure_file) self.supercell_matrix = np.eye(3) * 2 self.force_constants = parse_FORCE_CONSTANTS(fc_file)
def load(supercell_matrix, primitive_matrix=None, nac_params=None, unitcell=None, calculator="vasp", unitcell_filename=None, born_filename=None, force_sets_filename=None, force_constants_filename=None, factor=VaspToTHz, frequency_scale_factor=None, symprec=1e-5, is_symmetry=True, log_level=0): if unitcell is None: _unitcell, _ = read_crystal_structure(filename=unitcell_filename, interface_mode=calculator) else: _unitcell = unitcell # units keywords: factor, nac_factor, distance_to_A units = get_default_physical_units(calculator) phonon = Phonopy(_unitcell, supercell_matrix, primitive_matrix=primitive_matrix, factor=units['factor']) if nac_params is None: if born_filename is None: _nac_params = None else: _nac_params = parse_BORN(phonon.primitive, filename=born_filename) else: _nac_params = nac_params if _nac_params is not None: if _nac_params['factor'] is None: _nac_params['factor'] = units['nac_factor'] phonon.set_nac_params(_nac_params) if force_constants_filename is not None: dot_split = force_constants_filename.split('.') p2s_map = phonon.primitive.get_primitive_to_supercell_map() if len(dot_split) > 1 and dot_split[-1] == 'hdf5': fc = read_force_constants_hdf5(filename=force_constants_filename, p2s_map=p2s_map) else: fc = parse_FORCE_CONSTANTS(filename=force_constants_filename, p2s_map=p2s_map) phonon.set_force_constants(fc) elif force_sets_filename is not None: force_sets = parse_FORCE_SETS(filename=force_sets_filename) phonon.set_displacement_dataset(force_sets) phonon.produce_force_constants() return phonon
def make_omega2_pols(supercell_dims=[5, 5, 5], qgrid_dims=[51, 51, 51], force_constants='FORCE_CONSTANTS', poscar='POSCAR', fix_phase=True): """compute polarizations Inputs - force_constants: path of the FORCE_CONSTANTS file - poscar: path of the POSCAR file - supercell_dims: supercell dimensions, eg "5 5 5". should be consistent with the FORCE_CONSTANTS file - qgrid_dims: Q grid dimensions Output: - Omega2 - Polarizations """ print("* Constructing Q array") qgrid_dims = np.array(qgrid_dims, dtype=float) delta = 1. / (qgrid_dims - 1) Qx = np.arange(0, 1. + delta[0] / 2, delta[0]) Qy = np.arange(0, 1. + delta[1] / 2, delta[1]) Qz = np.arange(0, 1. + delta[2] / 2, delta[2]) Qs = [] for qx in Qx: for qy in Qy: for qz in Qz: Qs.append([qx, qy, qz]) continue Qs = np.array(Qs) # read force_constants from phonopy import file_IO force_constants = file_IO.parse_FORCE_CONSTANTS(force_constants) # !!! only need one symbol per specie # !!! follow vasp convention !!! supercell_matrix = np.diag(supercell_dims) print("* Calling phonopy to compute eigen values and eigen vectors") from . import onGrid qvecs, freq, pols = onGrid(Qs, supercell_matrix, force_constants, freq2omega=1, poscar=poscar) print("* Writing out freqencies") from mccomponents.sample.idf import Omega2, Polarizations freq[freq < 0] = 0 # min = np.min(freq) # if min < 0: freq += -min omega2 = freq**2 * 1e24 * (2 * np.pi)**2 Omega2.write(omega2) print("* Writing out polarizations") Polarizations.write(pols) return
def get_force_constants_from_file(file_name='FORCE_CONSTANTS', fc_supercell=None): # Just a wrapper to phonopy function force_constants = ForceConstants(np.array(parse_FORCE_CONSTANTS(filename=file_name))) if fc_supercell is not None: force_constants.set_supercell(fc_supercell) else: print('No force sets supercell defined, set to identity') force_constants.set_supercell(np.identity(3)) return force_constants
def _read_force_constants_file(phonon, force_constants_filename): dot_split = force_constants_filename.split('.') p2s_map = phonon.primitive.p2s_map if len(dot_split) > 1 and dot_split[-1] == 'hdf5': _fc = read_force_constants_from_hdf5(filename=force_constants_filename, p2s_map=p2s_map, calculator=phonon.calculator) else: _fc = parse_FORCE_CONSTANTS(filename=force_constants_filename, p2s_map=p2s_map) return _fc
def setUp(self): structure = io.read_from_file_structure_poscar('MgO_data/POSCAR') structure.set_force_constants( parse_FORCE_CONSTANTS(filename='MgO_data/FORCE_CONSTANTS')) structure.set_primitive_matrix([[0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]) structure.set_supercell_phonon([[2, 0, 0], [0, 2, 0], [0, 0, 2]]) trajectory = io.generate_test_trajectory(structure, supercell=[2, 2, 2], total_time=5, silent=False) self.calculation = dynaphopy.Quasiparticle(trajectory)
def setUp(self): self.structure = io.read_from_file_structure_poscar('GaN_data/POSCAR') self.structure.set_force_constants( parse_FORCE_CONSTANTS(filename='GaN_data/FORCE_CONSTANTS')) self.structure.set_primitive_matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]) self.structure.set_supercell_phonon([[3, 0, 0], [0, 3, 0], [0, 0, 3]]) if not os.path.exists('test_gan.h5'): trajectory = io.generate_test_trajectory(self.structure, supercell=[3, 3, 3], total_time=8, silent=False) self.calculation = dynaphopy.Quasiparticle(trajectory) self.calculation.save_velocity_hdf5('test_gan.h5', save_trajectory=True)
def get_initialized_phononopy_instance(initial_structure, phonopy_inputs, force_constants_path=None, born_path=None): """ Initializes and returns a valid Phonopy instance and with displacements internally generated. If force_constants_path is specified, the phonopy instance is initialized with the force constants at the given path. If the born_path is specified, the born file at this path is used to initialize the nac parameters of the phonopy instance, but only if the nac key has a value of true in the phonopy_inputs dictionary. phonopy_inputs should be a dictionary that looks like: phonopy_inputs_dictionary = { 'supercell_dimensions': [2, 2, 2], 'symprec': 0.001, 'displacement_distance': 0.01, 'nac': True ... } """ unit_cell_phonopy_structure = convert_structure_to_phonopy_atoms( initial_structure) supercell_dimensions_matrix = np.diag( phonopy_inputs['supercell_dimensions']) phonon = Phonopy(unitcell=unit_cell_phonopy_structure, supercell_matrix=supercell_dimensions_matrix, symprec=phonopy_inputs['symprec']) phonon.generate_displacements( distance=phonopy_inputs['displacement_distance']) if force_constants_path != None: force_constants = parse_FORCE_CONSTANTS(filename=force_constants_path) phonon.set_force_constants(force_constants) if born_path != None and (phonopy_inputs.has_key('nac') and phonopy_inputs['nac']): nac_params = parse_BORN(phonon.get_primitive(), filename=born_path) phonon.set_nac_params(nac_params) return phonon
def set_force_constants( phonon, dataset=None, force_constants_filename=None, force_sets_filename=None, calculator=None, use_alm=False): natom = phonon.supercell.get_number_of_atoms() _dataset = None if dataset is not None: _dataset = dataset elif force_constants_filename is not None: dot_split = force_constants_filename.split('.') p2s_map = phonon.primitive.get_primitive_to_supercell_map() if len(dot_split) > 1 and dot_split[-1] == 'hdf5': fc = read_force_constants_from_hdf5( filename=force_constants_filename, p2s_map=p2s_map, calculator=calculator) else: fc = parse_FORCE_CONSTANTS(filename=force_constants_filename, p2s_map=p2s_map) phonon.set_force_constants(fc) elif force_sets_filename is not None: _dataset = parse_FORCE_SETS(natom=natom, filename=force_sets_filename) elif os.path.isfile("FORCE_SETS"): _dataset = parse_FORCE_SETS(natom=natom) if _dataset: phonon.set_displacement_dataset(_dataset) try: phonon.produce_force_constants( calculate_full_force_constants=False, use_alm=use_alm) except RuntimeError: pass
def __init__(self, primitive, supercell, folder, vasp=False): self.atoms = PhonopyAtoms(symbols=primitive.get_chemical_symbols(), positions=primitive.positions, masses=primitive.get_masses(), cell=primitive.cell, pbc=primitive.pbc) self.supercell = supercell self.folder = folder if not vasp: self.phonopy = Phonopy(self.atoms, supercell) self._get_dynmatrix() self.primitive = self.phonopy._dynamical_matrix.get_primitive() else: from matdb.io import vasp_to_xyz self.phonopy = Phonopy(self.atoms, supercell) if path.isfile("FORCE_CONSTANTS"): fc = file_IO.parse_FORCE_CONSTANTS(filename="FORCE_CONSTANTS") self.phonopy.set_force_constants(fc) self.phonopy._set_dynamical_matrix() self.primitive = primitive vasp_to_xyz(folder) self.parent = quippy.Atoms(path.join(folder, "output.xyz"))
def _configure(self, dict_input): """ supercell_disordered: The structure corresponding to the force constants. """ self._atoms_disordered = read_vasp(dict_input["structure_disordered"]) self._atoms_average = read_vasp(dict_input["structure_average"]) self._symprec = dict_input["symprec"] self._map_s2s = dict_input["map_s2s"] self._random_seed = dict_input["random_seed"] self._num_configurations = dict_input['num_configurations'] primitive_matrix = parse_3x3_matrix(dict_input["primitive_matrix"]) self._supercell_matrix = dict_input["supercell_matrix"] self._enlargement_matrix = dict_input["enlargement_matrix"] self._fc_filename = dict_input["force_constants"] self._force_constants = parse_FORCE_CONSTANTS(self._fc_filename) self._supercell_disordered = Supercell( self._atoms_disordered, self._supercell_matrix, symprec=self._symprec) self._supercell_average = Supercell( self._atoms_average, self._supercell_matrix, symprec=self._symprec) # TODO(ikeda): The following part should be separated from this method. inv_supercell_matrix = np.linalg.inv(self._supercell_matrix) trans_mat = np.dot(inv_supercell_matrix, primitive_matrix) self._primitive_average = Primitive( self._supercell_average, trans_mat, symprec=self._symprec)
def __init__(self, PoscarName='POSCAR', BornFileName='BORN', ForceConstants=False, ForceFileName='FORCE_SETS', supercell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]] , nac=False, symprec=1e-5, masses=[], primitive=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], degeneracy_tolerance=1e-5): """ Class for calculating the IR spectra in the dipole approximation according to: P. Giannozzi and S. Baroni, J. Chem. Phys. 100, 8537 (1994). and D. Karhanek, T. Bucko, J. Hafner, J. Phys.: Condens. Matter 22 265006 (2010). This class was also carefully compared to the results of the script by D. Karhanek available at http://homepage.univie.ac.at/david.karhanek/downloads.html args: PoscarNamse (str): name of the POSCAR that was used for the phonon calculation BornFileName (str): name of the file with BORN charges (formatted with outcar-born) ForceConstants (boolean): If True, ForceConstants are read in. If False, forces are read in. ForceFileName (str): name of the file including force constants or forces supercell (list of lists): reads in supercell nac (boolean): If true, NAC is applied. symprec (float): contains symprec tag as used in Phonopy masses (list): Masses in this list are used instead of the ones prepared in Phonopy. Useful for isotopes. primitive (list of lists): contains rotational matrix to arrive at primitive cell degeneracy_tolerance (float): tolerance for degenerate modes """ self.__unitcell = read_vasp(PoscarName) self.__supercell = supercell self.__phonon = Phonopy(self.__unitcell, supercell_matrix=self.__supercell, primitive_matrix=primitive, factor=VaspToCm, symprec=symprec) self.__natoms = self.__phonon.get_primitive().get_number_of_atoms() self._degeneracy_tolerance = degeneracy_tolerance # If different masses are supplied if not ForceConstants: self.__force_sets = parse_FORCE_SETS(filename=ForceFileName) self.__phonon.set_displacement_dataset(self.__force_sets) self.__phonon.produce_force_constants() if ForceConstants: force_constants = parse_FORCE_CONSTANTS(filename=ForceFileName) self.__phonon.set_force_constants(force_constants) if masses: self.__phonon._build_supercell() self.__phonon._build_primitive_cell() # if ForceConstants: # force_constants = parse_FORCE_CONSTANTS(filename=ForceFileName) # self.__phonon.set_force_constants(force_constants) self.__phonon.set_masses(masses) self.__masses = self.__phonon.get_primitive().get_masses() # Forces or Force Constants # Read in BORN file BORN_file = parse_BORN(self.__phonon.get_primitive(), filename=BornFileName) self.__BORN_CHARGES = BORN_file['born'] # Apply NAC Correction if nac: self.__phonon.set_nac_params(BORN_file) self._frequencies, self._eigvecs = self.__phonon.get_frequencies_with_eigenvectors([0, 0, 0]) self.__NumberOfBands = len(self._frequencies) # Nicer format of the eigenvector file self.__FormatEigenvectors() # Get dipole approximation of the intensitiess self.__set_intensities()
from phonopy import Phonopy from phonopy.interface.vasp import read_vasp from phonopy.file_IO import parse_FORCE_SETS from phonopy.file_IO import parse_FORCE_CONSTANTS, write_FORCE_CONSTANTS cell = read_vasp("POSCAR") phonon = Phonopy(cell, [[2, 0, 0], [0, 2, 0], [0, 0, 2]]) force_sets = parse_FORCE_SETS() phonon.set_displacement_dataset(force_sets) phonon.produce_force_constants() write_FORCE_CONSTANTS(phonon.get_force_constants(), filename="FORCE_CONSTANTS") force_constants = parse_FORCE_CONSTANTS() phonon.set_force_constants(force_constants) phonon.symmetrize_force_constants(iteration=1) write_FORCE_CONSTANTS(phonon.get_force_constants(), filename="FORCE_CONSTANTS_NEW")
def __init__(self, poscar_filename="POSCAR", fc_filename="FORCE_CONSTANTS"): self._poscar = Poscar(poscar_filename) self._force_constants = parse_FORCE_CONSTANTS(fc_filename) self._fc_reduced = None
def ir_intensity_phonopy( run_dir=".", vasprun="vasprun.xml", BornFileName="BORN", PoscarName="POSCAR", ForceConstantsName="FORCE_CONSTANTS", supercell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], nac=True, symprec=1e-5, primitive=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], degeneracy_tolerance=1e-5, vector=[0, 0, 0], smoothen=False, ): """Calculate IR intensity using DFPT and phonopy.""" from phonopy import Phonopy from phonopy.interface.vasp import read_vasp from phonopy.file_IO import ( parse_BORN, parse_FORCE_CONSTANTS, ) import shutil from phonopy.units import VaspToCm # from phonopy.phonon.degeneracy import ( # degenerate_sets as get_degenerate_sets, # ) # adapted from https://github.com/JaGeo/IR # TODO: Make directory indepndent cwd = os.getcwd() print("Directory:", cwd) os.chdir(run_dir) if not os.path.exists(vasprun): shutil.copy2(vasprun, "vasprun.xml") cmd = str("phonopy --fc vasprun.xml") os.system(cmd) born_file = os.path.join(os.getcwd(), BornFileName) cmd = str("phonopy-vasp-born > ") + str(born_file) os.system(cmd) from jarvis.io.vasp.outputs import Vasprun v = Vasprun(vasprun) strt = v.all_structures[0] strt.write_poscar(PoscarName) unitcell = read_vasp(PoscarName) phonon = Phonopy( unitcell, supercell_matrix=supercell, primitive_matrix=primitive, factor=VaspToCm, symprec=symprec, ) natoms = phonon.get_primitive().get_number_of_atoms() force_constants = parse_FORCE_CONSTANTS(filename=ForceConstantsName) phonon.set_force_constants(force_constants) masses = phonon.get_primitive().get_masses() phonon.set_masses(masses) BORN_file = parse_BORN(phonon.get_primitive(), filename=BornFileName) BORN_CHARGES = BORN_file["born"] # print ('born_charges2',BORN_CHARGES) if nac: phonon.set_nac_params(BORN_file) frequencies, eigvecs = phonon.get_frequencies_with_eigenvectors(vector) # frequencies=VaspToTHz*frequencies/VaspToCm # x, y = ir_intensity( # phonon_eigenvectors=np.real(eigvecs), # phonon_eigenvalues=frequencies, # masses=masses, #np.ones(len(masses)), # born_charges=born_charges, # smoothen=smoothen, # ) NumberOfBands = len(frequencies) EigFormat = {} for alpha in range(NumberOfBands): laufer = 0 for beta in range(natoms): for xyz in range(0, 3): EigFormat[beta, alpha, xyz] = eigvecs[laufer][alpha] laufer = laufer + 1 Intensity = {} intensities = [] for freq in range(len(frequencies)): Intensity[freq] = 0 tmp = 0 for alpha in range(3): asum = 0 for n in range(natoms): for beta in range(3): asum = asum + BORN_CHARGES[n, alpha, beta] * np.real( EigFormat[n, freq, beta] ) / np.sqrt(masses[n]) tmp += asum Intensity[freq] = Intensity[freq] + np.power(np.absolute(asum), 2) intensities.append(Intensity[freq]) os.chdir(cwd) return frequencies, intensities
# Set up a Phonopy object to do the "heavy lifting" of generating the modulated structures. phonon = Phonopy( structure, args.SupercellMatrix, primitive_matrix = args.PrimitiveMatrix, symprec = args.tolerance ); # Set up the force constants. if args.ReadForceConstants: # If the --readfc flag was set, read the force constants directly from a FORCE_CONSTANTS file. phonon.set_force_constants( parse_FORCE_CONSTANTS() ); else: # If not, read the FORCE_SETS file, pass the dataset to the Phonopy object, and calculate the force constants. phonon.set_displacement_dataset( parse_FORCE_SETS() ); phonon.produce_force_constants(); # Set a scaling factor for the user-input normal-mode coordinate ranges. # The conversion from normal-mode coordinate amplitude to cartesian displacements in the Phonopy modulation routine uses a definition that leads to fitted harmonic frequencies (for modes with harmonic potential-energy surfaces) being a factor of \sqrt(N_a) too small. # By default, we therefore apply a scaling factor before passing the amplitudes to the Phonopy routines (unless overridden by the --no__q_scale argument). qScale = None;
def load_phonopy(filename, structure, dim, symprec=0.01, primitive_matrix=None, factor=VaspToTHz, symmetrise=True, born=None, write_fc=False): """Load phonopy output and return an ``phonopy.Phonopy`` object. Args: filename (str): Path to phonopy output. Can be any of ``FORCE_SETS``, ``FORCE_CONSTANTS``, or ``force_constants.hdf5``. structure (:obj:`~pymatgen.core.structure.Structure`): The unitcell structure. dim (list): The supercell size, as a :obj:`list` of :obj:`float`. symprec (:obj:`float`, optional): The tolerance for determining the crystal symmetry. primitive_matrix (:obj:`list` or :obj:`str`, optional): The transformation matrix from the conventional to primitive cell. Only required when the conventional cell was used as the starting structure. Should be provided as a 3x3 :obj:`list` of :obj:`float`. Alternatively the str 'auto' may be provided. factor (:obj:`float`, optional): The conversion factor for phonon frequency. Defaults to :obj:`phonopy.units.VaspToTHz`. symmetrise (:obj:`bool`, optional): Symmetrise the force constants. Defaults to ``True``. born (:obj:`str`, optional): Path to file containing Born effective charges. Should be in the same format as the file produced by the ``phonopy-vasp-born`` script provided by phonopy. write_fc (:obj:`bool` or :obj:`str`, optional): Write the force constants to disk. If ``True``, a ``FORCE_CONSTANTS`` file will be written. Alternatively, if set to ``"hdf5"``, a ``force_constants.hdf5`` file will be written. Defaults to ``False`` (force constants not written). """ unitcell = get_phonopy_structure(structure) num_atom = unitcell.get_number_of_atoms() num_satom = determinant(dim) * num_atom phonon = Phonopy(unitcell, dim, primitive_matrix=primitive_matrix, factor=factor, symprec=symprec) if 'FORCE_CONSTANTS' == filename or '.hdf5' in filename: # if force constants exist, use these to avoid recalculating them if '.hdf5' in filename: fc = file_IO.read_force_constants_hdf5(filename) elif 'FORCE_CONSTANTS' == filename: fc = file_IO.parse_FORCE_CONSTANTS(filename=filename) if fc.shape[0] != num_satom: msg = ("\nNumber of atoms in supercell is not consistent with the " "matrix shape of\nforce constants read from {}.\nPlease" "carefully check --dim.") logging.error(msg.format(filename)) sys.exit() phonon.set_force_constants(fc) elif 'FORCE_SETS' == filename: # load the force sets from file and calculate force constants fs = file_IO.parse_FORCE_SETS() if fs['natom'] != num_satom: msg = ("\nNumber of atoms in supercell is not consistent with the " "the data in FORCE_SETS\nPlease carefully check --dim.") logging.error(msg.format(filename)) sys.exit() phonon.set_displacement_dataset(fs) logging.info("Calculating force constants...") phonon.produce_force_constants() if born: # load born parameters from a file nac_params = file_IO.parse_BORN(phonon._primitive, symprec=symprec, filename=born) # set the nac unit conversion factor manual, specific to VASP nac_params['factor'] = Hartree * Bohr phonon.set_nac_params(nac_params) if symmetrise: phonon.symmetrize_force_constants() if write_fc == 'hdf5': file_IO.write_force_constants_to_hdf5(phonon.get_force_constants()) logging.info("Force constants written to force_constants.hdf5.") elif write_fc: file_IO.write_FORCE_CONSTANTS(phonon.get_force_constants()) logging.info("Force constants written to FORCE_CONSTANTS.") return phonon
def __set_ForceConstants(self, filename, phonon): """ sets force constants """ force_constants = parse_FORCE_CONSTANTS(filename=filename) phonon.set_force_constants(force_constants)
def get_force_constants_from_file(file_name='FORCE_CONSTANTS'): # Just a wrapper to phonopy function force_constants = parse_FORCE_CONSTANTS(filename=file_name) return force_constants
else: # default or vasp displacement_distance = 0.01 else: displacement_distance = settings.get_displacement_distance() # Supercell matrix if settings.get_supercell_matrix() is None: print_error_message("Supercell matrix (DIM or --dim) is not found.") if log_level > 0: print_end() sys.exit(1) num_atom = unitcell.get_number_of_atoms() num_satom = determinant(settings.get_supercell_matrix()) * num_atom if settings.get_is_force_constants() == 'read': if file_exists("FORCE_CONSTANTS", log_level): fc = file_IO.parse_FORCE_CONSTANTS(filename="FORCE_CONSTANTS") fc_filename = "FORCE_CONSTANTS" if log_level > 0: print("Force constants are read from %s." % fc_filename) if fc.shape[0] != num_satom: error_text = ("Number of atoms in supercell is not consistent with " "the matrix shape of\nforce constants read from ") if settings.get_is_hdf5(): error_text += "force_constants.hdf5.\n" else: error_text += "FORCE_CONSTANTS.\n" error_text += ("Please carefully check DIM, FORCE_CONSTANTS, " "and %s.") % unitcell_filename print_error_message(error_text)
def phonopy_to_abinit(unit_cell, supercell_matrix, out_ddb_path, ngqpt=None, qpt_list=None, force_constants=None, force_sets=None, born=None, primitive_matrix="auto", symprec=1e-5, tolsym=None, supercell=None, calculator=None, manager=None, workdir=None, pseudos=None, verbose=False): """ Converts the data from phonopy to an abinit DDB file. The data can be provided in form of arrays or paths to the phonopy files that should be parsed. The minimal input should contains the FORCE_CONSTANTS or FORCE_SETS. If BORN is present the Born effective charges (BEC) and dielectric tensor will also be added to the DDB. The best agreement is obtained with supercell_matrix and ngqpt being equivalent (i.e. supercell_matrix a diagonal matrix with ngqpt as diagonal elements). Non diagonal supercell_matrix are allowed as well, but the information encoded in the DDB will be the result of an interpolation done through phonopy. Phonopy is used to convert the IFC to the dynamical matrix. However, in order to determine the list of q-points in the irreducible Brillouin zone and to prepare the base for the final DDB file, abinit will be called for a very short and inexpensive run. 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: unit_cell: a |Structure| object that identifies the unit cell used for the phonopy calculation. supercell_matrix: a 3x3 array representing the supercell matrix used to generated the forces with phonopy. out_ddb_path: a full path to the file where the new DDB will be written ngqpt: a list of 3 elements indicating the grid of q points that will be used in the DDB. qpt_list: alternatively to ngqpt an explicit list of q-points can be provided here. At least one among ngqpt and qpt_list should be defined. force_constants: an array with shape (num atoms unit cell, num atoms supercell, 3, 3) containing the force constants. Alternatively a string with the path to the FORCE_CONSTANTS file. This or force_set should be defined. If both given this has precedence. force_sets: a dictionary obtained from the force sets generated with phonopy. Alternatively a string with the path to the FORCE_SETS file. This or force_constants should be defined. born: a dictionary with "dielectric" and "born" keywords as obtained from the nac_params in phonopy. Alternatively a string with the path to the BORN file. Notice that the "factor" attribute is not taken into account, so the values should be in default phonopy units. primitive_matrix: a 3x3 array with the primitive matrix passed to Phonopy. "auto" will use spglib to try to determine it automatically. If the DDB file should contain the actual unit cell this should be the identity matrix. 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. tolsym: Gives the tolerance to identify symmetries in abinit. See abinit documentation for more details. supercell: if given it should represent the supercell used to get the force constants, without any perturbation. It will be used to match it to the phonopy supercell and sort the IFC in the correct order. calculator: a string with the name of the calculator. Will be used to set the conversion factor for the force constants coming from phonopy. manager: |TaskManager| object. If None, the object is initialized from the configuration file pseudos: List of filenames or list of |Pseudo| objects or |PseudoTable| object. It will be used by abinit to generate the base DDB file. If None the abipy.data.hgh_pseudos.HGH_TABLE table will be used. verbose: verbosity level. Set it to a value > 0 to get more information workdir: path to the directory where the abinit calculation will be executed. Returns: a DdbFile instance of the file written in out_ddb_path. """ if ngqpt is None and qpt_list is None: raise ValueError( "at least one among nqgpt and qpt_list should be defined") if force_sets is None and force_constants is None: raise ValueError( "at least one of force_sets and force_constants should be provided" ) phon_at = get_phonopy_structure(unit_cell) if isinstance(force_constants, str): force_constants = parse_FORCE_CONSTANTS(filename=force_constants) elif force_constants is not None: force_constants = np.array(force_constants) force_sets = None if isinstance(force_sets, str): force_sets = parse_FORCE_SETS(filename=force_sets) # no nac_params here, otherwise they will be used for the interpolation phonon = Phonopy(phon_at, supercell_matrix, primitive_matrix=primitive_matrix, nac_params=None, symprec=symprec, calculator=calculator) primitive = get_pmg_structure(phonon.primitive) if isinstance(born, str): born = parse_BORN(phonon.primitive, filename=born) if supercell is not None: ph_supercell = get_pmg_structure(phonon.supercell) if not np.allclose(supercell.lattice.matrix, ph_supercell.lattice.matrix): raise RuntimeError("The lattice of the supercells do not match") sc_mapping = [] for i, site_orig in enumerate(supercell): for j, site_ph in enumerate(ph_supercell): d = supercell.lattice.get_distance_and_image( site_orig.frac_coords, site_ph.frac_coords)[0] if d < 1e-5: sc_mapping.append(j) break else: raise RuntimeError( f"Could not find a match for site {i} with coords " f"{site_orig.cart_coords} in the supercell.") # cross check that the same atom was not matched twice n_matches = len(set(sc_mapping)) if n_matches < len(supercell): raise RuntimeError( f"Found matches for {n_matches} different atoms in the supercell: {sc_mapping}" ) force_constants = force_constants[:, sc_mapping] if force_constants is not None: phonon.set_force_constants(force_constants) else: phonon.dataset = force_sets phonon.produce_force_constants() if calculator: units = get_default_physical_units(calculator) fc_factor = get_force_constant_conversion_factor( units["force_constants_unit"], None) phonon.set_force_constants(phonon.force_constants * fc_factor) if pseudos is None: from abipy.data.hgh_pseudos import HGH_TABLE pseudos = HGH_TABLE inp = minimal_scf_input(primitive, pseudos) # get the qpoints list if not defined if qpt_list is None: inp["ngkpt"] = ngqpt qpt_list = inp.abiget_ibz(verbose=verbose)[0] dm_list = get_dm(phonon, qpt_list, primitive) if born is not None: # for the conversion of the BEC the zion (i.e. the ionic charge of the pseudo) # it is an additive factor and should be the same that goes in the header of the DDB, # so take it from the pseudos used to generate it. zion = inp.valence_electrons_per_atom born_data = generate_born_deriv(born, zion, primitive) else: born_data = None inp = minimal_scf_input(primitive, pseudos) if tolsym is not None: inp["tolsym"] = tolsym task = inp.run_in_shell(workdir=workdir, manager=manager, verbose=verbose) # use the output of abinit to check that the spacegroup identified by # phonopy and abinit are the same. with GsrFile(task.opath_from_ext("GSR.nc")) as gsr: abi_spg = gsr.structure.abi_spacegroup.spgid spglib_spg = phonon.symmetry.dataset["number"] if abi_spg != spglib_spg: warnings.warn( "The space group number obtained based on the DDB symmetries differs " f"from the one calculated with spglib: {abi_spg} versus " f"{spglib_spg}. The convertion may be incorrect. Try changing symprec or tolsym." ) tmp_ddb_path = task.opath_from_ext("DDB") ddb = DdbFile(tmp_ddb_path) # remove the blocks generated by the calculation and that are meaningless ddb.remove_block(dord=0) ddb.remove_block(dord=1) add_data_ddb(ddb, dm_list, qpt_list, born_data) ddb.write(out_ddb_path) new_ddb = DdbFile(out_ddb_path) return new_ddb
# Read the structure file. structure = read_vasp(args.CellFile) # Set up a Phonopy object to do the "heavy lifting" of generating the modulated structures. phonon = Phonopy(structure, args.SupercellMatrix, primitive_matrix=args.PrimitiveMatrix) # Set up the force constants. if args.ReadForceConstants: # If the --readfc flag was set, read the force constants directly from a FORCE_CONSTANTS file. phonon.set_force_constants(parse_FORCE_CONSTANTS()) else: # If not, read the FORCE_SETS file, pass the dataset to the Phonopy object, and calculate the force constants. phonon.set_displacement_dataset(parse_FORCE_SETS()) phonon.produce_force_constants() # Set a scaling factor for the user-input normal-mode coordinate ranges. # The conversion from normal-mode coordinate amplitude to cartesian displacements in the Phonopy modulation routine uses a definition that leads to fitted harmonic frequencies (for modes with harmonic potential-energy surfaces) being a factor of \sqrt(N_a) too small. # By default, we therefore apply a scaling factor before passing the amplitudes to the Phonopy routines (unless overridden by the --no__q_scale argument). qScale = None if args.ScaleQ: qScale = math.sqrt(len(structure.get_scaled_positions()))
import phonopy from phonopy.file_IO import parse_FORCE_CONSTANTS, write_FORCE_CONSTANTS phonon = phonopy.load(supercell_matrix=[[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]], unitcell_filename="POSCAR", force_sets_filename="FORCE_SETS", born_filename="BORN") write_FORCE_CONSTANTS(phonon.get_force_constants(), filename="FORCE_CONSTANTS") force_constants = parse_FORCE_CONSTANTS() phonon.force_constants = force_constants phonon.symmetrize_force_constants() write_FORCE_CONSTANTS(phonon.get_force_constants(), filename="FORCE_CONSTANTS_NEW")