def get_band_gap(self): '''Compute the band gap from the DOS''' dosdata = self.get_dos() if type(dosdata) == type(None): return None # cannot find DOS else: energy = dosdata.conditions.scalars dos = dosdata.scalars step_size = energy[1].value - energy[0].value not_found = True l = 0 bot = 10**3 top = -10**3 while not_found and l < len(dos): # iterate through the data e = float(energy[l].value) dens = float(dos[l].value) # note: dos already shifted by efermi if e < 0 and dens > 1e-3: bot = e elif e > 0 and dens > 1e-3: top = e not_found = False l += 1 if top < bot: raise Exception('Algorithm failed to find the band gap') elif top - bot < step_size * 2: return Property(scalars=[Scalar(value=0)], units='eV') else: bandgap = float(top - bot) return Property(scalars=[Scalar(value=round(bandgap, 3))], units='eV')
def get_dos(self): '''Find the total DOS shifted by the Fermi energy''' # find the dos file fildos = '' for f in self._files: with open(f, 'r') as fp: 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(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 test_full_round_robin(): pif = System(properties=[ Property( name="foo", scalars=[Scalar(value=np.float32(2.4)), Scalar(value=np.int64(2))]), Property(name="bar", scalars=[Scalar(value=2.4), Scalar(value=2)]), Property(name="spam", files=[FileReference(relative_path="/tmp/file")]) ], preparation=[ ProcessStep(name="processed", details=[ Value(name="temp", scalars=[Scalar(value=1.0)]) ]) ], contacts=[Person(name=Name(family="Einstein"))]) pif2 = loads(dumps(pif)) assert pif2.as_dictionary() == pif.as_dictionary( ), "PIF contents are not the same" assert pif.properties[0].scalars[0].value == pif2.properties[0].scalars[ 0].value assert pif.properties[1].scalars[0].value == pif2.properties[1].scalars[ 0].value assert pif.properties[2].files[0].relative_path == pif2.properties[ 2].files[0].relative_path assert pif.preparation[0].details[0].scalars[0].value == pif2.preparation[ 0].details[0].scalars[0].value assert pif.contacts[0].name.family == pif2.contacts[0].name.family
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_condition(): """Test that conditions are flattened and added""" condition = Value(name="spam", scalars=[Scalar(value="eggs")]) sys = System(properties=[ Property(name="foo", scalars=[Scalar(value="bar")], conditions=[condition]) ]) user_data = _to_user_defined(sys) assert user_data["spam"] == "eggs"
def test_property_list(): """Test that a property with a list of scalars gets pulled out""" sys = System(properties=[ Property(name="foo", scalars=[Scalar( value="spam"), Scalar(value="eggs")]) ]) user_data = _to_user_defined(sys) assert user_data["foo"] == ["spam", "eggs"]
def test_property_vector(): """Test that a vector gets pulled out""" sys = System(properties=[ Property(name="foo", units="bar", vectors=[[Scalar( value="spam"), Scalar(value="eggs")]]) ]) user_data = _to_user_defined(sys) assert user_data["foo_bar"] == ["spam", "eggs"]
def get_stresses(self): '''Determine the stress tensor from the output''' if "stress" not in self.settings: return None wrapped = [[Scalar(value=x) for x in y] for y in self.settings["stress"]] return Property(matrices=[wrapped], units=self.settings["stress units"])
def get_number_of_atoms(self): """Get the number of atoms in the calculated structure. Returns: Property, where number of atoms is a scalar. """ strc = self.get_output_structure() if not strc: return None return Property(scalars=[Scalar(value=len(strc))], units="/unit cell")
def is_converged(self): '''Whether the calculation has converged Returns: Property where "scalar" is a boolean indicating ''' # Check for cached result if self._converged is None: self._converged = self._is_converged() return Property(scalars=[Scalar(value=self._converged)])
def test_add_datacite(): data_pif = System( properties=[Property(name="Foo", scalars=[Scalar(value="bar")])]) dc = { "identifier": { "identifier": "000.000", "identifierType": "DOI" }, "title": "The joy of the PIF", "publisher": "Ether", "publicationYear": "2014", "creators": [{ "creatorName": "Kyle Michel", "affiliations": ["Berklee", "NW"] }] } res = add_datacite(data_pif, dc) assert res.properties[0].scalars[0].value == "bar" assert res.references[0].doi == "000.000" data_pif2 = System( properties=[Property(name="Foo", scalars=[Scalar(value="bar")])]) dc2 = { "title": "The joy of the PIF", "publisher": "Ether", "publicationYear": "2014", "creators": [{ "creatorName": "Kyle Michel", "affiliations": ["Berklee", "NW"] }] } res2 = add_datacite(data_pif2, dc2) assert res2.properties[0].scalars[0].value == "bar" assert res2.references[0].doi is None
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_cutoff_energy(self): if not self._label: self._get_label() # Open up the label.txt file fp = open(os.path.join(self._directory, self._label + '.out'), 'r') foundecho = False # Look for ecut after the occurence of "echo values of preprocessed input variables" for line in fp: if "echo values of preprocessed input variables" in line: foundecho = True if "ecut" in line and foundecho: words = line.split() return Value(scalars=[Scalar(value=float(words[1]))], units=words[2]) # Error handling: ecut not found raise Exception('ecut not found')
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_forces(self): if "forces" not in self.settings: return None wrapped = [[Scalar(value=x) for x in y] for y in self.settings['forces']] return Property(vectors=wrapped, units=self.settings['force units'])
def get_positions(self): strc = self.get_output_structure() raw = strc.positions.tolist() wrapped = [[Scalar(value=x) for x in y] for y in raw] return Property(vectors=wrapped)
def get_density(self): """Compute the density from the output structure""" strc = self.get_output_structure() density = sum(strc.get_masses()) / strc.get_volume() * 1.660539040 return Property(scalars=[Scalar(value=density)], units="g/(cm^3)")
def get_final_volume(self): vols_n_units = self.get_list_of_volumes_n_units() if not vols_n_units: return None v, u = self._convert_to_cubic_ang(vols_n_units[-1][0], vols_n_units[-1][1]) return Property(scalars=[Scalar(value=v)], units=u)
def get_xc_functional(self): '''Determine the xc functional from the output''' return Value(scalars=[ Scalar(value=" ".join(self.settings["exchange-correlation"])) ])
def test_property_value(): """Test that a simple property gets pulled out""" sys = System( properties=[Property(name="foo", scalars=[Scalar(value="bar")])]) user_data = _to_user_defined(sys) assert user_data["foo"] == "bar"
test_pif1 = ChemicalSystem( uid="0", chemical_formula="CH4", names=["methane", "natural gas"], contacts=[ Person(name=Name(given="Albert", family="Einstein"), orcid="123456"), Person(name=Name(given="Adam", family="Min"), email="*****@*****.**") ], references=[ Reference(doi="doi", authors=[Name(given="Captain", family="Marvel")]) ], licenses=[License(url="url")], tags=["too long", "didn't read"], properties=[ Property(name="foo", scalars=[Scalar(value="bar")]), Property(name="spam", scalrs=[Scalar(value="eggs")]) ]) test_pif2 = ChemicalSystem(uid="0", composition=[ Composition(element="H"), Composition(element="S"), Composition(element="O") ], references=[]) @pytest.mark.skipif("CITRINATION_API_KEY" not in environ, reason="No API key available") def test_query_to_mdf_records(): """Big integration test to make sure everything is working"""
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_total_force(self): if "total force" not in self.settings: return None return Property(scalars=[Scalar(value=self.settings['total force'])], units=self.settings['force units'])
def _get_key_with_units(self, key): if key not in self.settings: return None return Property(scalars=[Scalar(value=self.settings[key])], units=self.settings["{} units".format(key)])