def write_supercells_with_displacements(interface_mode, supercell, cells_with_disps, optional_structure_info, displacement_ids=None, zfill_width=3, additional_info=None): """Utility method to write out supercell structures with displacements interface_mode : str Calculator interface such as 'vasp', 'qe', ... supercell : Supercell Supercell. cells_with_disps : list of PhonopyAtoms Supercells with displacements. optional_structure_info : tuple Information returned by the method ``read_crystal_structure``. See the docstring. displacements_ids : array_like or None, optional Integer 1d array with the length of cells_with_disps, containing numbers to be assigned to the supercells with displacements. Default is None, which gives [1, 2, 3, ...]. zfill_width : int, optional Supercell numbers are filled by zeros from the left with the digits as given, which results in 001, 002, ..., when zfill_width=3. additional_info : dict or None, optional Any information expected to be given to writers of calculators. Default is None. """ if displacement_ids is None: ids = np.arange(len(cells_with_disps), dtype=int) + 1 else: ids = displacement_ids args = (supercell, cells_with_disps, ids) kwargs = {'width': zfill_width} if 'pre_filename' in additional_info: kwargs['pre_filename'] = additional_info['pre_filename'] if interface_mode is None or interface_mode == 'vasp': import phonopy.interface.vasp as vasp vasp.write_supercells_with_displacements(*args, **kwargs) write_magnetic_moments(supercell, sort_by_elements=True) elif interface_mode == 'abinit': import phonopy.interface.abinit as abinit abinit.write_supercells_with_displacements(*args, **kwargs) elif interface_mode == 'qe': import phonopy.interface.qe as qe pp_filenames = optional_structure_info[1] qe_args = args + (pp_filenames, ) qe.write_supercells_with_displacements(*qe_args, **kwargs) write_magnetic_moments(supercell, sort_by_elements=False) elif interface_mode == 'wien2k': import phonopy.interface.wien2k as wien2k unitcell_filename, npts, r0s, rmts = optional_structure_info N = abs(determinant(additional_info['supercell_matrix'])) w2k_args = args + (npts, r0s, rmts, N) if 'pre_filename' not in kwargs: kwargs['pre_filename'] = unitcell_filename wien2k.write_supercells_with_displacements(*w2k_args, **kwargs) elif interface_mode == 'elk': import phonopy.interface.elk as elk sp_filenames = optional_structure_info[1] elk_args = args + (sp_filenames, ) elk.write_supercells_with_displacements(*elk_args, **kwargs) elif interface_mode == 'siesta': import phonopy.interface.siesta as siesta atypes = optional_structure_info[1] sst_args = args + (atypes, ) siesta.write_supercells_with_displacements(*sst_args, **kwargs) elif interface_mode == 'cp2k': import phonopy.interface.cp2k as cp2k cp2k_args = args + (optional_structure_info, ) cp2k.write_supercells_with_displacements(*cp2k_args, **kwargs) elif interface_mode == 'crystal': import phonopy.interface.crystal as crystal if additional_info is None: kwargs['template_file'] = "TEMPLATE" else: kwargs['template_file'] = additional_info.get( 'template_file', "TEMPLATE") conv_numbers = optional_structure_info[1] N = abs(determinant(additional_info['supercell_matrix'])) cst_args = args + (conv_numbers, N) crystal.write_supercells_with_displacements(*cst_args, **kwargs) elif interface_mode == 'dftbp': import phonopy.interface.dftbp as dftbp dftbp.write_supercells_with_displacements(*args, **kwargs) elif interface_mode == 'turbomole': import phonopy.interface.turbomole as turbomole turbomole.write_supercells_with_displacements(*args, **kwargs) elif interface_mode == 'aims': import phonopy.interface.aims as aims aims.write_supercells_with_displacements(*args, **kwargs) else: raise RuntimeError("No calculator interface was found.")
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 get_phonon_tb( # phonopy_atoms=[], atoms=[], fc=[], out_file="phonopyTB_hr.dat", distance_to_A=1.0, scell=np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), factor=VaspToTHz, symprec=1e-05, displacement_distance=0.01, ): """Generate phonon TB Hamiltonia, along with WannierHamn.""" # Forked from Wannier-tools unitcell = atoms.phonopy_converter() # unitcell = phonopy_atoms prim_mat = np.array(PhonopyInputs(atoms).prim_axis().split("=")[1].split(), dtype="float").reshape(3, 3) # print("cell", unitcell.cell) num_atom = unitcell.get_number_of_atoms() num_satom = determinant(scell) * num_atom if fc.shape[0] != num_satom: print("Check Force constant matrix.") phonon = Phonopy( unitcell, scell, primitive_matrix=prim_mat, factor=factor, dynamical_matrix_decimals=None, force_constants_decimals=None, symprec=symprec, is_symmetry=True, use_lapack_solver=False, log_level=1, ) supercell = phonon.get_supercell() primitive = phonon.get_primitive() # Set force constants phonon.set_force_constants(fc) phonon._set_dynamical_matrix() dmat = phonon._dynamical_matrix # rescale fcmat by THZ**2 fcmat = dmat._force_constants * factor**2 # FORCE_CONSTANTS # fcmat = dmat._force_constants * factor ** 2 # FORCE_CONSTANTS smallest_vectors = dmat._smallest_vectors # mass = dmat._mass mass = dmat._pcell.get_masses() print("mass=", mass) multi = dmat._multiplicity reduced_bases = get_reduced_bases(supercell.get_cell(), symprec) positions = np.dot(supercell.get_positions(), np.linalg.inv(reduced_bases)) # for pos in positions: pos -= np.rint(pos) relative_scale = np.dot(reduced_bases, np.linalg.inv(primitive.get_cell())) super_pos = np.zeros((num_satom, 3), dtype=np.float64) for i in range(num_satom): super_pos[i] = np.dot(positions[i], relative_scale) p2s_map = dmat._p2s_map = primitive.get_primitive_to_supercell_map() s2p_map = dmat._s2p_map = primitive.get_supercell_to_primitive_map() num_satom = supercell.get_number_of_atoms() num_patom = primitive.get_number_of_atoms() get_phonon_hr( fcmat, smallest_vectors, mass, multi, super_pos, p2s_map, s2p_map, num_satom, num_patom, out_file, ) print("phonopy_TB.dat generated! ")
def get_reciprocal_operations(rotations, transformation_matrix, D, Q, is_time_reversal=True): """Generate reciprocal rotation matrices. Collect unique real space rotation matrices and transpose them. When is_time_reversal=True, inversion is added if it is not in the list of the rotation matrices. Parameters ---------- rotations : ndarray Rotation matrices in real space. x' = Rx. shape=(rotations, 3, 3), dtype='int_' transformation_matrxi : array_like Transformation matrix of basis vectors in real space. Using this rotation matrices are transformed. D : array_like D of smith normal form 3x3. shape=(3, 3) Q : array_like Q of smith normal form 3x3. shape=(3, 3) is_time_reversal : bool When True, inversion operation is added. Returns ------- rotations_for_Q : ndarray Rotation matrices in reciprocal space. Grid points are sent by the symmetrically equivalent grid points as follows: g' = (R_Q g) % diagonal(D) shape=(rotations, 3, 3), dtype='int_', order='C' """ unique_rots = [] tmat_inv = np.linalg.inv(transformation_matrix) for r in collect_unique_rotations(rotations): _r = similarity_transformation(tmat_inv, r) _r_int = np.rint(_r).astype(int) assert (np.abs(_r - _r_int) < 1e-5).all() unique_rots.append(_r_int) ptg_ops, rec_ops = get_pointgroup_operations( unique_rots, is_time_reversal=is_time_reversal) Q_inv = np.linalg.inv(Q) rec_ops_Q = [] for r in rec_ops: _r = similarity_transformation(Q_inv, r) _r = similarity_transformation(D, _r) _r_int = np.rint(_r).astype(int) assert (np.abs(_r - _r_int) < 1e-5).all() assert abs(determinant(_r_int)) == 1 rec_ops_Q.append(_r_int) return np.array(rec_ops_Q, dtype="int_", order="C")
def create_phono3py_supercells(unitcell, supercell_matrix, phonon_supercell_matrix, displacement_distance, is_plusminus, is_diagonal, cutoff_pair_distance, write_supercells_with_displacements, optional_structure_file_information, is_symmetry, symprec, interface_mode='vasp', output_filename=None, log_level=1): if displacement_distance is None: if interface_mode in ('qe', 'abinit', 'turbomole'): distance = 0.06 elif interface_mode == 'crystal': distance = 0.03 else: distance = 0.03 else: distance = displacement_distance phono3py = Phono3py(unitcell, supercell_matrix, phonon_supercell_matrix=phonon_supercell_matrix, is_symmetry=is_symmetry, symprec=symprec) supercell = phono3py.get_supercell() phono3py.generate_displacements(distance=distance, cutoff_pair_distance=cutoff_pair_distance, is_plusminus=is_plusminus, is_diagonal=is_diagonal) dds = phono3py.get_displacement_dataset() if log_level: print('') print("Displacement distance: %s" % distance) if output_filename is None: filename = 'disp_fc3.yaml' else: filename = 'disp_fc3.' + output_filename + '.yaml' num_disps, num_disp_files = write_disp_fc3_yaml(dds, supercell, filename=filename) cells_with_disps = phono3py.get_supercells_with_displacements() if interface_mode == 'qe': pp_filenames = optional_structure_file_information[1] write_supercells_with_displacements(supercell, cells_with_disps, pp_filenames, width=5) elif interface_mode == 'crystal': conv_numbers = optional_structure_file_information[1] # N_FC3 = num_unitcells_in_supercell (here for FC3 supercell) N_FC3 = abs(determinant(supercell_matrix)) write_supercells_with_displacements(supercell, cells_with_disps, conv_numbers, N_FC3, width=5, template_file="TEMPLATE3") elif interface_mode == 'abinit': write_supercells_with_displacements(supercell, cells_with_disps, width=5) elif interface_mode == 'turbomole': write_supercells_with_displacements(supercell, cells_with_disps, width=5) else: # VASP write_supercells_with_displacements(supercell, cells_with_disps, width=5) if log_level: print("Number of displacements: %d" % num_disps) if cutoff_pair_distance is not None: print("Cutoff distance for displacements: %s" % cutoff_pair_distance) print("Number of displacement supercell files created: %d" % num_disp_files) if phonon_supercell_matrix is not None: phonon_dds = phono3py.get_phonon_displacement_dataset() phonon_supercell = phono3py.get_phonon_supercell() if output_filename is None: filename = 'disp_fc2.yaml' else: filename = 'disp_fc2.' + output_filename + '.yaml' num_disps = write_disp_fc2_yaml(phonon_dds, phonon_supercell, filename=filename) cells_with_disps = phono3py.get_phonon_supercells_with_displacements() if interface_mode == 'qe': pp_filenames = optional_structure_file_information[1] write_supercells_with_displacements(phonon_supercell, cells_with_disps, pp_filenames, pre_filename="supercell_fc2", width=5) elif interface_mode == 'crystal': conv_numbers = optional_structure_file_information[1] # N = num_unitcells_in_supercell (here for FC2 supercell) N_FC2 = abs(determinant(phonon_supercell_matrix)) write_supercells_with_displacements(phonon_supercell, cells_with_disps, conv_numbers, N_FC2, pre_filename="supercell_fc2", width=5, template_file="TEMPLATE") elif interface_mode == 'abinit': write_supercells_with_displacements(phonon_supercell, cells_with_disps, pre_filename="supercell_fc2", width=5) elif interface_mode == 'turbomole': write_supercells_with_displacements(phonon_supercell, cells_with_disps, pre_filename="supercell_fc2", width=5) else: write_supercells_with_displacements(phonon_supercell, cells_with_disps, pre_filename="POSCAR_FC2", width=5) if log_level: print("Number of displacements for special fc2: %d" % num_disps) return phono3py
or interface_mode == 'elk' or interface_mode == 'pwscf' or interface_mode == 'siesta'): displacement_distance = 0.02 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"