def get_KPPRA(self): # Open up the OUTCAR with open(os.path.join(self._directory, 'OUTCAR')) as fp: #store the number of atoms and number of irreducible K-points for line in fp: if "NIONS" in line: words = line.split() NI = int(words[11]) elif "NKPTS" in line: words = line.split() NIRK = float(words[3]) #check if the number of k-points was reduced by VASP if so, sum all the k-points weight if "irreducible" in open(os.path.join(self._directory, 'OUTCAR')).read(): fp.seek(0) for line in fp: #sum all the k-points weight if "Coordinates Weight" in line: NK = 0 counter = 0 for line in fp: if counter == NIRK: break NK += float(line.split()[3]) counter += 1 return Value(scalars=(NI * NK)) #if k-points were not reduced KPPRA equals the number of atoms * number of irreducible k-points else: return Value(scalars=(NI * NIRK)) # Error handling: NKPTS or NIONS not found raise Exception('NIONS, irredicuble or Coordinates not found')
def get_vdW_settings(self): '''Determine the vdW type if using vdW xc functional or correction scheme from the input otherwise''' xc = self.get_xc_functional().scalars[0].value if 'vdw' in xc.lower(): # vdW xc functional return Value(scalars=[Scalar(value=xc)]) else: # look for vdw_corr in input vdW_dict = { 'xdm': 'Becke-Johnson XDM', 'ts': 'Tkatchenko-Scheffler', 'ts-vdw': 'Tkatchenko-Scheffler', 'tkatchenko-scheffler': 'Tkatchenko-Scheffler', 'grimme-d2': 'Grimme D2', 'dft-d': 'Grimme D2' } if self._get_line('vdw_corr', self.inputf, return_string=False, case_sens=False): line = self._get_line('vdw_corr', self.inputf, return_string=True, case_sens=False) vdwkey = str( line.split('=')[-1].replace("'", "").replace( ',', '').lower().rstrip()) return Value(scalars=[Scalar(value=vdW_dict[vdwkey])]) return None
def test_convert_setter(): """Test that scalars are made rigid""" foo = Value() val = [1.2, ] foo.scalars = val assert foo.scalars[0].value == 1.2 foo.scalars.append(1.4) foo.normalize() assert foo.scalars[1].value == 1.4
def get_dos(self): file_path = os.path.join(self._directory, 'DOSCAR') if not os.path.isfile(file_path): return None #open DOSCAR with open(os.path.join(self._directory, 'DOSCAR')) as fp: for i in range(6): l = fp.readline() n_step = int(l.split()[2]) energy = [] dos = [] for i in range(n_step): l = fp.readline().split() e = float(l.pop(0)) energy.append(e) dens = 0 for j in range(int(len(l) / 2)): dens += float(l[j]) dos.append(dens) # Convert to property return Property(scalars=dos, units='number of states per unit cell', conditions=Value(name='energy', scalars=energy, units='eV'))
def test_round_robin(): foo = Value(name="foo", units="eV") assert foo.name == "foo", "Value object couldn't store name" assert foo.units == "eV", "Value object couldn't store units" round_robin = pif.loads(pif.dumps(foo), class_=Value) assert round_robin.name == "foo", "Name didn't survive json round robin" assert round_robin.units == "eV", "Units didn't survive json round robin"
def test_basic(): """Test that constructor arguments are saved""" foo = Value(name="foo", units="eV", tags=["tag1", "tag2"]) assert foo.name == "foo" assert foo.units == "eV" assert len(foo.tags) == 2 assert "tag1" in foo.tags assert "tag2" in foo.tags
def get_xc_functional(self): # Open up the OUTCAR with open(os.path.join(self._directory, 'OUTCAR')) as fp: # Look for TITEL for line in fp: if "TITEL" in line: words = line.split() return Value(scalars=words[2]) break
def __init__(self, name=None, scalars=None, vectors=None, matrices=None, files=None, units=None, conditions=None, method=None, data_type=None, references=None, contacts=None, licenses=None, tags=None, **kwargs): """ Constructor. :param name: String with the name of the property. :param scalars: One or more dictionaries, strings, numbers, or :class:`.Scalar` objects. :param vectors: One or more lists of dictionaries, strings, numbers, or :class:`.Scalar` objects, each representing a vector. :param matrices: One of more lists of lists of dictionaries, strings, numbers, or :class:`.Scalar` objects, each representing a matrix with rows as the innermost lists. :param files: One of more dictionaries, strings, or :class:`.FileReference` objects. :param units: String with the units of the property. :param conditions: List of dictionaries or :class:`.Value` objects with the conditions at which the property exists. :param method: Dictionary or :class:`.Method` object describing the method used to get the property value. :param data_type: String containing "EXPERIMENTAL", "COMPUTATIONAL", or "MACHINE_LEARNING" to set the broad category of data. :param references: List of dictionaries or :class:`.Reference` objects where information about the property is published. :param contacts: List of dictionaries, strings, or :class:`.Person` objects with people to contact for information about the property. :param licenses: List of dictionaries, strings, or :class:`.License` objects with licensing information for the property. :param tags: List of strings or numbers that are tags for this object. :param kwargs: Dictionary of fields that are not supported. """ # The order of the constructors is important here. The second constructor could overwrite values set during # the first if there is overlap. Value.__init__(self, name=name, scalars=scalars, vectors=vectors, matrices=matrices, units=units, tags=tags, **kwargs) self.references = references self.contacts = contacts self.licenses = licenses self._files = None self.files = files self._conditions = None self.conditions = conditions self._method = None self.method = method self._data_type = None self.data_type = data_type
def get_cutoff_energy(self): # Open up the OUTCAR with open(os.path.join(self._directory, 'OUTCAR'), 'r') as fp: # Look for ENCUT for line in fp: if "ENCUT" in line: words = line.split() return Value(scalars=float(words[2]), units=words[3]) # Error handling: ENCUT not found raise Exception('ENCUT not found')
def get_pp_name(self): '''Determine the pseudopotential names from the output''' ppnames = [] # Find the number of atom types natomtypes = int(self._get_line('number of atomic types', self.outputf).split()[5]) # Find the pseudopotential names with open(self.outputf) as fp: for line in fp: if "PseudoPot. #" in line: ppnames.append(Scalar(value=next(fp).split('/')[-1].rstrip())) if len(ppnames) == natomtypes: return Value(scalars=ppnames) raise Exception('Could not find %i pseudopotential names'%natomtypes)
def get_pp_name(self): # Open up the OUTCAR with open(os.path.join(self._directory, 'OUTCAR')) as fp: #initialize empty list to store pseudopotentials pp = [] # Look for TITEL for line in fp: if "TITEL" in line: words = line.split() pp.append(words[3]) return Value(scalars=pp) # Error handling: TITEL not found raise Exception('TITEL not found')
def get_xc_functional(self): '''Determine the xc functional from the output''' # the xc functional is described by 1 or 4 strings # SLA PZ NOGX NOGC ( 1 1 0 0 0) # SLA PW PBX PBC (1434) # PBE ( 1 4 3 4 0 0) # PBE0 (6484) # HSE (14*4) xcstring = self._get_line('Exchange-correlation', self.outputf).split()[2:6] for word in range(4): if xcstring[word][0] == '(': xcstring = xcstring[:word] break return Value(scalars=" ".join(xcstring))
def get_KPPRA(self): '''Determine the no. of k-points in the BZ (from the input) times the no. of atoms (from the output)''' # Find the no. of k-points fp = open(os.path.join(self._directory, self.inputf)).readlines() for l, ll in enumerate(fp): if "K_POINTS" in ll: # determine the type of input if len(ll.split()) > 1: if "gamma" in ll.split()[1].lower(): ktype = 'gamma' elif "automatic" in ll.split()[1].lower(): ktype = 'automatic' else: ktype = '' else: ktype = '' if ktype == 'gamma': # gamma point: # K_POINTS {gamma} nk = 1 elif ktype == 'automatic': # automatic: # K_POINTS automatic # 12 12 1 0 0 0 line = [int(i) for i in fp[l + 1].split()[0:3]] nk = line[0] * line[1] * line[2] else: # manual: # K_POINTS # 3 # 0.125 0.125 0.0 1.0 # 0.125 0.375 0.0 2.0 # 0.375 0.375 0.0 1.0 nk = 0 for k in range(int(fp[l + 1].split()[0])): nk += int(float(fp[l + 2 + k].split()[3])) # Find the no. of atoms natoms = int( self._get_line('number of atoms/cell', self.outputf).split()[4]) return Value(scalars=[Scalar(value=nk * natoms)]) fp.close() raise Exception( '%s not found in %s' % ('KPOINTS', os.path.join(self._directory, self.inputf)))
def get_U_settings(self): #Open up the OUTCAR with open(os.path.join(self._directory, 'OUTCAR')) as fp: #Check if U is used if "LDAU" in open(os.path.join(self._directory, 'OUTCAR')).read(): U_param = {} atoms = [] #get the list of pseupotential used for line in fp: if "TITEL" in line: atoms.append(line.split()[3]) #Get the U type used if "LDAUTYPE" in line: U_param['Type'] = int(line.split()[-1]) atoms.reverse() fp.seek(0) #Get the L value U_param['Values'] = {} for line in fp: for atom, i in zip(atoms, range(len(atoms))): if "LDAUL" in line: U_param['Values'][atom] = { 'L': int(line.split()[-1 - i]) } fp.seek(0) #Get the U value for line in fp: for atom, i in zip(atoms, range(len(atoms))): if "LDAUU" in line: U_param['Values'][atom]['U'] = float( line.split()[-1 - i]) fp.seek(0) #Get the J value for line in fp: for atom, i in zip(atoms, range(len(atoms))): if "LDAUJ" in line: U_param['Values'][atom]['J'] = float( line.split()[-1 - i]) return Value(**U_param) #if U is not used, return None else: return None
def get_U_settings(self): '''Determine the DFT+U type and parameters from the output''' with open(self.outputf) as fp: for line in fp: if "LDA+U calculation" in line: U_param = {} U_param['Type'] = line.split()[0] U_param['Values'] = {} # look through next several lines for nl in range(15): line2 = next(fp).split() if len(line2) > 1 and line2[0] == "atomic": pass # column titles elif len(line2) == 6: U_param['Values'][line2[0]] = {} U_param['Values'][line2[0]]['L'] = float(line2[1]) U_param['Values'][line2[0]]['U'] = float(line2[2]) U_param['Values'][line2[0]]['J'] = float(line2[4]) else: break # end of data block return Value(**U_param) return None
def get_vdW_settings(self): #define the name of the vdW methods in function of their keyword vdW_dict = { 'BO': 'optPBE-vdW', 'MK': 'optB88-vdW', 'ML': 'optB86b-vdW', 'RE': 'vdW-DF', 'OR': 'Klimes-Bowler-Michaelides' } #Open up the OUTCAR with open(os.path.join(self._directory, 'OUTCAR')) as fp: #Check if vdW is used if "LUSE_VDW" in open(os.path.join(self._directory, 'OUTCAR')).read(): #if vdW is used, get its keyword for line in fp: if "GGA =" in line: words = line.split() return Value(scalars=vdW_dict[words[2]]) #if vdW is not used, return None else: return None
def get_dos(self): '''Find the total DOS shifted by the Fermi energy''' # find the dos file fildos = '' files = [ f for f in os.listdir(self._directory) if os.path.isfile(os.path.join(self._directory, f)) ] for f in files: fp = open(os.path.join(self._directory, f), 'r') first_line = next(fp) if "E (eV)" in first_line and "Int dos(E)" in first_line: fildos = f ndoscol = len(next(fp).split()) - 2 # number of spin channels fp.close() break fp.close() if not fildos: return None # cannot find DOS # get the Fermi energy line = self._get_line('the Fermi energy is', self.outputf) efermi = float(line.split('is')[-1].split()[0]) # grab the DOS energy = [] dos = [] fp = open(os.path.join(self._directory, fildos), 'r') next(fp) # comment line for line in fp: ls = line.split() energy.append(Scalar(value=float(ls[0]) - efermi)) dos.append(Scalar(value=sum([float(i) for i in ls[1:1 + ndoscol]]))) return Property(scalars=dos, units='number of states per unit cell', conditions=Value(name='energy', scalars=energy, units='eV'))
def get_forces(self): self.atoms = read_vasp_out(os.path.join(self._directory, 'OUTCAR')) return Property( vectors=self.atoms.get_calculator().results['forces'].tolist(), conditions=Value(name="positions", vectors=self.atoms.positions.tolist()))
def test_convert_vector(): """Test that vectors are made rigid""" foo = Value(vectors=[1.2, 1.3]) assert foo.vectors[0][1].value == 1.3
def get_cutoff_energy(self): '''Determine the cutoff energy from the output''' return Value( scalars=[Scalar(value=self.settings["kinetic-energy cutoff"])], units=self.settings['kinetic-energy cutoff units'])
def get_xc_functional(self): '''Determine the xc functional from the output''' return Value(scalars=[ Scalar(value=" ".join(self.settings["exchange-correlation"])) ])
def get_cutoff_energy(self): '''Determine the cutoff energy from the output''' cutoff = self._get_line('kinetic-energy cutoff', self.outputf).split()[3:] return Value(scalars=float(cutoff[0]), units=cutoff[1])
def __init__(self, name=None, scalars=None, vectors=None, matrices=None, files=None, units=None, conditions=None, methods=None, data_type=None, references=None, contacts=None, licenses=None, tags=None, **kwargs): """ Constructor. :param name: String with the name of the property. :param scalars: One or more dictionaries, strings, numbers, or :class:`.Scalar` objects. :param vectors: One or more lists of dictionaries, strings, numbers, or :class:`.Scalar` objects, each representing a vector. :param matrices: One of more lists of lists of dictionaries, strings, numbers, or :class:`.Scalar` objects, each representing a matrix with rows as the innermost lists. :param files: One of more dictionaries, strings, or :class:`.FileReference` objects. :param units: String with the units of the property. :param conditions: List of dictionaries or :class:`.Value` objects with the conditions at which the property exists. :param methods: List of dictionary or :class:`.Method` object describing the method used to get the property value. :param data_type: String containing "EXPERIMENTAL", "COMPUTATIONAL", "FIT", or "MACHINE_LEARNING" to set the broad category of data. :param references: List of dictionaries or :class:`.Reference` objects where information about the property is published. :param contacts: List of dictionaries, strings, or :class:`.Person` objects with people to contact for information about the property. :param licenses: List of dictionaries, strings, or :class:`.License` objects with licensing information for the property. :param tags: List of strings or numbers that are tags for this object. :param kwargs: Dictionary of fields that are not supported. """ # The order of the constructors is important here. The second constructor could overwrite values set during # the first if there is overlap. Value.__init__(self, name=name, scalars=scalars, vectors=vectors, matrices=matrices, files=files, units=units, tags=tags, **kwargs) self.references = references self.contacts = contacts self.licenses = licenses self._conditions = None self.conditions = conditions if 'method' in kwargs: self.methods = kwargs['method'] self._methods = None self.methods = methods self._data_type = None self.data_type = data_type
def test_convert_matrix(): """Test that matrices are made rigid""" foo = Value(matrices=[[1.0, 2.0], [-2.0, 1.0]]) assert foo.matrices[0][0][1].value == 2.0 assert foo.matrices[0][1][0].value == -2.0
def test_convert_setter(): """Test that scalars are made rigid""" foo = Value() foo.scalars = 1.2 assert foo.scalars[0].value == 1.2
def get_poscar(self): raw_path = os.path.join(self._directory, 'POSCAR') if raw_path[0:2] == "./": raw_path = raw_path[2:] return Value(files=[FileReference(relative_path=raw_path)])