def setUp(self): try: __import__("igraph", fromlist=["Graph"]) except (ImportError, ModuleNotFoundError): raise unittest.SkipTest( "Skipping because python-igraph not installed") self.fw1 = Firework( PyTask(func="math.pow", inputs=["base", "exponent"], outputs=["first power"]), name="pow(2, 3)", spec={ "base": 2, "exponent": 3 }, ) self.fw2 = Firework( PyTask(func="math.pow", inputs=["first power", "exponent"], outputs=["second power"]), name="pow(pow(2, 3), 4)", spec={"exponent": 4}, ) self.fw3 = Firework(PyTask(func="print", inputs=["second power"]), name="the third one")
def setUp(self): try: __import__('igraph', fromlist=['Graph']) except (ImportError, ModuleNotFoundError): raise unittest.SkipTest('Skipping because python-igraph not installed') self.fw1 = Firework( PyTask( func='math.pow', inputs=['base', 'exponent'], outputs=['first power'] ), name='pow(2, 3)', spec={'base': 2, 'exponent': 3} ) self.fw2 = Firework( PyTask( func='math.pow', inputs=['first power', 'exponent'], outputs=['second power'] ), name='pow(pow(2, 3), 4)', spec={'exponent': 4} ) self.fw3 = Firework( PyTask( func='print', inputs=['second power'] ), name='the third one' )
def __init__(self, structure_file, functional, directory, is_metal=False, in_custodian=False, number_nodes=None, fw_action=None): # Create the PyTask that sets up the calculation setup_relax = PyTask(func="pybat.cli.commands.setup.relax", kwargs={ "structure_file": structure_file, "functional": functional, "calculation_dir": directory, "is_metal": is_metal }) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=directory) else: vasprun = VaspTask(directory=directory) # Extract the final cathode from the geometry optimization get_cathode = PyTask(func="pybat.cli.commands.get.get_cathode", kwargs={ "directory": os.path.join(directory), "write_cif": True }) # Create the PyTask that check the Pulay stresses pulay_task = PulayTask(directory=directory, in_custodian=in_custodian, number_nodes=number_nodes, fw_action=fw_action) # Only add number of nodes to spec if specified firework_spec = {"_launch_dir": os.getcwd()} if number_nodes is None: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) # Combine the FireTasks into one FireWork super(RelaxFirework, self).__init__( tasks=[setup_relax, vasprun, get_cathode, pulay_task], name="Geometry optimization", spec=firework_spec)
def make_firework(atoms, fw_name, vasp_settings): ''' This function makes a FireWorks rocket to perform a VASP relaxation Args: atoms `ase.Atoms` object to relax fw_name Dictionary of tags/etc to use as the FireWorks name vasp_settings Dictionary of VASP settings to pass to Vasp() Returns: firework An instance of a `fireworks.Firework` object that is set up to perform a VASP relaxation ''' # Warn the user if they're submitting a big one if len(atoms) > 80: warnings.warn( 'You are making a firework with %i atoms in it. This may ' 'take awhile.' % len(atoms), RuntimeWarning) # Take the `vasp_functions` submodule in GASpy and then pass it out to each # FireWork rocket to use. vasp_filename = vasp_functions.__file__ if vasp_filename.split( '.')[-1] == 'pyc': # Make sure we use the source file vasp_filename = vasp_filename[:-3] + 'py' with open(vasp_filename) as file_handle: vasp_functions_contents = file_handle.read() pass_vasp_functions = FileWriteTask( files_to_write=[{ 'filename': 'vasp_functions.py', 'contents': vasp_functions_contents }]) # Convert the atoms object to a string so that we can pass it through # FireWorks, and then tell the FireWork rocket to use our `vasp_functions` # submodule to unpack the string atom_trajhex = encode_atoms_to_trajhex(atoms) read_atoms_file = PyTask(func='vasp_functions.hex_to_file', args=['slab_in.traj', atom_trajhex]) # Tell the FireWork rocket to perform the relaxation relax = PyTask(func='vasp_functions.runVasp', args=['slab_in.traj', 'slab_relaxed.traj', vasp_settings], stored_data_varname='opt_results') fw_name['user'] = getpass.getuser() firework = Firework([pass_vasp_functions, read_atoms_file, relax], name=fw_name) return firework
def __init__(self, structure, supercell_matrix, t_min=5, t_max=2000, t_step=5, name="phonon", vasp_input_set=None, override_default_vasp_params=None, vasp_cmd="vasp", metadata=None, tag=None, qpoint_mesh=(50, 50, 50), prev_calc_loc=True, db_file=None, parents=None, stable_tor=0.01, **kwargs): metadata = metadata or {} tag = tag or metadata.get('tag') # generate a tag with a warning if tag is None: tag = str(uuid4()) warnings.warn('No ``tag`` was passed explicitly or in ``metadata`` to PhononFW. In order to find this Firework later, you should assign one. This was assigned: {}'.format(tag)) metadata['tag'] = tag override_default_vasp_params = override_default_vasp_params or {} ncell = int(0.5+np.linalg.det(supercell_matrix)) tmp = copy.deepcopy(override_default_vasp_params) if 'user_incar_settings' in tmp: if 'magmom' in tmp['user_incar_settings']: mag = tmp['user_incar_settings']['magmom'] supermag = [] for site in mag: n = str(site).split('*') if len(n)==1: supermag.append('{}*{}'.format(ncell,float(n[0]))) else: supermag.append('{}*{}'.format(ncell*int(n[0]),float(n[1]))) tmp['user_incar_settings']['magmom']=supermag print("phonon setting", tmp) vasp_input_set = vasp_input_set or ForceConstantsSet(structure, **tmp) supercell_structure = deepcopy(structure) supercell_structure.make_supercell(supercell_matrix) supercell_site_properties = deepcopy(supercell_structure.site_properties) t = [] # We need to get the POSCAR from the previous run or from the passed Structure # so it can be transformed to a supercell in the next step if parents: if prev_calc_loc: t.append(CopyVaspOutputs(calc_loc=prev_calc_loc, contcar_to_poscar=True)) else: # write the input set first, just to get the POSCAR file in the directory # the other inputs will get overridden by WriteVaspFromIOSetPrevStructure t.append(WriteVaspFromIOSetPrevStructure(structure=structure, vasp_input_set=vasp_input_set, site_properties=site_properties)) t.append(SupercellTransformation(supercell_matrix=supercell_matrix)) t.append(WriteVaspFromIOSetPrevStructure(vasp_input_set=vasp_input_set, site_properties=supercell_site_properties)) t.append(RunVaspCustodianNoValidate(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<", gzip_output=False)) # we skipped the validation so we can potentially fix the vasprun.xml file. # Fix and validate here. t.append(PyTask(func='dfttk.vasprun_fix.fix_vasprun', args=['vasprun.xml'])) t.append(PassCalcLocs(name=name)) t.append(CalculatePhononThermalProperties(supercell_matrix=supercell_matrix, t_min=t_min, t_max=t_max, t_step=t_step, db_file=">>db_file<<", tag=tag, metadata=metadata)) t.append(PhononStable(supercell_matrix=supercell_matrix, db_file=">>db_file<<", tag=tag, metadata=metadata, qpoint_mesh=qpoint_mesh, stable_tor=stable_tor)) super(PhononFW, self).__init__(t, parents=parents, name="{}-{}".format( structure.composition.reduced_formula, name), **kwargs)
def __init__(self, directory, nimages, functional, is_metal=False, is_migration=False, in_custodian=False, number_nodes=None): """ Create a FireWork for performing an NEB calculation. Args: directory (str): Directory in which the NEB calculation should be performed. nimages (int): Number of images to use for the NEB calculation. functional (tuple): Tuple with the functional choices. The first element contains a string that indicates the functional used ("pbe", "hse", ...), whereas the second element contains a dictionary that allows the user to specify the various functional tags. in_custodian (bool): Flag that indicates whether the calculation should be run inside a Custodian. is_metal (bool): Flag that indicates the material being studied is a metal, which changes the smearing from Gaussian to second order Methfessel-Paxton of 0.2 eV. is_migration (bool): Flag that indicates that the transition is a migration of an atom in the structure. number_nodes (int): Number of nodes that should be used for the calculations. Is required to add the proper `_category` to the Firework generated, so it is picked up by the right Fireworker. Returns: Firework: A firework that represents an NEB calculation. """ # Create the PyTask that sets up the calculation setup_neb = PyTask(func="pybat.cli.commands.setup.neb", kwargs={ "directory": directory, "nimages": nimages, "functional": functional, "is_metal": is_metal, "is_migration": is_migration }) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=directory) else: vasprun = VaspTask(directory=directory) # Add number of nodes to spec, or "none" firework_spec = {"_launch_dir": os.getcwd()} if number_nodes is None: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) # Combine the two FireTasks into one FireWork super(NebFirework, self).__init__(tasks=[setup_neb, vasprun], name="NEB calculation", spec=firework_spec)
def __init__(self, structure_file, functional, directory, write_chgcar=False, in_custodian=False, number_nodes=None): """ Create a FireWork for performing an SCF calculation. Args: structure_file (str): Path to the geometry file of the structure. functional (tuple): Tuple with the functional choices. The first element contains a string that indicates the functional used ("pbe", "hse", ...), whereas the second element contains a dictionary that allows the user to specify the various functional tags. directory (str): Directory in which the SCF calculation should be performed. write_chgcar (bool): Flag that indicates whether the CHGCAR file should be written. in_custodian (bool): Flag that indicates whether the calculation should be run inside a Custodian. number_nodes (int): Number of nodes that should be used for the calculations. Is required to add the proper `_category` to the Firework generated, so it is picked up by the right Fireworker. Returns: Firework: A firework that represents an SCF calculation. """ # Create the PyTask that sets up the calculation setup_scf = PyTask(func="pybat.cli.commands.setup.scf", kwargs={ "structure_file": structure_file, "functional": functional, "calculation_dir": directory, "write_chgcar": write_chgcar }) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=directory) else: vasprun = VaspTask(directory=directory) # Add number of nodes to spec, or "none" firework_spec = {"_launch_dir": os.getcwd()} if number_nodes is None: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) # Combine the two FireTasks into one FireWork super(ScfFirework, self).__init__(tasks=[setup_scf, vasprun], name="SCF calculation", spec=firework_spec)
def setUp(self): try: from fireworks.utilities.dagflow import DAGFlow except Exception: raise unittest.SkipTest("Skipping test, DagFlow not installed") self.fw1 = Firework(PyTask(func='math.pow', inputs=['base', 'exponent'], outputs=['first power']), name='pow(2, 3)', spec={ 'base': 2, 'exponent': 3 }) self.fw2 = Firework(PyTask(func='math.pow', inputs=['first power', 'exponent'], outputs=['second power']), name='pow(pow(2, 3), 4)', spec={'exponent': 4}) self.fw3 = Firework(PyTask(func='print', inputs=['second power']), name='the third one')
def test_dagflow_clashing_outputs(self): """ subsequent task overwrites output of a task """ from fireworks.utilities.dagflow import DAGFlow tasks = [ PyTask(func='math.pow', inputs=['first power 1', 'exponent'], outputs=['second power']), PyTask(func='math.pow', inputs=['first power 2', 'exponent'], outputs=['second power']) ] fwk = Firework(tasks, spec={ 'exponent': 4, 'first power 1': 8, 'first power 2': 4 }) msg = 'Several tasks may not use the same name in outputs list.' with self.assertRaises(AssertionError) as context: DAGFlow.from_fireworks(Workflow([fwk], {})).check() self.assertTrue(msg in str(context.exception))
def test_dagflow_input(self): """ missing input """ fw2 = Firework(PyTask(func='math.pow', inputs=['first power', 'exponent'], outputs=['second power']), name='pow(pow(2, 3), 4)') wfl = Workflow([self.fw1, fw2], {self.fw1: [fw2], fw2: []}) msg = (r"An input field must have exactly one source', 'step', " r"'pow(pow(2, 3), 4)', 'entity', 'exponent', 'sources', []") with self.assertRaises(AssertionError) as context: DAGFlow.from_fireworks(wfl) self.assertTrue(msg in str(context.exception))
def test_dagflow_clashing_outputs(self): """subsequent task overwrites output of a task""" from fireworks.utilities.dagflow import DAGFlow tasks = [ PyTask(func="math.pow", inputs=["first power 1", "exponent"], outputs=["second power"]), PyTask(func="math.pow", inputs=["first power 2", "exponent"], outputs=["second power"]), ] fwk = Firework(tasks, spec={ "exponent": 4, "first power 1": 8, "first power 2": 4 }) msg = "Several tasks may not use the same name in outputs list." with self.assertRaises(AssertionError) as context: DAGFlow.from_fireworks(Workflow([fwk], {})).check() self.assertTrue(msg in str(context.exception))
def test_dagflow_missing_input(self): """missing input""" from fireworks.utilities.dagflow import DAGFlow fw2 = Firework( PyTask(func="math.pow", inputs=["first power", "exponent"], outputs=["second power"]), name="pow(pow(2, 3), 4)", ) wfl = Workflow([self.fw1, fw2], {self.fw1: [fw2], fw2: []}) msg = ( r"Every input in inputs list must have exactly one source.', 'step', " r"'pow(pow(2, 3), 4)', 'entity', 'exponent', 'sources', []") with self.assertRaises(AssertionError) as context: DAGFlow.from_fireworks(wfl).check() self.assertTrue(msg in str(context.exception))
def test_dagflow_output(self): """ clashing inputs """ from fireworks.utilities.dagflow import DAGFlow fw2 = Firework( PyTask( func='math.pow', inputs=['first power', 'exponent'], outputs=['second power'] ), name='pow(pow(2, 3), 4)', spec={'exponent': 4, 'first power': 8} ) wfl = Workflow([self.fw1, fw2], {self.fw1: [fw2], fw2: []}) msg = (r"'An input field must have exactly one source', 'step', " r"'pow(pow(2, 3), 4)', 'entity', 'first power', 'sources'") with self.assertRaises(AssertionError) as context: DAGFlow.from_fireworks(wfl) self.assertTrue(msg in str(context.exception))
def test_dagflow_race_condition(self): """ two parent firework outputs overwrite each other """ from fireworks.utilities.dagflow import DAGFlow task = PyTask(func='math.pow', inputs=['base', 'exponent'], outputs=['second power']) fw1 = Firework(task, name='pow(2, 3)', spec={'base': 2, 'exponent': 3}) fw2 = Firework(task, name='pow(2, 3)', spec={'base': 2, 'exponent': 3}) wfl = Workflow([fw1, fw2, self.fw3], { fw1: [self.fw3], fw2: [self.fw3] }) msg = ( r"'Every input in inputs list must have exactly one source.', 'step', " r"'the third one', 'entity', 'second power', 'sources', [0, 1]") with self.assertRaises(AssertionError) as context: DAGFlow.from_fireworks(wfl).check() self.assertTrue(msg in str(context.exception))
def __init__(self, structure, supercell_matrix, t_min=5, t_max=2000, t_step=5, name="phonon", vasp_input_set=None, vasp_cmd="vasp", metadata=None, tag=None, prev_calc_loc=True, db_file=None, parents=None, **kwargs): metadata = metadata or {} tag = tag or metadata.get('tag') # generate a tag with a warning if tag is None: tag = str(uuid4()) warnings.warn( 'No ``tag`` was passed explicitly or in ``metadata`` to PhononFW. In order to find this Firework later, you should assign one. This was assigned: {}' .format(tag)) metadata['tag'] = tag vasp_input_set = vasp_input_set or ForceConstantsSet(structure) supercell_structure = deepcopy(structure) supercell_structure.make_supercell(supercell_matrix) supercell_site_properties = deepcopy( supercell_structure.site_properties) t = [] # We need to get the POSCAR from the previous run or from the passed Structure # so it can be transformed to a supercell in the next step if parents: if prev_calc_loc: t.append( CopyVaspOutputs(calc_loc=prev_calc_loc, contcar_to_poscar=True)) else: # write the input set first, just to get the POSCAR file in the directory # the other inputs will get overridden by WriteVaspFromIOSetPrevStructure t.append( WriteVaspFromIOSet(structure=structure, vasp_input_set=vasp_input_set)) t.append(SupercellTransformation(supercell_matrix=supercell_matrix)) t.append( WriteVaspFromIOSetPrevStructure( vasp_input_set=vasp_input_set, site_properties=supercell_site_properties)) t.append( RunVaspCustodianNoValidate(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<", gzip_output=False)) # we skipped the validation so we can potentially fix the vasprun.xml file. # Fix and validate here. t.append( PyTask(func='dfttk.vasprun_fix.fix_vasprun', args=['vasprun.xml'])) t.append(PassCalcLocs(name=name)) t.append( CalculatePhononThermalProperties(supercell_matrix=supercell_matrix, t_min=t_min, t_max=t_max, t_step=t_step, db_file=db_file, tag=tag, metadata=metadata)) super(PhononFW, self).__init__(t, parents=parents, name="{}-{}".format( structure.composition.reduced_formula, name), **kwargs)
launchpad = LaunchPad(host=host, name=name, username=username, password=password) db = connect('missing.db') for i, d in enumerate(db.select()): #if i != 0: # continue slab = d.toatoms() kvp = d.key_value_pairs kvp['metal'] = slab.get_chemical_symbols()[0] param = d.data slab.info = param # Encode the atoms encoding = atoms_to_encode(slab) # Two steps - write the input structure to an input file, then relax t0 = PyTask(func='qescripts.fwio.encode_to_atoms', args=[encoding]) t1 = PyTask(func='qescripts.fwespresso.get_potential_energy', stored_data_varname='trajectory') # Package the tasks into a firework, the fireworks into a workflow, # and submit the workflow to the launchpad firework = Firework([t0, t1], spec={'_priority': 1}, name=search_keys) workflow = Workflow([firework]) launchpad.add_wf(workflow)
def dos_workflow(structure_file, fix_part, fix_thickness, is_metal, k_product, in_custodian): """ Set up a workflow to calculate the DOS of a slab file. Will set up two FireWorks: "Slab Geometry Optimization": Optimizes the geometry of the slab given by the structure file. The user can also specify the part of the slab that is fixed using selective dynamics, as well as the number of layers to fix. "DOS Calculation": Calculates the density of states of the slab, as well as the local potential, which can be used to determine the vacuum level. After it is set up, the workflow is sent to the LAUNCHPAD. Args: structure_file (str): Name of the structure file which contains the slab geometry. fix_part (str): Defines the part of the slab that will remain fixed during the geometry optimization. fix_thickness (int): Number of atomic layers to fix for the geometry optimization. is_metal (bool): Specifies whether or not the material is metallic. Sets the smearing method to Methfessel-Paxton. k_product (int): Determines the density of the k-mesh in the density of states calculation. k_product represents the product of the number of k-points corresponding to a certain lattice vector with the length of that lattice vector. """ # TODO add checks # Currently the workflow will be submitted even if the file doesn't exist! current_dir = os.getcwd() # Set up the geometry optimization from the structure file. All input is # provided by the CLI arguments and options. The directory where the # geometry optimization is set up is returned and passed as output, # so it can be used by Firework children to run the calculation. setup_relax = PyTask(func="quotas.cli.commands.slab.relax", kwargs={ "structure_file": structure_file, "fix_part": fix_part, "fix_thickness": fix_thickness, "is_metal": is_metal, "verbose": False }, outputs=["relax_dir"]) if in_custodian: # Run the VASP calculation within a Custodian run_relax = PyTask(func="quotas.workflow.run_custodian", inputs=["relax_dir"]) else: # Run the VASP calculation. run_relax = PyTask(func="quotas.workflow.run_vasp", inputs=["relax_dir"]) relax_firework = Firework(tasks=[setup_relax, run_relax], name="Slab Geometry optimization", spec={"_launch_dir": current_dir}) # Set up the DOS calculation, based on the structure found from the # geometry optimization. setup_dos = PyTask(func="quotas.cli.commands.slab.dos", inputs=["relax_dir"], kwargs={"k_product": k_product}, outputs=["dos_dir"]) if in_custodian: # Run the VASP calculation within a Custodian run_dos = PyTask(func="quotas.workflow.run_custodian", inputs=["dos_dir"]) else: # Run the VASP calculation run_dos = PyTask(func="quotas.workflow.run_vasp", inputs=["dos_dir"]) dos_firework = Firework(tasks=[setup_dos, run_dos], name="DOS calculation") # Postprocessing # TODO Add postprocessing firework # Extract the necessary output # Calculate the work function -> send to database? # Add the workflow to the launchpad workflow = Workflow(fireworks=[relax_firework, dos_firework], links_dict={relax_firework: [dos_firework]}, name=structure_file + " DOS calculation") LAUNCHPAD.add_wf(workflow)
def bulk_optics_workflow(structure_file, is_metal, hse_calc, k_product, in_custodian): """ Sets up a workflow that calculates the dielectric function for the bulk structure of a material. Returns: """ current_dir = os.getcwd() # Set up the geometry optimization from the structure file. All input is # provided by the CLI arguments and options. The directory where the # geometry optimization is set up is returned and passed as output, # so it can be used by Firework children to run the calculation. setup_relax = PyTask(func="quotas.cli.commands.bulk.relax", kwargs={ "structure_file": structure_file, "is_metal": is_metal, "hse_calc": hse_calc, "verbose": False }, outputs=["relax_dir"]) if in_custodian: # Run the VASP calculation within a Custodian run_relax = PyTask(func="quotas.workflow.run_custodian", inputs=["relax_dir"]) else: # Run the VASP calculation run_relax = PyTask(func="quotas.workflow.run_vasp", inputs=["relax_dir"]) relax_firework = Firework(tasks=[setup_relax, run_relax], name="Bulk Geometry optimization", spec={"_launch_dir": current_dir}) # Set up the dielectric function calculation setup_optics = PyTask(func="quotas.cli.commands.bulk.optics", inputs=["relax_dir"], kwargs={ "k_product": k_product, "is_metal": is_metal, "hse_calc": hse_calc, "verbose": False }, outputs=["optics_dir"]) if in_custodian: # Run the VASP calculation within a Custodian run_optics = PyTask(func="quotas.workflow.run_custodian", inputs=["optics_dir"]) else: # Run the VASP calculation run_optics = PyTask(func="quotas.workflow.run_vasp", inputs=["optics_dir"]) optics_firework = Firework(tasks=[setup_optics, run_optics], name="Optics calculation") # Add the workflow to the launchpad workflow = Workflow(fireworks=[relax_firework, optics_firework], links_dict={relax_firework: [optics_firework]}, name=structure_file + " Optics calculation") LAUNCHPAD.add_wf(workflow)
def test_custodian(structure_file, fix_part, fix_thickness, is_metal, k_product): """ Testscript for using Custodian to gracefully recover from errors. Returns: None """ current_dir = os.getcwd() # Set up the geometry optimization from the structure file. All input is # provided by the CLI arguments and options. The directory where the # geometry optimization is set up is returned and passed as output, # so it can be used by Firework children to run the calculation. setup_relax = PyTask(func="quotas.cli.commands.slab.relax", kwargs={ "structure_file": structure_file, "fix_part": fix_part, "fix_thickness": fix_thickness, "is_metal": is_metal, "verbose": False }, outputs=["relax_dir"]) # Run the VASP calculation. run_relax = PyTask(func="quotas.workflow.run_custodian", inputs=["relax_dir"]) relax_firework = Firework(tasks=[setup_relax, run_relax], name="Slab Geometry optimization", spec={"_launch_dir": current_dir}) # -----> Here we would add a check to see if the job completed # successfully. If not, we can add another FireWork that makes the # necessary adjustments and restarts the calculation. # Set up the calculation setup_dos = PyTask(func="quotas.cli.commands.slab.dos", inputs=["relax_dir"], kwargs={"k_product": k_product}, outputs=["dos_dir"]) # Run the VASP calculation. run_dos = PyTask(func="quotas.workflow.run_custodian", inputs=["dos_dir"]) dos_firework = Firework(tasks=[setup_dos, run_dos], name="DOS calculation") # ----> Here we would add another check... ## Firework 3 # Extract the necessary output # Calculate the work function # Add the workflow to the launchpad workflow = Workflow(fireworks=[relax_firework, dos_firework], links_dict={relax_firework: [dos_firework]}, name=structure_file + " DOS calculation (Custodian)") LAUNCHPAD.add_wf(workflow)
def run_task(self, fw_spec): """ Args: fw_spec: Returns: FWAction """ # Extract the parameters into variables; this makes for cleaner code IMO directory = self["directory"] in_custodian = self.get("in_custodian", False) number_nodes = self.get("number_nodes", None) tolerance = self.get("tolerance", PulayTask.pulay_tolerance) fw_action = self.get('fw_action', {}) # Check if the lattice vectors have changed significantly initial_structure = Structure.from_file( os.path.join(directory, "POSCAR")) final_structure = Structure.from_file( os.path.join(directory, "CONTCAR")) sum_differences = np.linalg.norm(initial_structure.lattice.matrix - final_structure.lattice.matrix) # If the difference is small, return an empty FWAction if sum_differences < tolerance: if fw_action: return FWAction.from_dict(fw_action) else: return FWAction() # Else, set up another geometry optimization else: print( "Lattice vectors have changed significantly during geometry " "optimization. Performing another full geometry optimization to " "make sure there were no Pulay stresses present.\n\n") # Create the ScriptTask that copies the CONTCAR to the POSCAR copy_contcar = ScriptTask.from_str( "cp " + os.path.join(directory, "CONTCAR") + " " + os.path.join(directory, "POSCAR")) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=directory) else: vasprun = VaspTask(directory=directory) # Extract the final cathode from the geometry optimization get_cathode = PyTask(func="pybat.cli.commands.get.get_cathode", kwargs={ "directory": os.path.join(directory), "write_cif": True }) # Create the PyTask that check the Pulay stresses again pulay_task = PulayTask(directory=directory, in_custodian=in_custodian, number_nodes=number_nodes, tolerance=tolerance, fw_action=fw_action) # Add number of nodes to spec, or "none" firework_spec = {} if number_nodes is None or number_nodes == 0: firework_spec.update({"_category": "none"}) else: firework_spec.update( {"_category": str(number_nodes) + "nodes"}) # Combine the two FireTasks into one FireWork optimize_fw = Firework( tasks=[copy_contcar, vasprun, get_cathode, pulay_task], name="Pulay Step", spec=firework_spec) return FWAction(additions=optimize_fw)
def __init__(self, structure, functional, directory, is_metal=False, in_custodian=False, number_nodes=None, fw_action=None): """ Initialize a Firework for a geometry optimization. Args: structure: pymatgen.Structure OR path to structure file for which to run the geometry optimization. functional (tuple): Tuple with the functional choices. The first element contains a string that indicates the functional used ("pbe", "hse", ...), whereas the second element contains a dictionary that allows the user to specify the various functional tags. directory (str): Directory in which the geometry optimization should be performed. is_metal (bool): Flag that indicates the material being studied is a metal, which changes the smearing from Gaussian to second order Methfessel-Paxton of 0.2 eV. in_custodian (bool): Flag that indicates whether the calculation should be run inside a Custodian. number_nodes (int): Number of nodes that should be used for the calculations. Is required to add the proper `_category` to the Firework generated, so it is picked up by the right Fireworker. fw_action (fireworks.FWAction): FWAction to return after the final PulayTask is completed. """ # Create the PyTask that sets up the calculation setup_optimize = PyTask( func="pybat.cli.commands.setup.optimize", kwargs={"structure": structure, "functional": functional, "directory": directory, "is_metal": is_metal} ) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=directory) else: vasprun = VaspTask(directory=directory) # Extract the final cathode from the geometry optimization get_cathode = PyTask( func="pybat.cli.commands.get.get_cathode", kwargs={"directory": os.path.join(directory), "write_cif": True} ) # Create the PyTask that check the Pulay stresses pulay_task = PulayTask(directory=directory, in_custodian=in_custodian, number_nodes=number_nodes, fw_action=fw_action) # Only add number of nodes to spec if specified firework_spec = {} if number_nodes is None or number_nodes == 0: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) # Combine the FireTasks into one FireWork super(PybatOptimizeFW, self).__init__( tasks=[setup_optimize, vasprun, get_cathode, pulay_task], name="Geometry optimization", spec=firework_spec )
def get_wf_migration(structure, migration_indices=(0, 0), functional=("pbe", {}), is_metal=False, in_custodian=False, number_nodes=None): """ Set up a workflow that calculates the reaction energy for a migration in the current directory. Can later be expanded to also include kinetic barrier calculation. Args: structure (pybat.core.Cathode): Cathode for which to calculate the reaction energy of the migration. migration_indices (tuple): Tuple of the indices which designate the migrating site and the vacant site to which the cation will migrate. If no indices are provided, the user will be prompted. functional (tuple): Tuple with the functional details. The first element contains a string that indicates the functional used ("pbe", "hse", ...), whereas the second element contains a dictionary that allows the user to specify the various functional tags. is_metal (bool): Flag that indicates the material being studied is a metal, which changes the smearing from Gaussian to second order Methfessel-Paxton of 0.2 eV. Defaults to False. in_custodian (bool): Flag that indicates that the calculations should be run within a Custodian. Defaults to False. number_nodes (int): Number of nodes that should be used for the calculations. Is required to add the proper `_category` to the Firework generated, so it is picked up by the right Fireworker. """ # TODO Add setup steps to the workflow # In case adjustments need to made to the setup of certain calculations, # after which the calculation needs to be rerun, not adding the setup # steps to the workflow means that these will have to be rerun manually, # instead of simply relying on the fireworks commands. # TODO Can currently not be executed from jupyter notebook # Let the user define a migration migration_dir = define_migration(structure=structure, site=migration_indices[0], final_site=migration_indices[1], write_cif=True) # Set up the transition calculation transition(directory=migration_dir, functional=functional, is_metal=is_metal) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=os.path.join(migration_dir, "final")) else: vasprun = VaspTask(directory=os.path.join(migration_dir, "final")) # Extract the final cathode from the geometry optimization get_cathode = PyTask(func="pybat.cli.commands.get.get_cathode", kwargs={ "directory": os.path.join(migration_dir, "final"), "write_cif": True }) # Add number of nodes to spec, or "none" firework_spec = {} if number_nodes is None: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) transition_firework = Firework(tasks=[vasprun, get_cathode], name="Migration Geometry optimization", spec=firework_spec) # Set up the static calculation directory static_dir = os.path.join(migration_dir, "static_final") final_cathode = os.path.join(migration_dir, "final", "final_cathode.json") # Set up the static calculation static_fw = PybatStaticFW(structure=final_cathode, functional=functional, directory=static_dir, write_chgcar=False, in_custodian=in_custodian, number_nodes=number_nodes) struc_name = str(structure.composition.reduced_composition).replace( " ", "") return Workflow(fireworks=[transition_firework, static_fw], name=struc_name + " " + migration_dir.split("/")[-1], links_dict={transition_firework: [static_fw]})
def get_wf_dimer(structure, directory, dimer_indices, distance, functional=("pbe", {}), is_metal=False, in_custodian=False, number_nodes=None): """ Set up a workflow that calculates the thermodynamics for a dimer formation in the current directory. Can later be expanded to also include kinetic barrier calculation. Args: structure (pybat.core.LiRichCathode): LiRichCathode for which to perform a dimer workflow. Should be a LiRichCathode, as only for this class the dimer scripts are defined. directory (str): Path to the directory in which the dimer calculation should be run. dimer_indices (tuple): Indices of the oxygen sites which are to form a dimer. If no indices are provided, the user will be prompted. distance (float): Final distance between the oxygen atoms. If no distance is provided, the user will be prompted. functional (tuple): Tuple with the functional choices. The first element contains a string that indicates the functional used ("pbe", "hse", ...), whereas the second element contains a dictionary that allows the user to specify the various functional tags. is_metal (bool): Flag that indicates the material being studied is a metal, which changes the smearing from Gaussian to second order Methfessel-Paxton of 0.2 eV. Defaults to False. in_custodian (bool): Flag that indicates that the calculations should be run within a Custodian. Defaults to False. number_nodes (int): Number of nodes that should be used for the calculations. Is required to add the proper `_category` to the Firework generated, so it is picked up by the right Fireworker. """ # TODO Change naming scheme # Let the user define a dimer, unless one is provided setup_dimer = PyTask(func="pybat.cli.commands.define.dimer", kwargs={ "structure": structure, "directory": directory, "dimer_indices": dimer_indices, "distance": distance, "write_cif": True }) # Set up the FireTask that sets up the transition calculation setup_transition = PyTask(func="pybat.cli.commands.setup.transition", kwargs={ "directory": directory, "functional": functional, "is_metal": is_metal }) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=os.path.join(directory, "final")) else: vasprun = VaspTask(directory=os.path.join(directory, "final")) # Extract the final cathode from the geometry optimization get_cathode = PyTask(func="pybat.cli.commands.get.get_cathode", kwargs={ "directory": os.path.join(directory, "final"), "write_cif": True }) # Add number of nodes to spec, or "none" firework_spec = {} if number_nodes is None: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) dimer_firework = Firework( tasks=[setup_dimer, setup_transition, vasprun, get_cathode], name="Dimer Geometry optimization", spec=firework_spec) # Set up the static calculation directory static_dir = os.path.join(directory, "static_final") final_cathode = os.path.join(directory, "final", "final_cathode.json") # Set up the static calculation static_fw = PybatStaticFW(structure=final_cathode, functional=functional, directory=static_dir, write_chgcar=False, in_custodian=in_custodian, number_nodes=number_nodes) wf_name = str(structure.composition.reduced_composition).replace(" ", "") wf_name += "\n dimer" + str(dimer_indices) return Workflow(fireworks=[dimer_firework, static_fw], name=wf_name, links_dict={dimer_firework: [static_fw]})
def dimer_workflow(structure_file, dimer_indices=(0, 0), distance=0, functional=("pbe", {}), is_metal=False, in_custodian=False, number_nodes=None): """ Set up a workflow that calculates the thermodynamics for a dimer formation in the current directory. Can later be expanded to also include kinetic barrier calculation. Args: structure_file (str): Structure file of the cathode material. Note that the structure file should be a json format file that is derived from the Cathode class, i.e. it should contain the cation configuration of the structure. dimer_indices (tuple): Indices of the oxygen sites which are to form a dimer. If no indices are provided, the user will be prompted. distance (float): Final distance between the oxygen atoms. If no distance is provided, the user will be prompted. functional (tuple): Tuple with the functional choices. The first element contains a string that indicates the functional used ("pbe", "hse", ...), whereas the second element contains a dictionary that allows the user to specify the various functional tags. is_metal (bool): Flag that indicates the material being studied is a metal, which changes the smearing from Gaussian to second order Methfessel-Paxton of 0.2 eV. Defaults to False. in_custodian (bool): Flag that indicates that the calculations should be run within a Custodian. Defaults to False. number_nodes (int): Number of nodes that should be used for the calculations. Is required to add the proper `_category` to the Firework generated, so it is picked up by the right Fireworker. """ # TODO Change naming scheme # Let the user define a dimer, unless one is provided dimer_dir = define_dimer(structure_file=structure_file, dimer_indices=dimer_indices, distance=distance, write_cif=True) # Set up the FireTask that sets up the transition calculation setup_transition = PyTask( func="pybat.cli.commands.setup.transition", kwargs={"directory": dimer_dir, "functional": functional, "is_metal": is_metal, "is_migration": False} ) # Create the PyTask that runs the calculation if in_custodian: vasprun = CustodianTask(directory=os.path.join(dimer_dir, "final")) else: vasprun = VaspTask(directory=os.path.join(dimer_dir, "final")) # Extract the final cathode from the geometry optimization get_cathode = PyTask( func="pybat.cli.commands.get.get_cathode", kwargs={"directory": os.path.join(dimer_dir, "final"), "write_cif": True} ) # Add number of nodes to spec, or "none" firework_spec = {"_launch_dir": os.getcwd()} if number_nodes is None: firework_spec.update({"_category": "none"}) else: firework_spec.update({"_category": str(number_nodes) + "nodes"}) transition_firework = Firework(tasks=[setup_transition, vasprun, get_cathode], name="Dimer Geometry optimization", spec=firework_spec) # Set up the SCF calculation directory scf_dir = os.path.join(dimer_dir, "scf_final") final_cathode = os.path.join(dimer_dir, "final", "final_cathode.json") # Set up the SCF calculation scf_firework = ScfFirework( structure_file=final_cathode, functional=functional, directory=scf_dir, write_chgcar=False, in_custodian=in_custodian, number_nodes=number_nodes ) workflow = Workflow(fireworks=[transition_firework, scf_firework], name=structure_file + dimer_dir.split("/")[-1], links_dict={transition_firework: [scf_firework]}) LAUNCHPAD.add_wf(workflow)
def processfile(runfile): """Function to process testopia run yaml file and create workflows, add them to run in fireworks""" with open(runfile, 'r') as f: run_details = yaml.load(f) testcases = run_details['test_run']['cases'] print 'testcases:\n' print testcases testcasetype = type(testcases) print testcasetype run_id = int(run_details['test_run']['run_id']) print run_id environment_id = int(run_details['test_run']['environment_id']) print environment_id tcms = Testopia.from_config('/var/dt/tf/etc/testopia.cfg') environment_details = tcms.environment_get(environment_id) print environment_details rundetailsfromtcms = tcms.testrun_get(run_id) product_version = rundetailsfromtcms['product_version'] build_id = rundetailsfromtcms['build_id'] buildinfo = tcms.build_get(build_id) print buildinfo build_name = buildinfo['name'] print "build name: " + build_name print "product_version " + product_version environment_name = environment_details['name'] print environment_name environment_file = '/var/dt/tf/etc/environments/' + environment_name + '.py' environment_filepyc = environment_file + 'c' if os.path.isfile(environment_filepyc): print "environment pyc file is present, deleting it" os.remove(environment_filepyc) else: print "No cached environment pyc file found" print environment_file testsonfire = [] fwsequence = {} fwkey = '' fwvalue = '' for testcase in testcases.keys(): case_id = int(testcase) testcase_name = run_details['test_run']['cases'][testcase]['summary'] argsf = [ run_id, case_id, build_id, environment_id, environment_name, environment_file, testcase_name, product_version, build_name ] fw_test = Firework(PyTask(func='HookFW.runCase', args=argsf)) print "argsf are:" print argsf testsonfire.append(fw_test) if fwvalue: fwsequence[fwvalue] = fw_test fwvalue = fw_test else: fwvalue = fw_test #To be run as last firework in the workflow, to compile logs for the entire set of testcases rebotcmd = "cd /var/dt/tf/logs/" + str( run_id ) + '; rebot -N "DTTF" -R */*.xml; ln -s report.html index.html; echo ok ' fw_test = Firework(ScriptTask.from_str(rebotcmd)) testsonfire.append(fw_test) fwsequence[fwvalue] = fw_test print "tests on fire:" print testsonfire print "test sequence:" print fwsequence workflow = Workflow(testsonfire, fwsequence) launchpad = LaunchPad() launchpad.add_wf(workflow)