def gen_perturbations(casfile, supercell='Gamma'): """ Genterate input .cell files for CASTEP singlepoint energy simulations as part of a phonopy phonon calculation of a solid solution. str casfile : filename (incl. path) to .castep file to compute phonons of np.array(3, 3) supercell : size of real space supercell dictates k-points If supercell is 'Gamma', only unit cell displacements are created """ # Load the mixed data chem = casfile.replace('.castep', '') cas = rc.readcas(casfile) mixatoms = cas.extract_struc() spins = cas.get_final_spin() press = cas.get_ext_press() # Create pure cell mixkey = cas.get_mixkey() mapping = mixmap.mixmap(mixatoms, mixkey) pureatoms = mapping.mix2pure(mixatoms) mapping.setcellparams(spins=spins, pressure=press) # Generate perturbed cells (displacements) of pure cell if supercell == 'Gamma': # Gamma-point means only single unit cell supercell = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) GammaPhonon = phonopy.Phonopy(pureatoms, supercell, symprec=1e-4, factor=phonopy.units.VaspToCm) GammaPhonon.generate_displacements(distance=0.05) displcells = GammaPhonon.get_supercells_with_displacements() # Convert displaced pure cells to mixtures and write files for d, displcell in enumerate(displcells): mixdispl = mapping.pure2mix(displcells[d]) cellfile = chem + '_' + str(d) + '.cell' mapping.casprint(mixdispl, cellfile)
def castep_structure(filename, extension): #Get structure attributes if pure: atoms = casread(filename) nAtoms = atoms.get_global_number_of_atoms() elems = ' '.join(atoms.get_chemical_symbols()) cell = atoms.get_cell() posns = atoms.get_scaled_positions() else: extension = filename.split(".")[-1] assert extension in ["cell", "castep"], "Mixtures are only supported\ if they are .cell or .castep files." if extension == "cell": atoms = rc.readcell(filename) elif extension == "castep": atoms = rc.readcas(filename) else: ValueError("Could not read the file since it was a mixture and not\ a .cell or .castep file.") nAtoms = atoms.Nions elems = ' '.join(atoms.get_elements()) cell = atoms.get_cell() posns = atoms.get_posns() if verbose: print("Number of atoms:", nAtoms) print("Lattice vectors: ", cell) print("Fractional positions: ", posns) latvecs = [' '.join([str(c) for c in cell[i, :]])+'\r\n' for i in \ range(3)] return nAtoms, elems, cell, posns, latvecs
def main(pure=True): #Parse .castep filename casfile = parse_seed() casseed = casfile.replace(".castep", "") #Read .castep file cas = rc.readcas(casfile) print("Task: ", cas.get_task()) kpoints, offset = cas.get_kpoints() constrs = cas.get_cell_constrs() print("k-points: ", kpoints) print("offset: ", offset) print("Constraints: ", cas.get_cell_constrs()) print("---------------------------------------") print("Energy: ", cas.get_energy(), " eV") print("---------------------------------------") print("Now creating the .cell file (mixed)") mixatoms = cas.extract_struc() mixkey = cas.get_mixkey() mapping = mixmap.mixmap(mixatoms, mixkey) mapping.setcellparams(kpoints=kpoints, kpoints_offset=offset, cell_constrs=constrs) if pure: pureatoms = mapping.mix2pure(mixatoms) mapping.casprint(pureatoms, casseed + "_tutopure.cell", pure=pure) else: mapping.casprint()
def writeCIF(): casfile = parse_seed() cifFile = casfile.replace(".castep", "_pure.cif") cas = rc.readcas(casfile) mixatoms = cas.extract_struc() mixkey = cas.get_mixkey() mapping = mixmap.mixmap(mixatoms, mixkey) pureatoms = mapping.mix2pure(mixatoms) write(cifFile, pureatoms) return pureatoms
def mix(purelems): casfiles = glob("*.castep") for cfile in casfiles: print(cfile) cellname = cfile.replace(".castep", ".cell") if not glob(cellname): cas = rc.readcas(cfile) kpoints, offset = cas.get_kpoints() constrs = cas.get_cell_constrs() psps = cas.get_psps() mixatoms = cas.extract_struc() mixkey = cas.get_mixkey(pureelems=pureelems) #Map mapping = mixmap.mixmap(mixatoms, mixkey) mapping.casprint(mixatoms, cellname, pure=False)
def mainpure(): casfiles = glob("*.castep") for cfile in casfiles: print(cfile) cellname = cfile.replace(".castep", ".cell") if not glob(cellname): cas = rc.readcas(cfile) kpoints, offset = cas.get_kpoints() constrs = cas.get_cell_constrs() psps = cas.get_psps() pureatoms = cas.extract_struc() mixkey = cas.get_mixkey() mapping = mixmap.mixmap(pureatoms, mixkey) mapping.setcellparams(pseudos=psps, kpoints=kpoints,\ kpoints_offset=offset, cell_constrs=constrs) mapping.casprint(pureatoms, cellname, pure=True) elif not glob(cellname.replace(".cell", ".cif")): cell2cif(cellname) return None
pinchatoms.set_positions(pinchposnew) return pinchatoms ########################################################################## if __name__ == '__main__': """ Run from the command line, pinch the second cell to match the first """ cellfile0 = sys.argv[1] cellfile1 = sys.argv[2] # Load the fixed cell (incl generating pure structure) if '.cell' in cellfile0: mix0 = rc.readcell(cellfile0) elif '.castep' in cellfile0: mix0 = rc.readcas(cellfile0) mixatoms0 = mix0.extract_struc() mixkey0 = mix0.get_mixkey() mapping0 = mixmap.mixmap(mixatoms0, mixkey0) pureatoms0 = mapping0.mix2pure(mixatoms0) posns0 = pureatoms0.get_positions() Nions = len(pureatoms0) # Load the cell to be pinched (incl generating pure structure) mix1 = rc.readcell(cellfile1) mixatoms1 = mix1.extract_struc() mixkey1 = mix1.get_mixkey() mapping1 = mixmap.mixmap(mixatoms1, mixkey1) pureatoms1 = mapping1.mix2pure(mixatoms1) posns1 = pureatoms1.get_positions() cell1 = pureatoms1.get_cell()
print(cas.get_init_spin()) print(cas.get_mixkey()) print(cas.get_posns()) print(cas.get_ext_press()) print(cas.get_cell_constrs()) print(cas.get_cell()) mixkey = cas.get_mixkey() ######################################################## # Read mix castep print('\n\n\nMix Castep\n\n\n') cas = rc.readcas('examples/Ca2.15Sr0.85Ti2O7_Amam.castep') print(cas.get_kpoints()) print(cas.get_psps()) print(cas.get_elements()) print(cas.get_init_spin()) print(cas.get_mixkey()) print(cas.get_posns()) print(cas.get_ext_press()) print(cas.get_cell_constrs()) print(cas.get_cell()) print(cas.get_enthalpy()) print(cas.get_energy()) print(cas.get_forces()) print(cas.get_stresses()) print(cas.get_Fmax())
def calc_phonons(casfile, supercell='Gamma', method=2, postol=0.001, bands=None, verbose=False): """ Compute phonons from completed singlepoint CASTEP calculations of perturbations about a relaxed cell. Note that this function assumes that the perturbed files are in the same directory and use the same naming convention as the parent. str casfile : filename (incl. path) to .castep file to compute phonons of np.array(3, 3) supercell : size of real space supercell dictates k-points If supercell is 'Gamma', only unit cell displacements are created. int method : can be 1 (regenerate displacements and assume the same) or 2 (process all castep files that follow displacement naming convention) float postol : Tolerance (Ang) when ion considered displaced (2 only) np.array() bands : k-points to compute frequencies at bool verbose : function can take a while to run -> prints checkpoints. returns tuple (q_points, distances, frequencies, eigvecs) : output of phonopy_instance.get_band_structure() command. These are all lists of lists of np.arrays, where the relavent entry of frequencies is a list of freqs (in cm-1) of the form np.array(3*phonions) and the relevant entry of eigvecs is a matrix of phonon eigenvectors of the form np.array(3*phonions, 3*phonions). """ # Set up the PHONOPY object for the relaxed cell chem = casfile.replace('.castep', '') cas = rc.readcas(casfile) print("\nreading " + casfile + "\n") mixatoms = cas.extract_struc() mixkey = cas.get_mixkey() mapping = mixmap.mixmap(mixatoms, mixkey) pureatoms = mapping.mix2pure(mixatoms) pureions = pureatoms.get_number_of_atoms() if supercell == 'Gamma': # Gamma-point means only single unit cell supercell = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) bands = [np.array([0.0])] PhononObj = phonopy.Phonopy(pureatoms, supercell, factor=phonopy.units.VaspToCm) if method == 1: """ Generate more displs and ASSUME that they are the same as before. Less stable than method 2 and should only be used as a check. """ # Generate perturbed pure cells PhononObj.generate_displacements(distance=0.05) displcells = PhononObj.get_supercells_with_displacements() Ndispls = len(displcells) sets_of_forces = np.zeros((Ndispls, pureions, 3)) for d in range(Ndispls): displcasfile = chem + '_' + str(d) + '.castep' if verbose: print("reading " + displcasfile) displmix = rc.readcas(displcasfile) displmixforces = displmix.get_forces() displpureforces = mapping.mix2pure_forces(displmixforces) sets_of_forces[d] = displpureforces PhononObj.set_forces(sets_of_forces) elif method == 2: """ Load all the displaced structures and create a displacement_dataset object to load to the PHONOPY instance. """ # Detect displacement files allcasfiles = glob.glob(chem + '_*.castep') displcasfiles = [] for casfile in allcasfiles: n = casfile.replace(chem + '_', '').replace('.castep', '') try: int(n) displcasfiles.append(casfile) except ValueError: pass # file doesn't follow displacement naming convention Ndispls = len(displcasfiles) first_atoms_list = [] pureposns = pureatoms.get_positions() for d in range(Ndispls): # Load displacement files and compute displ relative to parent displcasfile = chem + '_' + str(d) + '.castep' if verbose: print("reading " + displcasfile) displmix = rc.readcas(displcasfile) displmixatoms = displmix.extract_struc() displpureatoms = mapping.mix2pure(displmixatoms) displpureatoms = pinpos.reorder_atoms(pureatoms, displpureatoms) puretotaldispl = displpureatoms.get_positions() - pureposns # Check that exactly one ion is displaced per perturbed cell displions = [] for i in range(pureions): displmagnitude = np.linalg.norm(puretotaldispl[i, :]) if displmagnitude > postol: displions.append(i) if len(displions) > 1: raise IndexError('The following ions were all displaced by ' + 'more than ' + str(postol) + ': ' + ' '.join([str(i) for i in displions])) elif not displions: raise IndexError('No ions were found to be displaced by ' + 'more than ' + str(postol)) displion = displions[0] # Extract (pure) forces and construct first_atoms_list # this list is later fed to construct displacement_dataset displmixforces = displmix.get_forces() displpureforces = mapping.mix2pure_forces(displmixforces) first_atoms_dict = {} first_atoms_dict['number'] = displion first_atoms_dict['displacement'] = puretotaldispl[displion, :] first_atoms_dict['forces'] = displpureforces first_atoms_list += [first_atoms_dict] # Now construct displacement_dataset (for all perturbations) displacement_dataset = {} displacement_dataset['natom'] = pureions displacement_dataset['first_atoms'] = first_atoms_list PhononObj.set_displacement_dataset(displacement_dataset) # End of Method 2 # Forces & displacements are now set so may compute the force constants if verbose: print("\nConstructing force constant matrix") PhononObj.produce_force_constants() phonopy.harmonic.force_constants.set_translational_invariance( PhononObj.force_constants) FCs = PhononObj.force_constants (FC1, FC2, FC3, FC4) = FCs.shape PhononObj.set_force_constants(FCs) # Force constants at this point ALREADY obey the ASR near perfectly # (i.e. columns/rows sum to zero) # Compute frequencies from dynamical matrix if verbose: print("\nDiagonalising dynamical matrix") PhononObj.set_band_structure(bands, is_eigenvectors=True) return PhononObj.get_band_structure()
#!/usr/bin/env python3 import mixmap import readmixcastep as rc import sys """ Command line tool to quickly get a pure cell file from a solid soln. """ # Load the input file (accepts .castep or .cell) casfile = str(sys.argv[1]) if '.castep' in casfile: chem = casfile.replace('.castep', '') cas = rc.readcas(casfile) elif '.cell' in casfile: chem = casfile.replace('.cell', '') cas = rc.readcell(casfile) # Extract calculation parameters and convert from mix to pure structure mixatom = cas.extract_struc(iteration=None) mixkey = cas.get_mixkey(iteration=None) press = cas.get_ext_press() kpoints, offset = cas.get_kpoints() pseudos = cas.get_psps() constraints = cas.get_cell_constrs() mapping = mixmap.mixmap(mixatom, mixkey) pureatom = mapping.mix2pure(mixatom) # Write the pure cell (always with the same handle plus the suffix _nonSS) mapping.setcellparams(pressure=press, cell_constrs=constraints, pseudos=pseudos, kpoints=kpoints,