def run_task(self, fw_spec): handler_groups = { "default": [VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler()], "strict": [VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), AliasingErrorHandler()], "md": [VaspErrorHandler(), NonConvergingErrorHandler()], "no_handler": [] } vasp_cmd = env_chk(self["vasp_cmd"], fw_spec) if isinstance(vasp_cmd, six.string_types): vasp_cmd = os.path.expandvars(vasp_cmd) vasp_cmd = shlex.split(vasp_cmd) # initialize variables job_type = self.get("job_type", "normal") scratch_dir = env_chk(self.get("scratch_dir"), fw_spec) gzip_output = self.get("gzip_output", True) max_errors = self.get("max_errors", 5) auto_npar = env_chk(self.get("auto_npar"), fw_spec, strict=False, default=False) gamma_vasp_cmd = env_chk(self.get("gamma_vasp_cmd"), fw_spec, strict=False, default=None) if gamma_vasp_cmd: gamma_vasp_cmd = shlex.split(gamma_vasp_cmd) # construct jobs if job_type == "normal": jobs = [VaspJob(vasp_cmd, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd)] elif job_type == "double_relaxation_run": jobs = VaspJob.double_relaxation_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), half_kpts_first_relax=False) elif job_type == "full_opt_run": jobs = VaspJob.full_opt_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), max_steps=5, half_kpts_first_relax=False) else: raise ValueError("Unsupported job type: {}".format(job_type)) # construct handlers handlers = handler_groups[self.get("handler_group", "default")] if self.get("max_force_threshold"): handlers.append(MaxForceErrorHandler(max_force_threshold=self["max_force_threshold"])) if self.get("wall_time"): handlers.append(WalltimeHandler(wall_time=self["wall_time"])) validators = [VasprunXMLValidator()] c = Custodian(handlers, jobs, validators=validators, max_errors=max_errors, scratch_dir=scratch_dir, gzipped_output=gzip_output) c.run()
def runvasp(cmd, opt=False, max_errors=3, backup=False, auto_gamma=False, auto_npar=False, ediffg=-.05): """ cmd example: cmd=['mpirun', '-np', '32' , '-machinefile', 'hosts','vasp_std'] """ if opt: jobs = cvj.full_opt_run(cmd, auto_npar=auto_npar, ediffg=ediffg, backup=backup, auto_gamma=auto_gamma) else: jobs = [ cvj(cmd, auto_npar=auto_npar, backup=backup, auto_gamma=auto_gamma) ] c = Custodian(handlers, jobs, validators=validators, max_errors=max_errors) c.run()
def run_task(self, fw_spec): handler_groups = { "default": [ VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), StdErrHandler(), DriftErrorHandler() ], "strict": [ VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), StdErrHandler(), AliasingErrorHandler(), DriftErrorHandler() ], "md": [VaspErrorHandler(), NonConvergingErrorHandler()], "no_handler": [] } vasp_cmd = env_chk(self["vasp_cmd"], fw_spec) if isinstance(vasp_cmd, str): vasp_cmd = os.path.expandvars(vasp_cmd) vasp_cmd = shlex.split(vasp_cmd) # initialize variables job_type = self.get("job_type", "normal") scratch_dir = env_chk(self.get("scratch_dir"), fw_spec) gzip_output = self.get("gzip_output", True) max_errors = self.get("max_errors", CUSTODIAN_MAX_ERRORS) auto_npar = env_chk(self.get("auto_npar"), fw_spec, strict=False, default=False) gamma_vasp_cmd = env_chk(self.get("gamma_vasp_cmd"), fw_spec, strict=False, default=None) if gamma_vasp_cmd: gamma_vasp_cmd = shlex.split(gamma_vasp_cmd) # construct jobs if job_type == "normal": jobs = [ VaspJob(vasp_cmd, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd) ] elif job_type == "double_relaxation_run": jobs = VaspJob.double_relaxation_run( vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), half_kpts_first_relax=self.get("half_kpts_first_relax", HALF_KPOINTS_FIRST_RELAX)) elif job_type == "metagga_opt_run": jobs = VaspJob.metagga_opt_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), half_kpts_first_relax=self.get( "half_kpts_first_relax", HALF_KPOINTS_FIRST_RELAX)) elif job_type == "full_opt_run": jobs = VaspJob.full_opt_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), max_steps=9, half_kpts_first_relax=self.get( "half_kpts_first_relax", HALF_KPOINTS_FIRST_RELAX)) elif job_type == "neb": # TODO: @shyuep @HanmeiTang This means that NEB can only be run (i) in reservation mode # and (ii) when the queueadapter parameter is overridden and (iii) the queue adapter # has a convention for nnodes (with that name). Can't the number of nodes be made a # parameter that the user sets differently? e.g., fw_spec["neb_nnodes"] must be set # when setting job_type=NEB? Then someone can use this feature in non-reservation # mode and without this complication. -computron nnodes = int(fw_spec["_queueadapter"]["nnodes"]) # TODO: @shyuep @HanmeiTang - I am not sure what the code below is doing. It looks like # it is trying to override the number of processors. But I tried running the code # below after setting "vasp_cmd = 'mpirun -n 16 vasp'" and the code fails. # (i) Is this expecting an array vasp_cmd rather than String? If so, that's opposite to # the rest of this task's convention and documentation # (ii) can we get rid of this hacking in the first place? e.g., allowing the user to # separately set the NEB_VASP_CMD as an env_variable and not rewriting the command # inside this. # -computron # Index the tag "-n" or "-np" index = [i for i, s in enumerate(vasp_cmd) if '-n' in s] ppn = int(vasp_cmd[index[0] + 1]) vasp_cmd[index[0] + 1] = str(nnodes * ppn) # Do the same for gamma_vasp_cmd if gamma_vasp_cmd: index = [i for i, s in enumerate(gamma_vasp_cmd) if '-n' in s] ppn = int(gamma_vasp_cmd[index[0] + 1]) gamma_vasp_cmd[index[0] + 1] = str(nnodes * ppn) jobs = [ VaspNEBJob(vasp_cmd, final=False, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd) ] else: raise ValueError("Unsupported job type: {}".format(job_type)) # construct handlers handler_group = self.get("handler_group", "default") if isinstance(handler_group, str): handlers = handler_groups[handler_group] else: handlers = handler_group if self.get("max_force_threshold"): handlers.append( MaxForceErrorHandler( max_force_threshold=self["max_force_threshold"])) if self.get("wall_time"): handlers.append(WalltimeHandler(wall_time=self["wall_time"])) if job_type == "neb": validators = [ ] # CINEB vasprun.xml sometimes incomplete, file structure different else: validators = [VasprunXMLValidator(), VaspFilesValidator()] c = Custodian(handlers, jobs, validators=validators, max_errors=max_errors, scratch_dir=scratch_dir, gzipped_output=gzip_output) c.run() if os.path.exists(zpath("custodian.json")): stored_custodian_data = { "custodian": loadfn(zpath("custodian.json")) } return FWAction(stored_data=stored_custodian_data)
def run_task(self, fw_spec): handler_groups = { "default": [ VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler() ], "strict": [ VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), AliasingErrorHandler() ], "md": [VaspErrorHandler(), NonConvergingErrorHandler()], "no_handler": [] } vasp_cmd = env_chk(self["vasp_cmd"], fw_spec) if isinstance(vasp_cmd, six.string_types): vasp_cmd = os.path.expandvars(vasp_cmd) vasp_cmd = shlex.split(vasp_cmd) # initialize variables job_type = self.get("job_type", "normal") scratch_dir = env_chk(self.get("scratch_dir"), fw_spec) gzip_output = self.get("gzip_output", True) max_errors = self.get("max_errors", 5) auto_npar = env_chk(self.get("auto_npar"), fw_spec, strict=False, default=False) gamma_vasp_cmd = env_chk(self.get("gamma_vasp_cmd"), fw_spec, strict=False, default=None) if gamma_vasp_cmd: gamma_vasp_cmd = shlex.split(gamma_vasp_cmd) # construct jobs if job_type == "normal": jobs = [ VaspJob(vasp_cmd, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd) ] elif job_type == "double_relaxation_run": jobs = VaspJob.double_relaxation_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), half_kpts_first_relax=False) elif job_type == "full_opt_run": jobs = VaspJob.full_opt_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), max_steps=5, half_kpts_first_relax=False) else: raise ValueError("Unsupported job type: {}".format(job_type)) # construct handlers handlers = handler_groups[self.get("handler_group", "default")] if self.get("max_force_threshold"): handlers.append( MaxForceErrorHandler( max_force_threshold=self["max_force_threshold"])) if self.get("wall_time"): handlers.append(WalltimeHandler(wall_time=self["wall_time"])) validators = [VasprunXMLValidator()] c = Custodian(handlers, jobs, validators=validators, max_errors=max_errors, scratch_dir=scratch_dir, gzipped_output=gzip_output) c.run()
def get_jobs(args): # Returns a generator of jobs. Allows of "infinite" jobs. vasp_command = args.command.split() # save initial INCAR for rampU runs n_ramp_u = args.jobs.count('rampU') ramps = 0 if n_ramp_u: incar = Incar.from_file('INCAR') ldauu = incar['LDAUU'] ldauj = incar['LDAUJ'] njobs = len(args.jobs) post_settings = [ ] # append to this list to have settings applied on next job for i, job in enumerate(args.jobs): final = False if i != njobs - 1 else True if any(c.isdigit() for c in job): suffix = "." + job else: suffix = ".{}{}".format(job, i + 1) settings = post_settings post_settings = [] backup = True if i == 0 else False copy_magmom = False vinput = VaspInput.from_directory(".") if i > 0: settings.append({ "file": "CONTCAR", "action": { "_file_copy": { "dest": "POSCAR" } } }) job_type = job.lower() auto_npar = True if args.no_auto_npar: auto_npar = False if job_type.startswith("static_derived"): from pymatgen.io.vasp.sets import MPStaticSet vis = MPStaticSet.from_prev_calc(".", user_incar_settings={ "LWAVE": True, "EDIFF": 1e-6 }, ediff_per_atom=False) settings.extend([{ "dict": "INCAR", "action": { "_set": dict(vis.incar) } }, { 'dict': 'KPOINTS', 'action': { '_set': vis.kpoints.as_dict() } }]) if job_type.startswith("static_dielectric_derived"): from pymatgen.io.vasp.sets import MPStaticSet, MPStaticDielectricDFPTVaspInputSet # vis = MPStaticSet.from_prev_calc( # ".", user_incar_settings={"EDIFF": 1e-6, "IBRION": 8, # "LEPSILON": True, 'LREAL':False, # "LPEAD": True, "ISMEAR": 0, # "SIGMA": 0.01}, # ediff_per_atom=False) vis = MPStaticDielectricDFPTVaspInputSet() incar = vis.get_incar(vinput["POSCAR"].structure) unset = {} for k in [ "NPAR", "KPOINT_BSE", "LAECHG", "LCHARG", "LVHAR", "NSW" ]: incar.pop(k, None) if k in vinput["INCAR"]: unset[k] = 1 kpoints = vis.get_kpoints(vinput["POSCAR"].structure) settings.extend([{ "dict": "INCAR", "action": { "_set": dict(incar), "_unset": unset } }, { 'dict': 'KPOINTS', 'action': { '_set': kpoints.as_dict() } }]) auto_npar = False elif job_type.startswith("static"): m = [i * args.static_kpoint for i in vinput["KPOINTS"].kpts[0]] settings.extend([{ "dict": "INCAR", "action": { "_set": { "NSW": 0 } } }, { 'dict': 'KPOINTS', 'action': { '_set': { 'kpoints': [m] } } }]) elif job_type.startswith("nonscf_derived"): from pymatgen.io.vasp.sets import MPNonSCFSet vis = MPNonSCFSet.from_prev_calc( ".", copy_chgcar=False, user_incar_settings={"LWAVE": True}) settings.extend([{ "dict": "INCAR", "action": { "_set": dict(vis.incar) } }, { 'dict': 'KPOINTS', 'action': { '_set': vis.kpoints.as_dict() } }]) elif job_type.startswith("optics_derived"): from pymatgen.io.vasp.sets import MPNonSCFSet vis = MPNonSCFSet.from_prev_calc(".", optics=True, copy_chgcar=False, nedos=2001, mode="uniform", nbands_factor=5, user_incar_settings={ "LWAVE": True, "ALGO": "Exact", "SIGMA": 0.01, "EDIFF": 1e-6 }, ediff_per_atom=False) settings.extend([{ "dict": "INCAR", "action": { "_set": dict(vis.incar) } }, { 'dict': 'KPOINTS', 'action': { '_set': vis.kpoints.as_dict() } }]) elif job_type.startswith("rampu"): f = ramps / (n_ramp_u - 1) settings.append({ "dict": "INCAR", "action": { "_set": { "LDAUJ": [j * f for j in ldauj], "LDAUU": [u * f for u in ldauu] } } }) copy_magmom = True ramps += 1 elif job_type.startswith("quick_relax") or job_type.startswith(\ "quickrelax"): kpoints = vinput["KPOINTS"] incar = vinput["INCAR"] structure = vinput["POSCAR"].structure if "ISMEAR" in incar: post_settings.append({ "dict": "INCAR", "action": { "_set": { "ISMEAR": incar["ISMEAR"] } } }) else: post_settings.append({ "dict": "INCAR", "action": { "_unset": { "ISMEAR": 1 } } }) post_settings.append({ "dict": "KPOINTS", "action": { "_set": kpoints.as_dict() } }) # lattice vectors with length < 9 will get >1 KPOINT low_kpoints = Kpoints.gamma_automatic( [max(int(18 / l), 1) for l in structure.lattice.abc]) settings.extend([{ "dict": "INCAR", "action": { "_set": { "ISMEAR": 0 } } }, { 'dict': 'KPOINTS', 'action': { '_set': low_kpoints.as_dict() } }]) # let vasp determine encut (will be lower than # needed for compatibility with other runs) if "ENCUT" in incar: post_settings.append({ "dict": "INCAR", "action": { "_set": { "ENCUT": incar["ENCUT"] } } }) settings.append({ "dict": "INCAR", "action": { "_unset": { "ENCUT": 1 } } }) elif job_type.startswith("relax"): pass elif job_type.startswith("full_relax"): for j in VaspJob.full_opt_run(vasp_command): yield j else: print("Unsupported job type: {}".format(job)) sys.exit(-1) if not job_type.startswith("full_relax"): yield VaspJob(vasp_command, final=final, suffix=suffix, backup=backup, settings_override=settings, copy_magmom=copy_magmom, auto_npar=auto_npar)
def get_jobs(args): # Returns a generator of jobs. Allows of "infinite" jobs. vasp_command = args.command.split() # save initial INCAR for rampU runs n_ramp_u = args.jobs.count('rampU') ramps = 0 if n_ramp_u: incar = Incar.from_file('INCAR') ldauu = incar['LDAUU'] ldauj = incar['LDAUJ'] njobs = len(args.jobs) post_settings = [] # append to this list to have settings applied on next job for i, job in enumerate(args.jobs): final = False if i != njobs - 1 else True if any(c.isdigit() for c in job): suffix = "." + job else: suffix = ".{}{}".format(job, i + 1) settings = post_settings post_settings = [] backup = True if i == 0 else False copy_magmom = False vinput = VaspInput.from_directory(".") if i > 0: settings.append( {"file": "CONTCAR", "action": {"_file_copy": {"dest": "POSCAR"}}}) job_type = job.lower() auto_npar = True if args.no_auto_npar: auto_npar = False if job_type.startswith("static_derived"): from pymatgen.io.vasp.sets import MPStaticSet vis = MPStaticSet.from_prev_calc( ".", user_incar_settings={"LWAVE": True, "EDIFF": 1e-6}, ediff_per_atom=False) settings.extend([ {"dict" : "INCAR", "action": {"_set": dict(vis.incar)}}, {'dict': 'KPOINTS', 'action': {'_set': vis.kpoints.as_dict()}}]) if job_type.startswith("static_dielectric_derived"): from pymatgen.io.vasp.sets import MPStaticSet, MPStaticDielectricDFPTVaspInputSet # vis = MPStaticSet.from_prev_calc( # ".", user_incar_settings={"EDIFF": 1e-6, "IBRION": 8, # "LEPSILON": True, 'LREAL':False, # "LPEAD": True, "ISMEAR": 0, # "SIGMA": 0.01}, # ediff_per_atom=False) vis = MPStaticDielectricDFPTVaspInputSet() incar = vis.get_incar(vinput["POSCAR"].structure) unset = {} for k in ["NPAR", "KPOINT_BSE", "LAECHG", "LCHARG", "LVHAR", "NSW"]: incar.pop(k, None) if k in vinput["INCAR"]: unset[k] = 1 kpoints = vis.get_kpoints(vinput["POSCAR"].structure) settings.extend([ {"dict": "INCAR", "action": {"_set": dict(incar), "_unset": unset}}, {'dict': 'KPOINTS', 'action': {'_set': kpoints.as_dict()}}]) auto_npar = False elif job_type.startswith("static"): m = [i * args.static_kpoint for i in vinput["KPOINTS"].kpts[0]] settings.extend([ {"dict": "INCAR", "action": {"_set": {"NSW": 0}}}, {'dict': 'KPOINTS', 'action': {'_set': {'kpoints': [m]}}}]) elif job_type.startswith("nonscf_derived"): from pymatgen.io.vasp.sets import MPNonSCFSet vis = MPNonSCFSet.from_prev_calc(".", copy_chgcar=False, user_incar_settings={"LWAVE": True}) settings.extend([ {"dict": "INCAR", "action": {"_set": dict(vis.incar)}}, {'dict': 'KPOINTS', 'action': {'_set': vis.kpoints.as_dict()}}]) elif job_type.startswith("optics_derived"): from pymatgen.io.vasp.sets import MPNonSCFSet vis = MPNonSCFSet.from_prev_calc( ".", optics=True, copy_chgcar=False, nedos=2001, mode="uniform", nbands_factor=5, user_incar_settings={"LWAVE": True, "ALGO": "Exact", "SIGMA": 0.01, "EDIFF": 1e-6}, ediff_per_atom=False) settings.extend([ {"dict": "INCAR", "action": {"_set": dict(vis.incar)}}, {'dict': 'KPOINTS', 'action': {'_set': vis.kpoints.as_dict()}}]) elif job_type.startswith("rampu"): f = ramps / (n_ramp_u - 1) settings.append( {"dict": "INCAR", "action": {"_set": {"LDAUJ": [j * f for j in ldauj], "LDAUU": [u * f for u in ldauu]}}}) copy_magmom = True ramps += 1 elif job_type.startswith("quick_relax") or job_type.startswith(\ "quickrelax"): kpoints = vinput["KPOINTS"] incar = vinput["INCAR"] structure = vinput["POSCAR"].structure if "ISMEAR" in incar: post_settings.append( {"dict": "INCAR", "action": {"_set": {"ISMEAR": incar["ISMEAR"]}}}) else: post_settings.append( {"dict": "INCAR", "action": {"_unset": {"ISMEAR": 1}}}) post_settings.append({"dict": "KPOINTS", "action": {"_set": kpoints.as_dict()}}) # lattice vectors with length < 9 will get >1 KPOINT low_kpoints = Kpoints.gamma_automatic( [max(int(18/l), 1) for l in structure.lattice.abc]) settings.extend([ {"dict": "INCAR", "action": {"_set": {"ISMEAR": 0}}}, {'dict': 'KPOINTS', 'action': {'_set': low_kpoints.as_dict()}}]) # let vasp determine encut (will be lower than # needed for compatibility with other runs) if "ENCUT" in incar: post_settings.append( {"dict": "INCAR", "action": {"_set": {"ENCUT": incar["ENCUT"]}}}) settings.append( {"dict": "INCAR", "action": {"_unset": {"ENCUT": 1}}}) elif job_type.startswith("relax"): pass elif job_type.startswith("full_relax"): for j in VaspJob.full_opt_run( vasp_command): yield j else: print("Unsupported job type: {}".format(job)) sys.exit(-1) if not job_type.startswith("full_relax"): yield VaspJob(vasp_command, final=final, suffix=suffix, backup=backup, settings_override=settings, copy_magmom=copy_magmom, auto_npar=auto_npar)
def run_task(self, fw_spec): handler_groups = { "default": [VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(),PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), StdErrHandler(), DriftErrorHandler()], "strict": [VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(),PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), StdErrHandler(), AliasingErrorHandler(), DriftErrorHandler()], "md": [VaspErrorHandler(), NonConvergingErrorHandler()], "no_handler": [] } vasp_cmd = env_chk(self["vasp_cmd"], fw_spec) if isinstance(vasp_cmd, six.string_types): vasp_cmd = os.path.expandvars(vasp_cmd) vasp_cmd = shlex.split(vasp_cmd) # initialize variables job_type = self.get("job_type", "normal") scratch_dir = env_chk(self.get("scratch_dir"), fw_spec) gzip_output = self.get("gzip_output", True) max_errors = self.get("max_errors", 5) auto_npar = env_chk(self.get("auto_npar"), fw_spec, strict=False, default=False) gamma_vasp_cmd = env_chk(self.get("gamma_vasp_cmd"), fw_spec, strict=False, default=None) if gamma_vasp_cmd: gamma_vasp_cmd = shlex.split(gamma_vasp_cmd) # construct jobs if job_type == "normal": jobs = [VaspJob(vasp_cmd, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd)] elif job_type == "double_relaxation_run": jobs = VaspJob.double_relaxation_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), half_kpts_first_relax=self.get("half_kpts_first_relax", HALF_KPOINTS_FIRST_RELAX)) elif job_type == "metagga_opt_run": jobs = VaspJob.metagga_opt_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), half_kpts_first_relax=self.get("half_kpts_first_relax", HALF_KPOINTS_FIRST_RELAX)) elif job_type == "full_opt_run": jobs = VaspJob.full_opt_run(vasp_cmd, auto_npar=auto_npar, ediffg=self.get("ediffg"), max_steps=9, half_kpts_first_relax=self.get("half_kpts_first_relax", HALF_KPOINTS_FIRST_RELAX)) elif job_type == "neb": # TODO: @shyuep @HanmeiTang This means that NEB can only be run (i) in reservation mode # and (ii) when the queueadapter parameter is overridden and (iii) the queue adapter # has a convention for nnodes (with that name). Can't the number of nodes be made a # parameter that the user sets differently? e.g., fw_spec["neb_nnodes"] must be set # when setting job_type=NEB? Then someone can use this feature in non-reservation # mode and without this complication. -computron nnodes = int(fw_spec["_queueadapter"]["nnodes"]) # TODO: @shyuep @HanmeiTang - I am not sure what the code below is doing. It looks like # it is trying to override the number of processors. But I tried running the code # below after setting "vasp_cmd = 'mpirun -n 16 vasp'" and the code fails. # (i) Is this expecting an array vasp_cmd rather than String? If so, that's opposite to # the rest of this task's convention and documentation # (ii) can we get rid of this hacking in the first place? e.g., allowing the user to # separately set the NEB_VASP_CMD as an env_variable and not rewriting the command # inside this. # -computron # Index the tag "-n" or "-np" index = [i for i, s in enumerate(vasp_cmd) if '-n' in s] ppn = int(vasp_cmd[index[0] + 1]) vasp_cmd[index[0] + 1] = str(nnodes * ppn) # Do the same for gamma_vasp_cmd if gamma_vasp_cmd: index = [i for i, s in enumerate(gamma_vasp_cmd) if '-n' in s] ppn = int(gamma_vasp_cmd[index[0] + 1]) gamma_vasp_cmd[index[0] + 1] = str(nnodes * ppn) jobs = [VaspNEBJob(vasp_cmd, final=False, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd)] else: raise ValueError("Unsupported job type: {}".format(job_type)) # construct handlers handler_group = self.get("handler_group", "default") if isinstance(handler_group, six.string_types): handlers = handler_groups[handler_group] else: handlers = handler_group if self.get("max_force_threshold"): handlers.append(MaxForceErrorHandler(max_force_threshold=self["max_force_threshold"])) if self.get("wall_time"): handlers.append(WalltimeHandler(wall_time=self["wall_time"])) if job_type == "neb": validators = [] # CINEB vasprun.xml sometimes incomplete, file structure different else: validators = [VasprunXMLValidator(), VaspFilesValidator()] c = Custodian(handlers, jobs, validators=validators, max_errors=max_errors, scratch_dir=scratch_dir, gzipped_output=gzip_output) c.run() if os.path.exists(zpath("custodian.json")): return FWAction(stored_data=loadfn(zpath("custodian.json")))