From d13a58526c2c81fa393177636e3ce9210ea7fe38 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Thu, 5 Oct 2023 10:51:30 +0100 Subject: [PATCH 1/5] Add paper --- .github/workflows/joss-pdf.yml | 23 ++++ paper/figure1.png | Bin 0 -> 6968 bytes paper/figure2.png | Bin 0 -> 21616 bytes paper/paper.md | 220 +++++++++++++++++++++++++++++++++ paper/refs.bib | 105 ++++++++++++++++ 5 files changed, 348 insertions(+) create mode 100644 .github/workflows/joss-pdf.yml create mode 100644 paper/figure1.png create mode 100644 paper/figure2.png create mode 100644 paper/paper.md create mode 100644 paper/refs.bib diff --git a/.github/workflows/joss-pdf.yml b/.github/workflows/joss-pdf.yml new file mode 100644 index 00000000..f85b711e --- /dev/null +++ b/.github/workflows/joss-pdf.yml @@ -0,0 +1,23 @@ +on: [push] + +jobs: + paper: + runs-on: ubuntu-latest + name: Paper Draft + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Build draft PDF + uses: openjournals/openjournals-draft-action@master + with: + journal: joss + # This should be the path to the paper within your repo. + paper-path: paper/paper.md + - name: Upload + uses: actions/upload-artifact@v1 + with: + name: paper + # This is the output path where Pandoc will write the compiled + # PDF. Note, this should be the same directory as the input + # paper.md + path: paper/paper.pdf diff --git a/paper/figure1.png b/paper/figure1.png new file mode 100644 index 0000000000000000000000000000000000000000..debf0eaefbd9d0c95209a8fc515b04e8ba124155 GIT binary patch literal 6968 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 literal 0 HcmV?d00001 diff --git a/paper/figure2.png b/paper/figure2.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd86175a15422b533c700383258e2d21acf2aa7 GIT binary patch literal 21616 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 Date: Thu, 5 Oct 2023 10:57:06 +0100 Subject: [PATCH 2/5] Fix tabs --- paper/paper.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index d268b5fd..7e1a273d 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -7,27 +7,27 @@ authors: - name: Andrew S. Rosen orcid: 0000-0002-0141-7006 affiliation: "1, 2" - - name: Max Gallant - orcid: 0009-0008-4099-6144 - affiliation: "1, 2" - - name: Janine George - orcid: 0000-0001-8907-0336 - affiliation: "3, 4" + - name: Max Gallant + orcid: 0009-0008-4099-6144 + affiliation: "1, 2" + - name: Janine George + orcid: 0000-0001-8907-0336 + affiliation: "3, 4" - name: Janosh Riebesell orcid: 0000-0001-5233-3462 affiliation: "2, 5" - - name: Hrushikesh Sahasrabuddhe - orcid: 0000-0001-7346-4568 - affiliation: "1, 6" + - name: Hrushikesh Sahasrabuddhe + orcid: 0000-0001-7346-4568 + affiliation: "1, 6" - name: Jimmy-Xuan Shen orcid: 0000-0002-2743-7531 affiliation: 7 - name: Mingjian Wen orcid: 0000-0003-0013-575X affiliation: 8 - - name: Matthew L. Evans - orcid: 0000-0002-1182-9098 - affiliation: "9, 10" + - name: Matthew L. Evans + orcid: 0000-0002-1182-9098 + affiliation: "9, 10" - name: Guido Petretto affiliation: 9 - name: David Waroquiers @@ -36,9 +36,9 @@ authors: - name: Gian-Marco Rignanese orcid: 0000-0002-1422-1205 affiliation: "9, 10, 11" - - name: Kristin A. Persson - orcid: 0000-0002-7212-6310 - affiliation: "1, 2, 12" + - name: Kristin A. Persson + orcid: 0000-0002-7212-6310 + affiliation: "1, 2, 12" - name: Anubhav Jain orcid: 0000-0001-5893-9967 affiliation: 6 @@ -50,10 +50,10 @@ affiliations: index: 1 - name: Materials Science Division, Lawrence Berkeley National Laboratory, Berkeley, CA, USA index: 2 - - name: Federal Institute for Materials Research and Testing, Department Materials Chemistry, Berlin, Germany - index: 3 - - name: Friedrich Schiller University Jena, Institute of Condensed Matter Theory and Solid-State Optics, Jena, Germany - index: 4 + - name: Federal Institute for Materials Research and Testing, Department Materials Chemistry, Berlin, Germany + index: 3 + - name: Friedrich Schiller University Jena, Institute of Condensed Matter Theory and Solid-State Optics, Jena, Germany + index: 4 - name: Department of Physics, University of Cambridge, Cambridge, UK index: 5 - name: Energy Storage and Distributed Resources Division, Lawrence Berkeley National Laboratory, Berkeley, CA, USA @@ -68,8 +68,8 @@ affiliations: index: 10 - name: School of Materials Science and Engineering, Northwestern Polytechnical University, No. 127 Youyi West Road, Xi’an 710072 Shaanxi, PR China index: 11 - - name: Molecular Foundry, Lawrence Berkeley National Laboratory, Berkeley, CA, USA - index: 12 + - name: Molecular Foundry, Lawrence Berkeley National Laboratory, Berkeley, CA, USA + index: 12 - name: Department of Chemistry, Imperial College London, London, UK index: 13 From d46f13fedac5ecdcc70d23ad8f9ca8aba69e041c Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Thu, 5 Oct 2023 11:04:53 +0100 Subject: [PATCH 3/5] Remove windows line breaks --- paper/refs.bib | 208 ++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/paper/refs.bib b/paper/refs.bib index 3ff2e563..9fb71169 100644 --- a/paper/refs.bib +++ b/paper/refs.bib @@ -1,105 +1,105 @@ -@misc{atomate2, -title = {Atomate2}, -url = {https://github.com/materialsproject/atomate2} -} -@misc{quacc, -doi = {10.5281/zenodo.7720998}, -title = {Quacc -- The Quantum Accelerator}, -url = {https://github.com/Quantum-Accelerators/quacc} -} -@software{rxnnetwork, -title = {Reaction Network}, -url = {https://github.com/materialsproject/reaction-network} -} -@article{pizzi2016aiida, -title={AiiDA: automated interactive infrastructure and database for computational science}, -author={Pizzi, Giovanni and Cepellotti, Andrea and Sabatini, Riccardo and Marzari, Nicola and Kozinsky, Boris}, -journal={Computational Materials Science}, -volume={111}, -pages={218--230}, -year={2016}, -publisher={Elsevier} -} -@article{mcdermott2021graph, -title={A graph-based network for predicting chemical reaction pathways in solid-state materials synthesis}, -author={McDermott, Matthew J and Dwaraknath, Shyam S and Persson, Kristin A}, -journal={Nature communications}, -volume={12}, -number={1}, -pages={3097}, -year={2021}, -publisher={Nature Publishing Group UK London} -} -@misc{wfacer, -title = {WFacer}, -year = {2023}, -url = {https://github.com/CederGroupHub/WFacer} -} -@misc{nptools, -title = {NanoParticleTools}, -url = {https://github.com/BlauGroup/NanoParticleTools} -} -@article{fireworks, -title={FireWorks: a dynamic workflow system designed for high-throughput applications}, -author={Jain, Anubhav and Ong, Shyue Ping and Chen, Wei and Medasani, Bharat and Qu, Xiaohui and Kocher, Michael and Brafman, Miriam and Petretto, Guido and Rignanese, Gian-Marco and Hautier, Geoffroy and others}, -journal={Concurrency and Computation: Practice and Experience}, -volume={27}, -number={17}, -pages={5037--5059}, -year={2015}, -publisher={Wiley Online Library} -} -@article{da2023workflows, -title={Workflows Community Summit 2022: A Roadmap Revolution}, -author={da Silva, Rafael Ferreira and Badia, Rosa M and Bala, Venkat and Bard, Debbie and Bremer, Peer-Timo and Buckley, Ian and Caino-Lores, Silvina and Chard, Kyle and Goble, Carole and Jha, Shantenu and others}, -journal={arXiv preprint arXiv:2304.00019}, -year={2023} -} -@inproceedings{ben2020workflows, -title={Workflows are the new applications: Challenges in performance, portability, and productivity}, -author={Ben-Nun, Tal and Gamblin, Todd and Hollman, Daisy S and Krishnan, Hari and Newburn, Chris J}, -booktitle={2020 IEEE/ACM International Workshop on Performance, Portability and Productivity in HPC (P3HPC)}, -pages={57--69}, -year={2020}, -organization={IEEE} -} -@misc{wflowsystems, -title={Existing Workflow Systems}, -url={https://s.apache.org/existing-workflow-systems} -} -@inproceedings{al2021exaworks, -title={Exaworks: Workflows for exascale}, -author={Al-Saadi, Aymen and Ahn, Dong H and Babuji, Yadu and Chard, Kyle and Corbett, James and Hategan, Mihael and Herbein, Stephen and Jha, Shantenu and Laney, Daniel and Merzky, Andre and others}, -booktitle={2021 IEEE Workshop on Workflows in Support of Large-Scale Science (WORKS)}, -pages={50--57}, -year={2021}, -organization={IEEE} -} -@inproceedings{babuji2019parsl, -title={Parsl: Pervasive parallel programming in python}, -author={Babuji, Yadu and Woodard, Anna and Li, Zhuozhao and Katz, Daniel S and Clifford, Ben and Kumar, Rohan and Lacinski, Lukasz and Chard, Ryan and Wozniak, Justin M and Foster, Ian and others}, -booktitle={Proceedings of the 28th International Symposium on High-Performance Parallel and Distributed Computing}, -pages={25--36}, -year={2019} -} -@misc{prefect, -title={Prefect}, -url={https://github.com/PrefectHQ/prefect} -} -@misc{redun, -title={Redun}, -url={https://github.com/insitro/redun} -} -@misc{covalent, -title={Covalent}, -doi={https://doi.org/10.5281/zenodo.5903364}, -url={https://github.com/AgnostiqHQ/covalent} -} -@misc{maggma, -title={Maggma}, -url={https://github.com/materialsproject/maggma} -} -@misc{montydb, -title={MontyDB}, -url={https://github.com/davidlatwe/montydb} +@misc{atomate2, +title = {Atomate2}, +url = {https://github.com/materialsproject/atomate2} +} +@misc{quacc, +doi = {10.5281/zenodo.7720998}, +title = {Quacc -- The Quantum Accelerator}, +url = {https://github.com/Quantum-Accelerators/quacc} +} +@software{rxnnetwork, +title = {Reaction Network}, +url = {https://github.com/materialsproject/reaction-network} +} +@article{pizzi2016aiida, +title={AiiDA: automated interactive infrastructure and database for computational science}, +author={Pizzi, Giovanni and Cepellotti, Andrea and Sabatini, Riccardo and Marzari, Nicola and Kozinsky, Boris}, +journal={Computational Materials Science}, +volume={111}, +pages={218--230}, +year={2016}, +publisher={Elsevier} +} +@article{mcdermott2021graph, +title={A graph-based network for predicting chemical reaction pathways in solid-state materials synthesis}, +author={McDermott, Matthew J and Dwaraknath, Shyam S and Persson, Kristin A}, +journal={Nature communications}, +volume={12}, +number={1}, +pages={3097}, +year={2021}, +publisher={Nature Publishing Group UK London} +} +@misc{wfacer, +title = {WFacer}, +year = {2023}, +url = {https://github.com/CederGroupHub/WFacer} +} +@misc{nptools, +title = {NanoParticleTools}, +url = {https://github.com/BlauGroup/NanoParticleTools} +} +@article{fireworks, +title={FireWorks: a dynamic workflow system designed for high-throughput applications}, +author={Jain, Anubhav and Ong, Shyue Ping and Chen, Wei and Medasani, Bharat and Qu, Xiaohui and Kocher, Michael and Brafman, Miriam and Petretto, Guido and Rignanese, Gian-Marco and Hautier, Geoffroy and others}, +journal={Concurrency and Computation: Practice and Experience}, +volume={27}, +number={17}, +pages={5037--5059}, +year={2015}, +publisher={Wiley Online Library} +} +@article{da2023workflows, +title={Workflows Community Summit 2022: A Roadmap Revolution}, +author={da Silva, Rafael Ferreira and Badia, Rosa M and Bala, Venkat and Bard, Debbie and Bremer, Peer-Timo and Buckley, Ian and Caino-Lores, Silvina and Chard, Kyle and Goble, Carole and Jha, Shantenu and others}, +journal={arXiv preprint arXiv:2304.00019}, +year={2023} +} +@inproceedings{ben2020workflows, +title={Workflows are the new applications: Challenges in performance, portability, and productivity}, +author={Ben-Nun, Tal and Gamblin, Todd and Hollman, Daisy S and Krishnan, Hari and Newburn, Chris J}, +booktitle={2020 IEEE/ACM International Workshop on Performance, Portability and Productivity in HPC (P3HPC)}, +pages={57--69}, +year={2020}, +organization={IEEE} +} +@misc{wflowsystems, +title={Existing Workflow Systems}, +url={https://s.apache.org/existing-workflow-systems} +} +@inproceedings{al2021exaworks, +title={Exaworks: Workflows for exascale}, +author={Al-Saadi, Aymen and Ahn, Dong H and Babuji, Yadu and Chard, Kyle and Corbett, James and Hategan, Mihael and Herbein, Stephen and Jha, Shantenu and Laney, Daniel and Merzky, Andre and others}, +booktitle={2021 IEEE Workshop on Workflows in Support of Large-Scale Science (WORKS)}, +pages={50--57}, +year={2021}, +organization={IEEE} +} +@inproceedings{babuji2019parsl, +title={Parsl: Pervasive parallel programming in python}, +author={Babuji, Yadu and Woodard, Anna and Li, Zhuozhao and Katz, Daniel S and Clifford, Ben and Kumar, Rohan and Lacinski, Lukasz and Chard, Ryan and Wozniak, Justin M and Foster, Ian and others}, +booktitle={Proceedings of the 28th International Symposium on High-Performance Parallel and Distributed Computing}, +pages={25--36}, +year={2019} +} +@misc{prefect, +title={Prefect}, +url={https://github.com/PrefectHQ/prefect} +} +@misc{redun, +title={Redun}, +url={https://github.com/insitro/redun} +} +@misc{covalent, +title={Covalent}, +doi={https://doi.org/10.5281/zenodo.5903364}, +url={https://github.com/AgnostiqHQ/covalent} +} +@misc{maggma, +title={Maggma}, +url={https://github.com/materialsproject/maggma} +} +@misc{montydb, +title={MontyDB}, +url={https://github.com/davidlatwe/montydb} } From af11ca0490a64003f6cf0b396900de90b3cf43ff Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Thu, 5 Oct 2023 11:10:51 +0100 Subject: [PATCH 4/5] Fix references --- paper/paper.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index 7e1a273d..473b00d1 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -83,11 +83,11 @@ We present Jobflow, a domain-agnostic Python package for writing computational w # Statement of Need -The current era of big data and high-performance computing has emphasized the significant need for robust, flexible, and scalable workflow management solutions that can be used to efficiently orchestrate scientific calculations `[@ben2020workflows; @da2023workflows]`. To date, a wide variety of workflow systems have been developed, and it has become clear that there is no one-size-fits-all solution due to the diverse needs of the computational community `[@wflowsystems; @al2021exaworks]`. While several popular software packages in this space have emerged over the last decade, many of them require the user to tailor their domain-specific code with the underlying workflow management framework closely in mind. This can be a barrier to entry for many users and puts significant constraints on the portability of the underlying workflows. +The current era of big data and high-performance computing has emphasized the significant need for robust, flexible, and scalable workflow management solutions that can be used to efficiently orchestrate scientific calculations [@ben2020workflows; @da2023workflows]. To date, a wide variety of workflow systems have been developed, and it has become clear that there is no one-size-fits-all solution due to the diverse needs of the computational community [@wflowsystems; @al2021exaworks]. While several popular software packages in this space have emerged over the last decade, many of them require the user to tailor their domain-specific code with the underlying workflow management framework closely in mind. This can be a barrier to entry for many users and puts significant constraints on the portability of the underlying workflows. -Here, we introduce Jobflow: a free, open-source Python library that makes it simple to transform collections of functions into complex workflows that can be executed either locally or across distributed computing environments. Jobflow has been intentionally designed to act as middleware between the user’s domain-specific routines that they wish to execute and the workflow “manager” that ultimately orchestrates the calculations across different computing environments. Jobflow uses a simple decorator-based syntax that is similar to that of other recently developed workflow tools `[@babuji2019parsl; @prefect; @covalent; @redun]`. This approach makes it possible to turn virtually any function into a Jobflow `Job` instance (i.e., a discrete unit of work) with minimal changes to the underlying code itself. +Here, we introduce Jobflow: a free, open-source Python library that makes it simple to transform collections of functions into complex workflows that can be executed either locally or across distributed computing environments. Jobflow has been intentionally designed to act as middleware between the user’s domain-specific routines that they wish to execute and the workflow “manager” that ultimately orchestrates the calculations across different computing environments. Jobflow uses a simple decorator-based syntax that is similar to that of other recently developed workflow tools [@babuji2019parsl; @prefect; @covalent; @redun]. This approach makes it possible to turn virtually any function into a Jobflow `Job` instance (i.e., a discrete unit of work) with minimal changes to the underlying code itself. -Jobflow has grown out of a need to carry out high-throughput computational materials science workflows at scale as part of the Materials Project `[@materialsproject]`. As the kinds of calculations — from _ab initio_ to semi-empirical to those based on machine learning — continue to evolve and the resulting data streams continue to diversify, it was necessary to rethink how we managed an increasingly diverse range of computational workflows. Going forward, Jobflow will become the computational backbone of the Materials Project, which we hope will inspire additional confidence in the readiness of Jobflow for production-quality scientific computing applications. +Jobflow has grown out of a need to carry out high-throughput computational materials science workflows at scale as part of the Materials Project [@materialsproject]. As the kinds of calculations — from _ab initio_ to semi-empirical to those based on machine learning — continue to evolve and the resulting data streams continue to diversify, it was necessary to rethink how we managed an increasingly diverse range of computational workflows. Going forward, Jobflow will become the computational backbone of the Materials Project, which we hope will inspire additional confidence in the readiness of Jobflow for production-quality scientific computing applications. # Features and Implementation @@ -155,7 +155,7 @@ responses = run_locally(flow) ## Data Management -Jobflow has first-class support for a variety of data stores through an interface with the `maggma` Python package `[@maggma]`. This makes it possible to easily store the results of workflows in a manner that is independent of the choice of storage medium and that is entirely decoupled from the workflow logic itself. Additionally, it is possible within Jobflow to specify multiple types of data stores for specific Python objects (e.g., primitive types vs. large binary blobs) created by a given workflow, which is often useful for storing a combination of metadata (e.g., in a NoSQL database like MongoDB or file-system based store like MontyDB `[@montydb]`) and raw data (e.g., in a cloud object store like Amazon S3 or Microsoft Azure). +Jobflow has first-class support for a variety of data stores through an interface with the `maggma` Python package [@maggma]. This makes it possible to easily store the results of workflows in a manner that is independent of the choice of storage medium and that is entirely decoupled from the workflow logic itself. Additionally, it is possible within Jobflow to specify multiple types of data stores for specific Python objects (e.g., primitive types vs. large binary blobs) created by a given workflow, which is often useful for storing a combination of metadata (e.g., in a NoSQL database like MongoDB or file-system based store like MontyDB [@montydb]`) and raw data (e.g., in a cloud object store like Amazon S3 or Microsoft Azure). ## Promoting Code Reuse @@ -190,7 +190,7 @@ responses = run_locally(flow) Unlike many other workflow packages, one of the major benefits of Jobflow is that it decouples the details related to workflow execution from the workflow definitions themselves. The simplest way to execute a workflow is to run it directly on the machine where the workflow is defined using the `run_locally(...)` function, as shown in the examples above. This makes it possible to quickly test even complex workflows without the need to rely on a database or configuring remote resources. -When deploying production calculations, workflows often need to be dispatched to large supercomputers through a remote execution engine. Jobflow has an interface with the FireWorks package `[@fireworks]` via a one-line command to convert a `Flow` and its underlying `Job` objects into the analogous FireWorks `Workflow` and `Firework` objects that enable execution on high-performance computing machines. The logic behind the `Job` and `Flow` objects are not tied to FireWorks in any direct way, such that the two packages are fully decoupled. +When deploying production calculations, workflows often need to be dispatched to large supercomputers through a remote execution engine. Jobflow has an interface with the FireWorks package [@fireworks] via a one-line command to convert a `Flow` and its underlying `Job` objects into the analogous FireWorks `Workflow` and `Firework` objects that enable execution on high-performance computing machines. The logic behind the `Job` and `Flow` objects are not tied to FireWorks in any direct way, such that the two packages are fully decoupled. Additionally, a remote mode of execution built solely around Jobflow is currently under active development. With this approach, workflows can be executed across multiple “workers” (e.g., a simple computer, a supercomputer or a cloud-based service) and managed through a modern command-line interface without relying on an external workflow execution engine. The Jobflow remote mode of execution has been designed such that no inbound connection from the workers to the database of jobs and results is needed, thus ensuring data and network security for professional usage. @@ -204,10 +204,10 @@ Jobflow has been designed with robustness in mind. The Jobflow codebase has 100% While domain-agnostic, Jobflow has been used in several materials science Python packages at the time of writing, including but not limited to: -- Atomate2 `[@atomate2]`, Quacc `[@quacc]`: Libraries of computational chemistry and materials science workflows. -- NanoParticleTools `[@nptools]`: Workflows for Monte Carlo simulations of nanoparticles. -- Reaction Network `[@rxnnetwork; @mcdermott2021graph]`: Workflows for constructing and analyzing inorganic chemical reaction networks. -- WFacer `[@wfacer]`: Workflows for modeling the statistical thermodynamics of solids via automated cluster expansion. +- Atomate2 [@atomate2], Quacc [@quacc]: Libraries of computational chemistry and materials science workflows. +- NanoParticleTools [@nptools]: Workflows for Monte Carlo simulations of nanoparticles. +- Reaction Network [@rxnnetwork; @mcdermott2021graph]: Workflows for constructing and analyzing inorganic chemical reaction networks. +- WFacer [@wfacer]: Workflows for modeling the statistical thermodynamics of solids via automated cluster expansion. # Additional Details From d64127631e7dd81f56a607783e2a17f37d5ca3e7 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Tue, 10 Oct 2023 08:19:25 +0100 Subject: [PATCH 5/5] Update paper --- paper/paper.md | 18 +++++++++--------- paper/refs.bib | 8 ++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index 473b00d1..35d152cf 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -79,13 +79,13 @@ bibliography: refs.bib # Summary -We present Jobflow, a domain-agnostic Python package for writing computational workflows tailored for high-throughput computing applications. With its simple decorator-based approach, functions and class methods can be transformed into compute jobs that can be stitched together into complex workflows. Jobflow fully supports dynamic workflows where the full acyclic graph of compute jobs is not known until runtime, such as compute jobs that launch other jobs based on the results of previous steps in the workflow. The results of all Jobflow compute jobs can be easily stored in a variety of filesystem- and cloud-based databases without the data storage process being part of the underlying workflow logic itself. Jobflow has been intentionally designed to be fully independent of the choice of workflow manager used to dispatch the calculations on remote computing resources. At the time of writing, Jobflow workflows can be executed either locally or across distributed compute environments via a FireWorks adapter, and Jobflow fully supports the integration of additional workflow execution adapters in the future. +We present Jobflow, a domain-agnostic Python package for writing computational workflows tailored for high-throughput computing applications. With its simple decorator-based approach, functions and class methods can be transformed into compute jobs that can be stitched together into complex workflows. Jobflow fully supports dynamic workflows where the full acyclic graph of compute jobs is not known until runtime, such as compute jobs that launch other jobs based on the results of previous steps in the workflow. The results of all Jobflow compute jobs can be easily stored in a variety of filesystem- and cloud-based databases without the data storage process being part of the underlying workflow logic itself. Jobflow has been intentionally designed to be fully independent of the choice of workflow manager used to dispatch the calculations on remote computing resources. At the time of writing, Jobflow workflows can be executed either locally or across distributed compute environments via an adapter to the FireWorks package, and Jobflow fully supports the integration of additional workflow execution adapters in the future. # Statement of Need The current era of big data and high-performance computing has emphasized the significant need for robust, flexible, and scalable workflow management solutions that can be used to efficiently orchestrate scientific calculations [@ben2020workflows; @da2023workflows]. To date, a wide variety of workflow systems have been developed, and it has become clear that there is no one-size-fits-all solution due to the diverse needs of the computational community [@wflowsystems; @al2021exaworks]. While several popular software packages in this space have emerged over the last decade, many of them require the user to tailor their domain-specific code with the underlying workflow management framework closely in mind. This can be a barrier to entry for many users and puts significant constraints on the portability of the underlying workflows. -Here, we introduce Jobflow: a free, open-source Python library that makes it simple to transform collections of functions into complex workflows that can be executed either locally or across distributed computing environments. Jobflow has been intentionally designed to act as middleware between the user’s domain-specific routines that they wish to execute and the workflow “manager” that ultimately orchestrates the calculations across different computing environments. Jobflow uses a simple decorator-based syntax that is similar to that of other recently developed workflow tools [@babuji2019parsl; @prefect; @covalent; @redun]. This approach makes it possible to turn virtually any function into a Jobflow `Job` instance (i.e., a discrete unit of work) with minimal changes to the underlying code itself. +Here, we introduce Jobflow: a free, open-source Python library that makes it simple to transform collections of functions into complex workflows that can be executed either locally or across distributed computing environments. Jobflow has been intentionally designed to act as middleware between the user’s domain-specific routines that they wish to execute and the workflow "manager" that ultimately orchestrates the calculations across different computing environments. Jobflow uses a simple decorator-based syntax that is similar to that of other recently developed workflow tools [@babuji2019parsl; @prefect; @covalent; @redun]. This approach makes it possible to turn virtually any function into a Jobflow `Job` instance (i.e., a discrete unit of work) with minimal changes to the underlying code itself. Jobflow has grown out of a need to carry out high-throughput computational materials science workflows at scale as part of the Materials Project [@materialsproject]. As the kinds of calculations — from _ab initio_ to semi-empirical to those based on machine learning — continue to evolve and the resulting data streams continue to diversify, it was necessary to rethink how we managed an increasingly diverse range of computational workflows. Going forward, Jobflow will become the computational backbone of the Materials Project, which we hope will inspire additional confidence in the readiness of Jobflow for production-quality scientific computing applications. @@ -120,7 +120,7 @@ responses = run_locally(flow) ## Dynamic Workflows -Beyond the typical acyclic graph of jobs, Jobflow fully supports dynamic workflows where the precise number of jobs is unknown until runtime. This is a particularly common requirement in chemistry and materials science workflows and is made possible through the use of a `Response` object that controls the flow execution. For instance, the example below is a `Flow` that will add two numbers (`1 + 2`), construct a list of random length containing the prior result (e.g. `[3, 3, 3]`), and then add an integer to each element of the list (`[3 + 10, 3 + 10, 3 + 10]`). The `Resfponse(replace=Flow(jobs))` syntax tells Jobflow to replace the current `Job` with a (sub)workflow after the `Job` completes. +Beyond the typical acyclic graph of jobs, Jobflow fully supports dynamic workflows where the precise number of jobs is unknown until runtime. This is a particularly common requirement in chemistry and materials science workflows and is made possible through the use of a `Response` object that controls the flow execution. For instance, the example below is a `Flow` that will add two numbers (`1 + 2`), construct a list of random length containing the prior result (e.g. `[3, 3, 3]`), and then add an integer to each element of the list (`[3 + 10, 3 + 10, 3 + 10]`). The `Response(replace=Flow(jobs))` syntax tells Jobflow to replace the current `Job` with a (sub)workflow after the `Job` completes. ![](figure2.png) @@ -188,21 +188,21 @@ responses = run_locally(flow) ## Workflow Execution -Unlike many other workflow packages, one of the major benefits of Jobflow is that it decouples the details related to workflow execution from the workflow definitions themselves. The simplest way to execute a workflow is to run it directly on the machine where the workflow is defined using the `run_locally(...)` function, as shown in the examples above. This makes it possible to quickly test even complex workflows without the need to rely on a database or configuring remote resources. +One of the major benefits of Jobflow is that it decouples the details related to workflow execution from the workflow definitions themselves. The simplest way to execute a workflow is to run it directly on the machine where the workflow is defined using the `run_locally(...)` function, as shown in the examples above. This makes it possible to quickly test even complex workflows without the need to rely on a database or configuring remote resources. When deploying production calculations, workflows often need to be dispatched to large supercomputers through a remote execution engine. Jobflow has an interface with the FireWorks package [@fireworks] via a one-line command to convert a `Flow` and its underlying `Job` objects into the analogous FireWorks `Workflow` and `Firework` objects that enable execution on high-performance computing machines. The logic behind the `Job` and `Flow` objects are not tied to FireWorks in any direct way, such that the two packages are fully decoupled. -Additionally, a remote mode of execution built solely around Jobflow is currently under active development. With this approach, workflows can be executed across multiple “workers” (e.g., a simple computer, a supercomputer or a cloud-based service) and managed through a modern command-line interface without relying on an external workflow execution engine. The Jobflow remote mode of execution has been designed such that no inbound connection from the workers to the database of jobs and results is needed, thus ensuring data and network security for professional usage. +Additionally, a remote mode of execution built solely around Jobflow is currently under active development. With this approach, workflows can be executed across multiple "workers" (e.g., a simple computer, a supercomputer, or a cloud-based service) and managed through a modern command-line interface without relying on an external workflow execution engine. The forthcoming Jobflow remote mode of execution has been designed such that no inbound connection from the workers to the database of jobs and results is needed, thus ensuring data and network security for professional usage. -More generally, it is possible for users to develop custom “adapter” interfaces to their personal workflow execution engine of choice. As a result, Jobflow fills a niche in the broader workflow community and can help make the same workflow definition interoperable across multiple workflow execution engines. +More generally, it is possible for users to develop custom "adapter" interfaces to their personal workflow execution engine of choice. As a result, Jobflow fills a niche in the broader workflow community and can help make the same workflow definition interoperable across multiple workflow execution engines. ## Testing and Documentation -Jobflow has been designed with robustness in mind. The Jobflow codebase has 100% test coverage and is fully documented. The detailed testing suite, along with continuous integration pipelines on GitHub, makes it easy for users to write their own workflows with confidence that they will continue to work as expected for the foreseeable future. Furthermore, the ability to run Jobflow `Flow` objects locally makes it simple to write unit tests when designing a new Python package built around Jobflow without the need for complex monkey-patching or spinning up a test server. +Jobflow has been designed with robustness in mind. The Jobflow codebase has 100% test coverage at the time of writing and is fully documented. The detailed testing suite, along with continuous integration pipelines on GitHub, makes it easy for users to write their own workflows with confidence that they will continue to work as expected for the foreseeable future. Furthermore, the ability to run Jobflow `Flow` objects locally makes it simple to write unit tests when designing a new Python package built around Jobflow without the need for complex monkey-patching or spinning up a test server. # Usage To-Date -While domain-agnostic, Jobflow has been used in several materials science Python packages at the time of writing, including but not limited to: +While domain-agnostic, Jobflow has been used in several materials science Python packages to date, including but not limited to: - Atomate2 [@atomate2], Quacc [@quacc]: Libraries of computational chemistry and materials science workflows. - NanoParticleTools [@nptools]: Workflows for Monte Carlo simulations of nanoparticles. @@ -215,6 +215,6 @@ Naturally, the summary presented in this article constitutes only a small subset # Acknowledgements -This work was primarily funded and intellectually led by the Materials Project, which is funded by the U.S. Department of Energy, Office of Science, Office of Basic Energy Sciences, Materials Sciences and Engineering Division, under Contract no. DE-AC02-05-CH11231: Materials Project program KC23MP. A.S.R. acknowledges support via a Miller Research Fellowship from the Miller Institute for Basic Research in Science, University of California, Berkeley. J.G would like to acknowledge the Gauss Centre for Supercomputing e.V. ([www.gauss-centre.eu](http://www.gauss-centre.eu/)) for funding workflow-related developments by providing generous computing time on the GCS Supercomputer SuperMUC-NG at Leibniz Supercomputing Centre ([www.lrz.de](http://www.lrz.de/)) (Project pn73da). J.R. acknowledges support from the German Academic Scholarship Foundation (Studienstiftung). M.L.E. thanks the BEWARE scheme of the Wallonia-Brussels Federation for funding under the European Commission's Marie Curie-Skłodowska Action (COFUND 847587). D.W. and G.M.R. acknowledge funding from the European Union’s Horizon 2020 research and innovation program under the grant agreement No 951786 (NOMAD CoE). A.M.G. is supported by EPSRC Fellowship EP/T033231/1. +This work was primarily funded and intellectually led by the Materials Project, which is funded by the U.S. Department of Energy, Office of Science, Office of Basic Energy Sciences, Materials Sciences and Engineering Division, under Contract no. DE-AC02-05-CH11231: Materials Project program KC23MP. A.S.R. acknowledges support via a Miller Research Fellowship from the Miller Institute for Basic Research in Science, University of California, Berkeley. J.G would like to acknowledge the Gauss Centre for Supercomputing e.V. ([www.gauss-centre.eu](http://www.gauss-centre.eu/)) for funding workflow-related developments by providing generous computing time on the GCS Supercomputer SuperMUC-NG at Leibniz Supercomputing Centre ([www.lrz.de](http://www.lrz.de/)) (Project pn73da). J.R. acknowledges support from the German Academic Scholarship Foundation (Studienstiftung). M.L.E. thanks the BEWARE scheme of the Wallonia-Brussels Federation for funding under the European Commission's Marie Curie-Skłodowska Action (COFUND 847587). G.P. and D.W. acknowledge Umicore for the financial support in developing the remote execution mode of jobflow. D.W. and G.M.R. acknowledge funding from the European Union’s Horizon 2020 research and innovation program under the grant agreement No 951786 (NOMAD CoE). A.M.G. is supported by EPSRC Fellowship EP/T033231/1. # References diff --git a/paper/refs.bib b/paper/refs.bib index 9fb71169..34984d80 100644 --- a/paper/refs.bib +++ b/paper/refs.bib @@ -1,14 +1,17 @@ @misc{atomate2, title = {Atomate2}, +year = {2023}, url = {https://github.com/materialsproject/atomate2} } @misc{quacc, doi = {10.5281/zenodo.7720998}, title = {Quacc -- The Quantum Accelerator}, +year = {2023}, url = {https://github.com/Quantum-Accelerators/quacc} } @software{rxnnetwork, title = {Reaction Network}, +year = {2023}, url = {https://github.com/materialsproject/reaction-network} } @article{pizzi2016aiida, @@ -37,6 +40,7 @@ @misc{wfacer } @misc{nptools, title = {NanoParticleTools}, +year = {2023}, url = {https://github.com/BlauGroup/NanoParticleTools} } @article{fireworks, @@ -88,18 +92,22 @@ @misc{prefect } @misc{redun, title={Redun}, +year = {2023}, url={https://github.com/insitro/redun} } @misc{covalent, title={Covalent}, +year = {2023}, doi={https://doi.org/10.5281/zenodo.5903364}, url={https://github.com/AgnostiqHQ/covalent} } @misc{maggma, title={Maggma}, +year = {2023}, url={https://github.com/materialsproject/maggma} } @misc{montydb, title={MontyDB}, +year = {2023}, url={https://github.com/davidlatwe/montydb} }