def get_deformation(self, settings): """ Either reads or queries for deformation matrix from settings dict""" if settings["initial_deformation"]["method"] == 'manual': deformation = np.array( settings["initial_deformation"]["deformation"]) elif settings["initial_deformation"]["method"] == 'auto': configname = settings["initial_deformation"]["configname"] calctype = settings["initial_deformation"]["calctype"] sel_tmp = Selection(self.selection.proj, "EMPTY", "config", False) sel_tmp.data = pandas.DataFrame( { "configname": configname, "selected": 1 }, index=range(1)) try: os.mkdir(os.path.join(self.selection.proj.path, ".casm/tmp")) except: pass sel_config = sel_tmp.saveas( os.path.join(self.selection.proj.path, ".casm/tmp", configname.replace('/', '.')), True) sel_config.query(["relaxation_strain(U,0:5,{})".format(calctype)]) deformation = np.array([ float(sel_config.data["relaxation_strain(U,{},{})".format( i, calctype)].loc[0]) for i in range(6) ]) if os.path.isfile( os.path.join(self.selection.proj.path, ".casm/tmp", configname.replace('/', '.'))): os.remove( os.path.join(self.selection.proj.path, ".casm/tmp", configname.replace('/', '.'))) else: raise VaspWrapperError( "use manual or auto mode to set initial deformation. see casm format --vasp for settings" ) if deformation.ndim == 1: deformation = np.array( [[deformation[0], deformation[5], deformation[4]], [deformation[5], deformation[1], deformation[3]], [deformation[4], deformation[3], deformation[2]]]) return deformation
def _calc_submit_node_info(settings, config_data): """return nodes, ppn from settings of a configuration""" if settings["nodes"] != None and settings["ppn"] != None: return int(settings["nodes"]), int(settings["ppn"]) elif settings["atom_per_proc"] != None and settings["ppn"] != None: pos = vasp.io.Poscar(os.path.join(config_data["calcdir"], "POSCAR")) num = len(pos.basis) nodes = int( math.ceil( float(num) / float(settings["atom_per_proc"]) / float(settings["ppn"]))) return nodes, int(settings["ppn"]) elif settings["nodes_per_image"] != None and settings["ppn"] != None: nodes = int(config_data["n_images"]) * \ float(settings["nodes_per_image"]) return nodes, int(settings["ppn"]) else: raise VaspWrapperError( "Not enough information to determine nodes and ppn information" )
def __init__(self, selection, calctype=None, auto=True, sort=True): """set up attributes for the base class""" self.selection = selection self.calctype = calctype self.auto = auto self.sort = sort self.casm_directories = self.selection.proj.dir self.casm_settings = self.selection.proj.settings if self.casm_settings is None: raise VaspWrapperError( "Not in a CASM project. The file '.casm' directory was not found." ) self.clex = self.casm_settings.default_clex if calctype: self.clex.calctype = calctype self.calc_subdir = "" # everything between $(calcdir)/run.*/ and OSZICAR and OUTCAR files self.results_subdir = '' self.calculator = None self.append_selection_data()
def __init__(self, configdir=None, auto=True, sort=True): """ Construct a VASP relaxation job object. Arguments ---------- configdir: str, optional, default=None Path to configuration directory. If None, uses the current working directory auto: boolean, optional, default=True, Use True to use the prisms_jobs module's JobDB to manage jobs sort: boolean, optional, default=True, Use True to sort atoms in POSCAR by type """ print("Construct a casm.vaspwrapper.Relax instance:") if configdir is None: configdir = os.getcwd() print(" Input directory:", configdir) # get the configname from the configdir path _res = os.path.split(configdir) self.configname = os.path.split(_res[0])[1] + "/" + _res[1] print(" Configuration:", self.configname) print(" Reading CASM settings") self.casm_directories = DirectoryStructure(configdir) self.casm_settings = ProjectSettings(configdir) if self.casm_settings is None: raise VaspWrapperError( "Not in a CASM project. The file '.casm' directory was not found." ) if os.path.abspath(configdir) != self.configdir: print("") print("input configdir:", configdir) print("determined configname:", self.configname) print("expected configdir given configname:", self.configdir) raise VaspWrapperError("Mismatch between configname and configdir") # fixed to default_clex for now self.clex = self.casm_settings.default_clex # store path to .../config/calctype.name, and create if not existing self.calcdir = self.casm_directories.calctype_dir( self.configname, self.clex) try: os.mkdir(self.calcdir) except: pass print(" Calculations directory:", self.calcdir) # read the settings json file print(" Reading relax.json settings file") sys.stdout.flush() setfile = self.casm_directories.settings_path_crawl( "relax.json", self.configname, self.clex) if setfile is None: raise VaspWrapperError( "Could not find \"relax.json\" in an appropriate \"settings\" directory" ) sys.stdout.flush() else: print(" Read settings from:", setfile) self.settings = read_settings(setfile) # set default settings if not present if not "ncore" in self.settings: self.settings["ncore"] = None if not "npar" in self.settings: self.settings["npar"] = None if not "kpar" in self.settings: self.settings["kpar"] = None if not "vasp_cmd" in self.settings: self.settings["vasp_cmd"] = None if not "ncpus" in self.settings: self.settings["ncpus"] = None if not "run_limit" in self.settings: self.settings["run_limit"] = None if not "prerun" in self.settings: self.settings["prerun"] = None if not "postrun" in self.settings: self.settings["postrun"] = None self.auto = auto self.sort = sort print(" DONE\n") sys.stdout.flush()
def run(self): """ Setup input files, run a vasp relaxation, and report results """ # construct the Relax object relaxation = vasp.Relax(self.calcdir, self.run_settings()) # check the current status (status, task) = relaxation.status() if status == "complete": print("Status:", status) sys.stdout.flush() # mark job as complete in db if self.auto: try: complete_job() except (JobsError, JobDBError, EligibilityError) as e: print(str(e)) sys.stdout.flush() # write results to properties.calc.json self.finalize() return elif status == "not_converging": print("Status:", status) self.report_status("failed", "run_limit") print("Returning") sys.stdout.flush() return elif status == "incomplete": if task == "setup": self.setup() self.report_status("started") (status, task) = relaxation.run() else: self.report_status("failed", "unknown") raise VaspWrapperError("unexpected relaxation status: '" + status + "' and task: '" + task + "'") sys.stdout.flush() # once the run is done, update database records accordingly if status == "not_converging": # mark error if self.auto: try: error_job("Not converging") except (JobsError, JobDBError) as e: print(str(e)) sys.stdout.flush() print("Not Converging!") sys.stdout.flush() self.report_status("failed", "run_limit") # print a local settings file, so that the run_limit can be extended if the # convergence problems are fixed config_set_dir = self.casm_directories.configuration_calc_settings_dir( self.configname, self.clex) try: os.makedirs(config_set_dir) except: pass settingsfile = os.path.join(config_set_dir, "relax.json") write_settings(self.settings, settingsfile) print("Writing:", settingsfile) print("Edit the 'run_limit' property if you wish to continue.") sys.stdout.flush() return elif status == "complete": # mark job as complete in db if self.auto: try: complete_job() except (JobsError, JobDBError, EligibilityError) as e: print(str(e)) sys.stdout.flush() # write results to properties.calc.json self.finalize() else: self.report_status("failed", "unknown") raise VaspWrapperError( "vasp relaxation complete with unexpected status: '" + status + "' and task: '" + task + "'") sys.stdout.flush()
def submit(self): """Submit a job for this VASP relaxation""" print("Submitting...") print("Configuration:", self.configname) # first, check if the job has already been submitted and is not completed db = JobDB() print("Calculation directory:", self.calcdir) id = db.select_regex_id("rundir", self.calcdir) print("JobID:", id) sys.stdout.flush() if id != []: for j in id: job = db.select_job(j) # taskstatus = ["Incomplete","Complete","Continued","Check","Error:.*","Aborted"] # jobstatus = ["C","Q","R","E","W","H","M"] if job["jobstatus"] != "C": print("JobID:", job["jobid"], " Jobstatus:", job["jobstatus"], " Not submitting.") sys.stdout.flush() return #elif job["taskstatus"] in ["Complete", "Check"] or re.match( "Error:.*", job["taskstatus"]): # print "JobID:", job["jobid"], " Taskstatus:", job["taskstatus"], " Not submitting." # sys.stdout.flush() # return # second, only submit a job if relaxation status is "incomplete" # construct the Relax object relaxation = vasp.Relax(self.calcdir, self.run_settings()) # check the current status (status, task) = relaxation.status() if status == "complete": print("Status:", status, " Not submitting.") sys.stdout.flush() # ensure job marked as complete in db if self.auto: for j in id: job = db.select_job(j) if job["taskstatus"] == "Incomplete": try: complete_job(jobid=j) except (JobsError, JobDBError, EligibilityError) as e: print(str(e)) sys.stdout.flush() # ensure results report written if not os.path.isfile( os.path.join(self.calcdir, "properties.calc.json")): self.finalize() return elif status == "not_converging": print("Status:", status, " Not submitting.") sys.stdout.flush() return elif status != "incomplete": raise VaspWrapperError("unexpected relaxation status: '" + status + "' and task: '" + task + "'") sys.stdout.flush() return print("Preparing to submit a VASP relaxation job") sys.stdout.flush() # cd to configdir, submit jobs from configdir, then cd back to currdir currdir = os.getcwd() os.chdir(self.calcdir) # determine the number of atoms in the configuration print("Counting atoms in the POSCAR") sys.stdout.flush() pos = vasp.io.Poscar(os.path.join(self.configdir, "POS")) N = len(pos.basis) # construct command to be run cmd = "" if self.settings["preamble"] is not None: # Append any instructions given in the 'preamble' file, if given preamble = self.casm_directories.settings_path_crawl( self.settings["preamble"], self.configname, self.clex) with open(preamble, 'rb') as my_preamble: cmd += "".join(my_preamble.read().decode('utf-8')) # Or just execute a single prerun line, if given if self.settings["prerun"] is not None: cmd += self.settings["prerun"] + "\n" cmd += "python -c \"import casm.vaspwrapper; casm.vaspwrapper.Relax('" + self.configdir + "').run()\"\n" if self.settings["postrun"] is not None: cmd += self.settings["postrun"] + "\n" print("Constructing a job") sys.stdout.flush() # construct a Job job = Job(name=wrapper.jobname(self.configname),\ account=self.settings["account"],\ nodes=int(math.ceil(float(N)/float(self.settings["atom_per_proc"])/float(self.settings["ppn"]))),\ ppn=int(self.settings["ppn"]),\ walltime=self.settings["walltime"],\ pmem=self.settings["pmem"],\ qos=self.settings["qos"],\ queue=self.settings["queue"],\ message=self.settings["message"],\ email=self.settings["email"],\ priority=self.settings["priority"],\ command=cmd,\ auto=self.auto) print("Submitting") sys.stdout.flush() # submit the job job.submit() self.report_status("submitted") # return to current directory os.chdir(currdir) print("CASM VASPWrapper relaxation job submission complete\n") sys.stdout.flush()
def run(self): """run the job of a selection""" for index, config_data in self.selection.data.iterrows(): settings = self.read_settings(config_data["setfile"]) calculation = self.calculator(config_data["calcdir"], self.run_settings(settings)) # check the current status (status, task) = calculation.status() if status == "complete": print("Status:", status) sys.stdout.flush() # mark job as complete in db if self.auto: try: complete_job() except (JobsError, JobDBError, EligibilityError) as e: print(str(e)) sys.stdout.flush() # write results to properties.calc.json if (is_converged(calculation)): self.finalize(config_data) continue elif status == "not_converging": print("Status:", status) self.report_status(config_data["calcdir"], "failed", "run_limit") print("Returning") sys.stdout.flush() continue elif status == "incomplete": self.report_status(config_data["calcdir"], "started") (status, task) = calculation.run() else: self.report_status(config_data["calcdir"], "failed", "unknown") raise VaspWrapperError("unexpected relaxation status: '" + status + "' and task: '" + task + "'") sys.stdout.flush() # once the run is done, update database records accordingly if status == "not_converging": # mark error if self.auto: try: error_job("Not converging") except (JobsError, JobDBError) as e: print(str(e)) sys.stdout.flush() print("Not Converging!") sys.stdout.flush() self.report_status(config_data["calcdir"], "failed", "run_limit") # print a local settings file, so that the run_limit can be extended if the # convergence problems are fixed config_set_dir = self.casm_directories.configuration_calc_settings_dir( config_data["name"], self.clex, self.calc_subdir) try: os.makedirs(config_set_dir) except: pass settingsfile = os.path.join(config_set_dir, "calc.json") write_settings(settings, settingsfile) print("Writing:", settingsfile) print("Edit the 'run_limit' property if you wish to continue.") sys.stdout.flush() continue elif status == "complete": # mark job as complete in db if self.auto: try: complete_job() except (JobsError, JobDBError, EligibilityError) as e: print(str(e)) sys.stdout.flush() # write results to properties.calc.json if is_converged(calculation): self.finalize(config_data) else: self.report_status(config_data["calcdir"], "failed", "unknown") raise VaspWrapperError( "vasp relaxation complete with unexpected status: '" + status + "' and task: '" + task + "'") sys.stdout.flush()
def submit(self): """ submit jobs for a selection""" self.pre_setup() db = pbs.JobDB() for index, config_data in self.selection.data.iterrows(): print("Submitting...") print("Configuration:", config_data["name"]) #first, check if the job has already been submitted and is not completed print("Calculation directory:", config_data["calcdir"]) id = db.select_regex_id("rundir", config_data["calcdir"]) print("JobID:", id) sys.stdout.flush() try: if id != []: db.update() for j in id: job = db.select_job(j) if job["jobstatus"] != "C": print("JobID:", job["jobid"], " Jobstatus:", job["jobstatus"], " Not submitting.") sys.stdout.flush() raise BreakException except BreakException: continue settings = self.read_settings(config_data["setfile"]) # construct the Relax object calculation = self.calculator(config_data["calcdir"], self.run_settings(settings)) # check the current status (status, task) = calculation.status() if status == "complete": print("Status:", status, " Not submitting.") sys.stdout.flush() # ensure job marked as complete in db if self.auto: for j in id: job = db.select_job(j) if job["taskstatus"] == "Incomplete": try: complete_job(jobid=j) except (JobsError, JobDBError, EligibilityError) as e: print(str(e)) sys.stdout.flush() # ensure results report written if not os.path.isfile( os.path.join(config_data["calcdir"], "properties.calc.json")): if (is_converged(calculation)): self.finalize(config_data) continue elif status == "not_converging": print("Status:", status, " Not submitting.") sys.stdout.flush() continue elif status != "incomplete": raise VaspWrapperError("unexpected relaxation status: '" + status + "' and task: '" + task + "'") sys.stdout.flush() continue print("Preparing to submit a VASP relaxation PBS job") sys.stdout.flush() # cd to configdir, submit jobs from configdir, then cd back to currdir currdir = os.getcwd() os.chdir(config_data["calcdir"]) self.config_setup(config_data) nodes, ppn = self._calc_submit_node_info(settings, config_data) # construct command to be run cmd = "" if settings["preamble"] is not None: # Append any instructions given in the 'preamble' file, if given preamble = self.casm_directories.settings_path_crawl( settings["preamble"], config_data["name"], self.clex, self.calc_subdir) with open(preamble) as my_preamble: cmd += "".join(my_preamble) # Or just execute a single prerun line, if given if settings["prerun"] is not None: cmd += settings["prerun"] + "\n" cmd += self.run_cmd(config_data["configdir"], self.calctype) if settings["postrun"] is not None: cmd += settings["postrun"] + "\n" print("Constructing a PBS job") sys.stdout.flush() # construct a pbs.Job job = pbs.Job(name=casm.jobname(config_data["configdir"]), account=settings["account"], nodes=nodes, ppn=ppn, walltime=settings["walltime"], pmem=settings["pmem"], qos=settings["qos"], queue=settings["queue"], message=settings["message"], email=settings["email"], priority=settings["priority"], command=cmd, auto=self.auto, software=db.config["software"]) print("Submitting") sys.stdout.flush() # submit the job job.submit() self.report_status(config_data["calcdir"], "submitted") # return to current directory os.chdir(currdir) print("CASM VASPWrapper relaxation PBS job submission complete\n") sys.stdout.flush()