def correct(self): backup(VASP_BACKUP_FILES) vi = VaspInput.from_directory(".") potim = float(vi["INCAR"].get("POTIM", 0.5)) ibrion = int(vi["INCAR"].get("IBRION", 0)) if potim < 0.2 and ibrion != 3: actions = [{ "dict": "INCAR", "action": { "_set": { "IBRION": 3, "SMASS": 0.75 } } }] else: actions = [{ "dict": "INCAR", "action": { "_set": { "POTIM": potim * 0.5 } } }] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["POTIM"], "actions": actions}
def correct(self): backup("*.nw*") actions = [] nwi = NwInput.from_file(self.input_file) for e in self.errors: if e == "autoz error": action = { "_set": { "geometry_options": ["units", "angstroms", "noautoz"] } } actions.append(action) elif e == "Bad convergence": t = nwi.tasks[self.ntasks - 1] if "cgmin" in t.theory_directives: nwi.tasks.pop(self.ntasks - 1) else: t.theory_directives["cgmin"] = "" for t in nwi.tasks: if t.operation.startswith("freq"): # You cannot calculate hessian with cgmin. t.theory_directives["nocgmin"] = "" action = {"_set": {"tasks": [t.as_dict() for t in nwi.tasks]}} actions.append(action) else: # For unimplemented errors, this should just cause the job to # die. return {"errors": self.errors, "actions": None} m = Modder() for action in actions: nwi = m.modify_object(action, nwi) nwi.write_file(self.input_file) return {"errors": self.errors, "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES) actions = [] vi = VaspInput.from_directory(".") incar = vi["INCAR"] outcar = Outcar("OUTCAR") # Move CONTCAR to POSCAR actions.append({"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}) # First try adding ADDGRID if not incar.get("ADDGRID", False) : actions.append({"dict": "INCAR", "action": {"_set": {"ADDGRID": True}}}) # Otherwise set PREC to High so ENAUG can be used to control Augmentation Grid Size elif incar.get("PREC", "Accurate").lower() != "high": actions.append({"dict": "INCAR", "action": {"_set": {"PREC": "High"}}}) actions.append({"dict": "INCAR", "action": {"_set": {"ENAUG": incar.get("ENCUT", 520) * 2}}}) # PREC is already high and ENAUG set so just increase it else: actions.append({"dict": "INCAR", "action": {"_set": {"ENAUG": int(incar.get("ENAUG", 1040) * self.enaug_multiply)}}}) curr_drift = outcar.data.get("drift", [])[::-1][:self.to_average] curr_drift = np.average([np.linalg.norm(d) for d in curr_drift]) VaspModder(vi=vi).apply_actions(actions) return {"errors": "Excessive drift {} > {}".format(curr_drift, self.max_drift), "actions": actions}
def correct(self): backup("*.nw*") actions = [] nwi = NwInput.from_file(self.input_file) for e in self.errors: if e == "autoz error": action = {"_set": {"geometry_options": ["units", "angstroms", "noautoz"]}} actions.append(action) elif e == "Bad convergence": t = nwi.tasks[self.ntasks - 1] if "cgmin" in t.theory_directives: nwi.tasks.pop(self.ntasks - 1) else: t.theory_directives["cgmin"] = "" for t in nwi.tasks: if t.operation.startswith("freq"): #You cannot calculate hessian with cgmin. t.theory_directives["nocgmin"] = "" action = {"_set": {"tasks": [t.as_dict() for t in nwi.tasks]}} actions.append(action) else: # For unimplemented errors, this should just cause the job to # die. return {"errors": self.errors, "actions": None} m = Modder() for action in actions: nwi = m.modify_object(action, nwi) nwi.write_file(self.input_file) return {"errors": self.errors, "actions": actions}
def setup(self): """ Performs initial setup for VaspJob, including overriding any settings and backing up. """ decompress_dir('.') if self.backup: for f in VASP_INPUT_FILES: shutil.copy(f, "{}.orig".format(f)) if self.auto_npar: try: incar = Incar.from_file("INCAR") # Only optimized NPAR for non-HF and non-RPA calculations. if not (incar.get("LHFCALC") or incar.get("LRPA") or incar.get("LEPSILON")): if incar.get("IBRION") in [5, 6, 7, 8]: # NPAR should not be set for Hessian matrix # calculations, whether in DFPT or otherwise. del incar["NPAR"] else: import multiprocessing # try sge environment variable first # (since multiprocessing counts cores on the current # machine only) ncores = os.environ.get('NSLOTS') or \ multiprocessing.cpu_count() ncores = int(ncores) for npar in range(int(math.sqrt(ncores)), ncores): if ncores % npar == 0: incar["NPAR"] = npar break incar.write_file("INCAR") except: pass if self.auto_continue: if os.path.exists("continue.json"): actions = loadfn("continue.json").get("actions") logger.info("Continuing previous VaspJob. Actions: {}".format(actions)) backup(VASP_BACKUP_FILES, prefix="prev_run") VaspModder().apply_actions(actions) else: # Default functionality is to copy CONTCAR to POSCAR and set # ISTART to 1 in the INCAR, but other actions can be specified if self.auto_continue is True: actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}, {"dict": "INCAR", "action": {"_set": {"ISTART": 1}}}] else: actions = self.auto_continue dumpfn({"actions": actions}, "continue.json") if self.settings_override is not None: VaspModder().apply_actions(self.settings_override)
def correct(self): backup(FEFF_BACKUP_FILES) feff_input = FEFFDictSet.from_directory(".") scf_values = feff_input.tags.get("SCF") nscmt = scf_values[2] ca = scf_values[3] nmix = scf_values[4] actions = [] #Add RESTART card to PARAMETERS if not "RESTART" in feff_input.tags: actions.append({"dict": "PARAMETERS", "action": {"_set": {"RESTART": []}}}) if nscmt < 100 and ca == 0.2: scf_values[2] = 100 scf_values[4] = 3 # Set nmix = 3 actions.append({"dict": "PARAMETERS", "action": {"_set": {"SCF": scf_values}}}) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nscmt == 100 and nmix == 3 and ca > 0.01: # Reduce the convergence accelerator factor scf_values[3] = round(ca / 2, 2) actions.append({"dict": "PARAMETERS", "action": {"_set": {"SCF": scf_values}}}) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nmix == 3 and ca == 0.01: # Set ca = 0.05 and set nmix scf_values[3] = 0.05 scf_values[4] = 5 actions.append({"dict": "PARAMETERS", "action": {"_set": {"SCF": scf_values}}}) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nmix == 5 and ca == 0.05: # Set ca = 0.05 and set nmix scf_values[3] = 0.05 scf_values[4] = 10 actions.append({"dict": "PARAMETERS", "action": {"_set": {"SCF": scf_values}}}) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nmix == 10 and ca < 0.2: # loop through ca with nmix = 10 scf_values[3] = round(ca * 2, 2) actions.append({"dict": "PARAMETERS", "action": {"_set": {"SCF": scf_values}}}) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} # Unfixable error. Just return None for actions. else: return {"errors": ["Non-converging job"], "actions": None}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) vi = VaspInput.from_directory(".") m = reduce(operator.mul, vi["KPOINTS"].kpts[0]) m = max(int(round(m ** (1 / 3))), 1) if vi["KPOINTS"].style.lower().startswith("m"): m += m % 2 actions = [{"dict": "KPOINTS", "action": {"_set": {"kpoints": [[m] * 3]}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["mesh_symmetry"], "actions": actions}
def correct(self): backup(orig_handlers.VASP_BACKUP_FILES) v = Vasprun(self.output_filename) actions = [{ "file": "CONTCAR", "action": { "_file_copy": { "dest": "POSCAR" } } }] if not v.converged_electronic: # For SCAN try switching to CG for the electronic minimization if "SCAN" in v.incar.get("METAGGA", "").upper(): new_settings = {"ALGO": "All"} else: new_settings = { "ISTART": 1, "ALGO": "Normal", "NELMDL": -6, "BMIX": 0.001, "AMIX_MAG": 0.8, "BMIX_MAG": 0.001 } if all( [v.incar.get(k, "") == val for k, val in new_settings.items()]): return {"errors": ["Unconverged"], "actions": None} actions.append({"dict": "INCAR", "action": {"_set": new_settings}}) # Instead of changing the IBRION, we reduce the EDIFF since we usually # use the constant EDIFF value as default. elif not v.converged_ionic: ediff = v.incar["EDIFF"] actions.append({ "dict": "INCAR", "action": { "_set": { "EDIFF": ediff * 0.5 } } }) actions.append({ "dict": "INCAR", "action": { "_set": { "ADDGRID": True } } }) ViseVaspModder().apply_actions(actions) return {"errors": ["Unconverged"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) vi = VaspInput.from_directory(".") actions = [] if vi["INCAR"].get("ALGO", "Normal") == "Fast": actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Frozen job"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) vi = VaspInput.from_directory(".") 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 = [{"dict": "KPOINTS", "action": {"_set": {"kpoints": [[m] * 3]}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["mesh_symmetry"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) vi = VaspInput.from_directory(".") ediff = float(vi["INCAR"].get("EDIFF", 1e-4)) ediffg = float(vi["INCAR"].get("EDIFFG", ediff * 10)) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}, {"dict": "INCAR", "action": {"_set": {"EDIFFG": ediffg * 0.5}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["MaxForce"], "actions": actions}
def correct(self): # change ALGO = Fast to Normal if ALGO is !Normal vi = VaspInput.from_directory(".") algo = vi["INCAR"].get("ALGO", "Normal") if algo.lower() not in ["normal", "n"]: backup(VASP_BACKUP_FILES) actions = [{"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Positive energy"], "actions": actions} # Unfixable error. Just return None for actions. else: return {"errors": ["Positive energy"], "actions": None}
def correct(self): backup(VASP_BACKUP_FILES) vi = VaspInput.from_directory(".") potim = float(vi["INCAR"].get("POTIM", 0.5)) ibrion = int(vi["INCAR"].get("IBRION", 0)) if potim < 0.2 and ibrion != 3: actions = [{"dict": "INCAR", "action": {"_set": {"IBRION": 3, "SMASS": 0.75}}}] else: actions = [{"dict": "INCAR", "action": {"_set": {"POTIM": potim * 0.5}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["POTIM"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) vi = VaspInput.from_directory('.') actions = [] if vi["INCAR"].get("ALGO", "Normal") == "Fast": actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Frozen job"], "actions": actions}
def correct(self): backup(["INCAR", "KPOINTS", "POSCAR", "OUTCAR", self.output_filename, "vasp.out"]) vi = VaspInput.from_directory(".") ediff = float(vi["INCAR"].get("EDIFF", 1e-4)) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}, {"dict": "INCAR", "action": {"_set": {"EDIFF": ediff*0.75}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["MaxForce"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) vi = VaspInput.from_directory(".") ediff = float(vi["INCAR"].get("EDIFF", 1e-4)) ediffg = float(vi["INCAR"].get("EDIFFG", ediff * 10)) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}, {"dict": "INCAR", "action": {"_set": {"EDIFFG": ediffg*0.5}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["MaxForce"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}, {"dict": "INCAR", "action": {"_set": {"ISTART": 1, "ALGO": "Normal", "NELMDL": -6, "BMIX": 0.001, "AMIX_MAG": 0.8, "BMIX_MAG": 0.001}}}] VaspModder().apply_actions(actions) return {"errors": ["Unconverged"], "actions": actions}
def correct(self): # change ALGO = Fast to Normal if ALGO is !Normal vi = VaspInput.from_directory(".") algo = vi["INCAR"].get("ALGO", "Normal") if algo.lower() not in ['normal', 'n']: backup(["INCAR", "KPOINTS", "POSCAR", "OUTCAR", "vasprun.xml"]) actions = [{"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Positive energy"], "actions": actions} #Unfixable error. Just return None for actions. else: return {"errors": ["Positive energy"], "actions": None}
def correct(self): backup([self.output_filename, "INCAR", "KPOINTS", "POSCAR", "OUTCAR", "vasprun.xml"]) vi = VaspInput.from_directory('.') actions = [] if vi["INCAR"].get("ALGO", "Normal") == "Fast": actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Frozen job"], "actions": actions}
def correct(self): # change ALGO = Fast to Normal if ALGO is !Normal vi = VaspInput.from_directory(".") algo = vi["INCAR"].get("ALGO", "Normal") if algo.lower() not in ['normal', 'n']: backup(VASP_BACKUP_FILES) actions = [{"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}] VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Positive energy"], "actions": actions} # Unfixable error. Just return None for actions. else: return {"errors": ["Positive energy"], "actions": None}
def correct(self): backup(AIMS_BACKUP_FILES | {self.output_filename}) actions = [] init_cons = [] if "energy_F_inconsistent" in self.errors: with open('geometry.in', 'rt') as f: content = f.readlines() for i, line in enumerate(content): if 'atom' in line: init_cons.append( self.check_constraints(content, i + 1, total_lines=len(content))) k = 0 content = [] with open('geometry.in.next_step', 'rt') as f: for line in f: if 'lattice_vector ' in line: content.append(line) if 'atom' in line: content.append(line) if init_cons[k][0]: content.append(' initial_moment {:3.3f}\n'.format( init_cons[k][0])) print(init_cons[k][1][0], init_cons[k][1][1], init_cons[k][1][2]) if init_cons[k][1][0] and init_cons[k][1][ 1] and init_cons[k][1][2]: content.append(' constrain_relaxation .true.\n') else: if init_cons[k][1][0]: content.append(' constrain_relaxation x\n') if init_cons[k][1][1]: content.append(' constrain_relaxation y\n') if init_cons[k][1][2]: content.append(' constrain_relaxation z\n') if not os.path.isfile('user_supplied_geometry.in'): os.rename('geometry.in', 'user_supplied_geometry.in') with open('geometry.in', 'wt') as f: for line in content: f.write(line) print(content) actions.append({'fixed': 'geo_step -> geo'}) return {"errors": list(self.errors), "actions": actions}
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 correct(self): backup(["INCAR", "KPOINTS", "POSCAR", "OUTCAR", "vasprun.xml", "vasp.out"]) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}, {"dict": "INCAR", "action": {"_set": {"ISTART": 1, "ALGO": "Normal", "NELMDL": -6, "BMIX": 0.001, "AMIX_MAG": 0.8, "BMIX_MAG": 0.001}}}] VaspModder().apply_actions(actions) return {"errors": ["Unconverged"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if "subspacematrix" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "All" } } }) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES) v = Vasprun(self.output_filename) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}] if not v.converged_electronic: actions.append({"dict": "INCAR", "action": {"_set": {"ISTART": 1, "ALGO": "Normal", "NELMDL": -6, "BMIX": 0.001, "AMIX_MAG": 0.8, "BMIX_MAG": 0.001}}}) if not v.converged_ionic: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION":1}}}) VaspModder().apply_actions(actions) return {"errors": ["Unconverged"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES) v = Vasprun(self.output_filename) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}] if not v.converged_electronic: actions.append({"dict": "INCAR", "action": {"_set": {"ISTART": 1, "ALGO": "Normal", "NELMDL": -6, "BMIX": 0.001, "AMIX_MAG": 0.8, "BMIX_MAG": 0.001}}}) if not v.converged_ionic: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) VaspModder().apply_actions(actions) return {"errors": ["Unconverged"], "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if "aliasing" in self.errors: with open("OUTCAR") as f: grid_adjusted = False changes_dict = {} r = re.compile(".+aliasing errors.*(NG.)\s*to\s*(\d+)") for line in f: m = r.match(line) if m: changes_dict[m.group(1)] = int(m.group(2)) grid_adjusted = True # Ensure that all NGX, NGY, NGZ have been checked if grid_adjusted and 'NGZ' in line: actions.append( {"dict": "INCAR", "action": {"_set": changes_dict}}) if vi["INCAR"].get("ICHARG", 0) < 10: actions.extend([{"file": "CHGCAR", "action": {"_file_delete": { 'mode': "actual"}}}, {"file": "WAVECAR", "action": {"_file_delete": { 'mode': "actual"}}}]) break if "aliasing_incar" in self.errors: # vasp seems to give different warnings depending on whether the # aliasing error was caused by user supplied inputs d = {k: 1 for k in ['NGX', 'NGY', 'NGZ'] if k in vi['INCAR'].keys()} actions.append({"dict": "INCAR", "action": {"_unset": d}}) if vi["INCAR"].get("ICHARG", 0) < 10: actions.extend([{"file": "CHGCAR", "action": { "_file_delete": {'mode': "actual"}}}, {"file": "WAVECAR", "action": { "_file_delete": {'mode': "actual"}}}]) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") # If we encounter a DAV Sub-Space-Matrix error if "subspacematrix" or "edddav" in self.errors: # Switch to the CG algorithm actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "All" } } }) # If we encounter a ZBRENT error if "zbrent" in self.errors: # Switch to Quasi-Newton algorithm actions.append({ "dict": "INCAR", "action": { "_set": { "IBRION": 1 } } }) # Move CONTCAR to POSCAR actions.append({ "file": "CONTCAR", "action": { "_file_copy": { "dest": "POSCAR" } } }) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): # if change_algo is True, change ALGO = Fast to Normal if ALGO is # Fast. If still not converging, following Kresse's # recommendation, we will try two iterations of different mixing # parameters. If this error is caught again, then kil the job vi = VaspInput.from_directory(".") algo = vi["INCAR"].get("ALGO", "Normal") amix = vi["INCAR"].get("AMIX", 0.4) bmix = vi["INCAR"].get("BMIX", 1.0) amin = vi["INCAR"].get("AMIN", 0.1) actions = [] if self.change_algo: if algo == "Fast": backup(VASP_BACKUP_FILES) actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) elif amix > 0.1 and bmix > 0.01: # try linear mixing backup(VASP_BACKUP_FILES) actions.append({"dict": "INCAR", "action": {"_set": {"AMIX": 0.1, "BMIX": 0.01, "ICHARG": 2}}}) elif bmix < 3.0 and amin > 0.01: # Try increasing bmix backup(VASP_BACKUP_FILES) actions.append({"dict": "INCAR", "action": {"_set": {"AMIN": 0.01, "BMIX": 3.0, "ICHARG": 2}}}) if actions: VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} # Unfixable error. Just return None for actions. else: return {"errors": ["Non-converging job"], "actions": None}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") 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 if "out_of_memory" in self.errors: if vi["INCAR"].get("KPAR", 1) > 1: reduced_kpar = max(vi["INCAR"].get("KPAR", 1) // 2, 1) actions.append({"dict": "INCAR", "action": {"_set": {"KPAR": reduced_kpar}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
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 correct(self): # if change_algo is True, change ALGO = Fast to Normal if ALGO is # Fast. If still not converging, following Kresse's # recommendation, we will try two iterations of different mixing # parameters. If this error is caught again, then kil the job vi = VaspInput.from_directory(".") algo = vi["INCAR"].get("ALGO", "Normal") amix = vi["INCAR"].get("AMIX", 0.4) bmix = vi["INCAR"].get("BMIX", 1.0) amin = vi["INCAR"].get("AMIN", 0.1) actions = [] if self.change_algo: if algo == "Fast": backup(VASP_BACKUP_FILES) actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Normal" } } }) elif amix > 0.1 and bmix > 0.01: #try linear mixing backup(VASP_BACKUP_FILES) actions.append({ "dict": "INCAR", "action": { "_set": { "AMIX": 0.1, "BMIX": 0.01, "ICHARG": 2 } } }) elif bmix < 3.0 and amin > 0.01: #Try increasing bmix backup(VASP_BACKUP_FILES) actions.append({ "dict": "INCAR", "action": { "_set": { "AMIN": 0.01, "BMIX": 3.0, "ICHARG": 2 } } }) if actions: VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} #Unfixable error. Just return None for actions. else: return {"errors": ["Non-converging job"], "actions": None}
def correct(self): backup(VASP_BACKUP_FILES) v = Vasprun(self.output_filename) actions = [{"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}] if not v.converged_electronic: new_settings = {"ISTART": 1, "ALGO": "Normal", "NELMDL": -6, "BMIX": 0.001, "AMIX_MAG": 0.8, "BMIX_MAG": 0.001} if all([v.incar.get(k,"") == val for k,val in new_settings.items()]): return {"errors": ["Unconverged"], "actions": None} actions.append({"dict": "INCAR", "action": {"_set": new_settings}}) if not v.converged_ionic: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) VaspModder().apply_actions(actions) return {"errors": ["Unconverged"], "actions": actions}
def correct(self): vi = VaspInput.from_directory(".") algo = vi["INCAR"].get("ALGO", "Normal") amix = vi["INCAR"].get("AMIX", 0.4) bmix = vi["INCAR"].get("BMIX", 1.0) amin = vi["INCAR"].get("AMIN", 0.1) actions = [] # Ladder from VeryFast to Fast to Fast to All # These progressively switches to more stable but more # expensive algorithms if algo == "VeryFast": actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Fast" } } }) elif algo == "Fast": actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Normal" } } }) elif algo == "Normal": actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "All" } } }) elif amix > 0.1 and bmix > 0.01: # Try linear mixing actions.append({ "dict": "INCAR", "action": { "_set": { "AMIX": 0.1, "BMIX": 0.01, "ICHARG": 2 } } }) elif bmix < 3.0 and amin > 0.01: # Try increasing bmix actions.append({ "dict": "INCAR", "action": { "_set": { "AMIN": 0.01, "BMIX": 3.0, "ICHARG": 2 } } }) if actions: backup(VASP_BACKUP_FILES) VaspModder(vi=vi).apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} # Unfixable error. Just return None for actions. else: return {"errors": ["Non-converging job"], "actions": None}
def correct(self): backup({self.input_file, self.output_file}) actions = [] if "SCF_failed_to_converge" in self.errors: # Check number of SCF cycles. If not set or less than scf_max_cycles, # increase to that value and rerun. If already set, check if # scf_algorithm is unset or set to DIIS, in which case set to RCA-DIIS. # Otherwise, tell user to call SCF error handler and do nothing. if self.qcinp.rem.get("max_scf_cycles") != str( self.scf_max_cycles): self.qcinp.rem["max_scf_cycles"] = self.scf_max_cycles actions.append({"max_scf_cycles": self.scf_max_cycles}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print( "More advanced changes may impact the SCF result. Use the SCF error handler" ) elif "out_of_opt_cycles" in self.errors: # Check number of opt cycles. If less than geom_max_cycles, increase # to that value, set last geom as new starting geom and rerun. if self.qcinp.rem.get( "geom_opt_max_cycles") != self.geom_max_cycles: self.qcinp.rem["geom_opt_max_cycles"] = self.geom_max_cycles actions.append({"geom_max_cycles:": self.scf_max_cycles}) if len(self.outdata.get("energy_trajectory")) > 1: if self.qcinp.molecule.spin_multiplicity != self.outdata.get( "molecule_from_last_geometry").spin_multiplicity: raise AssertionError('Multiplicities should match!') if self.qcinp.molecule.charge != self.outdata.get( "molecule_from_last_geometry").charge: raise AssertionError('Charges should match!') self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) else: print( "How do I get the geometry optimization converged when already at the maximum number of cycles?" ) elif "unable_to_determine_lamda" in self.errors: # Set last geom as new starting geom and rerun. If no opt cycles, # use diff SCF strat? Diff initial guess? Change basis? if len(self.outdata.get("energy_trajectory")) > 1: if self.qcinp.molecule.spin_multiplicity != self.outdata.get( "molecule_from_last_geometry").spin_multiplicity: raise AssertionError('Multiplicities should match!') if self.qcinp.molecule.charge != self.outdata.get( "molecule_from_last_geometry").charge: raise AssertionError('Charges should match!') self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print( "Use a different initial guess? Perhaps a different basis?" ) elif "linear_dependent_basis" in self.errors: # DIIS -> RCA_DIIS. If already RCA_DIIS, change basis? if self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print("Perhaps use a better basis?") elif "failed_to_transform_coords" in self.errors: # Check for symmetry flag in rem. If not False, set to False and rerun. # If already False, increase threshold? if not self.qcinp.rem.get("sym_ignore") or self.qcinp.rem.get( "symmetry"): self.qcinp.rem["sym_ignore"] = True self.qcinp.rem["symmetry"] = False actions.append({"sym_ignore": True}) actions.append({"symmetry": False}) else: print("Perhaps increase the threshold?") elif "input_file_error" in self.errors: print( "Something is wrong with the input file. Examine error message by hand." ) return {"errors": self.errors, "actions": None} elif "failed_to_read_input" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "IO_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "unknown_error" in self.errors: print("Examine error message by hand.") return {"errors": self.errors, "actions": None} else: # You should never get here. If correct is being called then errors should have at least one entry, # in which case it should have been caught by the if/elifs above. print( "If you get this message, something has gone terribly wrong!") return {"errors": self.errors, "actions": None} os.rename(self.input_file, self.input_file + ".last") self.qcinp.write_file(self.input_file) return {"errors": self.errors, "actions": actions}
def correct(self): #pylint: disable=R0915,R0912,R0914 """ "brmix"にてINCARにADDGRIDを追加する """ backup([self.output_filename, "INCAR", "KPOINTS", "POSCAR", "OUTCAR", "vasprun.xml"]) actions = [] vi = VaspInput.from_directory(".") if "tet" in self.errors or "dentet" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": 0}}}) if "inv_rot_mat" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8}}}) if "brmix" in self.errors and "NELECT" in vi["INCAR"]: #brmix error always shows up after DAV steps if NELECT is specified self.errors.remove("brmix") if "brmix" in self.errors or "zpotrf" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) #140814 add actions.append({"dict": "INCAR", "action": {"_set": {"ADDGRID": True}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with these errors. actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if "subspacematrix" in self.errors or "rspher" in self.errors or \ "real_optlay" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": False}}}) if "tetirr" in self.errors or "incorrect_shift" in self.errors or \ "rot_matrix" in self.errors: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) if "amin" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"AMIN": "0.01"}}}) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": new_s.to_dict}}, "transformation": trans.to_dict}) if "pricel" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8, "ISYM": 0}}}) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if "zbrent" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({"dict": "INCAR", "action": {"_set": {"NBANDS": int(1.1 * nbands)}}}) if "aliasing" in self.errors: with open("OUTCAR") as f: grid_adjusted = False changes_dict = {} for line in f: if "aliasing errors" in line: try: grid_vector = line.split(" NG", 1)[1] value = [int(s) for s in grid_vector.split(" ") if s.isdigit()][0] changes_dict["NG" + grid_vector[0]] = value grid_adjusted = True except (IndexError, ValueError): pass #Ensure that all NGX, NGY, NGZ have been checked if grid_adjusted and 'NGZ' in line: actions.append({"dict": "INCAR", "action": {"_set": changes_dict}}) break m = Modder(actions=[DictActions, FileActions]) modified = [] for a in actions: if "dict" in a: modified.append(a["dict"]) vi[a["dict"]] = m.modify_object(a["action"], vi[a["dict"]]) elif "file" in a: m.modify(a["action"], a["file"]) for f in modified: vi[f].write_file(f) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if self.errors.intersection(["tet", "dentet"]): actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": 0}}}) if "inv_rot_mat" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8}}}) if "brmix" in self.errors: # If there is not a valid OUTCAR already, increment # error count to 1 to skip first fix if self.error_count['brmix'] == 0: try: assert (Outcar(zpath(os.path.join( os.getcwd(), "OUTCAR"))).is_stopped is False) except: self.error_count['brmix'] += 1 if self.error_count['brmix'] == 0: # Valid OUTCAR - simply rerun the job and increment # error count for next time actions.append({"dict": "INCAR", "action": {"_set": {"ISTART": 1}}}) self.error_count['brmix'] += 1 elif self.error_count['brmix'] == 1: # Use Kerker mixing w/default values for other parameters actions.append({"dict": "INCAR", "action": {"_set": {"IMIX": 1}}}) self.error_count['brmix'] += 1 elif self.error_count['brmix'] == 2 and vi["KPOINTS"].style \ == Kpoints.supported_modes.Gamma: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Monkhorst"}}}) actions.append({"dict": "INCAR", "action": {"_unset": {"IMIX": 1}}}) self.error_count['brmix'] += 1 elif self.error_count['brmix'] in [2, 3] and vi["KPOINTS"].style \ == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) actions.append({"dict": "INCAR", "action": {"_unset": {"IMIX": 1}}}) self.error_count['brmix'] += 1 if vi["KPOINTS"].num_kpts < 1: all_kpts_even = all([ bool(n % 2 == 0) for n in vi["KPOINTS"].kpts[0] ]) print("all_kpts_even = {}".format(all_kpts_even)) if all_kpts_even: new_kpts = ( tuple(n + 1 for n in vi["KPOINTS"].kpts[0]),) print("new_kpts = {}".format(new_kpts)) actions.append({"dict": "KPOINTS", "action": {"_set": { "kpoints": new_kpts }}}) else: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": { "_set": {"generation_style": "Gamma"}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": { "_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": { "_file_delete": {'mode': "actual"}}}) if "zpotrf" in self.errors: # Usually caused by short bond distances. If on the first step, # volume needs to be increased. Otherwise, it was due to a step # being too big and POTIM should be decreased. If a static run # try turning off symmetry. try: oszicar = Oszicar("OSZICAR") nsteps = len(oszicar.ionic_steps) except: nsteps = 0 if nsteps >= 1: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append( {"dict": "INCAR", "action": {"_set": {"ISYM": 0, "POTIM": potim}}}) elif vi["INCAR"].get("NSW", 0) == 0 \ or vi["INCAR"].get("ISIF", 0) in range(3): actions.append( {"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) else: s = vi["POSCAR"].structure s.apply_strain(0.2) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": s.as_dict()}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if self.errors.intersection(["subspacematrix", "rspher", "real_optlay", "nicht_konv"]): s = vi["POSCAR"].structure if len(s) < self.natoms_large_cell: actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": False}}}) else: # for large supercell, try an in-between option LREAL = True # prior to LREAL = False if self.error_count['real_optlay'] == 0: # use real space projectors generated by pot actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": True}}}) self.error_count['real_optlay'] += 1 elif self.error_count['real_optlay'] == 1: actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": False}}}) self.error_count['real_optlay'] += 1 if self.errors.intersection(["tetirr", "incorrect_shift"]): if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": { "_set": {"generation_style": "Gamma"}}}) if "rot_matrix" in self.errors: if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": { "_set": {"generation_style": "Gamma"}}}) else: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if "amin" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"AMIN": "0.01"}}}) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": new_s.as_dict()}}, "transformation": trans.as_dict()}) if "pricel" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8, "ISYM": 0}}}) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if "zbrent" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) actions.append({"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}) if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({"dict": "INCAR", "action": {"_set": {"NBANDS": int(1.1 * nbands)}}}) if "pssyevx" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) if "eddrmm" in self.errors: # RMM algorithm is not stable for this calculation if vi["INCAR"].get("ALGO", "Normal") in ["Fast", "VeryFast"]: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) else: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if "edddav" in self.errors: if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "All"}}}) if "grad_not_orth" in self.errors: if vi["INCAR"].get("ISMEAR", 1) < 0: actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": "0"}}}) if "zheev" in self.errors: if vi["INCAR"].get("ALGO", "Fast").lower() != "exact": actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Exact"}}}) if "elf_kpar" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"KPAR": 1}}}) if "rhosyg" in self.errors: if vi["INCAR"].get("SYMPREC", 1e-4) == 1e-4: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-4}}}) if "posmap" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-6}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup([self.output_filename, "INCAR", "KPOINTS", "POSCAR", "OUTCAR", "OSZICAR", "vasprun.xml"]) actions = [] vi = VaspInput.from_directory(".") if self.errors.intersection(["tet", "dentet"]): actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": 0}}}) if "inv_rot_mat" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8}}}) if "brmix" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if "zpotrf" in self.errors: # Usually caused by short bond distances. If on the first step, # volume needs to be increased. Otherwise, it was due to a step # being too big and POTIM should be decreased. try: oszicar = Oszicar("OSZICAR") nsteps = len(oszicar.ionic_steps) except: nsteps = 0 if nsteps >= 1: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append( {"dict": "INCAR", "action": {"_set": {"ISYM": 0, "POTIM": potim}}}) else: s = vi["POSCAR"].structure s.apply_strain(0.2) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": s.as_dict()}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if self.errors.intersection(["subspacematrix", "rspher", "real_optlay"]): actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": False}}}) if self.errors.intersection(["tetirr", "incorrect_shift"]): if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) if "rot_matrix" in self.errors: if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) else: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if "amin" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"AMIN": "0.01"}}}) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": new_s.as_dict()}}, "transformation": trans.as_dict()}) if "pricel" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8, "ISYM": 0}}}) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if "zbrent" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({"dict": "INCAR", "action": {"_set": {"NBANDS": int(1.1 * nbands)}}}) if "aliasing" in self.errors: with open("OUTCAR") as f: grid_adjusted = False changes_dict = {} r = re.compile(".+aliasing errors.*(NG.)\s*to\s*(\d+)") for line in f: m = r.match(line) if m: changes_dict[m.group(1)] = int(m.group(2)) grid_adjusted = True #Ensure that all NGX, NGY, NGZ have been checked if grid_adjusted and 'NGZ' in line: actions.extend( [{"dict": "INCAR", "action": {"_set": changes_dict}}, {"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}, {"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}]) break if "aliasing_incar" in self.errors: #vasp seems to give different warnings depending on whether the #aliasing error was caused by user supplied inputs d = {k: 1 for k in ['NGX', 'NGY', 'NGZ'] if k in vi['INCAR'].keys()} actions.extend([{"dict": "INCAR", "action": {"_unset": d}}, {"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}, {"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}]) if "pssyevx" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) if "eddrmm" in self.errors: #RMM algorithm is not stable for this calculation if vi["INCAR"].get("ALGO", "Normal") in ["Fast", "VeryFast"]: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) else: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def postprocess(self): """ Renaming or gzipping all the output as needed """ if self.gzipped: backup("*", prefix=self.gzipped_prefix)
def correct(self): backup({self.input_file, self.output_file}) actions = [] self.qcinp = QCInput.from_file(self.input_file) if "SCF_failed_to_converge" in self.errors: # Check number of SCF cycles. If not set or less than scf_max_cycles, # increase to that value and rerun. If already set, check if # scf_algorithm is unset or set to DIIS, in which case set to GDM. # Otherwise, tell user to call SCF error handler and do nothing. if str(self.qcinp.rem.get("max_scf_cycles")) != str( self.scf_max_cycles): self.qcinp.rem["max_scf_cycles"] = self.scf_max_cycles actions.append({"max_scf_cycles": self.scf_max_cycles}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "gdm" actions.append({"scf_algorithm": "gdm"}) elif self.qcinp.rem.get("scf_algorithm", "gdm").lower() == "gdm": self.qcinp.rem["scf_algorithm"] = "diis_gdm" actions.append({"scf_algorithm": "diis_gdm"}) else: print( "More advanced changes may impact the SCF result. Use the SCF error handler" ) elif "out_of_opt_cycles" in self.errors: # Check number of opt cycles. If less than geom_max_cycles, increase # to that value, set last geom as new starting geom and rerun. if str(self.qcinp.rem.get( "geom_opt_max_cycles")) != str(self.geom_max_cycles): self.qcinp.rem["geom_opt_max_cycles"] = self.geom_max_cycles actions.append({"geom_max_cycles:": self.scf_max_cycles}) if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) # If already at geom_max_cycles, often can just get convergence by restarting # from the geometry of the last cycle. But we'll also save any structural # changes that happened along the way. else: self.opt_error_history += [self.outdata["structure_change"]] if len(self.opt_error_history) > 1: if self.opt_error_history[-1] == "no_change": # If no structural changes occured in two consecutive optimizations, # and we still haven't converged, then just exit. return {"errors": self.errors, "actions": None, "opt_error_history": self.opt_error_history} self.qcinp.molecule = self.outdata.get("molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif "unable_to_determine_lamda" in self.errors: # Set last geom as new starting geom and rerun. If no opt cycles, # use diff SCF strat? Diff initial guess? Change basis? if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print( "Use a different initial guess? Perhaps a different basis?" ) elif "linear_dependent_basis" in self.errors: # DIIS -> RCA_DIIS. If already RCA_DIIS, change basis? if self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print("Perhaps use a better basis?") elif "failed_to_transform_coords" in self.errors: # Check for symmetry flag in rem. If not False, set to False and rerun. # If already False, increase threshold? if not self.qcinp.rem.get("sym_ignore") or self.qcinp.rem.get( "symmetry"): self.qcinp.rem["sym_ignore"] = True self.qcinp.rem["symmetry"] = False actions.append({"sym_ignore": True}) actions.append({"symmetry": False}) else: print("Perhaps increase the threshold?") elif "input_file_error" in self.errors: print( "Something is wrong with the input file. Examine error message by hand." ) return {"errors": self.errors, "actions": None} elif "failed_to_read_input" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "IO_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "read_molecule_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "never_called_qchem" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "unknown_error" in self.errors: print("Examine error message by hand.") return {"errors": self.errors, "actions": None} else: # You should never get here. If correct is being called then errors should have at least one entry, # in which case it should have been caught by the if/elifs above. print( "If you get this message, something has gone terribly wrong!") return {"errors": self.errors, "actions": None} os.rename(self.input_file, self.input_file + ".last") self.qcinp.write_file(self.input_file) return {"errors": self.errors, "actions": actions}
def correct(self): backup({self.input_file, self.output_file}) actions = [] self.qcinp = QCInput.from_file(self.input_file) if "SCF_failed_to_converge" in self.errors: # Check number of SCF cycles. If not set or less than scf_max_cycles, # increase to that value and rerun. If already set, check if # scf_algorithm is unset or set to DIIS, in which case set to GDM. # Otherwise, tell user to call SCF error handler and do nothing. if str(self.qcinp.rem.get("max_scf_cycles")) != str( self.scf_max_cycles): self.qcinp.rem["max_scf_cycles"] = self.scf_max_cycles actions.append({"max_scf_cycles": self.scf_max_cycles}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "gdm" actions.append({"scf_algorithm": "gdm"}) elif self.qcinp.rem.get("scf_algorithm", "gdm").lower() == "gdm": self.qcinp.rem["scf_algorithm"] = "diis_gdm" actions.append({"scf_algorithm": "diis_gdm"}) else: print( "More advanced changes may impact the SCF result. Use the SCF error handler" ) elif "out_of_opt_cycles" in self.errors: # Check number of opt cycles. If less than geom_max_cycles, increase # to that value, set last geom as new starting geom and rerun. if str(self.qcinp.rem.get("geom_opt_max_cycles")) != str( self.geom_max_cycles): self.qcinp.rem["geom_opt_max_cycles"] = self.geom_max_cycles actions.append({"geom_max_cycles:": self.scf_max_cycles}) if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) # If already at geom_max_cycles, often can just get convergence by restarting # from the geometry of the last cycle. But we'll also save any structural # changes that happened along the way. else: self.opt_error_history += [self.outdata["structure_change"]] if len(self.opt_error_history) > 1: if self.opt_error_history[-1] == "no_change": # If no structural changes occured in two consecutive optimizations, # and we still haven't converged, then just exit. return { "errors": self.errors, "actions": None, "opt_error_history": self.opt_error_history } self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif "unable_to_determine_lamda" in self.errors: # Set last geom as new starting geom and rerun. If no opt cycles, # use diff SCF strat? Diff initial guess? Change basis? if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print( "Use a different initial guess? Perhaps a different basis?" ) elif "linear_dependent_basis" in self.errors: # DIIS -> RCA_DIIS. If already RCA_DIIS, change basis? if self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print("Perhaps use a better basis?") elif "failed_to_transform_coords" in self.errors: # Check for symmetry flag in rem. If not False, set to False and rerun. # If already False, increase threshold? if not self.qcinp.rem.get("sym_ignore") or self.qcinp.rem.get( "symmetry"): self.qcinp.rem["sym_ignore"] = True self.qcinp.rem["symmetry"] = False actions.append({"sym_ignore": True}) actions.append({"symmetry": False}) else: print("Perhaps increase the threshold?") elif "input_file_error" in self.errors: print( "Something is wrong with the input file. Examine error message by hand." ) return {"errors": self.errors, "actions": None} elif "failed_to_read_input" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "IO_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "read_molecule_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "never_called_qchem" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "unknown_error" in self.errors: print("Examine error message by hand.") return {"errors": self.errors, "actions": None} else: # You should never get here. If correct is being called then errors should have at least one entry, # in which case it should have been caught by the if/elifs above. print( "If you get this message, something has gone terribly wrong!") return {"errors": self.errors, "actions": None} os.rename(self.input_file, self.input_file + ".last") self.qcinp.write_file(self.input_file) return {"errors": self.errors, "actions": actions}
def correct(self): backup(orig_handlers.VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if self.errors.intersection(["tet", "dentet"]): actions.append({ "dict": "INCAR", "action": { "_set": { "ISMEAR": 0 } } }) if "inv_rot_mat" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "SYMPREC": 1e-8 } } }) # ----- added --------------------------------------------------- if "plane_wave_coeff" in self.errors: actions.append({ "file": "WAVECAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) # --------------------------------------------------------------- if "zpotrf" in self.errors: # Usually caused by short bond distances. If on the first step, # volume needs to be increased. Otherwise, it was due to a step # being too big and POTIM should be decreased. If a static run # try turning off symmetry. try: oszicar = Oszicar("OSZICAR") nsteps = len(oszicar.ionic_steps) except: nsteps = 0 if nsteps >= 1: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0, "POTIM": potim } } }) elif vi["INCAR"].get("NSW", 0) == 0 \ or vi["INCAR"].get("ISIF", 0) in range(3): actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0 } } }) else: s = vi["POSCAR"].structure s.apply_strain(0.2) actions.append({ "dict": "POSCAR", "action": { "_set": { "structure": s.as_dict() } } }) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "file": "WAVECAR", "action": { "_file_delete": { 'mode': "actual" } } }) if self.errors.intersection(["subspacematrix"]): if self.error_count["subspacematrix"] == 0: actions.append({ "dict": "INCAR", "action": { "_set": { "LREAL": False } } }) else: actions.append({ "dict": "INCAR", "action": { "_set": { "PREC": "Accurate" } } }) self.error_count["subspacematrix"] += 1 if self.errors.intersection(["rspher", "real_optlay", "nicht_konv"]): s = vi["POSCAR"].structure if len(s) < self.natoms_large_cell: actions.append({ "dict": "INCAR", "action": { "_set": { "LREAL": False } } }) else: # for large supercell, try an in-between option LREAL = True # prior to LREAL = False if self.error_count['real_optlay'] == 0: # use real space projectors generated by pot actions.append({ "dict": "INCAR", "action": { "_set": { "LREAL": True } } }) elif self.error_count['real_optlay'] == 1: actions.append({ "dict": "INCAR", "action": { "_set": { "LREAL": False } } }) self.error_count['real_optlay'] += 1 if self.errors.intersection(["tetirr", "incorrect_shift"]): # --Modified------------------------------------------------------ if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst or \ vi["KPOINTS"].kpts_shift != [0.0, 0.0, 0.0]: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Gamma", "usershift": [0.0, 0.0, 0.0] } } }) # ----------------------------------------------------------- if "rot_matrix" in self.errors: # --Modified------------------------------------------------------ if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst or \ vi["KPOINTS"].kpts_shift != [0.0, 0.0, 0.0]: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Gamma", "usershift": [0.0, 0.0, 0.0] } } }) # ----------------------------------------------------------- else: actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0 } } }) if "amin" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "AMIN": "0.01" } } }) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append({ "dict": "POSCAR", "action": { "_set": { "structure": new_s.as_dict() } }, "transformation": trans.as_dict() }) if "pricel" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "SYMPREC": 1e-8, "ISYM": 0 } } }) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({ "dict": "INCAR", "action": { "_set": { "POTIM": potim } } }) if "zbrent" in self.errors: # Modified so as not to use IBRION=1 as it does not show the # eigenvalues in vasprun.xml >>>>>>>>>>>> actions.append({ "dict": "INCAR", "action": { "_set": { "ADDGRID": True } } }) actions.append({ "file": "CONTCAR", "action": { "_file_copy": { "dest": "POSCAR" } } }) # actions.append({"dict": "INCAR", # "action": {"_set": {"IBRION": 1}}}) # actions.append({"file": "CONTCAR", # "action": {"_file_copy": {"dest": "POSCAR"}}}) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({ "dict": "INCAR", "action": { "_set": { "NBANDS": int(1.1 * nbands) } } }) if "pssyevx" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Normal" } } }) if "eddrmm" in self.errors: # RMM algorithm is not stable for this calculation if vi["INCAR"].get("ALGO", "Normal") in ["Fast", "VeryFast"]: actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Normal" } } }) else: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({ "dict": "INCAR", "action": { "_set": { "POTIM": potim } } }) if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "file": "WAVECAR", "action": { "_file_delete": { 'mode': "actual" } } }) if "edddav" in self.errors: if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "All" } } }) if "grad_not_orth" in self.errors: if vi["INCAR"].get("ISMEAR", 1) < 0: actions.append({ "dict": "INCAR", "action": { "_set": { "ISMEAR": "0" } } }) if "zheev" in self.errors: if vi["INCAR"].get("ALGO", "Fast").lower() != "exact": actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Exact" } } }) if "elf_kpar" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"KPAR": 1}}}) if "rhosyg" in self.errors: if vi["INCAR"].get("SYMPREC", 1e-4) == 1e-4: actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0 } } }) actions.append({ "dict": "INCAR", "action": { "_set": { "SYMPREC": 1e-4 } } }) if "posmap" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "SYMPREC": 1e-6 } } }) if "point_group" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) ViseVaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if self.errors.intersection(["tet", "dentet"]): actions.append({ "dict": "INCAR", "action": { "_set": { "ISMEAR": 0 } } }) if "inv_rot_mat" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "SYMPREC": 1e-8 } } }) if "brmix" in self.errors: if self.error_count['brmix'] == 0 and vi[ "KPOINTS"].style == Kpoints.supported_modes.Gamma: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Monkhorst" } } }) self.error_count['brmix'] += 1 elif self.error_count['brmix'] <= 1 and vi[ "KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Gamma" } } }) self.error_count['brmix'] += 1 if vi["KPOINTS"].num_kpts < 1: all_kpts_even = all( [bool(n % 2 == 0) for n in vi["KPOINTS"].kpts[0]]) print("all_kpts_even = {}".format(all_kpts_even)) if all_kpts_even: new_kpts = (tuple(n + 1 for n in vi["KPOINTS"].kpts[0]), ) print("new_kpts = {}".format(new_kpts)) actions.append({ "dict": "KPOINTS", "action": { "_set": { "kpoints": new_kpts } } }) else: actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0 } } }) if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Gamma" } } }) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "file": "WAVECAR", "action": { "_file_delete": { 'mode': "actual" } } }) if "zpotrf" in self.errors: # Usually caused by short bond distances. If on the first step, # volume needs to be increased. Otherwise, it was due to a step # being too big and POTIM should be decreased. try: oszicar = Oszicar("OSZICAR") nsteps = len(oszicar.ionic_steps) except: nsteps = 0 if nsteps >= 1: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0, "POTIM": potim } } }) else: s = vi["POSCAR"].structure s.apply_strain(0.2) actions.append({ "dict": "POSCAR", "action": { "_set": { "structure": s.as_dict() } } }) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "file": "WAVECAR", "action": { "_file_delete": { 'mode': "actual" } } }) if self.errors.intersection( ["subspacematrix", "rspher", "real_optlay"]): actions.append({ "dict": "INCAR", "action": { "_set": { "LREAL": False } } }) if self.errors.intersection(["tetirr", "incorrect_shift"]): if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Gamma" } } }) if "rot_matrix" in self.errors: if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({ "dict": "KPOINTS", "action": { "_set": { "generation_style": "Gamma" } } }) else: actions.append({ "dict": "INCAR", "action": { "_set": { "ISYM": 0 } } }) if "amin" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "AMIN": "0.01" } } }) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append({ "dict": "POSCAR", "action": { "_set": { "structure": new_s.as_dict() } }, "transformation": trans.as_dict() }) if "pricel" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "SYMPREC": 1e-8, "ISYM": 0 } } }) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({ "dict": "INCAR", "action": { "_set": { "POTIM": potim } } }) if "zbrent" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "IBRION": 1 } } }) if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({ "dict": "INCAR", "action": { "_set": { "NBANDS": int(1.1 * nbands) } } }) if "pssyevx" in self.errors: actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Normal" } } }) if "eddrmm" in self.errors: #RMM algorithm is not stable for this calculation if vi["INCAR"].get("ALGO", "Normal") in ["Fast", "VeryFast"]: actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "Normal" } } }) else: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({ "dict": "INCAR", "action": { "_set": { "POTIM": potim } } }) actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "file": "WAVECAR", "action": { "_file_delete": { 'mode': "actual" } } }) if "edddav" in self.errors: actions.append({ "file": "CHGCAR", "action": { "_file_delete": { 'mode': "actual" } } }) actions.append({ "dict": "INCAR", "action": { "_set": { "ALGO": "All" } } }) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): """ Perform corrections """ backup({self.input_file, self.output_file}) actions = [] self.qcinp = QCInput.from_file(self.input_file) if "SCF_failed_to_converge" in self.errors: # Check number of SCF cycles. If not set or less than scf_max_cycles, # increase to that value and rerun. If already set, check if # scf_algorithm is unset or set to DIIS, in which case set to GDM. # Otherwise, tell user to call SCF error handler and do nothing. if str(self.qcinp.rem.get("max_scf_cycles")) != str( self.scf_max_cycles): self.qcinp.rem["max_scf_cycles"] = self.scf_max_cycles actions.append({"max_scf_cycles": self.scf_max_cycles}) elif self.qcinp.rem.get("thresh", "10") != "14": self.qcinp.rem["thresh"] = "14" actions.append({"thresh": "14"}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "diis_gdm" actions.append({"scf_algorithm": "diis_gdm"}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis_gdm": self.qcinp.rem["scf_algorithm"] = "gdm" actions.append({"scf_algorithm": "gdm"}) elif self.qcinp.rem.get("scf_guess_always", "none").lower() != "true": self.qcinp.rem["scf_guess_always"] = True actions.append({"scf_guess_always": True}) else: print( "More advanced changes may impact the SCF result. Use the SCF error handler" ) elif "out_of_opt_cycles" in self.errors: # Check number of opt cycles. If less than geom_max_cycles, increase # to that value, set last geom as new starting geom and rerun. if str(self.qcinp.rem.get("geom_opt_max_cycles")) != str( self.geom_max_cycles): self.qcinp.rem["geom_opt_max_cycles"] = self.geom_max_cycles actions.append({"geom_max_cycles:": self.scf_max_cycles}) if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif self.qcinp.rem.get("thresh", "10") != "14": self.qcinp.rem["thresh"] = "14" actions.append({"thresh": "14"}) # Will need to try and implement this dmax handler below when I have more time # to fix the tests and the general handling procedure. # elif self.qcinp.rem.get("geom_opt_dmax",300) != 150: # self.qcinp.rem["geom_opt_dmax"] = 150 # actions.append({"geom_opt_dmax": "150"}) # If already at geom_max_cycles, thresh 14, and dmax 150, often can just get convergence # by restarting from the geometry of the last cycle. But we'll also save any structural # changes that happened along the way. else: self.opt_error_history += [self.outdata["structure_change"]] if len(self.opt_error_history) > 1: if self.opt_error_history[-1] == "no_change": # If no structural changes occurred in two consecutive optimizations, # and we still haven't converged, then just exit. return { "errors": self.errors, "actions": None, "opt_error_history": self.opt_error_history, } self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif "unable_to_determine_lamda" in self.errors: # Set last geom as new starting geom and rerun. If no opt cycles, # use diff SCF start? Diff initial guess? Change basis? Unclear. if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif self.qcinp.rem.get("thresh", "10") != "14": self.qcinp.rem["thresh"] = "14" actions.append({"thresh": "14"}) else: print( "Use a different initial guess? Perhaps a different basis?" ) elif "premature_end_FileMan_error" in self.errors: if self.qcinp.rem.get("thresh", "10") != "14": self.qcinp.rem["thresh"] = "14" actions.append({"thresh": "14"}) elif self.qcinp.rem.get("scf_guess_always", "none").lower() != "true": self.qcinp.rem["scf_guess_always"] = True actions.append({"scf_guess_always": True}) else: print( "We're in a bad spot if we get a FileMan error while always generating a new SCF guess..." ) elif "hessian_eigenvalue_error" in self.errors: if self.qcinp.rem.get("thresh", "10") != "14": self.qcinp.rem["thresh"] = "14" actions.append({"thresh": "14"}) else: print( "Not sure how to fix hessian_eigenvalue_error if thresh is already 14!" ) elif "NLebdevPts" in self.errors: # this error should only be possible if resp_charges or esp_charges is set if self.qcinp.rem.get("resp_charges") or self.qcinp.rem.get( "esp_charges"): # This error is caused by insufficient no. of Lebedev points on # the grid used to compute RESP charges # Increase the density of points on the Lebedev grid using the # esp_surface_density argument (see manual >= v5.4) # the default value is 500 (=0.001 Angstrom) # or disable RESP charges as a last resort if int(self.qcinp.rem.get("esp_surface_density", 500)) >= 500: self.qcinp.rem["esp_surface_density"] = "250" actions.append({"esp_surface_density": "250"}) elif int(self.qcinp.rem.get("esp_surface_density", 250)) >= 250: self.qcinp.rem["esp_surface_density"] = "125" actions.append({"esp_surface_density": "125"}) elif int(self.qcinp.rem.get("esp_surface_density", 125)) >= 125: # switch from Lebedev mode to spherical harmonics mode if self.qcinp.rem.get("resp_charges"): self.qcinp.rem["resp_charges"] = "2" actions.append({"resp_charges": "2"}) if self.qcinp.rem.get("esp_charges"): self.qcinp.rem["esp_charges"] = "2" actions.append({"esp_charges": "2"}) else: if self.qcinp.rem.get("resp_charges"): self.qcinp.rem["resp_charges"] = "false" actions.append({"resp_charges": "false"}) if self.qcinp.rem.get("esp_charges"): self.qcinp.rem["esp_charges"] = "false" actions.append({"esp_charges": "false"}) else: print( "Not sure how to fix NLebdevPts error if resp_charges is disabled!" ) elif "failed_to_transform_coords" in self.errors: # Check for symmetry flag in rem. If not False, set to False and rerun. # If already False, increase threshold? if not self.qcinp.rem.get("sym_ignore") or self.qcinp.rem.get( "symmetry"): self.qcinp.rem["sym_ignore"] = True self.qcinp.rem["symmetry"] = False actions.append({"sym_ignore": True}) actions.append({"symmetry": False}) else: print("Perhaps increase the threshold?") elif "basis_not_supported" in self.errors: print( "Specify a different basis set. At least one of the atoms is not supported." ) return {"errors": self.errors, "actions": None} elif "input_file_error" in self.errors: print( "Something is wrong with the input file. Examine error message by hand." ) return {"errors": self.errors, "actions": None} elif "failed_to_read_input" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun_job_no_changes": True}) elif "read_molecule_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun_job_no_changes": True}) elif "never_called_qchem" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun_job_no_changes": True}) elif "licensing_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun_job_no_changes": True}) elif "unknown_error" in self.errors: if self.qcinp.rem.get("scf_guess", "none").lower() == "read": del self.qcinp.rem["scf_guess"] actions.append({"scf_guess": "deleted"}) elif self.qcinp.rem.get("thresh", "10") != "14": self.qcinp.rem["thresh"] = "14" actions.append({"thresh": "14"}) else: print("Unknown error. Examine output and log files by hand.") return {"errors": self.errors, "actions": None} else: # You should never get here. If correct is being called then errors should have at least one entry, # in which case it should have been caught by the if/elifs above. print("Errors:", self.errors) print( "Must have gotten an error which is correctly parsed but not included in the handler. FIX!!!" ) return {"errors": self.errors, "actions": None} if { "molecule": "molecule_from_last_geometry" } in actions and str( self.qcinp.rem.get("geom_opt_hessian")).lower() == "read": del self.qcinp.rem["geom_opt_hessian"] actions.append({"geom_opt_hessian": "deleted"}) os.rename(self.input_file, self.input_file + ".last") self.qcinp.write_file(self.input_file) return { "errors": self.errors, "warnings": self.warnings, "actions": actions }
def correct(self): backup(FEFF_BACKUP_FILES) feff_input = FEFFDictSet.from_directory(".") scf_values = feff_input.tags.get("SCF") nscmt = scf_values[2] ca = scf_values[3] nmix = scf_values[4] actions = [] if nscmt < 100 and ca == 0.2: scf_values[2] = 100 scf_values[4] = 3 # Set nmix = 3 actions.append({ "dict": "PARAMETERS", "action": { "_set": { "SCF": scf_values } } }) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nscmt == 100 and nmix == 3 and ca > 0.01: # Reduce the convergence accelerator factor scf_values[3] = round(ca / 2, 2) actions.append({ "dict": "PARAMETERS", "action": { "_set": { "SCF": scf_values } } }) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nmix == 3 and ca == 0.01: # Set ca = 0.05 and set nmix scf_values[3] = 0.05 scf_values[4] = 5 actions.append({ "dict": "PARAMETERS", "action": { "_set": { "SCF": scf_values } } }) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nmix == 5 and ca == 0.05: # Set ca = 0.05 and set nmix scf_values[3] = 0.05 scf_values[4] = 10 actions.append({ "dict": "PARAMETERS", "action": { "_set": { "SCF": scf_values } } }) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} elif nmix == 10 and ca < 0.2: # loop through ca with nmix = 10 scf_values[3] = round(ca * 2, 2) actions.append({ "dict": "PARAMETERS", "action": { "_set": { "SCF": scf_values } } }) FeffModder().apply_actions(actions) return {"errors": ["Non-converging job"], "actions": actions} # Unfixable error. Just return None for actions. else: return {"errors": ["Non-converging job"], "actions": None}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if self.errors.intersection(["tet", "dentet"]): actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": 0}}}) if "inv_rot_mat" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8}}}) if "brmix" in self.errors: # If there is not a valid OUTCAR already, increment # error count to 1 to skip first fix if self.error_count['brmix'] == 0: try: assert(Outcar(zpath(os.path.join( os.getcwd(), "OUTCAR"))).is_stopped is False) except: self.error_count['brmix'] += 1 if self.error_count['brmix'] == 0: # Valid OUTCAR - simply rerun the job and increment # error count for next time actions.append({"dict": "INCAR", "action": {"_set": {"ISTART": 1}}}) self.error_count['brmix'] += 1 elif self.error_count['brmix'] == 1: # Use Kerker mixing w/default values for other parameters actions.append({"dict": "INCAR", "action": {"_set": {"IMIX": 1}}}) self.error_count['brmix'] += 1 elif self.error_count['brmix'] == 2 and vi["KPOINTS"].style \ == Kpoints.supported_modes.Gamma: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Monkhorst"}}}) actions.append({"dict": "INCAR", "action": {"_unset": {"IMIX": 1}}}) self.error_count['brmix'] += 1 elif self.error_count['brmix'] in [2, 3] and vi["KPOINTS"].style \ == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) actions.append({"dict": "INCAR", "action": {"_unset": {"IMIX": 1}}}) self.error_count['brmix'] += 1 if vi["KPOINTS"].num_kpts < 1: all_kpts_even = all([ bool(n % 2 == 0) for n in vi["KPOINTS"].kpts[0] ]) print("all_kpts_even = {}".format(all_kpts_even)) if all_kpts_even: new_kpts = (tuple(n+1 for n in vi["KPOINTS"].kpts[0]),) print("new_kpts = {}".format(new_kpts)) actions.append({"dict": "KPOINTS", "action": {"_set": { "kpoints": new_kpts }}}) else: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if "zpotrf" in self.errors: # Usually caused by short bond distances. If on the first step, # volume needs to be increased. Otherwise, it was due to a step # being too big and POTIM should be decreased. try: oszicar = Oszicar("OSZICAR") nsteps = len(oszicar.ionic_steps) except: nsteps = 0 if nsteps >= 1: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append( {"dict": "INCAR", "action": {"_set": {"ISYM": 0, "POTIM": potim}}}) else: s = vi["POSCAR"].structure s.apply_strain(0.2) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": s.as_dict()}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if self.errors.intersection(["subspacematrix", "rspher", "real_optlay"]): actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": False}}}) if self.errors.intersection(["tetirr", "incorrect_shift"]): if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) if "rot_matrix" in self.errors: if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) else: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if "amin" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"AMIN": "0.01"}}}) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": new_s.as_dict()}}, "transformation": trans.as_dict()}) if "pricel" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8, "ISYM": 0}}}) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if "zbrent" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) actions.append({"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}) if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({"dict": "INCAR", "action": {"_set": {"NBANDS": int(1.1 * nbands)}}}) if "pssyevx" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) if "eddrmm" in self.errors: # RMM algorithm is not stable for this calculation if vi["INCAR"].get("ALGO", "Normal") in ["Fast", "VeryFast"]: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) else: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {'mode': "actual"}}}) if "edddav" in self.errors: if vi["INCAR"].get("ICHARG", 0) < 10: actions.append({"file": "CHGCAR", "action": {"_file_delete": {'mode': "actual"}}}) actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "All"}}}) if "grad_not_orth" in self.errors: if vi["INCAR"].get("ISMEAR", 1) < 0: actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": "0"}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup(VASP_BACKUP_FILES | {self.output_filename}) actions = [] vi = VaspInput.from_directory(".") if self.errors.intersection(["tet", "dentet"]): actions.append({"dict": "INCAR", "action": {"_set": {"ISMEAR": 0}}}) if "inv_rot_mat" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8}}}) if "brmix" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. actions.append({"file": "CHGCAR", "action": {"_file_delete": {"mode": "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {"mode": "actual"}}}) if "zpotrf" in self.errors: # Usually caused by short bond distances. If on the first step, # volume needs to be increased. Otherwise, it was due to a step # being too big and POTIM should be decreased. try: oszicar = Oszicar("OSZICAR") nsteps = len(oszicar.ionic_steps) except: nsteps = 0 if nsteps >= 1: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0, "POTIM": potim}}}) else: s = vi["POSCAR"].structure s.apply_strain(0.2) actions.append({"dict": "POSCAR", "action": {"_set": {"structure": s.as_dict()}}}) # Based on VASP forum's recommendation, you should delete the # CHGCAR and WAVECAR when dealing with this error. actions.append({"file": "CHGCAR", "action": {"_file_delete": {"mode": "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {"mode": "actual"}}}) if self.errors.intersection(["subspacematrix", "rspher", "real_optlay"]): actions.append({"dict": "INCAR", "action": {"_set": {"LREAL": False}}}) if self.errors.intersection(["tetirr", "incorrect_shift"]): if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) if "rot_matrix" in self.errors: if vi["KPOINTS"].style == Kpoints.supported_modes.Monkhorst: actions.append({"dict": "KPOINTS", "action": {"_set": {"generation_style": "Gamma"}}}) else: actions.append({"dict": "INCAR", "action": {"_set": {"ISYM": 0}}}) if "amin" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"AMIN": "0.01"}}}) if "triple_product" in self.errors: s = vi["POSCAR"].structure trans = SupercellTransformation(((1, 0, 0), (0, 0, 1), (0, 1, 0))) new_s = trans.apply_transformation(s) actions.append( { "dict": "POSCAR", "action": {"_set": {"structure": new_s.as_dict()}}, "transformation": trans.as_dict(), } ) if "pricel" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"SYMPREC": 1e-8, "ISYM": 0}}}) if "brions" in self.errors: potim = float(vi["INCAR"].get("POTIM", 0.5)) + 0.1 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) if "zbrent" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"IBRION": 1}}}) if "too_few_bands" in self.errors: if "NBANDS" in vi["INCAR"]: nbands = int(vi["INCAR"]["NBANDS"]) else: with open("OUTCAR") as f: for line in f: if "NBANDS" in line: try: d = line.split("=") nbands = int(d[-1].strip()) break except (IndexError, ValueError): pass actions.append({"dict": "INCAR", "action": {"_set": {"NBANDS": int(1.1 * nbands)}}}) if "pssyevx" in self.errors: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) if "eddrmm" in self.errors: # RMM algorithm is not stable for this calculation if vi["INCAR"].get("ALGO", "Normal") in ["Fast", "VeryFast"]: actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "Normal"}}}) else: potim = float(vi["INCAR"].get("POTIM", 0.5)) / 2.0 actions.append({"dict": "INCAR", "action": {"_set": {"POTIM": potim}}}) actions.append({"file": "CHGCAR", "action": {"_file_delete": {"mode": "actual"}}}) actions.append({"file": "WAVECAR", "action": {"_file_delete": {"mode": "actual"}}}) if "edddav" in self.errors: actions.append({"file": "CHGCAR", "action": {"_file_delete": {"mode": "actual"}}}) actions.append({"dict": "INCAR", "action": {"_set": {"ALGO": "All"}}}) VaspModder(vi=vi).apply_actions(actions) return {"errors": list(self.errors), "actions": actions}
def correct(self): backup(AIMS_BACKUP_FILES | {self.output_filename}) actions = [] return {"errors": ["Non-convergent"], "actions": actions}