def get_KPPRA(self): # Open up the OUTCAR with open(self.outcar) as fp: #store the number of atoms and number of irreducible K-points for line in fp: if "number of ions NIONS =" in line: words = line.split() NI = int(words[11]) elif "k-points 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(self.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=[Scalar(value=NI * NK)]) #if k-points were not reduced KPPRA equals the number of atoms * number of irreducible k-points else: return Value(scalars=[Scalar(value=NI * NIRK)])
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=[Scalar(value=NI * NK)]) #if k-points were not reduced KPPRA equals the number of atoms * number of irreducible k-points else: return Value(scalars=[Scalar(value=NI * NIRK)]) # Error handling: NKPTS or NIONS not found raise Exception('NIONS, irredicuble or Coordinates not found')
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(Scalar(value=e)) dens = 0 for j in range(int(len(l) / 2)): dens += float(l[j]) dos.append(Scalar(value=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_unambig(): """Test that properties are mirrored in a top level dic""" pif = System() pif.properties = [ Property(name="foo", scalars=[Scalar(value=1.0)]), Property(name="bar", scalars=[Scalar(value=2.0)]) ] r = ReadView(pif) assert r["foo"].scalars[0].value == 1.0 assert r["bar"].scalars[0].value == 2.0
def get_forces(self): self.atoms = read_vasp_out(os.path.join(self._directory, 'OUTCAR')) forces_raw = self.atoms.get_calculator().results['forces'].tolist() forces_wrapped = [[Scalar(value=x) for x in y] for y in forces_raw] positions_raw = self.atoms.positions.tolist() positions_wrapped = [[Scalar(value=x) for x in y] for y in positions_raw] return Property(vectors=forces_wrapped, conditions=Value(name="positions", vectors=positions_wrapped))
def test_condition_elevation(): """Test that read views elevate conditions""" condition = Value(name="spam", scalars=[Scalar(value="eggs")]) pif = System(properties=[ Property( name="foo", scalars=[Scalar(value="bar")], conditions=[condition]) ]) r = ReadView(pif) assert r["foo"].scalars[0].value == "bar", "Didn't elevate property key" assert r["spam"].scalars[0].value == "eggs", "Didn't elevate condition key"
def test_read_view(): """Test that properties are passed through to the readview""" pif = System() pif.uid = "10245" pif.names = ["example", "ex"] pif.properties = [ Property(name="foo", scalars=[Scalar(value=1.0)]), Property(name="bar", scalars=[Scalar(value=2.0)]) ] r = ReadView(pif) assert r.uid == pif.uid assert r.names == pif.names assert r.properties["foo"].scalars[0].value == 1.0 assert r.properties["bar"].scalars[0].value == 2.0
def test_update_conflict(): """Test that update works when not extending and a field is redefined""" more_pif = System( properties=[ Property(name="band gap", scalars=[Scalar(value=1.3)]), Property(name="phase", scalars=[Scalar(value="gas")]), ] ) combined = update(test_pif, more_pif) expected = {"band gap": 1.3, "phase": "gas"} assert set(x.name for x in combined.properties) == set(expected.keys()) assert set(x.scalars[0].value for x in combined.properties) == set(expected.values()) for prop in combined.properties: assert expected[prop.name] == prop.scalars[0].value
def test_update_extend(): """Test that update works when extending with no dups""" more_pif = System( properties=[ Property(name="band gap", scalars=[Scalar(value=1.3)]), Property(name="phase", scalars=[Scalar(value="gas")]), ] ) combined = update(test_pif, more_pif, extend=True) expected = {"band gap": 1.3, "phase": "gas", "foo": "bar", "spam": 2.7} assert set(x.name for x in combined.properties) == set(expected.keys()) assert set(x.scalars[0].value for x in combined.properties) == set(expected.values()) for prop in combined.properties: assert expected[prop.name] == prop.scalars[0].value
def test_nested_read_view(): """Test that nested Pios (system here) are recursively processed""" pif = System() pif.uid = "10245" pif.properties = [ Property(name="foo", scalars=[Scalar(value=1.0)]), Property(name="bar", scalars=[Scalar(value=2.0)]) ] pif2 = System(sub_systems=[pif]) r = ReadView(pif2) assert r.sub_systems["10245"].uid == pif.uid assert r["10245"].uid == pif.uid assert r.sub_systems["10245"].properties["foo"].scalars[0].value == 1.0 assert r.sub_systems["10245"].properties["bar"].scalars[0].value == 2.0 assert r["foo"].scalars[0].value == 1.0 assert r["bar"].scalars[0].value == 2.0
def get_stresses(self): #Check if ISIF = 0 is used if "ISIF = 0" in open(os.path.join(self._directory, 'OUTCAR')).read(): return None #Check if ISIF = 1 is used elif "ISIF = 1" in open(os.path.join(self._directory, 'OUTCAR')).read(): return None else: #scan file in reverse to have the final pressure for line in open(os.path.join(self._directory, 'OUTCAR')).readlines(): if "in kB" in line: words = line.split() XX = float(words[2]) YY = float(words[3]) ZZ = float(words[4]) XY = float(words[5]) YZ = float(words[6]) ZX = float(words[7]) matrix = [[XX, XY, ZX], [XY, YY, YZ], [ZX, YZ, ZZ]] wrapped = [[Scalar(value=x) for x in y] for y in matrix] return Property(matrices=[wrapped], units='kbar') # Error handling: "in kB" not found raise Exception('in kB not found')
def test_update_conflicts(): """Test that update works when there are conflicts""" conflict_pif = System( properties=[ Property(name="band gap", scalars=[Scalar(value=1.3)]), Property(name="phase", scalars=[Scalar(value="gas")]), Property(name="spam", scalars=[Scalar(value=2.0)]), ] ) combined = update(test_pif, conflict_pif, extend=True) expected = {"band gap": 1.3, "phase": "gas", "foo": "bar", "spam": 2.0} assert set(x.name for x in combined.properties) == set(expected.keys()) assert set(x.scalars[0].value for x in combined.properties) == set(expected.values()) for prop in combined.properties: assert expected[prop.name] == prop.scalars[0].value
def test_multiple_instances(): """Test that keys that show up in different places with the same value are kept""" pif = System() pif.uid = "10245" pif.properties = [ Property(name="foo", scalars=[Scalar(value=1.0)]), Property(name="bar", scalars=[Scalar(value=2.0)]) ] pif2 = System( sub_systems=[ pif, ], properties=[Property(name="bar", scalars=[Scalar(value=2.0)])]) r = ReadView(pif2) assert r.properties["bar"].scalars[0].value == 2.0 assert r.sub_systems["10245"].properties["bar"].scalars[0].value == 2.0 assert r["bar"].scalars[0].value == 2.0
def get_total_energy(self): with open(self.outcar) as fp: last_energy = None for line in fp: if line.startswith(' free energy TOTEN'): last_energy = float(line.split()[4]) if last_energy is None: return None return Property(scalars=[Scalar(value=last_energy)], units='eV')
def get_xc_functional(self): # Open up the OUTCAR with open(self.outcar) as fp: # Look for TITEL for line in fp: if "TITEL" in line: words = line.split() return Value(scalars=[Scalar(value=words[2])])
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=[Scalar(value=words[2])]) break
def get_band_gap(self): """Get the bandgap, either from the EIGENVAL or DOSCAR files""" if self.outcar is not None and self.eignval is not None: bandgap = VaspParser._get_bandgap_eigenval(self.eignval, self.outcar) elif self.doscar is not None: bandgap = VaspParser._get_bandgap_doscar(self.doscar) else: return None return Property(scalars=[Scalar(value=round(bandgap, 3))], units='eV')
def test_method_software(): """Testing that method and software names are elevated""" method = Method(name="spam", software=[Software(name="magic")]) pif = System(properties=[ Property(name="foo", scalars=[Scalar(value="bar")], methods=[method]) ]) r = ReadView(pif) assert r["foo"].scalars[0].value == "bar", "Didn't elevate property key" assert "spam" in r.keys(), "Expected spam in keys" assert "magic" in r.keys(), "Expected magic in keys"
def test_ambiguity(): """Test that ambiguous keys are removed from the top level dict""" pif = System() pif.uid = "10245" pif.properties = [ Property(name="foo", scalars=[Scalar(value=1.0)]), Property(name="bar", scalars=[Scalar(value=2.0)]) ] pif2 = System( sub_systems=[ pif, ], properties=[Property(name="foo", scalars=[Scalar(value=10.0)])]) r = ReadView(pif2) assert r.properties["foo"].scalars[0].value == 10.0 assert r.sub_systems["10245"].properties["foo"].scalars[0].value == 1.0 assert "foo" not in r.keys() assert r.sub_systems["10245"]["foo"].scalars[0].value == 1.0 assert r["bar"].scalars[0].value == 2.0
def get_pp_name(self): # Open up the OUTCAR with open(self.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(vectors=[[Scalar(value=x) for x in pp]])
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=[Scalar(value=float(words[2]))], units=words[3]) # Error handling: ENCUT not found raise Exception('ENCUT not found')
def get_total_magnetization(self): if self.outcar is None: return None parser = OutcarParser() with open(self.outcar, "r") as fp: matches = list( filter(lambda x: "total magnetization" in x, parser.parse(fp.readlines()))) if len(matches) == 0: return None total_magnetization = matches[-1]["total magnetization"] return Property(scalars=[Scalar(value=total_magnetization)], units="Bohr")
def get_band_gap(self): """Get the bandgap, either from the EIGENVAL or DOSCAR files""" doscar_path = os.path.join(self._directory, 'DOSCAR') outcar_path = os.path.join(self._directory, 'OUTCAR') eigenval_path = os.path.join(self._directory, 'EIGENVAL') if os.path.isfile(outcar_path) and os.path.isfile(eigenval_path): bandgap = VaspParser._get_bandgap_eigenval(eigenval_path, outcar_path) elif os.path.isfile(doscar_path): bandgap = VaspParser._get_bandgap_doscar(doscar_path) else: return None return Property(scalars=[Scalar(value=round(bandgap, 3))], units='eV')
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(vectors=[[Scalar(value=x) for x in pp]]) # Error handling: TITEL not found raise Exception('TITEL not found')
def get_pressure(self): #define pressure dictionnary because since when is kB = kbar? Come on VASP people pressure_dict = {'kB': 'kbar'} #Check if ISIF = 0 is used if "ISIF = 0" in open(self.outcar).read(): #if ISIF = 0 is used, print this crap return None #if ISIF is not 0 then extract pressure and units else: #scan file in reverse to have the final pressure for line in reversed(open(self.outcar).readlines()): if "external pressure" in line: words = line.split() return Property(scalars=[Scalar(value=float(words[3]))], units=pressure_dict[words[4]]) break
def get_stresses(self): #Check if ISIF = 0 is used if "ISIF = 0" in open(self.outcar).read(): return None #Check if ISIF = 1 is used elif "ISIF = 1" in open(self.outcar).read(): return None else: #scan file in reverse to have the final pressure for line in open(self.outcar).readlines(): if "in kB" in line: words = line.split() XX = float(words[2]) YY = float(words[3]) ZZ = float(words[4]) XY = float(words[5]) YZ = float(words[6]) ZX = float(words[7]) matrix = [[XX, XY, ZX], [XY, YY, YZ], [ZX, YZ, ZZ]] wrapped = [[Scalar(value=x) for x in y] for y in matrix] return Property(matrices=[wrapped], units='kbar')
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(self.outcar) as fp: #Check if vdW is used if "LUSE_VDW" in open(self.outcar).read(): #if vdW is used, get its keyword for line in fp: if "GGA =" in line: words = line.split() return Value( scalars=[Scalar(value=vdW_dict[words[2]])]) #if vdW is not used, return None else: return None
def make_pif(df): """ Extracts information from Pandas Dataframe with GDB-9 molecule data to create a PIF object containing metadata and structural information :param: df - Pandas Dataframe object :return: PIF object """ pif_data = ChemicalSystem() pif_data.contacts = [ Person( name=Name(given='Lawrence', family='Crosby'), email='*****@*****.**', orcid='0000-0001-7644-3762' ) ] pif_data.references = [Reference(doi='10.1038/sdata.2014.22')] pif_data.licenses = [ License( name='CC0 1.0', description='Creative Commons Public Domain Dedication', url='https://creativecommons.org/publicdomain/zero/1.0/' ) ] software_list = [ Software(name='Corina', version='3.491 2013', producer='Altamira LLC'), Software(name='MOPAC', version='13.136L 2012', producer='CAChe Research LLC') ] pif_data.preparation = [ProcessStep(software=software_list)] pif_data.chemical_formula = df.iloc[-1, 0].split('/')[1] # extract chem formula from InChI # set from last row, first element in DataFrame pif_data.uid = df.iloc[-1, 1] # use B3LYP InChI as uid # set from last row, second element in DataFrame ids = [] gdb9_id = Id(name='GDB9 Id', value=df.iloc[1, 1]) ids.append(gdb9_id) inchi_id_corina = Id(name='InChI Corina', value=df.iloc[-1, 0]) ids.append(inchi_id_corina) # add Corina InChI to id list smiles_id_gdb17 = Id(name='SMILES GDB-17', value=df.iloc[-2, 0]) ids.append(smiles_id_gdb17)# add SMILES GDB-17 to id list smiles_id_b3lyp = Id(name='SMILES B3LYP', value=df.iloc[-2, 1]) ids.append(smiles_id_b3lyp)# add SMILES B3YLP to id list pif_data.ids = ids properties = [] vib_freqs = Property(name='Harmonic Vibrational Frequencies', units='cm-1', dataType='COMPUTATIONAL') vib_freqs.scalars = [Scalar(value=x) for x in df.iloc[-3, :]] # set vibrational frequencies using 3rd from last row in DataFrame properties.append(vib_freqs) num_atoms = Property(name='Number of Atoms', dataType='COMPUTATIONAL') n_atoms = df.iloc[0, 0] # get n_atoms from first element of DataFrame num_atoms.scalars = [Scalar(value=n_atoms)] properties.append(num_atoms) atoms = Property(name='Atoms', dataType='COMPUTATIONAL') elems = [df.iloc[a, 0] for a in range(2, int(n_atoms)+2)] # set elements using 1st column starting from 2nd row of DateFrame atoms.scalars = [Scalar(elem) for elem in elems] properties.append(atoms) atomic_positions = Property(name='Atomic Positions', dataType='COMPUTATIONAL', units='angstrom') x_coords = [df.iloc[a, 1] for a in range(2, int(n_atoms)+2)] y_coords = [df.iloc[a, 2] for a in range(2, int(n_atoms)+2)] z_coords = [df.iloc[a, 3] for a in range(2, int(n_atoms)+2)] # set coordinates using 2nd, 3rd, and 4th columns starting from 2nd row of DateFrame atomic_positions.vectors = [ [ Scalar(x_coords[i]), Scalar(y_coords[i]), Scalar(z_coords[i]) ] for i in range(int(n_atoms)) ] properties.append(atomic_positions) partial_charges = Property(name='Partial Charge', dataType='COMPUTATIONAL', units='e') charges = [df.iloc[a, 4] for a in range(2, int(n_atoms)+2)] # set charges using 5th columns starting from 2nd row of DateFrame partial_charges.scalars = [Scalar(charge) for charge in charges] properties.append(partial_charges) rot_a = Property( name='Rotational Constant A', dataType='COMPUTATIONAL', units='GHz', scalars=Scalar(value=df.iloc[1, 2]) ) properties.append(rot_a) rot_b = Property( name='Rotational Constant B', dataType='COMPUTATIONAL', units='GHz', scalars=Scalar(value=df.iloc[1, 3]) ) properties.append(rot_b) rot_c = Property( name='Rotational Constant C', dataType='COMPUTATIONAL', units='GHz', scalars=Scalar(value=df.iloc[1, 4]) ) properties.append(rot_b) mu = Property( name='Dipole Moment', dataType='COMPUTATIONAL', units='D', scalars=Scalar(value=df.iloc[1, 5]) ) properties.append(mu) alpha = Property( name='Isotropic Polarizability', dataType='COMPUTATIONAL', units='angstrom^3', scalars=Scalar(value=df.iloc[1, 6]) ) properties.append(alpha) e_homo = Property( name='Energy of H**O', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 7]) ) properties.append(e_homo) e_lumo = Property( name='Energy of LUMO', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 8]) ) properties.append(e_lumo) e_gap = Property( name='Energy Gap', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 9]) ) properties.append(e_gap) r2 = Property( name='Electronic Spatial Extent', dataType='COMPUTATIONAL', units='angstrom^2', scalars=Scalar(value=df.iloc[1, 10]) ) properties.append(r2) zpve = Property( name='Zero Point Vibrational Energy', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 11]) ) properties.append(zpve) u_0 = Property( name='Internal Energy at OK', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 12]) ) properties.append(u_0) u = Property( name='Internal Energy at 298K', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 13]) ) properties.append(u) h = Property( name='Enthalpy at 298K', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 14]) ) properties.append(h) g = Property( name='Free Energy at 298K', dataType='COMPUTATIONAL', units='Hartree', scalars=Scalar(value=df.iloc[1, 15]) ) properties.append(g) c_v = Property( name='Heat Capacity at 298K', dataType='COMPUTATIONAL', units='cal/mol/K', scalars=Scalar(value=df.iloc[1, 16]) ) properties.append(c_v) pif_data.properties = properties return pif_data
from pypif_sdk.func import replace_by_key, copy from pypif_sdk.accessor import get_property_by_name from pypif.obj import System, Property, Scalar, Value, FileReference test_pif = System(names=["methane"], properties=[ Property(name="foo", scalars=[Scalar(value="bar")]), Property(name="spam", units="eV", scalars=[Scalar(value=2.7)], conditions=[ Value(name="tomato", units="eV", scalars=[Scalar(value=1.0)]) ]), Property( name="image", files=[FileReference(relative_path="/tmp/file.png")]) ]) def test_simple_replace(): """Test replace a single field with default arguments""" prop = get_property_by_name(copy(test_pif), "image") assert prop.files[ 0].relative_path == "/tmp/file.png", "Didn't shorten file name" new_pif = replace_by_key(test_pif, "relative_path", {"/tmp/file.png": "file.png"}) prop = get_property_by_name(new_pif, "image") assert prop.files[ 0].relative_path == "file.png", "Didn't shorten file name"
from pypif_sdk.func import update from pypif.obj import System, Property, Scalar test_pif = System( properties=[ Property(name="foo", scalars=[Scalar(value="bar")]), Property(name="spam", scalars=[Scalar(value=2.7)]), ] ) def test_update_no_conflicts(): """Test that update works when there are no conflicts""" no_conflict_pif = System( names=["gas", "methane"] ) combined = update(test_pif, no_conflict_pif) expected = {"foo": "bar", "spam": 2.7} assert set(x.name for x in combined.properties) == set(expected.keys()) assert set(x.scalars[0].value for x in combined.properties) == set(expected.values()) for prop in combined.properties: assert expected[prop.name] == prop.scalars[0].value assert combined.names == ["gas", "methane"] def test_update_conflict(): """Test that update works when not extending and a field is redefined""" more_pif = System(