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_force_constants_from_phonopy(structure, ph_settings, force_sets): """ Calculate the force constants locally using phonopy :param structure: :param phonopy_input: ParameterData object that contains phonopy settings :param force_sets: ForceSetsData object that contains the atomic forces and displacements info (datasets dict in phonopy) :return: ForceConstantsData object containing the 2nd order force constants calculated with phonopy """ from phonopy import Phonopy # Generate phonopy phonon object phonon = Phonopy(phonopy_bulk_from_structure(structure), ph_settings.dict.supercell, primitive_matrix=ph_settings.dict.primitive, symprec=ph_settings.dict.symmetry_precision) phonon.generate_displacements(distance=ph_settings.dict.distance) # Build data_sets from forces of supercells with displacments phonon.set_displacement_dataset(force_sets.get_force_sets()) phonon.produce_force_constants() force_constants = ForceConstantsData(data=phonon.get_force_constants()) return {'force_constants': force_constants}
def get_data_from_dir(directory, i_volume): data_sets = file_IO.parse_FORCE_SETS( filename=directory + '/phonon-{0:02d}/FORCE_SETS'.format(i_volume)) yaml_file = open( directory + '/phonon-{0:02d}/phonon.yaml'.format(i_volume), 'r') data = yaml.load_all(yaml_file).next() unit_cell = PhonopyAtoms( symbols=[item['symbol'] for item in data['points']], scaled_positions=[item['coordinates'] for item in data['points']], cell=data['lattice']) phonon = Phonopy(unit_cell, data['supercell_matrix']) phonon.set_displacement_dataset(data_sets) phonon.produce_force_constants() force_constants = phonon.get_force_constants() supercell = phonon.get_supercell() volume = unit_cell.get_volume() energy = data['electric_total_energy'] return supercell, volume, energy, force_constants, data['supercell_matrix']
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_force_constants_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() # 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']) # Build data_sets from forces of supercells with displacments data_sets = phonon.get_displacement_dataset() for i, first_atoms in enumerate(data_sets['first_atoms']): first_atoms['forces'] = kwargs.pop( 'force_{}'.format(i)).get_array('forces')[0] # Calculate and get force constants phonon.set_displacement_dataset(data_sets) phonon.produce_force_constants() force_constants = phonon.get_force_constants().tolist() # Set force constants ready to return force_constants = phonon.get_force_constants() data = ArrayData() data.set_array('force_constants', force_constants) data.set_array('force_sets', np.array(data_sets)) return {'phonopy_output': data}
def get_force_constants_from_phonopy(**kwargs): """ Calculate the force constants using phonopy :param kwargs: :return: """ from phonopy.structure.atoms import Atoms as PhonopyAtoms from phonopy import Phonopy import numpy as np # print 'function',kwargs structure = kwargs.pop('structure') phonopy_input = kwargs.pop('phonopy_input').get_dict() # 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.generate_displacements(distance=phonopy_input['distance']) # Build data_sets from forces of supercells with displacments data_sets = phonon.get_displacement_dataset() for i, first_atoms in enumerate(data_sets['first_atoms']): forces = kwargs.pop('forces_{}'.format(i)).get_array('forces')[0] first_atoms['forces'] = np.array(forces, dtype='double', order='c') # LOCAL calculation # Calculate and get force constants phonon.set_displacement_dataset(data_sets) phonon.produce_force_constants() force_constants = phonon.get_force_constants() array_data = ArrayData() array_data.set_array('force_constants', force_constants) return {'array_data': array_data}
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
freqlim_low, freqlim_up, doslim_low, doslim_up, flip_pdos_xy, legend_bool, save_svg, ) if run_mode == 'jdos': np.save('ir_grid_points-{}{}{}.npy'.format(*pdos_mesh), phonon.mesh.get_ir_grid_points()) np.save('grid_addresses-{}{}{}.npy'.format(*pdos_mesh), phonon.mesh.get_grid_address()) np.save('ir_grid_weights-{}{}{}.npy'.format(*pdos_mesh), phonon.mesh.get_weights()) from phono3py import Phono3pyJointDos as JDOS jdos = JDOS( phonon.get_supercell(), phonon.get_primitive(), pdos_mesh, phonon.get_force_constants(), nac_params=nac_params, temperatures=temp, num_frequency_points=num_freq_points, ) jdos.run( grid_points=phonon.mesh.get_ir_grid_points(), write_jdos=True, )
def abinit_to_phonopy(anaddbnc, supercell_matrix, symmetrize_tensors=False, output_dir_path=None, prefix_outfiles="", symprec=1e-5, set_masses=False): """ Converts the interatomic force constants(IFC), born effective charges(BEC) and dielectric tensor obtained from anaddb to the phonopy format. Optionally writes the standard phonopy files to a selected directory: FORCE_CONSTANTS, BORN (if BECs are available) POSCAR of the unit cell, POSCAR of the supercell. The conversion is performed taking the IFC in the Wigner–Seitz supercell with weights as produced by anaddb and reorganizes them in a standard supercell multiple of the unit cell. Operations are vectorized using numpy. This may lead to the allocation of large arrays in case of very large supercells. Performs a check to verify if the two codes identify the same symmetries and it gives a warning in case of failure. Mismatching symmetries may lead to incorrect conversions. Args: anaddbnc: an instance of AnaddbNcFile. Should contain the output of the IFC analysis, the BEC and the dielectric tensor. supercell_matrix: the supercell matrix used for phonopy. Any choice is acceptable, however the best agreement between the abinit and phonopy results is obtained if this is set to a diagonal matrix with on the diagonal the ngqpt used to generate the anaddb.nc. symmetrize_tensors: if True the tensors will be symmetrized in the Phonopy object and in the output files. This will apply to IFC, BEC and dielectric tensor. output_dir_path: a path to a directory where the phonopy files will be created prefix_outfiles: a string that will be added as a prefix to the name of the written files symprec: distance tolerance in Cartesian coordinates to find crystal symmetry in phonopy. It might be that the value should be tuned so that it leads to the the same symmetries as in the abinit calculation. set_masses: if True the atomic masses used by abinit will be added to the PhonopyAtoms and will be present in the returned Phonopy object. This should improve compatibility among abinit and phonopy results if frequencies needs to be calculated. Returns: An instance of a Phonopy object that contains the IFC, BEC and dieletric tensor data. """ ifc = anaddbnc.ifc nac_params = None becs = None epsinf = None if anaddbnc.becs is not None and anaddbnc.epsinf is not None: becs = anaddbnc.becs.values epsinf = anaddbnc.epsinf # according to the phonopy website 14.399652 is not the coefficient for abinit # probably it relies on the other conventions in the output. nac_params = {"born": becs, "dielectric": epsinf, "factor": 14.399652} s = anaddbnc.structure phon_at = get_phonopy_structure(s) if set_masses: phon_at.masses = [anaddbnc.amu[n] for n in phon_at.numbers] # use phonopy to get the proper supercell given by the primitive and the matrix # and convert it to pymatgen phonon = Phonopy(phon_at, supercell_matrix, primitive_matrix=np.eye(3), nac_params=nac_params, symprec=symprec) phon_supercell = phonon.get_supercell() supercell = get_pmg_structure(phon_supercell) abi_hall_num = s.abi_spacegroup.get_spglib_hall_number() spglib_hall_num = phonon.symmetry.dataset["hall_number"] if abi_hall_num != spglib_hall_num: warnings.warn( "The hall number obtained based on the DDB symmetries differs " f"from the one calculated with spglib: {abi_hall_num} versus " f"{spglib_hall_num}. The conversion may be incorrect. Try changing symprec." ) # convert to phonopy units at_cart = ifc.atoms_cart_coord * abu.Bohr_Ang ifccc = ifc.ifc_cart_coord * abu.Ha_eV / abu.Bohr_Ang**2 weights = ifc.ifc_weights latt = supercell.lattice ifcph = np.zeros((len(s), len(supercell), 3, 3)) # loop over the atoms in the primitive cell # other operations are vectorized using numpy arrays. Some array may require large allocations for i, (site, c_list, w_list) in enumerate(zip(s, at_cart, weights)): ind_w = np.where(w_list > 0) ifccc_loc = ifccc[i, ind_w[0]] w_list = w_list[ind_w] c_list = c_list[ind_w] # align the coordinates of the first atom in the list (the site under consideration) # with the site in the primitive cell. c_list = c_list - c_list[0] + site.coords # convert to fractional coordinates as needed by the Lattice to get the distances f_list = latt.get_fractional_coords(c_list) sc_fcoords = supercell.frac_coords # construct the list of sites of the supercell that are closer to sites in # the primitive cell dist_and_img = [ latt.get_distance_and_image(f_list[0], fc) for fc in sc_fcoords ] # the function gives the translation of the image, but it should be applied to the coordinates. # Only the positions are needed nearest_sc_fcoords = [ fc + trasl for (_, trasl), fc in zip(dist_and_img, sc_fcoords) ] # divide by the corresponding weights. Elements with weights 0 were discarded above ifccc_loc = np.transpose(ifccc_loc, (0, 2, 1)) / w_list[:, None, None] # create an array with all the possible pairs # instantiating this array seems slow but seems still faster than the required loops coord_pairs = np.array( list(itertools.product(nearest_sc_fcoords, f_list))) # find the pairs that match between the coordinates of the modified supercell and the f_list ind_match = np.where( np.abs(coord_pairs[:, 0] - coord_pairs[:, 1]).sum(axis=1) < 1e-6)[0] # set the ifc for phonopy in the final array corresponding to the matching indices. n_points_f_list = len(f_list) ifcph[i, ind_match // n_points_f_list] = ifccc_loc[ind_match % n_points_f_list] phonon.set_force_constants(ifcph) if symmetrize_tensors: phonon.symmetrize_force_constants() if output_dir_path: makedirs_p(output_dir_path) fc_filepath = os.path.join(output_dir_path, prefix_outfiles + "FORCE_CONSTANTS") write_FORCE_CONSTANTS(phonon.get_force_constants(), fc_filepath) if becs is not None and epsinf is not None: born_filepath = os.path.join(output_dir_path, prefix_outfiles + "BORN") write_BORN(phon_at, borns=becs, epsilon=epsinf, filename=born_filepath, symmetrize_tensors=symmetrize_tensors) poscar_filepath = os.path.join(output_dir_path, prefix_outfiles + "POSCAR") poscar = Poscar(s) poscar.write_file(poscar_filepath, significant_figures=15) supercell_filepath = os.path.join(output_dir_path, prefix_outfiles + "supercell_POSCAR") superce_poscar = Poscar(supercell) superce_poscar.write_file(supercell_filepath, significant_figures=15) return phonon
if settings.get_is_force_constants() == 'read': phonon.set_force_constants(fc) # Impose cutoff radius on force constants cutoff_radius = settings.get_cutoff_radius() if cutoff_radius: phonon.set_force_constants_zero_with_radius(cutoff_radius) # Enforce space group symmetry to force constants if settings.get_fc_spg_symmetry(): if log_level > 0: print('') print("Force constants are symmetrized by space group operations.") print("This may take some time...") phonon.symmetrize_force_constants_by_space_group() file_IO.write_FORCE_CONSTANTS(phonon.get_force_constants(), filename='FORCE_CONSTANTS_SPG') if log_level > 0: print( "Symmetrized force constants are written into " "FORCE_CONSTANTS_SPG.") # Imporse translational invariance and index permulation symmetry to # force constants if settings.get_fc_symmetry_iteration() > 0: phonon.symmetrize_force_constants(settings.get_fc_symmetry_iteration()) # Write FORCE_CONSTANTS if settings.get_is_force_constants() == "write": if settings.get_is_hdf5(): file_IO.write_force_constants_to_hdf5(phonon.get_force_constants())
def get_phonon_distrib_alist( prim_cell, NNN, T, seed_range, calc, cp_files=None, plus_minus=True, delta=0.01, ): """ prim_cell (str) ASE readable primitive unitcell structure file. NNN (list of int, shape: (3,3)) Supercell matrix used to calculate force constants. T (float) Temperature in Kelvin unit. seed_range (range or list of int) Seeds for random number generation. calc (str, choices: ('lmp', 'vasp')) Calculator for force calculation. cp_files (list of str) List of input files for force calculation. plus_minus (bool) Option handed to ASE function. delta (float) Displacement in Angstrom for finite displacement method. """ # Main from ase.io import read, write atoms = read(prim_cell) from phonopy import Phonopy phonon = Phonopy( atoms, NNN, ) phonon.generate_displacements( delta, ) pho_super = phonon.get_supercell() pho_disp = phonon.get_supercells_with_displacements() from phonopy.interface import vasp vasp.write_supercells_with_displacements( pho_super, pho_disp, ) import ss_phonopy as ssp phonon = ssp.calc_phonon( calc, phonon, cp_files=cp_files, ) masses = pho_super.masses job_name = 'eig_x{}{}{}_d{:5.3f}_sym{}'.format(NNN[0][0], NNN[1][1], NNN[2][2], delta, phonon._is_symmetry) try: e_s = np.load('{}.npz'.format(job_name)) except: print('Failed to load {}.npz file. Start to solve eigen problem.'.format(job_name)) eigen_set = get_eigen_set( phonon.get_force_constants(), masses, ) np.savez('{}.npz'.format(job_name), w2=eigen_set[0], D=eigen_set[1]) else: print('Successfully loaded {}.npz file!'.format(job_name)) eigen_set = (e_s['w2'], e_s['D']) from ase.md.velocitydistribution import phonon_harmonics from ase import Atoms, units alist = [] for i in seed_range: d_ac, v_ac = phonon_harmonics( None, masses, T *units.kB, eigen_set=eigen_set, # rng=np.random.rand, seed=i, quantum=True, plus_minus=plus_minus, # return_eigensolution=False, # failfast=True, ) new_super = Atoms( cell = pho_super.get_cell(), symbols = pho_super.get_chemical_symbols(), positions = pho_super.get_positions() + d_ac, velocities = v_ac, pbc = True, ) alist.append(new_super) return(alist)
from phonopy import Phonopy from phonopy.interface.vasp import read_vasp 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]], is_auto_displacements=False) 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 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 }
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 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
force_set = PhonIO.parse_FORCE_SETS() # parse force_sets phonon_scell.set_displacement_dataset( force_set) # force_set is a list of forces and displacements if NAC == True: nac_params = PhonIO.get_born_parameters( open("BORN"), phonon_scell.get_primitive(), phonon_scell.get_primitive_symmetry()) if nac_params['factor'] == None: physical_units = get_default_physical_units(interface_mode) nac_params['factor'] = physical_units['nac_factor'] phonon_scell._nac_params = nac_params phonon_scell.produce_force_constants() phonon_scell.symmetrize_force_constants() api_ph.write_ShengBTE_FC2(phonon_scell.get_force_constants(), filename='FORCE_CONSTANTS_2ND') # phonopy 2.7 changed format, ShengBTE won't read, use the file in api_qpv to write. # calc and plot bandstructure bands = api_ph.qpoints_Band_paths(Qpoints, Band_points) phonon_scell.set_band_structure(bands, is_eigenvectors=True, labels=band_labels) phonon_scell.write_yaml_band_structure() bs_plt = phonon_scell.plot_band_structure() bs_plt.xlabel("") bs_plt.ylabel("Frequency (THz)", fontsize=16) bs_plt.xticks(fontsize=16) bs_plt.yticks(fontsize=16) bs_plt.savefig("Bands_quip.png", dpi=300, bbox_inches='tight')
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")