def test_check_correct_ionic(self): shutil.copy("vasprun.xml.ionic", "vasprun.xml") h = UnconvergedErrorHandler() self.assertTrue(h.check()) d = h.correct() self.assertEqual(d["errors"], ['Unconverged']) os.remove("vasprun.xml")
def test_check_correct_electronic_repeat(self): shutil.copy("vasprun.xml.electronic2", "vasprun.xml") h = UnconvergedErrorHandler() self.assertTrue(h.check()) d = h.correct() self.assertEqual(d, {"errors": ["Unconverged"], "actions": None}) os.remove("vasprun.xml")
def test_check_correct_scan(self): shutil.copy("vasprun.xml.scan", "vasprun.xml") h = UnconvergedErrorHandler() self.assertTrue(h.check()) d = h.correct() self.assertEqual(d["errors"], ['Unconverged']) self.assertIn({"dict": "INCAR", "action": {"_set": {"ALGO": "All"}}},d["actions"]) os.remove("vasprun.xml")
def test_is_converged(self): import pymatgen print(pymatgen.__file__) print(pymatgen.__version__) import custodian print(custodian.__version__) path = os.path.join(TEST_PATH, self.path, 'unconverged', 'vasprun.xml') handler = UnconvergedErrorHandler(path) print(handler.check())
def test_check_correct(self): subdir = os.path.join(test_dir, "unconverged") os.chdir(subdir) shutil.copy("INCAR", "INCAR.orig") shutil.copy("KPOINTS", "KPOINTS.orig") shutil.copy("POSCAR", "POSCAR.orig") shutil.copy("CONTCAR", "CONTCAR.orig") h = UnconvergedErrorHandler() self.assertTrue(h.check()) d = h.correct() self.assertEqual(d["errors"], ['Unconverged']) os.remove(os.path.join(subdir, "error.1.tar.gz")) shutil.move("INCAR.orig", "INCAR") shutil.move("KPOINTS.orig", "KPOINTS") shutil.move("POSCAR.orig", "POSCAR") shutil.move("CONTCAR.orig", "CONTCAR")
def test_to_from_dict(self): h = UnconvergedErrorHandler("random_name.xml") h2 = UnconvergedErrorHandler.from_dict(h.as_dict()) self.assertEqual(type(h2), UnconvergedErrorHandler) self.assertEqual(h2.output_filename, "random_name.xml")
def run_task(self, fw_spec): ueh = UnconvergedErrorHandler() custodian_out = ueh.correct() return FWAction(stored_data={'error_list': custodian_out['errors']})
def run_task(self, fw_spec): if '_fizzled_parents' in fw_spec and not 'prev_vasp_dir' in fw_spec: prev_dir = get_loc(fw_spec['_fizzled_parents'][0]['launches'][0]['launch_dir']) update_spec = {} # add this later when creating new FW fizzled_parent = True parse_dos = False else: prev_dir = get_loc(fw_spec['prev_vasp_dir']) update_spec = {'prev_vasp_dir': prev_dir, 'prev_task_type': fw_spec['prev_task_type'], 'run_tags': fw_spec['run_tags'], 'parameters': fw_spec.get('parameters')} fizzled_parent = False parse_dos = 'Uniform' in fw_spec['prev_task_type'] if 'run_tags' in fw_spec: self.additional_fields['run_tags'] = fw_spec['run_tags'] else: self.additional_fields['run_tags'] = fw_spec['_fizzled_parents'][0]['spec']['run_tags'] if MOVE_TO_GARDEN_DEV: prev_dir = move_to_garden(prev_dir, prod=False) elif MOVE_TO_GARDEN_PROD: prev_dir = move_to_garden(prev_dir, prod=True) # get the directory containing the db file db_dir = os.environ['DB_LOC'] db_path = os.path.join(db_dir, 'tasks_db.json') logging.basicConfig(level=logging.INFO) logger = logging.getLogger('MPVaspDrone') logger.setLevel(logging.INFO) sh = logging.StreamHandler(stream=sys.stdout) sh.setLevel(getattr(logging, 'INFO')) logger.addHandler(sh) with open(db_path) as f: db_creds = json.load(f) drone = MPVaspDrone( host=db_creds['host'], port=db_creds['port'], database=db_creds['database'], user=db_creds['admin_user'], password=db_creds['admin_password'], collection=db_creds['collection'], parse_dos=parse_dos, additional_fields=self.additional_fields, update_duplicates=self.update_duplicates) t_id, d = drone.assimilate(prev_dir, launches_coll=LaunchPad.auto_load().launches) mpsnl = d['snl_final'] if 'snl_final' in d else d['snl'] snlgroup_id = d['snlgroup_id_final'] if 'snlgroup_id_final' in d else d['snlgroup_id'] update_spec.update({'mpsnl': mpsnl, 'snlgroup_id': snlgroup_id}) print 'ENTERED task id:', t_id stored_data = {'task_id': t_id} if d['state'] == 'successful': update_spec['analysis'] = d['analysis'] update_spec['output'] = d['output'] return FWAction(stored_data=stored_data, update_spec=update_spec) # not successful - first test to see if UnconvergedHandler is needed if not fizzled_parent: unconverged_tag = 'unconverged_handler--{}'.format(fw_spec['prev_task_type']) output_dir = last_relax(os.path.join(prev_dir, 'vasprun.xml')) ueh = UnconvergedErrorHandler(output_filename=output_dir) if ueh.check() and unconverged_tag not in fw_spec['run_tags']: print 'Unconverged run! Creating dynamic FW...' spec = {'prev_vasp_dir': prev_dir, 'prev_task_type': fw_spec['task_type'], 'mpsnl': mpsnl, 'snlgroup_id': snlgroup_id, 'task_type': fw_spec['prev_task_type'], 'run_tags': list(fw_spec['run_tags']), 'parameters': fw_spec.get('parameters'), '_dupefinder': DupeFinderVasp().to_dict(), '_priority': fw_spec['_priority']} snl = StructureNL.from_dict(spec['mpsnl']) spec['run_tags'].append(unconverged_tag) spec['_queueadapter'] = QA_VASP fws = [] connections = {} f = Composition.from_formula( snl.structure.composition.reduced_formula).alphabetical_formula fws.append(FireWork( [VaspCopyTask({'files': ['INCAR', 'KPOINTS', 'POSCAR', 'POTCAR', 'CONTCAR'], 'use_CONTCAR': False}), SetupUnconvergedHandlerTask(), get_custodian_task(spec)], spec, name=get_slug(f + '--' + spec['task_type']), fw_id=-2)) spec = {'task_type': 'VASP db insertion', '_allow_fizzled_parents': True, '_priority': fw_spec['_priority'], '_queueadapter': QA_DB, 'run_tags': list(fw_spec['run_tags'])} spec['run_tags'].append(unconverged_tag) fws.append( FireWork([VaspToDBTask()], spec, name=get_slug(f + '--' + spec['task_type']), fw_id=-1)) connections[-2] = -1 wf = Workflow(fws, connections) return FWAction(detours=wf) # not successful and not due to convergence problem - FIZZLE raise ValueError("DB insertion successful, but don't know how to fix this FireWork! Can't continue with workflow...")
def test_to_from_dict(self): h = UnconvergedErrorHandler("random_name.xml") h2 = UnconvergedErrorHandler.from_dict(h.as_dict()) self.assertEqual(type(h2), UnconvergedErrorHandler) self.assertEqual(h2.output_filename, "random_name.xml")
from custodian.vasp.jobs import VaspJob as cvj from custodian.vasp.validators import VaspFilesValidator, VasprunXMLValidator from custodian.vasp.handlers import VaspErrorHandler,UnconvergedErrorHandler, \ NonConvergingErrorHandler,FrozenJobErrorHandler,StdErrHandler,\ WalltimeHandler,PositiveEnergyErrorHandler from custodian import Custodian import argparse handlers = [ VaspErrorHandler(), FrozenJobErrorHandler(), StdErrHandler(), NonConvergingErrorHandler(), WalltimeHandler(), PositiveEnergyErrorHandler(), UnconvergedErrorHandler() ] validators = [VaspFilesValidator(), VasprunXMLValidator()] def runvasp(cmd, opt=False, max_errors=3, backup=False, auto_gamma=False, auto_npar=True, ediffg=-.05): """ cmd example: cmd=['mpirun', '-np', '32' , '-machinefile', 'hosts','vasp_std'] """
def run_task(self, fw_spec): handler_groups = { "default": [VaspErrorHandler(), MeshSymmetryErrorHandler(), UnconvergedErrorHandler(), NonConvergingErrorHandler(),PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(), StdErrHandler()], "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 launch_workflow(self, launchpad_dir="", k_product=50, job=None, user_incar_settings=None, potcar_functional='PBE', additional_handlers=[]): """ Creates a list of Fireworks. Each Firework represents calculations that will be done on a slab system of a compound in a specific orientation. Each Firework contains a oriented unit cell relaxation job and a WriteSlabVaspInputs which creates os. Firework(s) depending on whether or not Termination=True. Vasp outputs from all slab and oriented unit cell calculations will then be inserted into a database. Args: launchpad_dir (str path): The path to my_launchpad.yaml. Defaults to the current working directory containing your runs k_product: kpts[0][0]*a. Decide k density without kpoint0, default to 50 cwd: (str path): The curent working directory. Location of where you want your vasp outputs to be. job (VaspJob): The command (cmd) entered into VaspJob object. Default is specifically set for running vasp jobs on Carver at NERSC (use aprun for Hopper or Edison). user_incar_settings(dict): A dict specifying additional incar settings, default to None (ediff_per_atom=False) potcar_functional (str): default to PBE """ launchpad = LaunchPad.from_file( os.path.join(os.environ["HOME"], launchpad_dir, "my_launchpad.yaml")) if self.reset: launchpad.reset('', require_password=False) # Scratch directory reffered to by custodian. # May be different on non-Nersc systems. if not job: job = VaspJob(["mpirun", "-n", "64", "vasp"], auto_npar=False, copy_magmom=True) handlers = [ VaspErrorHandler(), NonConvergingErrorHandler(), UnconvergedErrorHandler(), PotimErrorHandler(), PositiveEnergyErrorHandler(), FrozenJobErrorHandler(timeout=3600) ] if additional_handlers: handlers.extend(additional_handlers) cust_params = { "custodian_params": { "scratch_dir": os.path.join("/global/scratch2/sd/", os.environ["USER"]) }, "jobs": job.double_relaxation_run(job.vasp_cmd, auto_npar=False), "handlers": handlers, "max_errors": 100 } # will return a list of jobs # instead of just being one job fws = [] for key in self.miller_dict.keys(): # Enumerate through all compounds in the dictionary, # the key is the compositional formula of the compound print key for miller_index in self.miller_dict[key]: # Enumerates through all miller indices we # want to create slabs of that compound from print str(miller_index) max_norm = max( miller_index) if self.max_normal_search else None # Whether or not we want to use the # max_normal_search algorithm from surface.py print 'true or false max norm is ', max_norm, self.max_normal_search slab = SlabGenerator(self.unit_cells_dict[key][0], miller_index, self.ssize, self.vsize, max_normal_search=max_norm) oriented_uc = slab.oriented_unit_cell if self.fail_safe and len(oriented_uc) > 199: break # This method only creates the oriented unit cell, the # slabs are created in the WriteSlabVaspInputs task. # WriteSlabVaspInputs will create the slabs from # the contcar of the oriented unit cell calculation handler = [] tasks = [] folderbulk = '/%s_%s_k%s_s%sv%s_%s%s%s' % ( oriented_uc.composition.reduced_formula, 'bulk', k_product, self.ssize, self.vsize, str(miller_index[0]), str(miller_index[1]), str(miller_index[2])) cwd = os.getcwd() if self.get_bulk_e: tasks.extend([ WriteUCVaspInputs( oriented_ucell=oriented_uc, folder=folderbulk, cwd=cwd, user_incar_settings=user_incar_settings, potcar_functional=potcar_functional, k_product=k_product), RunCustodianTask(dir=folderbulk, cwd=cwd, **cust_params), VaspSlabDBInsertTask(struct_type="oriented_unit_cell", loc=folderbulk, cwd=cwd, miller_index=miller_index, **self.vaspdbinsert_params) ]) # Slab will inherit average final magnetic moment # of the bulk from outcar, will have to generalize # this for systems with different elements later # element = oriented_uc.species[0] # out = Outcar(cwd+folderbulk) # out_mag = out.magnetization # tot_mag = [mag['tot'] for mag in out_mag] # magmom = np.mean(tot_mag) # user_incar_settings['MAGMOM'] = {element: magmom} tasks.append( WriteSlabVaspInputs( folder=folderbulk, cwd=cwd, user_incar_settings=user_incar_settings, terminations=self.terminations, custodian_params=cust_params, vaspdbinsert_parameters=self.vaspdbinsert_params, potcar_functional=potcar_functional, k_product=k_product, miller_index=miller_index, min_slab_size=self.ssize, min_vacuum_size=self.vsize, ucell=self.unit_cells_dict[key][0])) fw = Firework(tasks, name=folderbulk) fws.append(fw) wf = Workflow(fws, name='Surface Calculations') launchpad.add_wf(wf)
def run_task(self, fw_spec): ueh = UnconvergedErrorHandler() custodian_out = ueh.correct() return FWAction(stored_data={'error_list': custodian_out['errors']})
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 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) jobs = [ VaspJob(vasp_cmd, auto_npar=auto_npar, gamma_vasp_cmd=gamma_vasp_cmd) ] # construct handlers handlers = handler_groups[self.get("handler_group", "default")] validators = [] c = Custodian(handlers, jobs, validators=validators, max_errors=max_errors, scratch_dir=scratch_dir, gzipped_output=gzip_output) c.run()
from pymatgen.io.vasp.inputs import Incar, Poscar, VaspInput,Potcar, Kpoints import os,shutil from custodian.vasp.jobs import VaspJob from custodian.vasp.handlers import VaspErrorHandler, UnconvergedErrorHandler,MeshSymmetryErrorHandler, NonConvergingErrorHandler, PotimErrorHandler from custodian.vasp.validators import VasprunXMLValidator from custodian.custodian import Custodian inc=Incar.from_file("INCAR") pot=Potcar.from_file("POTCAR") pos=Poscar.from_file("POSCAR") kp=Kpoints.from_file("KPOINTS") shutil.copy2('/users/knc6/bin/vdw_kernel.bindat','./') vinput = VaspInput.from_directory(".") job=VaspJob(['mpirun', '-np', '16', '/users/knc6/VASP/vasp54/src/vasp.5.4.1/bin/vasp_std'], final=False, backup=False) handlers = [VaspErrorHandler(), MeshSymmetryErrorHandler(),UnconvergedErrorHandler(), NonConvergingErrorHandler(),PotimErrorHandler()] validators = [VasprunXMLValidator()] c = Custodian(handlers, [job],max_errors=5,validators=validators) c.run()
def run_task(self, fw_spec): if '_fizzled_parents' in fw_spec and not 'prev_vasp_dir' in fw_spec: prev_dir = get_loc( fw_spec['_fizzled_parents'][0]['launches'][0]['launch_dir']) update_spec = {} # add this later when creating new FW fizzled_parent = True parse_dos = False else: prev_dir = get_loc(fw_spec['prev_vasp_dir']) update_spec = { 'prev_vasp_dir': prev_dir, 'prev_task_type': fw_spec['prev_task_type'], 'run_tags': fw_spec['run_tags'], 'parameters': fw_spec.get('parameters') } fizzled_parent = False parse_dos = 'Uniform' in fw_spec['prev_task_type'] if 'run_tags' in fw_spec: self.additional_fields['run_tags'] = fw_spec['run_tags'] else: self.additional_fields['run_tags'] = fw_spec['_fizzled_parents'][ 0]['spec']['run_tags'] if MOVE_TO_GARDEN_DEV: prev_dir = move_to_garden(prev_dir, prod=False) elif MOVE_TO_GARDEN_PROD: prev_dir = move_to_garden(prev_dir, prod=True) # get the directory containing the db file db_dir = os.environ['DB_LOC'] db_path = os.path.join(db_dir, 'tasks_db.json') logging.basicConfig(level=logging.INFO) logger = logging.getLogger('MPVaspDrone') logger.setLevel(logging.INFO) sh = logging.StreamHandler(stream=sys.stdout) sh.setLevel(getattr(logging, 'INFO')) logger.addHandler(sh) with open(db_path) as f: db_creds = json.load(f) drone = MPVaspDrone(host=db_creds['host'], port=db_creds['port'], database=db_creds['database'], user=db_creds['admin_user'], password=db_creds['admin_password'], collection=db_creds['collection'], parse_dos=parse_dos, additional_fields=self.additional_fields, update_duplicates=self.update_duplicates) t_id, d = drone.assimilate( prev_dir, launches_coll=LaunchPad.auto_load().launches) mpsnl = d['snl_final'] if 'snl_final' in d else d['snl'] snlgroup_id = d['snlgroup_id_final'] if 'snlgroup_id_final' in d else d[ 'snlgroup_id'] update_spec.update({'mpsnl': mpsnl, 'snlgroup_id': snlgroup_id}) print 'ENTERED task id:', t_id stored_data = {'task_id': t_id} if d['state'] == 'successful': update_spec['analysis'] = d['analysis'] update_spec['output'] = d['output'] return FWAction(stored_data=stored_data, update_spec=update_spec) # not successful - first test to see if UnconvergedHandler is needed if not fizzled_parent: unconverged_tag = 'unconverged_handler--{}'.format( fw_spec['prev_task_type']) output_dir = last_relax(os.path.join(prev_dir, 'vasprun.xml')) ueh = UnconvergedErrorHandler(output_filename=output_dir) if ueh.check() and unconverged_tag not in fw_spec['run_tags']: print 'Unconverged run! Creating dynamic FW...' spec = { 'prev_vasp_dir': prev_dir, 'prev_task_type': fw_spec['task_type'], 'mpsnl': mpsnl, 'snlgroup_id': snlgroup_id, 'task_type': fw_spec['prev_task_type'], 'run_tags': list(fw_spec['run_tags']), 'parameters': fw_spec.get('parameters'), '_dupefinder': DupeFinderVasp().to_dict(), '_priority': fw_spec['_priority'] } snl = StructureNL.from_dict(spec['mpsnl']) spec['run_tags'].append(unconverged_tag) spec['_queueadapter'] = QA_VASP fws = [] connections = {} f = Composition.from_formula( snl.structure.composition.reduced_formula ).alphabetical_formula fws.append( FireWork([ VaspCopyTask({ 'files': [ 'INCAR', 'KPOINTS', 'POSCAR', 'POTCAR', 'CONTCAR' ], 'use_CONTCAR': False }), SetupUnconvergedHandlerTask(), get_custodian_task(spec) ], spec, name=get_slug(f + '--' + spec['task_type']), fw_id=-2)) spec = { 'task_type': 'VASP db insertion', '_allow_fizzled_parents': True, '_priority': fw_spec['_priority'], '_queueadapter': QA_DB, 'run_tags': list(fw_spec['run_tags']) } spec['run_tags'].append(unconverged_tag) fws.append( FireWork([VaspToDBTask()], spec, name=get_slug(f + '--' + spec['task_type']), fw_id=-1)) connections[-2] = -1 wf = Workflow(fws, connections) return FWAction(detours=wf) # not successful and not due to convergence problem - FIZZLE raise ValueError( "DB insertion successful, but don't know how to fix this FireWork! Can't continue with workflow..." )