def test_as_dict(self): filepath = os.path.join(test_dir, "vasprun.xml") vasprun = Vasprun(filepath, parse_potcar_file=False) # Test that as_dict() is json-serializable self.assertIsNotNone(json.dumps(vasprun.as_dict())) self.assertEqual( vasprun.as_dict()["input"]["potcar_type"], ["PAW_PBE", "PAW_PBE", "PAW_PBE", "PAW_PBE", "PAW_PBE"] )
def test_as_dict(self): filepath = os.path.join(test_dir, 'vasprun.xml') vasprun = Vasprun(filepath, parse_potcar_file=False) #Test that as_dict() is json-serializable self.assertIsNotNone(json.dumps(vasprun.as_dict())) self.assertEqual( vasprun.as_dict()["input"]["potcar_type"], ['PAW_PBE', 'PAW_PBE', 'PAW_PBE', 'PAW_PBE', 'PAW_PBE'])
def get_structure(vasprun_dos, vasprun_bands): ## get structure object and "save" in hidden div in json format if vasprun_dos: structure = Vasprun(vasprun_dos).structures[-1] elif vasprun_bands: structure = Vasprun(vasprun_bands).structures[-1] return json.dumps(structure.as_dict())
def parse_fols(hkl=None, bulk_per_atom=None, **kwargs): """ Parses the convergence folders to get the surface energy, total energy, energy per atom and time taken for each slab and vacuum thickness combination Args: hkl (tuple): Miller index of the slab bulk_per_atom (float): bulk energy per atom from a converged bulk calculation Returns: hkl_data.csv """ # Check all neccessary input parameters are present if not any ([hkl, bulk_per_atom]): raise ValueError('One or more of the required arguments (bulk_per_atom, ' 'hkl) were not supplied.') df_list = [] hkl_sorted = ''.join(map(str, hkl)) for root, fols in os.walk('.'): for fol in fols: if not any([fol==root, fol=='.ipynb_checkpoints']): path = os.path.join(root, fol) vsp_path = '{}/vasprun.xml'.format(path) # instantiate structure, slab and vasprun objects vsp = Vasprun(vsp_path, **kwargs) slab = slab_from_file(vsp_path, hkl) vsp_dict = vsp.as_dict() # extract the data area = slab.surface_area atoms = vsp_dict['nsites'] slab_energy = vsp.final_energy energy_per_atom = slab_energy / atoms surface_energy = (slab_energy - bulk_per_atom * atoms)/(2 * area) * 16.02 # name of fol has to be ./slabthickness_vacthickness_index slab_vac_index = fol.split('_') # reads the outcar to get the time taken with open('{}/OUTCAR'.format(path), 'r') as otc: lines = list(otc) line = lines[-8].split(':') df_list.append({'slab_thickness': slab_vac_index[0], 'vac_thickness': slab_vac_index[1], 'slab_index': slab_vac_index[2], 'surface_energy': surface_energy, 'slab_toten': slab_energy, 'slab_per_atom': energy_per_atom, 'time_taken': line[1].strip()}) df = pd.DataFrame(df_list) df.to_csv('{}_data.csv'.format(hkl_sorted), index=False)
def check_dft_calcs(self): """ Helper function to check DFT calculations via polling AWS batch. Updates current data with latest AWS batch response. """ for structure_id, calc in self.current_data.iterrows(): if calc["status"] in ["SUCCEEDED", "FAILED"]: continue path = calc["path"] print("Checking status of {}: {}".format(path, structure_id)) aws_cmd = "aws batch describe-jobs --jobs " "--region=us-east-1 {}".format( calc["jobId"]) result = subprocess.check_output(shlex.split(aws_cmd)) result = json.loads(result) aws_status = result["jobs"][0]["status"] if aws_status == "SUCCEEDED": os.chdir(path) subprocess.call("trisync") os.chdir("simulation") try: vr = Vasprun("static/vasprun.xml") vr_dict = vr.as_dict() delta_e = get_qmpy_formation_energy( vr_dict["output"]["final_energy_per_atom"], vr_dict["pretty_formula"], 1, ) data = { "status": "SUCCEEDED", "error": None, "result": vr, "delta_e": delta_e, } except Exception as e: error_doc = {} if os.path.isfile("err"): with open("err") as errfile: error_doc.update({"trisub_stderr": errfile.read()}) error_doc.update({ "camd_exception": "{}".format(e), "camd_traceback": traceback.format_exc(), }) # Dump error docs to avoid Pandas issues with dict values data = {"status": "FAILED", "error": json.dumps(error_doc)} os.chdir(path) elif aws_status == "FAILED": error_doc = { "aws_fail": result["jobs"][0]["attempts"][-1]["statusReason"] } data = {"status": "FAILED", "error": json.dumps(error_doc)} else: data = {"status": aws_status} update_dataframe_row(self.current_data, structure_id, data)
def check_dft_calcs(calc_status): """ Args: calc_status (dict): Returns: updated calc_status dictionary """ for structure_id, calc in calc_status.items(): if calc['status'] in ['SUCCEEDED', 'FAILED']: continue path = calc['path'] print("Checking status of {}: {}".format(path, structure_id)) aws_cmd = "aws batch describe-jobs --jobs " \ "--region=us-east-1 {}".format(calc['jobId']) result = subprocess.check_output(shlex.split(aws_cmd)) result = json.loads(result) aws_status = result["jobs"][0]["status"] if aws_status == "SUCCEEDED": os.chdir(path) subprocess.call('trisync') os.chdir('simulation') try: vr = Vasprun('static/vasprun.xml') calc.update({ "status": "SUCCEEDED", "error": None, "result": vr.as_dict() }) except Exception as e: error_doc = {} with open('err') as errfile: error_doc.update({"trisub_stderr": errfile.read()}) error_doc.update({ "camd_exception": "{}".format(e), "camd_traceback": traceback.format_exc() }) calc.update({ "status": "FAILED", "error": error_doc, "result": None }) elif aws_status == "FAILED": error_doc = { "aws_fail": result['jobs'][0]['attempts'][-1]['statusReason'] } calc.update({"status": "FAILED", "error": error_doc}) else: calc.update({"status": aws_status}) return calc_status
def test_get_vasprun_method(testdata): from pymatgen.io.vasp.outputs import Vasprun from aiida_cusp.data.outputs.vasp_vasprun import VaspVasprunData from aiida_cusp.utils.defaults import VasprunParsingDefaults default_parsing_args = VasprunParsingDefaults.PARSER_ARGS vasprun_xml = testdata / 'vasprun.xml' vasprun_node = VaspVasprunData(file=vasprun_xml) # create vasprun object from node and compare to the original # pymatgen class generated from the test file vasprun_obj_node = vasprun_node.get_vasprun() vasprun_obj_pmg = Vasprun(vasprun_xml, **default_parsing_args) node_contents = json.dumps(vasprun_obj_node.as_dict(), sort_keys=True) pmg_contents = json.dumps(vasprun_obj_pmg.as_dict(), sort_keys=True) assert node_contents == pmg_contents
def data(vasprun_file, data="basic"): """ Extract data from a vasprun.xml file and write it as a data.json. Mainly used to make the data files more compact. Args: vasprun_file (str): Path to the vasprun.xml file. data: String or List of strings that details the data to extract from the vasprun.xml. Defaults to "basic", which simply parses the vasprun.xml file with the standard kwargs of the Vasprun class, see pymatgen.io.vasp.outputs.Vasprun. Other options include: "energy": The final energy "structure": The final structure "dos": The CompleteDos Returns: """ directory = os.path.dirname(os.path.abspath(vasprun_file)) vr = Vasprun(vasprun_file) data_dict = {} if "basic" in data: data_dict.update(vr.as_dict()) if "energy" in data: data_dict.update({"energy": vr.final_energy}) if "structure" in data: data_dict.update({"structure": vr.final_structure.to_json()}) if "dos" in data: data_dict.update({"dos": vr.complete_dos.as_dict()}) with zopen(os.path.join(directory, "data.json"), "w") as file: file.write(json.dumps(data_dict))
def convert_xml_to_pickle(): import pickle from pymatgen.io.vasp.outputs import Vasprun vasprun = Vasprun('./vasprun.xml') pickle.dump(vasprun.as_dict(), open('./vasprun.p', 'wb'))
def test_properties(self): filepath = os.path.join(test_dir, 'vasprun.xml.nonlm') vasprun = Vasprun(filepath, parse_potcar_file=False) orbs = list(vasprun.complete_dos.pdos[vasprun.final_structure[ 0]].keys()) self.assertIn(OrbitalType.s, orbs) filepath = os.path.join(test_dir, 'vasprun.xml') vasprun = Vasprun(filepath, parse_potcar_file=False) #Test NELM parsing. self.assertEqual(vasprun.parameters["NELM"], 60) #test pdos parsing pdos0 = vasprun.complete_dos.pdos[vasprun.final_structure[0]] self.assertAlmostEqual(pdos0[Orbital.s][Spin.up][16], 0.0026) self.assertAlmostEqual(pdos0[Orbital.pz][Spin.down][16], 0.0012) self.assertEqual(pdos0[Orbital.s][Spin.up].shape, (301, )) filepath2 = os.path.join(test_dir, 'lifepo4.xml') vasprun_ggau = Vasprun(filepath2, parse_projected_eigen=True, parse_potcar_file=False) totalscsteps = sum([len(i['electronic_steps']) for i in vasprun.ionic_steps]) self.assertEqual(29, len(vasprun.ionic_steps)) self.assertEqual(len(vasprun.structures), len(vasprun.ionic_steps)) self.assertEqual(vasprun.lattice, vasprun.lattice_rec.reciprocal_lattice) for i, step in enumerate(vasprun.ionic_steps): self.assertEqual(vasprun.structures[i], step["structure"]) self.assertTrue(all([vasprun.structures[i] == vasprun.ionic_steps[i][ "structure"] for i in range(len(vasprun.ionic_steps))])) self.assertEqual(308, totalscsteps, "Incorrect number of energies read from vasprun.xml") self.assertEqual(['Li'] + 4 * ['Fe'] + 4 * ['P'] + 16 * ["O"], vasprun.atomic_symbols) self.assertEqual(vasprun.final_structure.composition.reduced_formula, "LiFe4(PO4)4") self.assertIsNotNone(vasprun.incar, "Incar cannot be read") self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.eigenvalues, "Eigenvalues cannot be read") self.assertAlmostEqual(vasprun.final_energy, -269.38319884, 7) self.assertAlmostEqual(vasprun.tdos.get_gap(), 2.0589, 4) expectedans = (2.539, 4.0906, 1.5516, False) (gap, cbm, vbm, direct) = vasprun.eigenvalue_band_properties self.assertAlmostEqual(gap, expectedans[0]) self.assertAlmostEqual(cbm, expectedans[1]) self.assertAlmostEqual(vbm, expectedans[2]) self.assertEqual(direct, expectedans[3]) self.assertFalse(vasprun.is_hubbard) self.assertEqual(vasprun.potcar_symbols, ['PAW_PBE Li 17Jan2003', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE P 17Jan2003', 'PAW_PBE O 08Apr2002']) self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints, "Actual kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints_weights, "Actual kpoints weights cannot be read") for atomdoses in vasprun.pdos: for orbitaldos in atomdoses: self.assertIsNotNone(orbitaldos, "Partial Dos cannot be read") # test skipping ionic steps. vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False) self.assertEqual(vasprun_skip.nionic_steps, 29) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) self.assertEqual(len(vasprun_skip.ionic_steps), len(vasprun_skip.structures)) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) # Check that nionic_steps is preserved no matter what. self.assertEqual(vasprun_skip.nionic_steps, vasprun.nionic_steps) self.assertNotAlmostEqual(vasprun_skip.final_energy, vasprun.final_energy) # Test with ionic_step_offset vasprun_offset = Vasprun(filepath, 3, 6, parse_potcar_file=False) self.assertEqual(len(vasprun_offset.ionic_steps), int(len(vasprun.ionic_steps) / 3) - 1) self.assertEqual(vasprun_offset.structures[0], vasprun_skip.structures[2]) self.assertTrue(vasprun_ggau.is_hubbard) self.assertEqual(vasprun_ggau.hubbards["Fe"], 4.3) self.assertAlmostEqual(vasprun_ggau.projected_eigenvalues[Spin.up][ 0][0][96][0], 0.0032) d = vasprun_ggau.as_dict() self.assertEqual(d["elements"], ["Fe", "Li", "O", "P"]) self.assertEqual(d["nelements"], 4) filepath = os.path.join(test_dir, 'vasprun.xml.unconverged') with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. vasprun_unconverged = Vasprun(filepath, parse_potcar_file=False) # Verify some things self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, UnconvergedVASPWarning)) self.assertTrue(vasprun_unconverged.converged_ionic) self.assertFalse(vasprun_unconverged.converged_electronic) self.assertFalse(vasprun_unconverged.converged) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt') vasprun_dfpt = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][0], 3.26105533) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][1], -0.00459066) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[2][2], 3.24330517) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][0], 3.33402531) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][1], -0.00559998) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[2][2], 3.31237357) self.assertTrue(vasprun_dfpt.converged) entry = vasprun_dfpt.get_computed_entry() entry = MaterialsProjectCompatibility(check_potcar_hash=False).process_entry(entry) self.assertAlmostEqual(entry.uncorrected_energy + entry.correction, entry.energy) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.ionic') vasprun_dfpt_ionic = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][0], 515.73485838) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][1], -0.00263523) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[2][2], 19.02110169) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.unconverged') vasprun_dfpt_unconv = Vasprun(filepath, parse_potcar_file=False) self.assertFalse(vasprun_dfpt_unconv.converged_electronic) self.assertTrue(vasprun_dfpt_unconv.converged_ionic) self.assertFalse(vasprun_dfpt_unconv.converged) vasprun_uniform = Vasprun(os.path.join(test_dir, "vasprun.xml.uniform"), parse_potcar_file=False) self.assertEqual(vasprun_uniform.kpoints.style, Kpoints.supported_modes.Reciprocal) vasprun_no_pdos = Vasprun(os.path.join(test_dir, "Li_no_projected.xml"), parse_potcar_file=False) self.assertIsNotNone(vasprun_no_pdos.complete_dos) self.assertFalse(vasprun_no_pdos.dos_has_errors) vasprun_diel = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric"), parse_potcar_file=False) self.assertAlmostEqual(0.4294,vasprun_diel.dielectric[0][10]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][0]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][1]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[1][51][3]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][0]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][1]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[2][85][3]) v = Vasprun(os.path.join(test_dir, "vasprun.xml.indirect.gz")) (gap, cbm, vbm, direct) = v.eigenvalue_band_properties self.assertFalse(direct)
def boltztrap(tmax=1001, tstep=50, tmin=None, doping=np.logspace(18, 21, 17), ke_mode='boltzmann', vasprun='vasprun.xml', kpoints=None, relaxation_time=1e-14, lpfac=10, run=True, analyse=True, output='boltztrap.hdf5', **kwargs): """Runs BoltzTraP from a VASP density of states (DoS). Runs quicker and more robustly than the pymatgen from_files version, and outputs an hdf5 file. Note: BoltzTraP can be a fickle friend, so if you're getting errors, it may be worth reinstalling or trying on a different machine. Arguments --------- tmax : float, optional maximum temperature in K. Default: 1000. tstep : float, optional temperature step in K. Default: 50. tmin : float, optional minimum temperature in K. This does not reduce how many temperatures are run in BoltzTraP, only how many are saved to hdf5. Default: tstep. doping : array-like, optional doping concentrations in cm-1. Default: np.logspace(18, 21, 17). k_mode : str, optional method for calculating the electronic thermal conductivity. Options: boltzmann (default): standard boltztrap method. Madsen and Singh, Comput. Phys. Commun. 2006, 175, 67. wiedemann: Wiedemann-Franz law with constant L = 2.44E-8. Franz and Wiedemann, Ann. Phys. 1853, 165, 497. snyder: Wiedemann-Franz law, with L varying with Seebeck. Kim et al., APL Mat. 2015, 3, 041506. vasprun : str, optional path to vasprun. Default: vasprun.xml. kpoints : str, optional path to KPOINTS file if there are zero-weighted k-points. Default: KPOINTS. relaxation_time : float, optional charge carrier relaxation time. Default: 1e-14. lpfac : int, optional DoS interpolation factor. Default: 10. run : bool, optional run BoltzTraP. Default: True. analyse : bool, optional analyse BoltzTraP. Default: True. output : str, optional output hdf5 filename. Default: boltztrap.hdf5. kwargs passed to pymatgen.electronic.structure.boltztrap.BoltztrapRunner. Returns ------- None instead prints to hdf5 (see below). hdf5 File Contents ------------------ average_eff_mass : dict the charge carrier effective mass in units of m_e, taking into account all bands, as opposed to the single parabolic band model. Data is a dictionary with an array each for n and p doping, of shape (temperatures, concentrations, 3, 3). conductivity : dict electric conductivity in S m-1. Data is a dictionary with an array each for n and p doping, of shape (temperatures, concentrations, 3, 3). doping : array-like carrier concentration in cm-1. Identical to input. electronic_thermal_conductivity : dict electronic thermal conductivity in W m-1 K-1. Data is a dictionary with an array each for n and p doping, of shape (temperatures, concentrations, 3, 3). fermi_level : dict fermi level at different temperatures in units of eV. Data is a dictionary with an array each for n and p doping, of shape (temperatures, concentrations). power_factor : dict power factor in W m-1 K-2. Data is a dictionary with an array each for n and p doping, of shape (temperatures, concentrations, 3, 3). seebeck : dict Seebeck coefficient in muV K-1. Data is a dictionary with an array each for n and p doping, of shape (temperatures, concentrations, 3, 3). temperature : numpy array temperatures in K. meta : dict metadata: interpolation_factor : int lpfac. ke_mode : str as input. relaxation_time : float as input. soc : bool spin-orbit coupling calculation. units : dict units of each property above. """ import h5py import os from pymatgen.electronic_structure.boltztrap \ import BoltztrapRunner, BoltztrapAnalyzer, BoltztrapError from pymatgen.io.vasp.outputs import Vasprun from scipy import constants # check inputs for name, value in zip(['run', 'analyse'], [run, analyse]): assert isinstance(value, bool), '{} must be True or False'.format(name) ke_mode = ke_mode.lower() ke_modes = ['boltzmann', 'wiedemann', 'snyder'] assert ke_mode in ke_modes, 'ke_mode must be {} or {}.'.format( ', '.join(ke_modes[:-1]), ke_modes[-1]) tmax += tstep tmin = tstep if tmin is None else tmin temperature = np.arange(tmin, tmax, tstep) if run: # run boltztrap from vasprun.xml -> boltztrap directory doping = np.array(doping) vr = Vasprun(vasprun, parse_potcar_file=False) soc = vr.as_dict()['input']['parameters']['LSORBIT'] try: bs = vr.get_band_structure(line_mode=False) nelect = vr.parameters['NELECT'] btr = BoltztrapRunner(bs, nelect, doping=list(doping), tmax=tmax, tgrid=tstep, soc=soc, lpfac=lpfac, **kwargs) print('Running Boltztrap...', end='') btr_dir = btr.run(path_dir='.') print('Done.') except BoltztrapError: bs = vr.get_band_structure(line_mode=True, kpoints_filename=kpoints) nelect = vr.parameters['NELECT'] btr = BoltztrapRunner(bs, nelect, doping=list(doping), tmax=tmax, tgrid=tstep, soc=soc, lpfac=lpfac, **kwargs) btr_dir = btr.run(path_dir='.') print('Done.') """ Detects whether the BoltzTraP build on this computer writes the doping concentrations correctly, and if it doesn't, writes them. """ with open('boltztrap/boltztrap.outputtrans', 'r') as f: line = f.readlines()[-2] if len(line) >= 23 and line[:23] == ' Calling FermiIntegrals': with open(os.path.join(btr_dir, 'boltztrap.outputtrans'), 'a') as f: for i, x in enumerate(np.concatenate((doping, -doping))): f.write( 'Doping level number {} n = {} carriers/cm3\n'.format( i, x)) else: btr_dir = 'boltztrap' if analyse: # run boltztrap from boltztrap directory -> hdf5 file print('Analysing Boltztrap...', end='') bta = BoltztrapAnalyzer.from_files(btr_dir) print('Done.') data = { 'average_eff_mass': {}, 'conductivity': {}, 'doping': doping, 'electronic_thermal_conductivity': {}, 'power_factor': {}, 'seebeck': {}, 'temperature': temperature, 'meta': { 'units': { 'average_eff_mass': 'm_e', 'conductivity': 'S m-1', 'doping': 'cm-1', 'electronic_thermal_conductivity': 'W m-1 K-1', 'fermi_level': 'eV', 'power_factor': 'W m-1 K-2', 'seebeck': 'muV K-1', 'temperature': 'K' }, 'interpolation_factor': lpfac, 'ke_mode': ke_mode, 'relaxation_time': relaxation_time, 'soc': soc } } # load data print('Calculating transport...', end='') c = bta._cond_doping dp = bta.doping e = constants.e f = bta.mu_doping k = bta._kappa_doping me = constants.m_e s = bta._seebeck_doping # calculate transport properties for d in ['n', 'p']: c[d] = np.array([c[d][t] for t in temperature]) dp[d] = np.array(dp[d]) k[d] = np.array([k[d][t] for t in temperature]) f[d] = np.array([f[d][t] for t in temperature]) s[d] = np.array([s[d][t] for t in temperature]) data['average_eff_mass'][d] = np.linalg.inv(c[d]) \ * dp[d][None, :, None, None] \ * 1e6 * e ** 2 / me data['conductivity'][d] = np.multiply(c[d], relaxation_time) data['seebeck'][d] = np.multiply(s[d], 1e6) data['power_factor'][d] = tp.calculate.power_factor( data['conductivity'][d], data['seebeck'][d]) if ke_mode == 'boltztrap': data['electronic_thermal_conductivity'][d] = \ k[d] * relaxation_time \ - data['power_factor'][d] * temperature[:,None,None,None] else: if ke_mode == 'wiedemann': L = 2.44E-8 else: L = (1.5 + np.exp(-np.abs(data['seebeck'][d]) / 116)) * 1e-8 data['electronic_thermal_conductivity'][d] = \ L * data['conductivity'][d] * temperature[:,None,None,None] data['fermi_level'] = f print('Done.') tp.data.save.hdf5(data, output) return
def process_data(bulk_per_atom, parse_hkl=True, path_to_fols=None, hkl_dict=None, parse_core_energy=False, core_atom=None, bulk_nn=None, parse_vacuum=False, save_csv=True, csv_fname='data.csv', **kwargs): """ Parses the folders to collect all final data on relevant input and output parameters, and optionally core and vacuum level energies. If you are processing data for folder structures generated with `generation` make sure you use `convergence.parse_fols` function. This function is for parsing full sets of information from the output of production run calculations. The folder structure for parsing of data is fairly flexible and can be: 1. automatically parsed if `parse_hkl=True` - the function searches for folders with names three digits long in cwd (default) e.g. it finds folders cwd/100 and cwd/010 that correspond to Miller indices (1,0,0) and (0,1,0) 2. automatically parsed from a specific working directory if `path_to_fols` is specified 3. manually specified using `hkl_dict`, where the Miller index is mapped directly to the path to where the files are. If you are only interested in the specified folders, do not forget to change `parse_hkl=False`. e.g. hkl_dict = {(0,1,1): 'path/to/001/files/', (2,0,1): 'path/to/201/files/'} 4. automatically parsed from cwd or a specific working directory in addition to a defined `hkl_dict` Each of the folders must contain POSCAR and vasprun.xml files and optionally LOCPOT (or potential.csv) and OUTCAR files if vacuum or core energy are parsed. The function returns None by default and saves the DataFrame to a csv file. Optionally, it can return the DataFrame. Args: bulk_per_atom (`float`): Bulk energy per atom in eV per atom. parse_hkl (`bool`, optional): If ``True`` the script parses the names of the folders to get the Miller indices. Defaults to ``True``. path_to_fols (`str`, optional): Path to where surfaxe should look for the hkl folders are. Defaults to None which searches in cwd. hkl_dict (`dict`, optional): dictionary of tuples of Miller indices and paths to the folders the relevant outputs. Defaults to ``None``. E.g. If the outputs of the calculations on the (1,-1,2) slab are in folder ``path/to/folder/112``, the ``hkl_dict`` would be: {(1,-1,2): 'path/to/folder/112'} parse_core_energy (`bool`, optional): If True the scripts attempts to parse core energies from a supplied OUTCAR. Defaults to ``False``. core_atom (`str`, optional): The symbol of atom the core state energy level should be parsed from. Defaults to ``None``. bulk_nn (`list`, optional): The symbols of the nearest neighbours of the `core_atom`. Defaults to ``None``. parse_vacuum (`bool`, optional): if ``True`` the script attempts to parse LOCPOT using analysis.electrostatic_potential to use the maximum value of planar potential as the vacuum energy level. Defaults to ``True``. save_csv (`bool`, optional): If ``True``, it writes data to a csv file. Defaults to ``True``. csv_fname (`str`, optional): The filename of the csv. Defaults to data.csv Returns: DataFrame """ # Check if hkl_dict is correctly set up if hkl_dict: for key, value in hkl_dict.items(): if not isinstance(key, tuple): raise TypeError( 'The keys supplied to hkl_dict are not tuples.') if not isinstance(value, str): raise TypeError( 'The values supplied to hkl_dict are not strings.') cwd = os.getcwd() if path_to_fols: cwd = path_to_fols # Get the Miller indices as tuples and strings from folders in root dir if parse_hkl: if not hkl_dict: hkl_dict = {} for fol in os.listdir(cwd): if os.path.isdir(os.path.join(cwd, fol)) and len(fol)==3 and\ fol.isdigit(): hkl_dict[tuple(map(int, fol))] = os.path.join(cwd, fol) # Set up additional arguments for get_core_energy get_core_energy_kwargs = { 'orbital': '1s', 'ox_states': None, 'nn_method': CrystalNN() } get_core_energy_kwargs.update( (k, kwargs[k]) for k in get_core_energy_kwargs.keys() & kwargs.keys()) get_core = False if parse_core_energy: if core_atom is not None and bulk_nn is not None: get_core = True else: warnings.formatwarning = _custom_formatwarning warnings.warn(('Core atom or bulk nearest neighbours were not ' 'supplied. Core energy will not be parsed.')) # For each miller index, check if the folders specified are there and # parse them for data df_list, electrostatic_list, core_energy_list = ([] for i in range(3)) for hkl_tuple, path in hkl_dict.items(): vsp_path = '{}/vasprun.xml'.format(path) psc_path = '{}/POSCAR'.format(path) vsp = Vasprun(vsp_path, parse_potcar_file=False) slab = slab_from_file(psc_path, hkl_tuple) vsp_dict = vsp.as_dict() df_list.append({ 'hkl': ''.join(map(str, hkl_tuple)), 'hkl_tuple': hkl_tuple, 'area': slab.surface_area, 'atoms': vsp_dict['nsites'], 'functional': vsp_dict['run_type'], 'encut': vsp_dict['input']['incar']['ENCUT'], 'algo': vsp_dict['input']['incar']['ALGO'], 'ismear': vsp_dict['input']['parameters']['ISMEAR'], 'sigma': vsp_dict['input']['parameters']['SIGMA'], 'kpoints': vsp_dict['input']['kpoints']['kpoints'], 'bandgap': vsp_dict['output']['bandgap'], 'slab_energy': vsp_dict['output']['final_energy'], 'slab_per_atom': vsp_dict['output']['final_energy_per_atom'] }) if parse_vacuum: electrostatic_list.append(vacuum(path)) if get_core: otc_path = '{}/OUTCAR'.format(path) core_energy_list.append( core_energy(core_atom, bulk_nn, outcar=otc_path, structure=psc_path, **get_core_energy_kwargs)) df = pd.DataFrame(df_list) df['surface_energy'] = ((df['slab_energy'] - bulk_per_atom * df['atoms']) / (2 * df['area']) * 16.02) df['surface_energy_ev'] = ( (df['slab_energy'] - bulk_per_atom * df['atoms']) / (2 * df['area'])) if electrostatic_list: df['vacuum_potential'] = electrostatic_list if core_energy_list: df['core_energy'] = core_energy_list # Save to csv or return DataFrame if save_csv: if not csv_fname.endswith('.csv'): csv_fname += '.csv' df.to_csv(csv_fname, header=True, index=False) else: return df
def _mp_helper_energy(parse_vacuum, get_core, hkl, path, slab_thickness, vac_thickness, slab_index, core_atom=None, bulk_nn=None, **kwargs): """ Helper function for multiprocessing, returns a list of lists of the main extracted data, electrostatic potential and core energies Same args as for parse_fols, only that path is the path to the folder in which the vasprun and OUTCAR for the specific slab/vacuum/index slab are. """ df_list, electrostatic_list, core_energy_list, gradient_list = ( [] for i in range(4)) # instantiate structure, slab, vasprun and outcar objects vsp_path = '{}/vasprun.xml'.format(path) otc_path = '{}/OUTCAR'.format(path) vsp = Vasprun(vsp_path, parse_potcar_file=False) otc = Outcar(otc_path) slab = slab_from_file(vsp.final_structure, hkl) vsp_dict = vsp.as_dict() # extract the time data otc_times = otc.run_stats df_list.append({ 'hkl_string': ''.join(map(str, hkl)), 'hkl_tuple': hkl, 'slab_thickness': slab_thickness, 'vac_thickness': vac_thickness, 'slab_index': slab_index, 'atoms': vsp_dict['nsites'], 'area': slab.surface_area, 'bandgap': vsp_dict['output']['bandgap'], 'slab_energy': vsp_dict['output']['final_energy'], 'slab_per_atom': vsp_dict['output']['final_energy_per_atom'], 'time_taken': otc_times['Elapsed time (sec)'] }) if parse_vacuum: electrostatic_list.append(vacuum(path)) lpt = '{}/LOCPOT'.format(path) p = electrostatic_potential(lpt, save_plt=False, save_csv=False) # gradient in eV g = p['gradient'].to_numpy() ratio = int(vac_thickness) / (int(vac_thickness) + int(slab_thickness)) # check if slab is centred so can get the gradient if 0.45 < slab.center_of_mass[2] < 0.55: # divide by 2 bc two regions, 0.75 is a scaling factor that # should hopefully work to avoid any charge from dangling # bonds? a = int(len(g) * ratio / 2 * 0.75) gradient_list.append(np.mean(g[:a]) * 1000) else: a = int(len(g) * ratio * 0.75) # if atoms are more towards the end of the slab, the start # should be vacuum if slab.center_of_mass[2] > 0.5: gradient_list.append(np.mean(g[:a]) * 1000) # and then if atoms are at the start, the vacuum is at # the end else: gradient_list.append(np.mean(g[(len(g) - a):]) * 1000) if get_core: core_energy_list.append( core_energy(core_atom, bulk_nn, outcar=otc_path, structure=slab, **kwargs)) return [df_list, electrostatic_list, core_energy_list, gradient_list]
#!/shared/apps/.intel/2019/python/3.6.8/bin/python import numpy as np import matplotlib.pyplot as plt from pymatgen.io.vasp.outputs import Vasprun vaspout = Vasprun("./vasprun.xml") vaspout_dict = vaspout.as_dict() incar_input = vaspout.incar print('') if 'LOPTICS' in incar_input: if incar_input['LOPTICS'] == True: print('"LOPTICS = .TRUE." found in INCAR \n') epsilon = vaspout.dielectric real_part_0 = epsilon[1][0] print('Real part of dielectric function at 0 frequency:') print(real_part_0) print('') if 'LEPSILON' in incar_input: if incar_input['LEPSILON'] == True: print('"LEPSILON = .TRUE." found in INCAR \n') if incar_input['IBRION'] == 8: print('"IBRION = 8" found in INCAR \n') epsilon_static = vaspout.epsilon_static print('Macroscopic static dielectric tensor:') print(epsilon_static) print('')
def fetch_cached(self, candidate_data): """ Fetches cached data based on candidate data Args: candidate_data (pd.DataFrame): Pandas dataframe Returns: (pandas.DataFrame) dataframe with data filled out """ tri_path = os.environ.get("TRI_PATH") tri_bucket = os.environ.get("TRI_BUCKET") s3_client = boto3.client("s3") cached_experiments = pd.DataFrame() for structure_id, row in candidate_data.iterrows(): calc_path = os.path.join(self.parent_dir, get_chemsys(row['structure']), structure_id.replace('-', ''), "_1/") # Scrub tri_path and replace model with simulation # to get s3 key calc_path = calc_path.replace(tri_path + '/', "") calc_path = calc_path.replace('model', 'simulation') with ScratchDir('.'): # Figure out whether prior submission exists response = s3_client.list_objects_v2(Bucket=tri_bucket, Prefix=calc_path, Delimiter='/') if response.get('Contents'): cached_experiments = cached_experiments.append(row) # TODO: figure out whether file exists in s3 # TODO: this is a little crude, could use boto3 try: # import pdb; pdb.set_trace() vr_path = os.path.join(calc_path, "static", "vasprun.xml") cmd = "aws s3 cp s3://{}/{} .".format( tri_bucket, vr_path) subprocess.call(shlex.split(cmd)) vr = Vasprun("vasprun.xml") vr_dict = vr.as_dict() delta_e = get_qmpy_formation_energy( vr_dict["output"]["final_energy_per_atom"], vr_dict["pretty_formula"], 1, ) data = { "status": "SUCCEEDED", "error": None, "result": vr, "delta_e": delta_e, } except Exception as e: error_doc = {} try: err_obj = s3_client.get_object(Bucket=tri_bucket, Key=os.path.join( calc_path, 'err')) errtxt = err_obj['Body'].read().decode('utf-8') error_doc.update({"mc1_stderr": errtxt}) except ClientError: print('No error file for {}'.format(calc_path)) error_doc.update({ "camd_exception": "{}".format(e), "camd_traceback": traceback.format_exc(), }) # Dump error docs to avoid Pandas issues with dict values data = { "status": "FAILED", "error": json.dumps(error_doc) } update_dataframe_row(cached_experiments, structure_id, data, add_columns=True) return cached_experiments
def parse_energies(hkl, bulk_per_atom, path_to_fols=None, parse_core_energy=False, core_atom=None, bulk_nn=None, parse_vacuum=False, remove_first_energy=False, plt_surfen=True, plt_surfen_fname='surface_energy.png', save_csv=True, csv_fname=None, verbose=False, **kwargs): """ Parses the convergence folders to get the surface energy, total energy, energy per atom, band gap and time taken for each slab and vacuum thickness combination. Calculates surface energies using Fiorentini-Methfessel and Boettger methods. It can optionally parse vacuum and core level energies. ``path_to_fols`` specifies the parent directory containing subdirectories that must include the miller index specified. e.g. if ``hkl=(0,0,1)`` there must be a ``001/`` subdirectory present somewhere on the path. Each directory within the subdirectory must contain a vasprun.xml and OUTCAR file. Args: hkl (`tuple`): Miller index of the slab. bulk_per_atom (`float`): Bulk energy per atom from a converged bulk calculation in eV per atom. path_to_fols (`str`, optional): Path to the convergence folders. Defaults to None which is cwd parse_core_energy (`bool`, optional): If ``True`` the script attempts to parse core energies from a supplied OUTCAR. Defaults to ``False``. core_atom (`str`, optional): The symbol of atom the core state energy level should be parsed from. Defaults to ``None``. bulk_nn (`list`, optional): The symbols of the nearest neighbours of the `core_atom`. Defaults to ``None``. parse_vacuum (`bool`, optional): if ``True`` the script attempts to parse LOCPOT using analysis.electrostatic_potential to use the max value of planar potential as the vacuum energy level (eV). It also calculates the average gradient of the vacuum region (meV). Defaults to ``False``. remove_first_energy (`bool`, optional): Remove the first data point in calculation of Fiorentini-Metfessel and Boettger surface energy. Use if the first energy is somewhat of an outlier. plt_surfen (`bool`, optional): Plots the surface energy. Defaults to ``True``. plt_surfen_fname (`str`, optional): The name of the surface energy plot. Defaults to ``surface_energy.png`` save_csv (`bool`, optional): Saves the csv. Defaults to ``True``. csv_fname (`str`, optional): Name of the csv file to save. Defaults to hkl_data.csv, where hkl are the miller indices. verbose (`bool`, optional): Whether or not to print extra info about the folders being parsed. Defaults to ``False``. Returns: DataFrame """ # Update kwargs for core energy get_core_energy_kwargs = { 'orbital': '1s', 'ox_states': None, 'nn_method': CrystalNN() } get_core_energy_kwargs.update( (k, kwargs[k]) for k in get_core_energy_kwargs.keys() & kwargs.keys()) get_core = False if parse_core_energy: if core_atom is not None and bulk_nn is not None: get_core = True else: warnings.formatwarning = _custom_formatwarning warnings.warn(('Core atom or bulk nearest neighbours were not ' 'supplied. Core energy will not be parsed.')) # Set directory cwd = os.getcwd() if path_to_fols is None else path_to_fols # Get all paths to slab_vac_index folders list_of_paths = [] for root, fols, files in os.walk(cwd): for fol in fols: # Perform a loose check that we are looking in the right place, # also avoid .ipynb_checkpoint files if ''.join(map(str, hkl)) in root.split('/') and '.' not in fol: if len(fol.split('_')) == 3: list_of_paths.append([ os.path.join(root, fol), fol.split('_')[0], fol.split('_')[1], fol.split('_')[2] ]) if verbose: print(root, fol) if len(list_of_paths) > 20 and parse_core_energy: warnings.formatwarning = _custom_formatwarning warnings.warn( ('Determining core energies for {} slabs may be slow. ' 'Running on {} cores.').format(len(list_of_paths), multiprocessing.cpu_count())) # Check if multiple cores are available, iterate through paths to folders # and parse folders if multiprocessing.cpu_count() > 1: with multiprocessing.Pool() as pool: mp_list = pool.starmap( functools.partial(_mp_helper_energy, parse_vacuum, get_core, hkl, core_atom=core_atom, bulk_nn=bulk_nn, **get_core_energy_kwargs), list_of_paths) # len(mp_list) == len(list_of_paths), mp_list[0][0] the is main data # collected for the dataframe, mp_list[0][1] are the potentials, # mp_list[0][2] are the core energies df_list = list(itertools.chain.from_iterable([i[0] for i in mp_list])) electrostatic_list = list( itertools.chain.from_iterable([i[1] for i in mp_list])) core_energy_list = list( itertools.chain.from_iterable([i[2] for i in mp_list])) gradient_list = list( itertools.chain.from_iterable([i[3] for i in mp_list])) else: df_list, electrostatic_list, core_energy_list, gradient_list = ( [] for i in range(4)) for path, slab_thickness, vac_thickness, slab_index in list_of_paths: vsp_path = '{}/vasprun.xml'.format(path) otc_path = '{}/OUTCAR'.format(path) # instantiate structure, slab, vasprun and outcar objects vsp = Vasprun(vsp_path, parse_potcar_file=False) otc = Outcar(otc_path) slab = slab_from_file(vsp.final_structure, hkl) vsp_dict = vsp.as_dict() # extract the time data otc_times = otc.run_stats df_list.append({ 'hkl_string': ''.join(map(str, hkl)), 'hkl_tuple': hkl, 'slab_thickness': slab_thickness, 'vac_thickness': vac_thickness, 'slab_index': slab_index, 'atoms': vsp_dict['nsites'], 'area': slab.surface_area, 'bandgap': vsp_dict['output']['bandgap'], 'slab_energy': vsp_dict['output']['final_energy'], 'slab_per_atom': vsp_dict['output']['final_energy_per_atom'], 'time_taken': otc_times['Elapsed time (sec)'] }) if parse_vacuum: # get value of potential in vacuum electrostatic_list.append(vacuum(path)) lpt = '{}/LOCPOT'.format(path) p = electrostatic_potential(lpt, save_plt=False, save_csv=False) # gradient in eV g = p['gradient'].to_numpy() ratio = int(vac_thickness) / (int(vac_thickness) + int(slab_thickness)) # check if slab is centred so can get the gradient if 0.45 < slab.center_of_mass[2] < 0.55: # divide by 2 bc two regions, 0.75 is a scaling factor that # should hopefully work to avoid any charge from dangling # bonds? # mean is in meV a = int(len(g) * ratio / 2 * 0.75) gradient_list.append(np.mean(g[:a]) * 1000) else: a = int(len(g) * ratio * 0.75) # if atoms are more towards the end of the slab, the start # should be vacuum if slab.center_of_mass[2] > 0.5: gradient_list.append(np.mean(g[:a]) * 1000) # meV # and then if atoms are at the start, the vacuum is at # the end else: gradient_list.append(np.mean(g[(len(g) - a):]) * 1000) if get_core: core_energy_list.append( core_energy(core_atom, bulk_nn, outcar=otc_path, structure=slab, **get_core_energy_kwargs)) df = pd.DataFrame(df_list) if electrostatic_list: df['vacuum_potential'] = electrostatic_list if gradient_list: df['vacuum_gradient'] = gradient_list # in meV if core_energy_list: df['core_energy'] = core_energy_list df['surface_energy'] = ((df['slab_energy'] - bulk_per_atom * df['atoms']) / (2 * df['area']) * 16.02) # Add Fiorentini-Methfessel and Boettger methods for calculating # surface energies dfs = [] for index in df.groupby('slab_index'): df_index = index[1].sort_values('vac_thickness') for group in df_index.groupby('vac_thickness'): df2 = group[1].sort_values('slab_thickness') # deepcopy to keep it fresh df3 = copy.deepcopy(df2) # Fiorentini-methfessel # remove first data point if it's too much of an outlier and there are # more than three data points if remove_first_energy and len(df2['atoms']) >= 3: x = np.delete(df2['atoms'].to_numpy(), 0).reshape(-1, 1) y = np.delete(df2['slab_energy'].to_numpy(), 0) else: x = df2['atoms'].to_numpy().reshape(-1, 1) y = df2['slab_energy'].to_numpy() model = LinearRegression().fit(x, y) df3['surface_energy_fm'] = ( (df3['slab_energy'] - model.coef_ * df3['atoms']) / (2 * df3['area']) * 16.02) # Boettger # new dataframe, just in case df4 = group[1].sort_values('slab_thickness') if remove_first_energy and len(df4['atoms']) >= 3: # big energy = M+1 layers energy, small energy = M layers, # calculating bulk energy for M layers # remove first two from M+1 energy, add a nan in place of one and # at the end; also replace the first from the M energies with nan; # same with atoms big_energy = df4['slab_energy'].iloc[2:].to_numpy() big_energy = np.append(big_energy, np.nan) big_energy = np.insert(big_energy, 0, np.nan) small_energy = df4['slab_energy'].iloc[1:].to_numpy() small_energy = np.insert(small_energy, 0, np.nan) big_atoms = df4['atoms'].iloc[2:].to_numpy() big_atoms = np.append(big_atoms, np.nan) big_atoms = np.insert(big_atoms, 0, np.nan) small_atoms = df4['atoms'].astype('float').iloc[1:].to_numpy() small_atoms = np.insert(small_atoms, 0, np.nan) else: # need to remove the first from big energy and add a nan at the end big_energy = df4['slab_energy'].iloc[1:].to_numpy() big_energy = np.append(big_energy, np.nan) small_energy = df4['slab_energy'].to_numpy() big_atoms = df4['atoms'].iloc[1:].to_numpy() big_atoms = np.append(big_atoms, np.nan) small_atoms = df4['atoms'].to_numpy() # difference M+1 - M, get bulk energy from E(M+1)-E(M) / (M+1)-M diff_energy = big_energy - small_energy diff_atoms = big_atoms - small_atoms bulk_energies = diff_energy / diff_atoms # make last energy a nan to get a nan surface energy small_energy[-1] = np.nan df3['surface_energy_boettger'] = ( (small_energy - df3['atoms'] * bulk_energies) / (2 * df3['area']) * 16.02) dfs.append(df3) # Concat list back to one dataframe df = pd.concat(dfs) if remove_first_energy and len(df2['atoms']) < 3: warnings.formatwarning = _custom_formatwarning warnings.warn('First data point was not removed - less than three ' 'data points were present in dataset') # Plot surface energy plt_kwargs = {'colors': None, 'width': 6, 'height': 5} plt_kwargs.update( (k, kwargs[k]) for k in plt_kwargs.keys() & kwargs.keys()) if plt_surfen: plot_surfen(df, plt_fname=plt_surfen_fname, **plt_kwargs) # Save the csv or return the dataframe if save_csv: csv_fname = '{}_data.csv'.format(''.join(map( str, hkl))) if csv_fname is None else csv_fname if not csv_fname.endswith('.csv'): csv_fname += '.csv' df.to_csv(csv_fname, header=True, index=False) else: return df
print('Phase total energy p.f.u.\n') for dir in list_dir: path = os.path.dirname(dir) # identifying last folder of path subfold = os.path.basename(path) # getting name for the phase from the directory name phase = subfold # build path of OUTCAR file path_vasprun = (dir + 'vasprun.xml') vasprun = Vasprun(path_vasprun) # getting total energy PER FORMULA UNIT total_energy = vasprun.final_energy vasprun_dict = vasprun.as_dict() # n° atoms in calculation nsites = vasprun_dict['nsites'] # dictionary for reduced cell composition reduced_cell_formula = vasprun_dict['reduced_cell_formula'] # n° atoms per formula unit nsites_pfu = 0 for el in reduced_cell_formula: nsites_pfu += reduced_cell_formula[el] # n° of formula units in calculation n_formula_units = nsites / nsites_pfu total_energy_pfu = total_energy / n_formula_units # writing computed phases dictionary computed_phases.update({phase: total_energy_pfu})
def test_properties(self): filepath = os.path.join(test_dir, 'vasprun.xml.nonlm') vasprun = Vasprun(filepath, parse_potcar_file=False) orbs = list(vasprun.complete_dos.pdos[vasprun.final_structure[ 0]].keys()) self.assertIn(OrbitalType.s, orbs) filepath = os.path.join(test_dir, 'vasprun.xml') vasprun = Vasprun(filepath, parse_potcar_file=False) #Test NELM parsing. self.assertEqual(vasprun.parameters["NELM"], 60) #test pdos parsing pdos0 = vasprun.complete_dos.pdos[vasprun.final_structure[0]] self.assertAlmostEqual(pdos0[Orbital.s][Spin.up][16], 0.0026) self.assertAlmostEqual(pdos0[Orbital.pz][Spin.down][16], 0.0012) self.assertEqual(pdos0[Orbital.s][Spin.up].shape, (301, )) filepath2 = os.path.join(test_dir, 'lifepo4.xml') vasprun_ggau = Vasprun(filepath2, parse_projected_eigen=True, parse_potcar_file=False) totalscsteps = sum([len(i['electronic_steps']) for i in vasprun.ionic_steps]) self.assertEqual(29, len(vasprun.ionic_steps)) self.assertEqual(len(vasprun.structures), len(vasprun.ionic_steps)) self.assertEqual(vasprun.lattice, vasprun.lattice_rec.reciprocal_lattice) for i, step in enumerate(vasprun.ionic_steps): self.assertEqual(vasprun.structures[i], step["structure"]) self.assertTrue(all([vasprun.structures[i] == vasprun.ionic_steps[i][ "structure"] for i in range(len(vasprun.ionic_steps))])) self.assertEqual(308, totalscsteps, "Incorrect number of energies read from vasprun.xml") self.assertEqual(['Li'] + 4 * ['Fe'] + 4 * ['P'] + 16 * ["O"], vasprun.atomic_symbols) self.assertEqual(vasprun.final_structure.composition.reduced_formula, "LiFe4(PO4)4") self.assertIsNotNone(vasprun.incar, "Incar cannot be read") self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.eigenvalues, "Eigenvalues cannot be read") self.assertAlmostEqual(vasprun.final_energy, -269.38319884, 7) self.assertAlmostEqual(vasprun.tdos.get_gap(), 2.0589, 4) expectedans = (2.539, 4.0906, 1.5516, False) (gap, cbm, vbm, direct) = vasprun.eigenvalue_band_properties self.assertAlmostEqual(gap, expectedans[0]) self.assertAlmostEqual(cbm, expectedans[1]) self.assertAlmostEqual(vbm, expectedans[2]) self.assertEqual(direct, expectedans[3]) self.assertFalse(vasprun.is_hubbard) self.assertEqual(vasprun.potcar_symbols, ['PAW_PBE Li 17Jan2003', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE P 17Jan2003', 'PAW_PBE O 08Apr2002']) self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints, "Actual kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints_weights, "Actual kpoints weights cannot be read") for atomdoses in vasprun.pdos: for orbitaldos in atomdoses: self.assertIsNotNone(orbitaldos, "Partial Dos cannot be read") # test skipping ionic steps. vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False) self.assertEqual(vasprun_skip.nionic_steps, 29) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) self.assertEqual(len(vasprun_skip.ionic_steps), len(vasprun_skip.structures)) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) # Check that nionic_steps is preserved no matter what. self.assertEqual(vasprun_skip.nionic_steps, vasprun.nionic_steps) self.assertNotAlmostEqual(vasprun_skip.final_energy, vasprun.final_energy) # Test with ionic_step_offset vasprun_offset = Vasprun(filepath, 3, 6, parse_potcar_file=False) self.assertEqual(len(vasprun_offset.ionic_steps), int(len(vasprun.ionic_steps) / 3) - 1) self.assertEqual(vasprun_offset.structures[0], vasprun_skip.structures[2]) self.assertTrue(vasprun_ggau.is_hubbard) self.assertEqual(vasprun_ggau.hubbards["Fe"], 4.3) self.assertAlmostEqual(vasprun_ggau.projected_eigenvalues[(Spin.up, 0, 0, 96, Orbital.s)], 0.0032) d = vasprun_ggau.as_dict() self.assertEqual(d["elements"], ["Fe", "Li", "O", "P"]) self.assertEqual(d["nelements"], 4) filepath = os.path.join(test_dir, 'vasprun.xml.unconverged') with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. vasprun_unconverged = Vasprun(filepath, parse_potcar_file=False) # Verify some things self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, UnconvergedVASPWarning)) self.assertTrue(vasprun_unconverged.converged_ionic) self.assertFalse(vasprun_unconverged.converged_electronic) self.assertFalse(vasprun_unconverged.converged) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt') vasprun_dfpt = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][0], 3.26105533) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][1], -0.00459066) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[2][2], 3.24330517) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][0], 3.33402531) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][1], -0.00559998) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[2][2], 3.31237357) self.assertTrue(vasprun_dfpt.converged) entry = vasprun_dfpt.get_computed_entry() entry = MaterialsProjectCompatibility(check_potcar_hash=False).process_entry(entry) self.assertAlmostEqual(entry.uncorrected_energy + entry.correction, entry.energy) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.ionic') vasprun_dfpt_ionic = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][0], 515.73485838) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][1], -0.00263523) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[2][2], 19.02110169) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.unconverged') vasprun_dfpt_unconv = Vasprun(filepath, parse_potcar_file=False) self.assertFalse(vasprun_dfpt_unconv.converged_electronic) self.assertTrue(vasprun_dfpt_unconv.converged_ionic) self.assertFalse(vasprun_dfpt_unconv.converged) vasprun_uniform = Vasprun(os.path.join(test_dir, "vasprun.xml.uniform"), parse_potcar_file=False) self.assertEqual(vasprun_uniform.kpoints.style, Kpoints.supported_modes.Reciprocal) vasprun_no_pdos = Vasprun(os.path.join(test_dir, "Li_no_projected.xml"), parse_potcar_file=False) self.assertIsNotNone(vasprun_no_pdos.complete_dos) self.assertFalse(vasprun_no_pdos.dos_has_errors) vasprun_diel = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric"), parse_potcar_file=False) self.assertAlmostEqual(0.4294,vasprun_diel.dielectric[0][10]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][0]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][1]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[1][51][3]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][0]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][1]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[2][85][3]) v = Vasprun(os.path.join(test_dir, "vasprun.xml.indirect.gz")) (gap, cbm, vbm, direct) = v.eigenvalue_band_properties self.assertFalse(direct)
def get_dos(vasprun_dos): ## get CompleteDos object and "save" in hidden div in json format dos = Vasprun(vasprun_dos).complete_dos return json.dumps(dos.as_dict())