Customizing Workflows¶
Introduction¶
The Creating Workflows guide gave details on constructing workflows. This group of tutorials will give specific examples for customizations to workflows as you create them.
For some of these customizations, preset workflows cannot be used. Preset workflows are designed to give generically reasonable options. More full access for customizing the workflows can be achieved by using the atomate.vasp.workflows.base
workflows instead of the presets.
Objectives¶
Provide examples for customizating workflows
Prerequisites¶
It’s best if you are able to create workflows on your own in Python. See the creating workflows guide
Powerups¶
Powerups are all designed to be used as functions where you pass in your original workflow and other keyword arguments and get back the modified workflow. An example is shown below, but does not show all of the powerups. To see more powerups go to the powerups documentation for the package you are using, e.g. VASP is :py:mod`atomate.vasp.powerups`.
An example for adding an INCAR setting to use a different force convergence criteria for the only the structure optimization in the elastic workflow is
from atomate.vasp.workflows.presets.core import wf_elastic_constant
from atomate.vasp.powerups import add_modify_incar
from pymatgen.core import Structure
# load your structure, e.g. from a POSCAR
struct = Structure.from_file('POSCAR')
# create the workflow
orig_wf = wf_elastic_constant(struct)
# use the powerup to change any Fireworks with 'optimization' in the name to use EDIFFG=-0.05
# note: the 'incar_update' is *required* if you want to update
# note: not passing the ``modify_incar_params`` keyword will result in the Firework getting
# the 'incar_update' key and values from your FireWorker's env
modified_wf = add_modify_incar(orig_wf, modify_incar_params={'incar_update': {'EDIFFG': -0.05}},
fw_name_constraint='optimization')
# print if you want to check the tasks. Warning: several lines long.
# print(orig_wf.fws[0].tasks)
# print(modified_wf.fws[0].tasks)
VASP Calculation Settings¶
Most VASP calculation-specific settings (e.g. those from INCAR, KPOINTS, and POTCAR files) are controlled by pymatgen’s vasp sets . VASP workflows take vasp_input_set
options and you can directly import and use them or customize them before using them in atomate workflows.
Note
Using the vasp_input_set
or vis
keywords in workflow constructors usually only controls the first Firework that uses that set. If you want to have multiple Fireworks use custom input sets (or just not the first one, e.g. in a bandstructure workflow) then you have to make a custom workflow yourself.
Using a different functional¶
To use a different functional, for instance in a optimization calculation, you can do the following:
from fireworks import Workflow
from atomate.vasp.fireworks.core import OptimizeFW
from pymatgen.io.vasp.sets import MPRelaxSet
from pymatgen.core import Structure
def get_optimize_wf(structure, name="optimization wf", vasp_input_set=None,
vasp_cmd="vasp", db_file=None, user_kpoints_settings=None,
tag="", metadata=None):
"""
Returns a structure optimization workflow.
Args:
structure (Structure): input structure to be optimized and run
name (str): some appropriate name for the transmuter fireworks.
vasp_input_set (DictSet): vasp input set.
vasp_cmd (str): command to run
db_file (str): path to file containing the database credentials.
user_kpoints_settings (dict): example: {"grid_density": 7000}
tag (str): some unique string that will be appended to the names of the fireworks so that
the data from those tagged fireworks can be queried later during the analysis.
metadata (dict): meta data
Returns:
Workflow
"""
# input set for relaxation
vis_relax = vasp_input_set or MPRelaxSet(structure)
if user_kpoints_settings:
v = vis_relax.as_dict()
v.update({"user_kpoints_settings": user_kpoints_settings})
vis_relax = vis_relax.__class__.from_dict(v)
# Structure optimization firework
fws = [OptimizeFW(structure=structure, vasp_input_set=vis_relax, vasp_cmd=vasp_cmd,
db_file=db_file, name="{} structure optimization".format(tag))]
wfname = "{}:{}".format(structure.composition.reduced_formula, name)
return Workflow(fws, name=wfname, metadata=metadata)
# load your structure, e.g. from a POSCAR
struct = Structure.from_file('POSCAR')
# create a custom input set
my_custom_input_set = MPRelaxSet(struct, potcar_functional='LDA')
# create the workflow
my_wf = get_optimize_wf(struct, vasp_input_set=my_custom_input_set)
For the supported options, see the VASP documentation and pymatgen’s vasp sets documentation. PBE (default), LDA, PW91, LDA_US were supported at the time of writing.
Custom KPOINTS settings¶
KPOINTS settings can also be similarly customized using the above example. You can control them with the following keywords (from pymatgen’s vasp sets):
force_gamma
: always use gamma centered kpoint generation. Default (False) is to use Automatic Density kpoint scheme, which will use the Gamma centered generation scheme for hexagonal cells, and Monkhorst-Pack otherwise.user_kpoints_settings
: Override kpoints setting by supplying a dict. E.g.,{"reciprocal_density": 1000}
. Other options aregrid_density
orlength
.
from pymatgen.io.vasp.sets import MPRelaxSet
from pymatgen.core import Structure
# load your structure, e.g. from a POSCAR
struct = Structure.from_file('POSCAR')
# create a custom input set
my_custom_input_set = MPRelaxSet(struct, force_gamma=True, {"grid_density": 10} )
# create the workflow
my_wf = get_optimize_wf(struct, vasp_input_set=my_custom_input_set)
If you need more control, create the Kpoints
object directly with pymatgen. It is flexible and only a brief example will be shown. See the full Kpoints documentation for more
from pymatgen.io.vasp.sets import MPRelaxSet
from pymatgen.io.vasp.inputs import Kpoints
from pymatgen.core import Structure
# load your structure, e.g. from a POSCAR
struct = Structure.from_file('POSCAR')
# the simples way to do this is to create a subclass of the input set you want
# and override the kpoints property to return what you want.
class MyInputSet(MPRelaxSet):
def __init__(self, structure, points=(5,5,5), shift=(0,0,0), **kwargs):
super(MPRelaxSet, self).__init__(structure, MPRelaxSet.CONFIG, **kwargs)
self.points = points
self.shift = shift
@property
def kpoints(self):
# choose either of these
# use Monkhorst-Pack scheme
return Kpoints.monkhorst_automatic(kpts=self.points, shift=self.shift)
# use a Gamma centered scheme
return Kpoints.gamma_automatic(kpts=self.points, shift=self.shift)
# create an instance of the custom input set
my_custom_input_set = MyInputSet(struct, points=(5,5,5), shift=(1,1,1))
# show that the set applied
print(my_custom_input_set.kpoints)
# create the workflow
my_wf = get_optimize_wf(struct, vasp_input_set=my_custom_input_set)
Custom INCAR settings¶
Custom INCAR settings can also be accomplished using VaspInputSet
objects, but it is often more efficient to use a add_modify_incar Powerup
Use a different POTCAR¶
Which POTCAR file you want to use is controlled by the input set as well. The easist way to control it is by updating the config_dict
dictionary of your input set.
from pymatgen.io.vasp.sets import MPRelaxSet
from pymatgen.core import Structure
# load your structure, e.g. from a POSCAR
struct = Structure.from_file('POSCAR')
# create a custom input set
my_custom_input_set = MPRelaxSet(struct)
print('Config dict example: {}\n'.format(my_custom_input_set.config_dict))
print('Before change: {}'.format(my_custom_input_set.config_dict['POTCAR']['Mg']))
my_custom_input_set.config_dict['POTCAR']['Mg'] = 'Mg'
print('After change: {}'.format(my_custom_input_set.config_dict['POTCAR']['Mg']))
# create the workflow
my_wf = get_optimize_wf(struct, vasp_input_set=my_custom_input_set)
Warning
Make sure not to try a nested dictionary update (e.g. my_custom_input_set.config_dict.update({'POTCAR': {'Mg': 'Mg'}})
)! It will wipe out all of the other POTCAR
entries in the dict.