def process_task(self, path): try: #Override incorrect outcar subdocs for two step relaxations if os.path.exists(os.path.join(path, "relax2")): try: run_stats = {} for i in [1,2]: outcar = Outcar(zpath(os.path.join(path,"relax"+str(i), "OUTCAR"))) m_key = "calculations."+str(i-1)+".output.outcar" self.tasks.update({'dir_name_full': path}, {'$set': {m_key: outcar.as_dict()}}) run_stats["relax"+str(i)] = outcar.run_stats except: logger.error("Bad OUTCAR for {}.".format(path)) try: overall_run_stats = {} for key in ["Total CPU time used (sec)", "User time (sec)", "System time (sec)", "Elapsed time (sec)"]: overall_run_stats[key] = sum([v[key] for v in run_stats.values()]) run_stats["overall"] = overall_run_stats except: logger.error("Bad run stats for {}.".format(path)) self.tasks.update({'dir_name_full': path}, {'$set': {"run_stats": run_stats}}) print 'FINISHED', path else: print 'SKIPPING', path except: print '-----' print 'ENCOUNTERED AN EXCEPTION!!!', path traceback.print_exc() print '-----'
def check(self): incar = Incar.from_file("INCAR") is_npt = incar.get("MDALGO") == 3 if not is_npt: return False outcar = Outcar("OUTCAR") patterns = {"MDALGO": "MDALGO\s+=\s+([\d]+)"} outcar.read_pattern(patterns=patterns) if outcar.data["MDALGO"] == [['3']]: return False else: return True
def run_task(self, fw_spec): wd = os.getcwd() IrrepCaller(wd) try: raw_struct = Structure.from_file(wd + "/POSCAR") formula = raw_struct.composition.formula structure = raw_struct.as_dict() outcar = Outcar(wd + "/OUTCAR") efermi = outcar.efermi nelect = outcar.nelect except FileNotFoundError: formula = None structure = None efermi = None nelect = None data = IrrepOutput(wd + "/outir.txt", efermi=efermi) return FWAction( update_spec={ "irrep_out": data.as_dict(), "structure": structure, "formula": formula, "efermi": efermi, "nelect": nelect, })
def run_task(self, fw_spec): wd = os.getcwd() IRVSPCaller(wd) try: raw_struct = Structure.from_file(wd + "/POSCAR") formula = raw_struct.composition.formula structure = raw_struct.as_dict() outcar = Outcar(wd + "/OUTCAR") efermi = outcar.efermi except: formula = None structure = None efermi = None data = IRVSPOutput(wd + "/outir.txt") return FWAction( update_spec={ "irvsp_out": data.as_dict(), "structure": structure, "formula": formula, "efermi": efermi, } )
def test_make_perfect_band_edge_state_from_vasp(vasp_files): procar = Procar(vasp_files / "MgO_2x2x2_perfect" / "PROCAR") vasprun = Vasprun(vasp_files / "MgO_2x2x2_perfect" / "vasprun.xml") outcar = Outcar(vasp_files / "MgO_2x2x2_perfect" / "OUTCAR") actual = make_perfect_band_edge_state_from_vasp(procar, vasprun, outcar) vbm_info = EdgeInfo(band_idx=127, kpt_coord=(0.25, 0.25, 0.25), orbital_info=OrbitalInfo(energy=2.7746, orbitals={ 'Mg': [0.0, 0.0, 0.0, 0.0], 'O': [0.0, 0.704, 0.0, 0.0] }, occupation=1.0)) cbm_info = EdgeInfo(band_idx=128, kpt_coord=(0.25, 0.25, 0.25), orbital_info=OrbitalInfo(energy=8.2034, orbitals={ 'Mg': [0.192, 0.0, 0.0, 0.0], 'O': [0.224, 0.096, 0.0, 0.0] }, occupation=0.0)) expected = PerfectBandEdgeState(vbm_info=vbm_info, cbm_info=cbm_info) assert actual == expected
def test_band_edge_properties_from_vasp(test_data_files): vasprun_file = str(test_data_files / "MnO_uniform_vasprun.xml") vasprun = Vasprun(vasprun_file) outcar_file = str(test_data_files / "MnO_uniform_OUTCAR") outcar = Outcar(outcar_file) band_edge = VaspBandEdgeProperties(vasprun, outcar) assert pytest.approx(band_edge.band_gap) == 0.4702
def make_calc_results(args): for d in args.dirs: logger.info(f"Parsing data in {d} ...") calc_results = make_calc_results_from_vasp( vasprun=Vasprun(d / defaults.vasprun), outcar=Outcar(d / defaults.outcar)) calc_results.to_json_file(filename=Path(d) / "calc_results.json")
def calc_effective_mass(args: Namespace): vasprun, outcar = Vasprun(args.vasprun), Outcar(args.outcar) band_edge_prop = VaspBandEdgeProperties(vasprun, outcar) effective_mass = make_effective_mass(vasprun, args.temperature, args.concentrations, band_edge_prop.band_gap) print(effective_mass)
def get_magnetizations(mydir, ion_list): data = [] max_row = 0 for (parent, subdirs, files) in os.walk(mydir): for f in files: if re.match(r"OUTCAR*", f): try: row = [] fullpath = os.path.join(parent, f) outcar = Outcar(fullpath) mags = outcar.magnetization mags = [m["tot"] for m in mags] all_ions = list(range(len(mags))) row.append(fullpath.lstrip("./")) if ion_list: all_ions = ion_list for ion in all_ions: row.append(str(mags[ion])) data.append(row) if len(all_ions) > max_row: max_row = len(all_ions) except: pass for d in data: if len(d) < max_row + 1: d.extend([""] * (max_row + 1 - len(d))) headers = ["Filename"] for i in range(max_row): headers.append(str(i)) print(tabulate(data, headers))
def postprocess(self): """ Postprocessing includes renaming and gzipping where necessary. Also copies the magmom to the incar if necessary """ for f in VASP_OUTPUT_FILES + [self.output_file]: if os.path.exists(f): if self.final and self.suffix != "": shutil.move(f, "{}{}".format(f, self.suffix)) elif self.suffix != "": shutil.copy(f, "{}{}".format(f, self.suffix)) if self.copy_magmom and not self.final: try: outcar = Outcar("OUTCAR") magmom = [m['tot'] for m in outcar.magnetization] incar = Incar.from_file("INCAR") incar['MAGMOM'] = magmom incar.write_file("INCAR") except: logger.error('MAGMOM copy from OUTCAR to INCAR failed') # Remove continuation so if a subsequent job is run in # the same directory, will not restart this job. if os.path.exists("continue.json"): os.remove("continue.json")
def data_from_outcars_in_folder(folder): initLogging() if not os.path.exists(config['data_load_file']): different_energies = [] different_structures = [] poscar = Poscar.from_file(folder + '/POSCAR') logging.info('Assigned Spin values Energy Unique energy FilePath') for outcar_file in sorted(glob.glob(folder + '/OUTCAR*')): structure = poscar.structure.copy() magnetic_element_index = [ n for n, e in enumerate(structure) if e.species_string in config['magnetic_elements'] ] magnetic_substructure = Structure.from_sites([ e for e in structure if e.species_string in config['magnetic_elements'] ]) outcar = Outcar(outcar_file) try: magnetization = np.array([ entry['tot'] for entry in outcar.magnetization ])[magnetic_element_index] except IndexError: logging.info(f'Bad OUTCAR: {outcar_file}') continue spins = np.zeros_like(magnetization) for i, m in enumerate(magnetization): spins[i] = np.sign(m) * config['spin_values'][i] #if abs(m) > config['spin_threshold']: # spins[i] = config['spin_value'] * np.sign(m) magnetic_substructure.add_spin_by_site(spins) magnetic_substructure.vasp_energy = outcar.final_energy magnetic_substructure.name = outcar_file.split('/')[-1] isUnique = False if is_unique(different_energies, magnetic_substructure.vasp_energy, 1e-15): different_energies.append(magnetic_substructure.vasp_energy) isUnique = True different_structures.append(magnetic_substructure) #energy_checked = np.round(magnetic_substructure.vasp_energy, decimals=3) #if not np.in1d(energy_checked, different_energies).any(): # different_energies.append(energy_checked) # isUnique = True # different_structures.append(magnetic_substructure) logging.info((spins, magnetic_substructure.vasp_energy, isUnique, outcar_file)) logging.info( f'Data reading complete, saving to {config["data_load_file"]}') with open(config['data_load_file'], 'wb') as f: pickle.dump(different_structures, f) logging.info('Data load complete. Rerun script') import sys sys.exit() else: with open(config['data_load_file'], 'rb') as f: different_structures = pickle.load(f) for s in different_structures: logging.info(s.vasp_energy) return different_structures
def plot_absorption(args: Namespace): diele_func_data = make_diele_func(Vasprun(args.vasprun), Outcar(args.outcar), use_vasp_real=not args.calc_kk, ita=args.ita) plotter = AbsorptionCoeffMplPlotter(diele_func_data, yranges=args.y_ranges) plotter.construct_plot() plotter.plt.savefig(args.filename, format="pdf")
def test_make_diele_func_2(test_data_files): v = Vasprun(test_data_files / "MgSe_absorption_vasprun_gamma.xml") o = Outcar(test_data_files / "MgSe_absorption_OUTCAR_gamma") actual = make_shifted_diele_func(make_diele_func(v, o), original_band_gap=1.997, shift=1.0) assert isinstance(actual.diele_func_imag[0], list) assert isinstance(actual.diele_func_imag[0][0], float)
def test_band_edge_properties_from_vasp_non_mag(test_data_files): vasprun_file = str(test_data_files / "MgO_band_vasprun.xml") vasprun = Vasprun(vasprun_file) outcar_file = str(test_data_files / "MgO_band_OUTCAR") outcar = Outcar(outcar_file) band_edge = VaspBandEdgeProperties(vasprun, outcar) assert pytest.approx(band_edge.band_gap) == 4.6597
def make_perfect_band_edge_state(args): procar = Procar(args.dir / defaults.procar) vasprun = Vasprun(args.dir / defaults.vasprun) outcar = Outcar(args.dir / defaults.outcar) perfect_band_edge_state = \ make_perfect_band_edge_state_from_vasp(procar, vasprun, outcar) perfect_band_edge_state.to_json_file(args.dir / "perfect_band_edge_state.json")
def process_task(self, path): try: #Override incorrect outcar subdocs for two step relaxations if os.path.exists(os.path.join(path, "relax2")): try: run_stats = {} for i in [1, 2]: outcar = Outcar( zpath( os.path.join(path, "relax" + str(i), "OUTCAR"))) m_key = "calculations." + str(i - 1) + ".output.outcar" self.tasks.update({'dir_name_full': path}, {'$set': { m_key: outcar.as_dict() }}) run_stats["relax" + str(i)] = outcar.run_stats except: logger.error("Bad OUTCAR for {}.".format(path)) try: overall_run_stats = {} for key in [ "Total CPU time used (sec)", "User time (sec)", "System time (sec)", "Elapsed time (sec)" ]: overall_run_stats[key] = sum( [v[key] for v in run_stats.values()]) run_stats["overall"] = overall_run_stats except: logger.error("Bad run stats for {}.".format(path)) self.tasks.update({'dir_name_full': path}, {'$set': { "run_stats": run_stats }}) print 'FINISHED', path else: print 'SKIPPING', path except: print '-----' print 'ENCOUNTERED AN EXCEPTION!!!', path traceback.print_exc() print '-----'
def magnetic_moments(self, outcar): """ Extracts magnetic moments. Returns: list """ mag = Outcar(outcar).magnetization return [[0, 0, ion['tot']] if isinstance(ion['tot'], float) else ion['tot'].moment.tolist() for ion in mag]
def make_unitcell_from_vasp(vasprun_band: Vasprun, outcar_band: Outcar, outcar_dielectric_clamped: Outcar, outcar_dielectric_ionic: Outcar, system_name: str = None) -> Unitcell: name = (system_name or vasprun_band.final_structure.composition.reduced_formula) outcar_dielectric_clamped.read_lepsilon() outcar_dielectric_ionic.read_lepsilon_ionic() band_edge_properties = VaspBandEdgeProperties(vasprun_band, outcar_band) vbm, cbm = band_edge_properties.vbm_cbm return Unitcell( system=name, # vbm and cbm are <class 'numpy.float64'>. vbm=float(vbm), cbm=float(cbm), ele_dielectric_const=outcar_dielectric_clamped.dielectric_tensor, ion_dielectric_const=outcar_dielectric_ionic.dielectric_ionic_tensor)
def test_make_calc_results_from_vasp_results(vasp_files): vasprun = Vasprun(vasp_files / "MgO_conv_Va_O_0" / "vasprun.xml") outcar = Outcar(vasp_files / "MgO_conv_Va_O_0" / "OUTCAR") results = make_calc_results_from_vasp(vasprun, outcar) expected_structure = \ Structure.from_file(vasp_files / "MgO_conv_Va_O_0" / "CONTCAR") assert results.structure == expected_structure assert results.energy == -34.91084360 assert results.magnetization == 1.03e-05 assert results.potentials ==\ [35.9483, 36.066, 35.948, 35.9478, 69.799, 69.7994, 69.7995]
def pot_al(outcar, ref_outcar, tol=0.5): """ given a reference outcar, and a outcar of interest, will calculate a potential alignment: args: outcar: outcar from defect calculation ref_outcar: outcar from stoichiometric calculation tol: tolerance factor for electrostatic potentials considered 'far' from the defect """ avg_defect = [] avg_ref = [] for i, j in zip( Outcar.read_avg_core_poten(ref_outcar)[-1], Outcar.read_avg_core_poten(outcar)[-1]): diff = i - j if diff < tol and diff > -tol: avg_defect.append(j) avg_ref.append(i) plt.plot(avg_defect) plt.plot(avg_ref) pot_al = np.mean(np.array(avg_defect)) - np.mean(np.array(avg_ref)) return pot_al
def make_composition_energies(args): if args.yaml_file: composition_energies = CompositionEnergies.from_yaml(args.yaml_file) else: composition_energies = CompositionEnergies() for d in args.dirs: outcar = Outcar(d / defaults.outcar) composition = Structure.from_file(d / defaults.contcar).composition energy = float(outcar.final_energy) # original type is FloatWithUnit composition_energies[composition] = CompositionEnergy(energy, "local") composition_energies.to_yaml_file()
def calc_effective_mass(args: Namespace): vasprun, outcar = Vasprun(args.vasprun), Outcar(args.outcar) band_edge_prop = VaspBandEdgeProperties(vasprun, outcar) try: vbm, cbm = band_edge_prop.vbm_cbm except TypeError: logger.warning("Band gap does not exist, so not suited for effective" "mass calculation.") return effective_mass = make_effective_mass(vasprun, args.temperature, args.concentrations, vbm, cbm) print(effective_mass)
def test_runs_assimilate(self): drone = VaspDrone(runs=["relax1", "relax2"]) doc = drone.assimilate(self.relax2) oszicar2 = Oszicar(os.path.join(self.relax2, "OSZICAR.relax2.gz")) outcar1 = Outcar(os.path.join(self.relax2, "OUTCAR.relax1.gz")) outcar2 = Outcar(os.path.join(self.relax2, "OUTCAR.relax2.gz")) outcar1 = outcar1.as_dict() outcar2 = outcar2.as_dict() run_stats1 = outcar1.pop("run_stats") run_stats2 = outcar2.pop("run_stats") self.assertEqual(len(doc["calcs_reversed"]), 2) self.assertEqual(doc["composition_reduced"], {"Si": 1.0}) self.assertEqual(doc["composition_unit_cell"], {"Si": 2.0}) self.assertAlmostEqual(doc["output"]["energy"], oszicar2.ionic_steps[-1]["E0"]) self.assertEqual(doc["formula_pretty"], "Si") self.assertEqual(doc["formula_anonymous"], "A") self.assertEqual(list(doc["calcs_reversed"][0]["input"].keys()), list(doc["calcs_reversed"][1]["input"].keys())) self.assertEqual( list(doc["calcs_reversed"][0]["output"].keys()), list(doc["calcs_reversed"][1]["output"].keys()) ) self.assertEqual(doc["calcs_reversed"][0]["output"]["energy"], doc["output"]["energy"]) self.assertEqual(doc["run_stats"][doc["calcs_reversed"][0]["task"]["name"]], run_stats2) self.assertEqual(doc["run_stats"][doc["calcs_reversed"][1]["task"]["name"]], run_stats1) self.assertEqual(doc["calcs_reversed"][0]["output"]["outcar"], outcar2) self.assertEqual(doc["calcs_reversed"][1]["output"]["outcar"], outcar1)
def make_edge_characters(args): for d in args.dirs: logger.info(f"Parsing data in {d} ...") vasprun = Vasprun(d / defaults.vasprun) procar = Procar(d / defaults.procar) outcar = Outcar(d / defaults.outcar) calc_results = loadfn(d / "calc_results.json") structure_analyzer = DefectStructureAnalyzer( calc_results.structure, args.perfect_calc_results.structure) edge_characters = MakeEdgeCharacters( procar, vasprun, outcar, structure_analyzer.neighboring_atom_indices).edge_characters edge_characters.to_json_file(d / "edge_characters.json")
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if "lrf_comm" in self.errors: if Outcar(zpath(os.path.join( os.getcwd(), "OUTCAR"))).is_stopped is False: if not vi["INCAR"].get("LPEAD"): actions.append({"dict": "INCAR", "action": {"_set": {"LPEAD": True}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def check(self): incar = Incar.from_file("INCAR") if incar.get("EDIFFG", 0.1) >= 0 or incar.get("NSW",0) == 0: # Only activate when force relaxing and ionic steps # NSW check prevents accidental effects when running DFPT return False if not self.max_drift: self.max_drift = incar["EDIFFG"] * -1 outcar = Outcar("OUTCAR") if len(outcar.data.get('drift', [])) < self.to_average: # Ensure enough steps to get average drift return False else: curr_drift = outcar.data.get("drift", [])[::-1][:self.to_average] curr_drift = np.average([np.linalg.norm(d) for d in curr_drift]) return curr_drift > self.max_drift
def make_energy_yaml(): dirs = [f.name for f in os.scandir(".") if f.is_dir()] for e in list(Element): e = str(e) if e not in dirs or is_target_element(e) is False: continue try: v = Vasprun(Path(e) / "vasprun.xml") if v.converged_electronic is False: logger.warning(f"Calculation for {e} is not converged.") continue except ParseError: logger.warning(f"Parsing vasprun.xml for {e} failed.") continue outcar = Outcar(Path(e) / "OUTCAR") print(f"{e + ':':<3} {outcar.final_energy:11.8f}")
def postprocess(self): """ Postprocessing includes renaming and gzipping where necessary. Also copies the magmom to the incar if necessary """ for f in VASP_OUTPUT_FILES + [self.output_file]: if os.path.exists(f): if self.final and self.suffix != "": shutil.move(f, "{}{}".format(f, self.suffix)) elif self.suffix != "": shutil.copy(f, "{}{}".format(f, self.suffix)) if self.copy_magmom and not self.final: try: outcar = Outcar("OUTCAR") magmom = [m['tot'] for m in outcar.magnetization] incar = Incar.from_file("INCAR") incar['MAGMOM'] = magmom incar.write_file("INCAR") except: logging.error('MAGMOM copy from OUTCAR to INCAR failed')
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if "lrf_comm" in self.errors: if self.error_count['lrf_comm'] == 0: if Outcar(zpath(os.path.join(os.getcwd(), "OUTCAR"))).is_stopped is False: # simply rerun the job and increment # error count for next time actions.append({ "dict": "INCAR", "action": { "_set": { "ISTART": 1 } } }) self.error_count['lrf_comm'] += 1 if "kpoints_trans" in self.errors: if self.error_count["kpoints_trans"] == 0: m = reduce(operator.mul, vi["KPOINTS"].kpts[0]) m = max(int(round(m**(1 / 3))), 1) if vi["KPOINTS"].style.name.lower().startswith("m"): m += m % 2 actions.append({ "dict": "KPOINTS", "action": { "_set": { "kpoints": [[m] * 3] } } }) self.error_count['kpoints_trans'] += 1 VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def prior_info_from_calc_dir(prev_dir_path: Path, vasprun: str = "vasprun.xml", outcar: str = "OUTCAR", potcar: str = "POTCAR"): vasprun = Vasprun(str(prev_dir_path / vasprun)) outcar = Outcar(str(prev_dir_path / outcar)) potcar = Potcar.from_file(str(prev_dir_path / potcar)) charge = get_net_charge_from_vasp(vasprun.final_structure, vasprun.parameters["NELECT"], potcar) structure = vasprun.final_structure.copy() energy_per_atom = outcar.final_energy / len(structure) band_edge_property = VaspBandEdgeProperties(vasprun, outcar) total_magnetization = outcar.total_mag return PriorInfo(structure=structure, charge=charge, energy_per_atom=energy_per_atom, band_gap=band_edge_property.band_gap, vbm_cbm=band_edge_property.vbm_cbm, total_magnetization=total_magnetization)
def main(): df = pd.read_csv('calc_data.csv') converged = df['converged'] == True few_steps = df['ionic_steps'] < 10 to_run = list(df[converged & few_steps].iloc[:, 0]) converged_calculations = [] for converged_calculation in tqdm(to_run): if os.path.exists( f'mkdir {converged_calculation}/../run.final') == False: os.system(f'mkdir {converged_calculation}/../run.final') outcar = Outcar(f'{converged_calculation}/OUTCAR') mags = [i['tot'] for i in outcar.magnetization] structure = Poscar.from_file( f'{converged_calculation}/CONTCAR').structure structure.add_site_property('magmom', mags) incar = Incar.from_file(f'{converged_calculation}/INCAR') incar.update(static_params) try: del incar['MAGMOM'] except: None potcar = Potcar.from_file(f'{converged_calculation}/POTCAR') calculation = DictSet(structure, { 'INCAR': incar, 'POTCAR': potcar }) calculation.incar.write_file( f'{converged_calculation}/../run.final/INCAR') calculation.poscar.write_file( f'{converged_calculation}/../run.final/POSCAR') os.system( f'cp {converged_calculation}/POTCAR {converged_calculation}/../run.final ; cp {converged_calculation}/job.sh {converged_calculation}/../run.final' ) os.system( f'touch {converged_calculation}/../run.final/vasp_out ; touch {converged_calculation}/../run.final/vasprun.xml' )
def plot_dos(args: Namespace): vasprun = Vasprun(args.vasprun) outcar = Outcar(args.outcar) band_edge = VaspBandEdgeProperties(vasprun, outcar) if band_edge.band_gap: vertical_lines = [band_edge.vbm_info.energy, band_edge.cbm_info.energy] else: vertical_lines = [vasprun.efermi] if args.base_energy is None: base = vertical_lines[0] else: base = args.base_energy dos_data_from_vasp = \ DosDataFromVasp(vasprun, vertical_lines, base, args.crop_first_value) dos_data = dos_data_from_vasp.make_dos_data() ylim_set = None if args.y_max_ranges: if dos_data.spin: ylim_set = [[-y_max, y_max] for y_max in args.y_max_ranges] else: ylim_set = [[0, y_max] for y_max in args.y_max_ranges] structure = vasprun.final_structure grouped_atom_indices = args.type.grouped_atom_indices( structure, args.target) logger.info(f"Grouped atom indices: {grouped_atom_indices}") plot_data = dos_data.dos_plot_data(grouped_atom_indices, xlim=args.x_range, ylim_set=ylim_set) plot_data.to_json_file() plotter = DosPlotter(plot_data, args.legend) plotter.construct_plot() plotter.plt.savefig(args.filename, format="pdf")
def main(): df = pd.read_csv('calc_data.csv') converged = df['converged'] == True few_steps = df['ionic_steps'] < 10 to_scrape = list(df[converged & few_steps].iloc[:, 0]) converged_calculations = [] for converged_calculation in tqdm(to_scrape): vr = Vasprun(f'{converged_calculation}/vasprun.xml', parse_potcar_file=False) entry = vr.get_computed_entry() entry.entry_id = converged_calculation entry_dict = entry.as_dict() if vr.parameters['LORBIT'] == 11: outcar = Outcar(f'{converged_calculation}/OUTCAR') entry_dict.update({'MAGMOMS': outcar.magnetization}) converged_calculations.append(entry_dict) with open('calculation_data.json', 'w') as calc_data: json.dump(converged_calculations, calc_data)
def post_process(self, dir_name, d): """ Simple post-processing for various files other than the vasprun.xml. Called by generate_task_doc. Modify this if your runs have other kinds of processing requirements. Args: dir_name: The dir_name. d: Current doc generated. """ logger.info("Post-processing dir:{}".format(dir_name)) fullpath = os.path.abspath(dir_name) # VASP input generated by pymatgen's alchemy has a # transformations.json file that keeps track of the origin of a # particular structure. This is extremely useful for tracing back a # result. If such a file is found, it is inserted into the task doc # as d["transformations"] transformations = {} filenames = glob.glob(os.path.join(fullpath, "transformations.json*")) if len(filenames) >= 1: with zopen(filenames[0], "rt") as f: transformations = json.load(f) try: m = re.match("(\d+)-ICSD", transformations["history"][0]["source"]) if m: d["icsd_id"] = int(m.group(1)) except Exception as ex: logger.warning("Cannot parse ICSD from transformations " "file.") pass else: logger.warning("Transformations file does not exist.") other_parameters = transformations.get("other_parameters") new_tags = None if other_parameters: # We don't want to leave tags or authors in the # transformations file because they'd be copied into # every structure generated after this one. new_tags = other_parameters.pop("tags", None) new_author = other_parameters.pop("author", None) if new_author: d["author"] = new_author if not other_parameters: # if dict is now empty remove it transformations.pop("other_parameters") d["transformations"] = transformations # Calculations done using custodian has a custodian.json, # which tracks the jobs performed and any errors detected and fixed. # This is useful for tracking what has actually be done to get a # result. If such a file is found, it is inserted into the task doc # as d["custodian"] filenames = glob.glob(os.path.join(fullpath, "custodian.json*")) if len(filenames) >= 1: with zopen(filenames[0], "rt") as f: d["custodian"] = json.load(f) # Parse OUTCAR for additional information and run stats that are # generally not in vasprun.xml. try: run_stats = {} for filename in glob.glob(os.path.join(fullpath, "OUTCAR*")): outcar = Outcar(filename) i = 1 if re.search("relax2", filename) else 0 taskname = "relax2" if re.search("relax2", filename) else \ "relax1" d["calculations"][i]["output"]["outcar"] = outcar.as_dict() run_stats[taskname] = outcar.run_stats except: logger.error("Bad OUTCAR for {}.".format(fullpath)) try: overall_run_stats = {} for key in ["Total CPU time used (sec)", "User time (sec)", "System time (sec)", "Elapsed time (sec)"]: overall_run_stats[key] = sum([v[key] for v in run_stats.values()]) run_stats["overall"] = overall_run_stats except: logger.error("Bad run stats for {}.".format(fullpath)) d["run_stats"] = run_stats #Convert to full uri path. if self.use_full_uri: d["dir_name"] = get_uri(dir_name) if new_tags: d["tags"] = new_tags logger.info("Post-processed " + fullpath)