This page is available as a Jupyter notebook: tutorials/7-generalized-makers.ipynb.

Writing generalized Makers

Creating a generalized maker (ex. a defect maker that works for all supported DFT codes) is difficult since the general functionalities built around DFT code (VASP, CP2K, etc.) can differ significantly. Ideally you don’t want to write completely independent Makers for each supported DFT code from scratch since much of the logic will be shared between these builders.

Assuming you have a sufficiently complex workflow made up of many job, the logic in each job will usually be mostly DFT-code-independent with a few crucial steps that are specific to each code. An example will be reading the structure form an exiting directory which requires the code-specific parsing functions.

Disentangling the DFT-code-dependent and independent parts can be a massive headache.

As such we recommend the the following approach.

  1. Define a base Maker object that defines the DFT-code-independent Flow in its make function. Code

  2. The specific jobs invoked by the common Maker will accept Callable parameters for each code-specific operation.

  3. The code-specific operations will be defined as abstract functions in the base Maker.

  4. Each code-specific operation should be implemented in the child Maker which will be concrete implementations of the base Maker.

[2]:
from jobflow import Flow, Maker, job
from jobflow.managers.local import run_locally
[3]:
class BaseMaker(Maker):
    def code_specific_func(self, arg1):
        raise NotImplementedError

    def make(self):
        return Flow([job1(self.code_specific_func, "ARG1")])


@job
def job1(func, arg1):
    print("DO CODE INDEPENDENT STUFF")
    func(arg1)
[4]:
class Code1Maker(BaseMaker):
    def code_specific_func(self, arg1):
        print("DO STUFF specific to CODE 1")


flow = Code1Maker().make()
responses = run_locally(flow)
2023-06-08 09:57:53,829 INFO Started executing jobs locally
2023-06-08 09:57:53,896 INFO Starting job - job1 (b6557183-838d-4c04-b1ab-356b8923016d)
DO CODE INDEPENDENT STUFF
DO STUFF specific to CODE 1
2023-06-08 09:57:53,896 INFO Finished job - job1 (b6557183-838d-4c04-b1ab-356b8923016d)
2023-06-08 09:57:53,896 INFO Finished executing jobs locally
[5]:
class Code2Maker(BaseMaker):
    def code_specific_func(self, arg1):
        print("DO STUFF specific to CODE 2")


flow = Code2Maker().make()
responses = run_locally(flow)
2023-06-08 09:57:53,900 INFO Started executing jobs locally
2023-06-08 09:57:53,900 INFO Starting job - job1 (7d744b4f-e0ab-46f0-adb2-72371e0c5070)
DO CODE INDEPENDENT STUFF
DO STUFF specific to CODE 2
2023-06-08 09:57:53,901 INFO Finished job - job1 (7d744b4f-e0ab-46f0-adb2-72371e0c5070)
2023-06-08 09:57:53,901 INFO Finished executing jobs locally