def setup(self, initdir): """ mv all files and directories (besides initdir) into initdir """ print("Moving files into initial run directory:", initdir) initdir = os.path.abspath(initdir) for my_prop in os.listdir(self.propdir): if (my_prop in io.VASP_INPUT_FILE_LIST + self.settings["extra_input_files"]) and (os.path.join( self.propdir, my_prop) != initdir): os.rename(os.path.join(self.propdir, my_prop), os.path.join(initdir, my_prop)) print("") sys.stdout.flush() # Keep a backup copy of the base INCAR shutil.copyfile(os.path.join(initdir, "INCAR"), os.path.join(self.propdir, "INCAR.base")) # If an initial incar is called for, copy it in and set the appropriate flag if (self.settings["initial"] != None) and (os.path.isfile( os.path.join(self.propdir, self.settings["initial"]))): new_values = io.Incar( os.path.join(self.propdir, self.settings["initial"])).tags io.set_incar_tag(new_values, initdir) print(" Set INCAR tags:", new_values, "\n") sys.stdout.flush()
def fix(self, err_jobdir, new_jobdir, settings): """ Up symprec, or turn off symmetry""" continue_job(err_jobdir, new_jobdir, settings) symprec = io.get_incar_tag("SYMPREC", jobdir=new_jobdir) if symprec is None or symprec > 1.1e-8: print(" Set SYMPREC = 1e-8") io.set_incar_tag({"SYMPREC": 1e-8}, jobdir=new_jobdir) elif io.get_incar_tag("ISYM", jobdir=new_jobdir) != 0: print(" Set ISYM = 0") io.set_incar_tag({"ISYM": 0}, jobdir=new_jobdir)
def fix(self, err_jobdir, new_jobdir, settings): """ Try to fix the error by changing the algo""" continue_job(err_jobdir, new_jobdir, settings) # Replace the potentially bad POSCAR shutil.copyfile(os.path.join(err_jobdir, "POSCAR"), os.path.join(new_jobdir, "POSCAR")) # First, see if a change of ALGO helps curr_algo = io.get_incar_tag("ALGO", new_jobdir).upper() if curr_algo == 'FAST': io.set_incar_tag({ "ALGO": "Normal", "IALGO": None }, jobdir=new_jobdir) print(" Set ALGO = Normal") elif curr_algo == 'NORMAL': io.set_incar_tag({"ALGO": "All", "IALGO": None}, jobdir=new_jobdir) print(" Set ALGO = All") elif curr_algo == 'ALL': io.set_incar_tag({ "ALGO": "Damped", "IALGO": None }, jobdir=new_jobdir) io.set_incar_tag({"TIME": "0.4"}, jobdir=new_jobdir) print(" Set ALGO = Damped, TIME = 0.4")
def fix(self, err_jobdir, new_jobdir, settings): """ First attempt: Set ALGO = VeryFast Unset IALGO Second attempt: Set IBRION = 1 and POTIM = 0.1 Final attempt: Set LREAL = .FALSE. """ continue_job(err_jobdir, new_jobdir, settings) if io.get_incar_tag("ALGO", jobdir=new_jobdir) != "VeryFast": print(" Set Algo = VeryFast, and Unset IALGO") io.set_incar_tag({ "IALGO": None, "ALGO": "VeryFast" }, jobdir=new_jobdir) elif io.get_incar_tag("IBRION", jobdir=new_jobdir) != 1: print(" Set IBRION = 1 and POTIM = 0.1") sys.stdout.flush() io.set_incar_tag({"IBRION": 1, "POTIM": 0.1}, jobdir=new_jobdir) elif io.get_incar_tag("LREAL", jobdir=new_jobdir) != "False": print(" Set LREAL = .FALSE.") sys.stdout.flush() io.set_incar_tag({"LREAL": False}, jobdir=new_jobdir) else: print(" Set Algo = Normal, and Unset IALGO") sys.stdout.flush() io.set_incar_tag({ "IALGO": None, "ALGO": "Normal" }, jobdir=new_jobdir)
def fix(self, err_jobdir, new_jobdir, settings): """ Try to fix the error by increasing the number of bands""" continue_job(err_jobdir, new_jobdir, settings) with open(os.path.join(err_jobdir, 'OUTCAR')) as f: err_outcar = f.read().splitlines() nbands_line = [] for line in err_outcar: if "NBANDS" in line: nbands_line.append(line) if len(nbands_line) < 1: print("SERIOUS WARNING : ") print( " Couldn't find any reference to nbands in the OUTCAR. Continuing without fixing" ) else: for l in nbands_line: if 'k-points' in l.strip().split(): print(" Set NBANDS = " + str(int(1.1 * float(l.strip().split()[-1])))) sys.stdout.flush() io.set_incar_tag( {"NBANDS": int(1.1 * float(l.strip().split()[-1]))}, jobdir=new_jobdir) break
def setup(self, initdir, settings): """ mv all files and directories (besides initdir) into initdir """ ### still has to handle the images print("Moving files and directories into initial run directory:", initdir) initdir = os.path.abspath(initdir) for p in os.listdir(self.calcdir): if (p in (io.VASP_INPUT_FILE_LIST + self.settings["extra_input_files"])) and (os.path.join( self.calcdir, p) != initdir): os.rename(os.path.join(self.calcdir, p), os.path.join(initdir, p)) ## copying the folders with image poscars into initdir for i in range(settings["n_images"] + 2): folder_name = str(i).zfill( 2) #max(2, len(str(settings["n_images"]))+1 )) ##too fancy!!! shutil.copytree(os.path.join(self.calcdir, "poscars", folder_name), os.path.join(initdir, folder_name)) print("") sys.stdout.flush() # Keep a backup copy of the base INCAR shutil.copyfile(os.path.join(initdir, "INCAR"), os.path.join(self.calcdir, "INCAR.base")) os.rename(os.path.join(initdir, "POSCAR"), os.path.join(self.calcdir, "POSCAR.start")) # If an initial incar is called for, copy it in and set the appropriate flag if (self.settings["initial"] != None) and (os.path.isfile( os.path.join(self.calcdir, self.settings["initial"]))): new_values = io.Incar( os.path.join(self.calcdir, self.settings["initial"])).tags io.set_incar_tag(new_values, initdir) print(" Set INCAR tags:", new_values, "\n") sys.stdout.flush()
def fix(self, err_jobdir, new_jobdir, settings): """ First attempt: Set IBRION = 2 Second attempt: Reduce POTIM to 0.1 Final attempt: Reduce POTIM to 0.01 """ continue_job(err_jobdir, new_jobdir, settings) if io.get_incar_tag("IBRION", jobdir=new_jobdir) != 2: print(" Set IBRION = 2") io.set_incar_tag({"IBRION": 2}, jobdir=new_jobdir) elif io.get_incar_tag("POTIM", jobdir=new_jobdir) > 0.1: print(" Set POTIM = 0.1") sys.stdout.flush() io.set_incar_tag({"POTIM": 0.1}, jobdir=new_jobdir) elif io.get_incar_tag("POTIM", jobdir=new_jobdir) > 0.01: print(" Set POTIM = 0.01") sys.stdout.flush() io.set_incar_tag({"POTIM": 0.01}, jobdir=new_jobdir)
def run(jobdir=None, stdout="std.out", stderr="std.err", npar=None, ncore=None, command=None, ncpus=None, kpar=None, poll_check_time=5.0, err_check_time=60.0, err_types=None, is_neb=False): """ Run vasp using subprocess. The 'command' is executed in the directory 'jobdir'. Args: jobdir: directory to run vasp. If jobdir is None, the current directory is used. stdout: filename to write to. If stdout is None, "std.out" is used. stderr: filename to write to. If stderr is None, "std.err" is used. npar: (int or None) VASP INCAR NPAR setting. If npar is None, then NPAR is removed from INCAR kpar: (int or None) VASP INCAR KPAR setting. If kpar is None, then KPAR is removed from INCAR ncore: (int or None) VASP INCAR NCORE setting. If not npar is None or ncore is None, then NCORE is removed from INCAR command: (str or None) vasp execution command If command != None: then 'command' is run in a subprocess Else, if ncpus == 1, then command = "vasp" Else, command = "mpirun -np {NCPUS} vasp" ncpus: (int) if '{NCPUS}' is in 'command' string, then 'ncpus' is substituted in the command. if ncpus==None, $PBS_NP is used if it exists, else 1 poll_check_time: how frequently to check if the vasp job is completed err_check_time: how frequently to parse vasp output to check for errors err_types: List of error types to check for. Supported errors: 'IbzkptError', 'SubSpaceMatrixError', 'NbandsError'. Default: None, in which case only SubSpaceMatrixErrors are checked. """ print("Begin vasp run:") sys.stdout.flush() if jobdir is None: jobdir = os.getcwd() currdir = os.getcwd() os.chdir(jobdir) if ncpus is None: if "PBS_NP" in os.environ: ncpus = os.environ["PBS_NP"] elif "SLURM_NTASKS" in os.environ: ncpus = os.environ["SLURM_NTASKS"] else: ncpus = 1 if command is None: if ncpus == 1: command = "vasp" else: command = "mpirun -np {NCPUS} vasp" if re.search("\{NCPUS\}", command): command = command.format(NCPUS=str(ncpus)) ### Expand remaining environment variables command = os.path.expandvars(command) if npar is not None: ncore = None if npar is not None or ncore is not None: io.set_incar_tag({"NPAR": npar, "NCORE": ncore}, jobdir) if kpar is not None: io.set_incar_tag({"KPAR": kpar}, jobdir) print(" jobdir:", jobdir) print(" exec:", command) sys.stdout.flush() if is_neb: # checkdir = os.path.join(jobdir, "01") sout = open(os.path.join(jobdir, stdout), 'w') else: # checkdir = jobdir sout = open(os.path.join(jobdir, stdout), 'w') serr = open(os.path.join(jobdir, stderr), 'w') err = None p = subprocess.Popen(command.split(), stdout=sout, stderr=serr) # wait for process to end, and periodically check for errors poll = p.poll() last_check = time.time() stopcar_time = None while poll is None: time.sleep(poll_check_time) if time.time() - last_check > err_check_time: last_check = time.time() if is_neb: err = error_check_neb(jobdir, os.path.join(jobdir, stdout), err_types) else: err = error_check(jobdir, os.path.join(jobdir, stdout), err_types) if err != None: # FreezeErrors are fatal and usually not helped with STOPCAR if "FreezeError" in err.keys(): print(" VASP is frozen, killing job") sys.stdout.flush() # Sometimes p.kill doesn't work if the process is on multiple nodes os.kill(p.pid, signal.SIGKILL) p.kill() # If the job is re-invoked (e.g. via mpirun or srun) too quickly # after the previous job ended, infinitiband clusters can have # some issues with resource allocation. A 30s sleep solves this. time.sleep(30) # Other errors can be killed with STOPCAR, which is safer elif stopcar_time is None: print(" Found errors:", end='') for e in err: print(e, end='') print("\n Killing job with STOPCAR") sys.stdout.flush() io.write_stopcar('e', jobdir) stopcar_time = time.time() time.sleep(30) # If the STOPCAR exists, wait 5 min before manually killing the job elif time.time() - stopcar_time > 300: print(" VASP is non-responsive, killing job") sys.stdout.flush() os.kill(p.pid, signal.SIGKILL) p.kill() # If the job is re-invoked (e.g. via mpirun or srun) too quickly # after the previous job ended, infinitiband clusters can have # some issues with resource allocation. A 30s sleep solves this. time.sleep(30) poll = p.poll() # close output files sout.close() serr.close() os.chdir(currdir) print("Run complete") sys.stdout.flush() # check finished job for errors if err is None: # Crash-type errors take priority over any other error that may show up if is_neb: #if its neb it checks for crashes in the first image err = crash_check(os.path.join(jobdir, "01"), os.path.join(jobdir, stdout), err_types) else: err = crash_check(jobdir, os.path.join(jobdir, stdout), err_types) if err is None: if is_neb: err = error_check_neb(jobdir, os.path.join(jobdir, stdout), err_types) else: err = error_check(jobdir, os.path.join(jobdir, stdout), err_types) if err != None: print(" Found errors:", end='') for e in err: print(e, end='') print("\n") sys.stdout.flush() return err
def run(self): """ Perform a series of vasp jobs to relax a structure. Performs a series of vasp calculations until convergence is reached according to the criteria in 'status()'. Then performs a final constant volume run {"ISIF":2, "ISMEAR":-5, "NSW":0, "IBRION":-1}. """ print("Begin VASP convergence run") sys.stdout.flush() # get current status of the relaxation: (status, task) = self.status() print("\n++ status:", status, " next task:", task) sys.stdout.flush() while status == "incomplete": if task == "setup": self.add_rundir() self.setup(self.rundir[-1]) elif task == "relax": self.add_rundir() continue_job(self.rundir[-2], self.rundir[-1], self.settings) shutil.copyfile(os.path.join(self.propdir, "INCAR.base"), os.path.join(self.rundir[-1], "INCAR")) elif task == "constant": self.add_rundir() continue_job(self.rundir[-2], self.rundir[-1], self.settings) # set INCAR to ISIF = 2, ISMEAR = -5, NSW = 0, IBRION = -1 if (self.settings["final"] != None) and (os.path.isfile( os.path.join(self.propdir, self.settings["final"]))): new_values = io.Incar( os.path.join(self.propdir, self.settings["final"])).tags else: new_values = { "ISIF": 2, "ISMEAR": -5, "NSW": 0, "IBRION": -1 } # set INCAR system tag to denote 'final' if io.get_incar_tag("SYSTEM", self.rundir[-1]) is None: new_values["SYSTEM"] = "final" else: new_values["SYSTEM"] = io.get_incar_tag( "SYSTEM", self.rundir[-1]) + " final" io.set_incar_tag(new_values, self.rundir[-1]) print(" Set INCAR tags:", new_values, "\n") sys.stdout.flush() else: # probably hit walltime self.add_rundir() continue_job(self.rundir[-2], self.rundir[-1], self.settings) while True: # run vasp result = run(self.rundir[-1], npar=self.settings["npar"], ncore=self.settings["ncore"], command=self.settings["vasp_cmd"], ncpus=self.settings["ncpus"], kpar=self.settings["kpar"], err_types=self.settings["err_types"]) # if no errors, continue if result is None or self.not_converging(): # Check for actions that should be taken after the initial run if len(self.rundir) == 1: if self.settings["fine_ngx"]: outcarfile = os.path.join(self.rundir[-1], "OUTCAR") if not os.path.isfile(outcarfile): # This is an error but I'm not sure what to do about it pass else: init_outcar = io.Outcar(outcarfile) if not init_outcar.complete: # This is an error but I'm not sure what to do about it pass elif (init_outcar.ngx is None or init_outcar.ngy is None or init_outcar.ngz is None): # This is an error but I'm not sure what to do about it pass else: ng_tags = { "ngx": init_outcar.ngx * 2, "ngy": init_outcar.ngy * 2, "ngz": init_outcar.ngz * 2 } print(ng_tags) io.set_incar_tag(ng_tags, self.propdir, "INCAR.base") break # else, attempt to fix first error self.add_errdir() os.mkdir(self.rundir[-1]) # self.add_rundir() err = result.itervalues().next() print("\n++ status:", "error", " next task:", "fix_error") sys.stdout.flush() print("Attempting to fix error:", str(err)) err.fix(self.errdir[-1], self.rundir[-1], self.settings) print("") sys.stdout.flush() if (self.settings["backup"] != None) and len(self.rundir) > 1: print("Restoring from backups:") for my_file in self.settings["backup"]: if os.path.isfile( os.path.join(self.rundir[-2], my_file + "_BACKUP.gz")): f_in = gzip.open( os.path.join(self.rundir[-2], my_file + "_BACKUP.gz", 'rb')) f_out = open( os.path.join(self.rundir[-1], my_file, 'wb')) f_out.write(f_in.read()) f_in.close() f_out.close() print(my_file, " restored!") sys.stdout.flush() (status, task) = self.status() print("\n++ status:", status, " next task:", task) sys.stdout.flush() if status == "complete": if not os.path.isdir(self.finaldir): # mv final results to relax.final print("mv", os.path.basename(self.rundir[-1]), os.path.basename(self.finaldir)) sys.stdout.flush() os.rename(self.rundir[-1], self.finaldir) self.rundir.pop() complete_job(self.finaldir, self.settings) return (status, task)
def run(self): """ Perform a series of vasp jobs to run calculations. Performs a series of vasp calculations until convergence is reached according to the criteria in 'status()'. """ print("Begin VASP relaxation run") sys.stdout.flush() # get current status of the relaxation: (status, task) = self.status() print("\n++ status:", status, " next task:", task) sys.stdout.flush() while status == "incomplete": if task == "setup": self.add_rundir() self.setup(self.rundir[-1], self.settings) elif task == "new_run": self.add_rundir() # if "n_images" in settings then image CONTCARs will be copied casm.vasp.continue_job(self.rundir[-2], self.rundir[-1], self.settings) shutil.copyfile( os.path.join(self.calcdir, "INCAR.base"), os.path.join(self.rundir[-1], "INCAR")) ## should it be enforced?? elif task == "constant": self.add_rundir() # if "n_images" in settings then image CONTCARs will be copied casm.vasp.continue_job(self.rundir[-2], self.rundir[-1], self.settings) # set INCAR to ISIF = 2, ISMEAR = -5, NSW = 0, IBRION = -1 if (self.settings["final"] != None) and (os.path.isfile( os.path.join(self.calcdir, self.settings["final"]))): new_values = io.Incar( os.path.join(self.calcdir, self.settings["final"])).tags else: new_values = { "ISIF": 2, "ISMEAR": -5, "NSW": 0, "IBRION": -1 } # set INCAR system tag to denote 'final' if io.get_incar_tag("SYSTEM", self.rundir[-1]) is None: new_values["SYSTEM"] = "final" else: new_values["SYSTEM"] = io.get_incar_tag( "SYSTEM", self.rundir[-1]) + " final" io.set_incar_tag(new_values, self.rundir[-1]) print(" Set INCAR tags:", new_values, "\n") sys.stdout.flush() else: ## redundent self.add_rundir() casm.vasp.continue_job(self.rundir[-2], self.rundir[-1], self.settings) while True: # run vasp result = casm.vasp.run(self.rundir[-1], stdout="stdout", npar=self.settings["npar"], ncore=self.settings["ncore"], command=self.settings["vasp_cmd"], ncpus=self.settings["ncpus"], kpar=self.settings["kpar"], err_types=self.settings["err_types"], is_neb=True) # if no errors, continue if result is None or self.not_converging(): break # else, attempt to fix first error self.add_errdir() os.mkdir(self.rundir[-1]) # self.add_rundir() err = result.itervalues().next() print("\n++ status:", "error", " next task:", "fix_error") sys.stdout.flush() print("Attempting to fix error:", str(err)) err.fix(self.errdir[-1], self.rundir[-1], self.settings) print("") sys.stdout.flush() (status, task) = self.status() print("\n++ status:", status, " next task:", task) sys.stdout.flush() if status == "complete": if not os.path.isdir(self.finaldir): # mv final results to relax.final print("mv", os.path.basename(self.rundir[-1]), os.path.basename(self.finaldir)) sys.stdout.flush() os.rename(self.rundir[-1], self.finaldir) self.rundir.pop() casm.vasp.complete_job(self.finaldir, self.settings) return (status, task)