def read_outcar(outcar_file): if os.path.exists(outcar_file): f = Outcar(outcar_file) # with Outcar(outcar_file) as f: # print(f) forces = f.read_table_pattern( header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+", row_pattern= r"\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)", footer_pattern=r"\s--+", postprocess=lambda x: float(x), last_one_only=False) return (forces) else: print( "No OUTCAR file reads in, at least make sure you have '{}' by default" .format(outcar_file), file=sys.stderr)
def forces_from_outcar(filename='OUTCAR'): """Finds and returns forces from the OUTCAR file. Args: filename (:obj:'str', optional): the name of the ``OUTCAR`` file to be read. Default is `OUTCAR`. Returns: (np.array): The force as found in the ``OUTCAR`` file, as a NSTEPS x NIONS x 3 numpy array. """ outcar = Outcar(filename) forces = outcar.read_table_pattern( header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+", row_pattern= r"\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)", footer_pattern=r"\s--+", postprocess=lambda x: float(x), last_one_only=False) return np.array(forces)
def forces_from_outcar( filename='OUTCAR' ): """Finds and returns forces from the OUTCAR file. Args: filename (:obj:'str', optional): the name of the ``OUTCAR`` file to be read. Default is `OUTCAR`. Returns: (np.array): The force as found in the ``OUTCAR`` file, as a NSTEPS x NIONS x 3 numpy array. """ outcar = Outcar("OUTCAR") forces = outcar.read_table_pattern( header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+", row_pattern=r"\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)", footer_pattern=r"\s--+", postprocess=lambda x: float(x), last_one_only=False ) return np.array( forces )
def stresses_from_outcar(filename='OUTCAR'): """ Finds and returns stress tensors from the OUTCAR file. Args: filename (:obj:'str', optional): the name of the ``OUTCAR`` file to be read. Default is `OUTCAR`. Returns: (np.array): The stresses as found in the ``OUTCAR`` file in kBar, as a 1D numpy array. """ outcar = Outcar(filename) stresses = outcar.read_table_pattern( header_pattern= r"\s+Fock(\s+[+-]?\d+\.\d+)*\n\s+-+\n\s+Total(\s+[+-]?\d+\.\d+)*", row_pattern= r"\s+\D+\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)", footer_pattern=r"\s+external.+", postprocess=lambda x: float(x), last_one_only=False) return np.array(stresses).flatten()
def load_from_outcar(self, path, structure, mode): """ This function reads atom positions, unit cell, forces and stress tensor from the VASP OUTCAR file path: structure: """ if mode == 'scf': filename = os.path.join(path, 'OUTCAR') self.name = filename.split('/')[-2] elif mode == 'nscf': filename = os.path.join(path, 'nscf_SOC/OUTCAR') self.name = filename.split('/')[-3] else: raise Exception( f"Calculation mode {mode} is wrong. Must be scf or nscf") if os.access(filename, os.R_OK): outcar = Outcar(filename) else: raise Exception("Missing OUTCAR file in {}".format(filename)) print(self.name) # ATOMIC PROPERTIES self.num_atoms = int( structure.composition.num_atoms) # total number of atoms self.atoms_frac = structure.frac_coords # fraction coordinates self.atoms_cart = structure.cart_coords # cartesian coordinates self.num_per_type = [ int(x) for x in structure.composition.get_el_amt_dict().values() ] # number of atoms per type self.species = [x.symbol for x in structure.species ] # list with atomic symbols for each specie self.pomass = [ Element(x.symbol).atomic_mass for x in structure.species ] # list with atomic masses for each specie self.charges = [x['tot'] for x in outcar.charge] # list with charges # read zval dict and create a mapping outcar.read_pseudo_zval() zval_dict = outcar.zval_dict self.zvals = [zval_dict[x.symbol] for x in structure.species] # UNIT CELL self.unit_cell = structure.lattice.matrix # unit cell self.recip_cell = structure.lattice.inv_matrix # inverse unit cell self.volume = structure.lattice.volume # total energy in eV self.energy = outcar.final_energy # atomic positions read from Outcar self.atoms = np.array( outcar.read_table_pattern( header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+", row_pattern= r"\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+", footer_pattern=r"\s--+", postprocess=lambda x: float(x), last_one_only=False)[0]) # forces acting on atoms from Outcar self.forces = np.array( outcar.read_table_pattern( header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+", row_pattern= r"\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)", footer_pattern=r"\s--+", postprocess=lambda x: float(x), last_one_only=False)[0]) # READ STRESS: (XX, YY, ZZ, XY, YZ, ZX) and convert values to array outcar.read_pattern( { 'stress': r"in kB\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)" }, terminate_on_match=False, postprocess=float) stress = outcar.data.get("stress")[0] self.stress = np.array([[stress[0], stress[3], stress[5]], [stress[3], stress[1], stress[4]], [stress[5], stress[4], stress[2]]]) # Conversion from kbar to ev/A^3. self.stress *= KBAR_TO_EVA3 # MAGNETIZATION and its PROJECTION ON EVERY ATOM try: # non-collinear outcar.read_pattern( { 'total_mag': r"number of electron\s+\S+\s+magnetization\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s" }, terminate_on_match=False, postprocess=float) self.__magnetization = outcar.data.get("total_mag")[-1] self.proj_magn = np.array([ mag['tot'].moment for mag in outcar.magnetization ]) # 2-D array except: # collinear outcar.read_pattern( { 'total_mag': r"number of electron\s+\S+\s+magnetization\s+(" r"\S+)" }, terminate_on_match=False, postprocess=float) self.__magnetization = np.zeros(3) self.__magnetization[2] = outcar.data.get("total_mag")[-1][0] self.proj_magn = np.zeros((self.num_atoms, 3)) for i in range(self.num_atoms): self.proj_magn[i, 2] = outcar.magnetization[i]['tot'] # 2-D array # NOTE: sum of magnetization projected on atoms differs from the total magnetization self.proj_magn_sum = np.sum(self.proj_magn, axis=0) self.get__magnetization() # POLARIZATION self.load_polarization(path) self.fileID = filename