{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Back to the main [Index](index.ipynb) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Tasks, Workflows and Flow\n", "\n", "\n", "## Table of Contents\n", "[[back to top](#top)]\n", "\n", "- [Building a Flow for band structure calculations](#Building-a-Flow-for-band-structure-calculations)\n", "- [How to build and run the Flow](#How-to-build-and-run-the-Flow)\n", "- [Executing a Flow](#Executing-a-Flow)\n", "- [More on Works, Tasks and dependencies](#More-on-Works,-Tasks-and-dependencies)\n", "- [Abirun.py](#Abirun.py)\n", "\n", "In this notebook we discuss some of the basic concepts used in AbiPy \n", "to automate ab-initio calculations. \n", "In particular we will focus on the following three objects: \n", "\n", " * `Task`\n", " * `Work`\n", " * `Flow`\n", " \n", "The `Task` represent the most *elementary step* of the automatic workflow. \n", "Roughly speaking, it corresponds to the execution of a single Abinit calculation **without** multiple datasets.\n", "\n", "From the point of view of AbiPy, a calculation consists of a set of `Tasks` that are connected \n", "by dependencies. \n", "Each task has a list of files that are needed to start the calculation, \n", "and a list of files that are produced at the end of the run.\n", "\n", "Some of the input files needed by a `Task` must be provided by the user in the form of Abinit input variables \n", "(e.g. the crystalline structure, the pseudopotentials), other inputs may be produced by other tasks.\n", "When a `Task` **B** requires the output file `DEN` of another task **A**, \n", "we say that **B** depends on **A** through a `DEN` file, and we express this dependency with the dictionary:\n", "\n", "```python\n", "B_deps = {A: \"DEN\"}\n", "```\n", "\n", "To clarify this point, let's take a standard KS band structure calculation as an example.\n", "In this case, we have an initial `ScfTask` that solves the KS equations self-consistently to produce a `DEN` file. \n", "The density is then used by a second `NscfTask` to compute a band structure on an arbitrary \n", "set of $k$-points.\n", "The `NscfTask` thus has a dependency on the `ScfTask` in the sense that it cannot be executed \n", "until the `ScfTask` is completed and the `DEN` file is produced by the `ScfTask`.\n", "\n", "Now that we have clarified the concept of `Task`, we can finally turn to `Works` and `Flow`.\n", "The `Work` can be seen as a list of `Tasks`, while the `Flow` is essentially a list of `Work` objects.\n", "Works are usually used to group tasks that are connected to each other.\n", "Flows are the final objects that are executed. The `Flow` provides an easy-to-use\n", "interface for performing this execution. \n", "The `Flow` provides a high-level API to perform common operations like launching the actual jobs, checking the status of the `Tasks`, correcting problems etc. \n", "\n", "AbiPy provides several tools to generate Flows for typical first-principles calculations, so called factory functions.\n", "This means that you do not need to understand all the technical details of the python implementation.\n", "In many cases, indeed, we already provide some kind of `Work` or `Flow` that automates \n", "your calculation, and you only need to provide the correct list of input files.\n", "This list, obviously, must be consistent with the kind Flow/Work you are using.\n", "(For instance, you should not pass a list of inputs for performing a band structure calculation to a Work \n", "that is expected to compute phonons with DFPT!)\n", "\n", "All the `Works` and the `Tasks` of a flow are created and executed inside the working directory (`workdir`). \n", "This is usually specified by the user during the creation of the `Flow` object.\n", "AbiPy creates the workdir of the different Works/Tasks when the `Flow` is executed\n", "for the first time.\n", "\n", "Each `Task` contains a set of input variables that will be used to generate the \n", "Abinit input file. \n", "This input **must** be provided by the user during the creation of the `Task`.\n", "Fortunately, AbiPy provides an object named `AbinitInput` to facilitate the creation \n", "of such input. \n", "Once you have an `AbinitInput`, you can create the corresponding `Task` with the (pseudo) code:\n", "\n", "```python\n", "new_task = Task(abinit_input_object)\n", "```\n", "\n", "The `Task` provides several methods for monitoring the status of the calculation and \n", "post-processing the results.\n", "Note that the concept of dependency is not limited to files. All the Tasks in the \n", "flow are connected and can interact with each other. This allows programmers to implements python\n", "functions that will be invoked by the framework at run time. For example, one can \n", "implement a Task that fetches the relaxed structure from a previous Task and \n", "use this configuration to start a DFPT calculation.\n", "\n", "In the next paragraph, we discuss how to construct a `Flow` for band-structure calculations\n", "with a high-level interface that only requires the specifications of the input files.\n", "This example allows us to discuss the most important methods of the `Flow`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building a Flow for band structure calculations\n", "[[back to top](#top)]\n", "\n", "Let's start by creating a function that produces two input files. \n", "The first input is a standard self-consistent ground-state run.\n", "The second input uses the density produced in the first run to perform \n", "a non self-consistent band structure calculation." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# This line configures matplotlib to show figures embedded in the notebook.\n", "# Replace `inline` with `notebook` in classic notebook\n", "%matplotlib inline \n", "\n", "# Option available in jupyterlab. See https://github.com/matplotlib/jupyter-matplotlib\n", "#%matplotlib widget \n", "\n", "import warnings\n", "warnings.filterwarnings(\"ignore\") # to get rid of deprecation warnings\n", "\n", "from abipy import abilab\n", "import os\n", "import abipy.flowtk as flowtk\n", "import abipy.data as abidata\n", "\n", "def make_scf_nscf_inputs():\n", " \"\"\"Build ands return the input files for the GS-SCF and the GS-NSCF tasks.\"\"\"\n", " multi = abilab.MultiDataset(structure=abidata.cif_file(\"si.cif\"),\n", " pseudos=abidata.pseudos(\"14si.pspnc\"), ndtset=2)\n", "\n", " # Set global variables (dataset1 and dataset2)\n", " multi.set_vars(ecut=6, nband=8)\n", "\n", " # Dataset 1 (GS-SCF run)\n", " multi[0].set_kmesh(ngkpt=[8,8,8], shiftk=[0,0,0])\n", " multi[0].set_vars(tolvrs=1e-6)\n", "\n", " # Dataset 2 (GS-NSCF run on a k-path)\n", " kptbounds = [\n", " [0.5, 0.0, 0.0], # L point\n", " [0.0, 0.0, 0.0], # Gamma point\n", " [0.0, 0.5, 0.5], # X point\n", " ]\n", "\n", " multi[1].set_kpath(ndivsm=6, kptbounds=kptbounds)\n", " multi[1].set_vars(tolwfr=1e-12)\n", " \n", " # Return two input files for the GS and the NSCF run\n", " scf_input, nscf_input = multi.split_datasets()\n", " return scf_input, nscf_input" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once we have our two input files, we pass them to the \n", "factory function `bandstructure_flow` that returns our `Flow`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "scf_input, nscf_input = make_scf_nscf_inputs()\n", "\n", "workdir = \"/tmp/hello_bands\"\n", "flow = flowtk.bandstructure_flow(workdir, scf_input, nscf_input)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`bandstructure_flow` took care of creating the correct dependency between the two tasks.\n", "The `NscfTask`, indeed, depends on the `ScfTask` in w0/t0, whereas the `ScfTask` has no dependency:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174773, workdir=../../../../../tmp/hello_bands\n", "\n", "clusterw0\n", "\n", "BandStructureWork (w0)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "ScfTask\n", "\n", "\n", "\n", "w0_t1\n", "\n", "w0_t1\n", "NscfTask\n", "\n", "\n", "\n", "w0_t0->w0_t1\n", "\n", "\n", "DEN\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flow.get_graphviz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "Note that we have not used `getden2 = -1` in the second dataset \n", "since AbiPy knows how to connect the two Tasks.\n", "So no need for `get*` or `ird*` variables with Abipy. \n", "Just specify the correct dependency and python will do the rest!\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To have useful information on the status of the flow, one uses:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Work #0: , Finalized=False\n", "+--------+-------------+---------+--------------+------------+----------+-----------------+--------+-----------+\n", "| Task | Status | Queue | MPI|Omp|Gb | Warn|Com | Class | Sub|Rest|Corr | Time | Node_ID |\n", "+========+=============+=========+==============+============+==========+=================+========+===========+\n", "| w0_t0 | Initialized\u001b[0m | None | 1| 1|2.0 | 1| 1 | ScfTask | (0, 0, 0) | None | 174775 |\n", "+--------+-------------+---------+--------------+------------+----------+-----------------+--------+-----------+\n", "| w0_t1 | Initialized\u001b[0m | None | 1| 1|2.0 | 0| 3 | NscfTask | (0, 0, 0) | None | 174776 |\n", "+--------+-------------+---------+--------------+------------+----------+-----------------+--------+-----------+\n", "\n" ] } ], "source": [ "flow.show_status()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Meaning of the different columns:\n", " \n", " * *Task*: short name of the task (usually *w[index_of_work_in_flow]_t[index_of_task_in_work]*\n", " * *Status*: Status of the task\n", " * *Queue*: QueueName@Job identifier returned by the resource manager when the task is submitted\n", " * *(MPI|Omp|Gb)*: Number of MPI procs, OMP threads, and memory per MPI proc\n", " * *(Warn|Com)*: Number of Error/Warning/Comment messages found in the ABINIT log\n", " * *Class*: The class of the `Task`\n", " * *(Sub|Rest|Corr)*: Number of (submissions/restart/AbiPy corrections) performed\n", " * *Node_ID* : identifier of the task, used to select tasks or works in python code or `abirun.py`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both `Flow` and `Work` are *iterable*. \n", "Iterating on a `Flow` gives `Work` objects, whereas\n", "iterating over a `Work` gives the `Tasks` inside that particular `Work`.\n", "\n", "```python\n", "for work in flow:\n", " for task in work:\n", " print(task)\n", "```\n", "\n", "`Flows` and `Works` are containers and we can select items in these containers\n", "with the syntax: flow[start:stop] or work[start:stop].\n", "This means that the previous loop is equivalent to the much more verbose version: \n", "\n", "```python\n", "for i in range(len(flow)):\n", " work = flow[i]\n", " for t in range(len(work):\n", " print(work[t])\n", "```\n", "\n", "At this point it should not be so difficult to understand that:\n", "\n", "```python\n", "flow[0][0]\n", "```\n", "\n", "gives the first task in the first work of the flow while\n", "\n", "```python\n", "flow[-1][-1]\n", "```\n", "\n", "selects the last `Task` in the last `Work`.\n", "In several cases, we only need to iterate over a flat list of tasks without caring about the works.\n", "In this case, we can use:\n", "\n", "```python\n", "for task in flow.iflat_tasks():\n", " print(task)\n", "```\n", "\n", "to iterate over all Tasks in the Flow." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to build and run the Flow\n", "[[back to top](#top)]\n", "\n", "The flow is still in memory and no file has been produced. \n", "In order to build the workflow, use: " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "if os.path.isdir(\"/tmp/hello_bands/\"): \n", " import shutil\n", " shutil.rmtree(\"/tmp/hello_bands\")\n", "\n", "flow.build_and_pickle_dump()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function creates the directories of the `Flow`:\n", "\n", "(If you rely on MacOSX, the tree command might not be available. To fix this, see http://osxdaily.com/2016/09/09/view-folder-tree-terminal-mac-os-tree-equivalent/)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/bin/sh: tree: command not found\n" ] } ], "source": [ "!tree /tmp/hello_bands" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's have a look at the files/directories associated to the first work (flow[0]):" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "directory\n", "\n", "/tmp/hello_bands/w0\n", "\n", "cluster_/tmp/hello_bands/w0\n", "\n", "w0\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/tmpdata\n", "\n", "tmpdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/indata\n", "\n", "indata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/outdata\n", "\n", "outdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1\n", "\n", "t1\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0\n", "\n", "t0\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1/tmpdata\n", "\n", "tmpdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1/indata\n", "\n", "indata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1/outdata\n", "\n", "outdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0/tmpdata\n", "\n", "tmpdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0/indata\n", "\n", "indata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0/outdata\n", "\n", "outdata\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.abi\n", "\n", "run.abi\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/job.sh\n", "\n", "job.sh\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.files\n", "\n", "run.files\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.abi\n", "\n", "run.abi\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/job.sh\n", "\n", "job.sh\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.files\n", "\n", "run.files\n", "\n", "\n", "\n", "\n", "\n", "__0:cluster_/tmp/hello_bands/w0->__1:cluster_/tmp/hello_bands/w0/tmpdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__2:cluster_/tmp/hello_bands/w0->__3:cluster_/tmp/hello_bands/w0/indata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__4:cluster_/tmp/hello_bands/w0->__5:cluster_/tmp/hello_bands/w0/outdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__6:cluster_/tmp/hello_bands/w0->__7:cluster_/tmp/hello_bands/w0/t1\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__8:cluster_/tmp/hello_bands/w0->__9:cluster_/tmp/hello_bands/w0/t0\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__10:cluster_/tmp/hello_bands/w0/t1->__11:cluster_/tmp/hello_bands/w0/t1/tmpdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__12:cluster_/tmp/hello_bands/w0/t1->__13:cluster_/tmp/hello_bands/w0/t1/indata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__14:cluster_/tmp/hello_bands/w0/t1->__15:cluster_/tmp/hello_bands/w0/t1/outdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__16:cluster_/tmp/hello_bands/w0/t0->__17:cluster_/tmp/hello_bands/w0/t0/tmpdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__18:cluster_/tmp/hello_bands/w0/t0->__19:cluster_/tmp/hello_bands/w0/t0/indata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__20:cluster_/tmp/hello_bands/w0/t0->__21:cluster_/tmp/hello_bands/w0/t0/outdata\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flow[0].get_graphviz_dirtree()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`w0` is the directory containing the input files of the first workflow (well, we have only one workflow in our example).\n", "`t0` and `t1` contain the input files needed to run the SCF and the NSC run, respectively.\n", "\n", "You might have noticed that each `Task` directory present the same structure:\n", " \n", " * *run.abi*: Input file\n", " * *run.files*: Files file\n", " * *job.sh*: Submission script\n", " * *outdata*: Directory containing output data files\n", " * *indata*: Directory containing input data files \n", " * *tmpdata*: Directory with temporary files\n", " \n", "
\n", "`__AbinitFlow__.pickle` is the pickle file used to save the status of `Flow`. **Don't touch it!** \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An Abinit Task *has* an [AbinitInput](abinit_input.ipynb) which in turn has a [Structure](structure.ipynb):" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "##############################################
#### SECTION: basic
##############################################
ecut 6
nband 8
ngkpt 8 8 8
kptopt 1
nshiftk 1
shiftk 0 0 0
tolvrs 1e-06
##############################################
#### STRUCTURE
##############################################
natom 2
ntypat 1
typat 1 1
znucl 14
xred
0.0000000000 0.0000000000 0.0000000000
0.2500000000 0.2500000000 0.2500000000
acell 1.0 1.0 1.0
rprim
6.3285005272 0.0000000000 3.6537614829
2.1095001757 5.9665675167 3.6537614829
0.0000000000 0.0000000000 7.3075229659" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ " flow[0][0].input" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Full Formula (Si2)
Reduced Formula: Si
abc : 3.866975 3.866975 3.866975
angles: 60.000000 60.000000 60.000000
Sites (2)
# SP a b c
--- ---- ---- ---- ----
0 Si 0 0 0
1 Si 0.25 0.25 0.25" ], "text/plain": [ "Structure Summary\n", "Lattice\n", " abc : 3.86697462 3.86697462 3.86697462\n", " angles : 59.99999999999999 59.99999999999999 59.99999999999999\n", " volume : 40.88829179346891\n", " A : 3.3488982567096763 0.0 1.9334873100000005\n", " B : 1.1162994189032256 3.1573715557642927 1.9334873100000005\n", " C : 0.0 0.0 3.86697462\n", "PeriodicSite: Si (0.0000, 0.0000, 0.0000) [0.0000, 0.0000, 0.0000]\n", "PeriodicSite: Si (1.1163, 0.7893, 1.9335) [0.2500, 0.2500, 0.2500]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flow[0][0].input.structure" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " summary: Troullier-Martins psp for element Si Thu Oct 27 17:31:21 EDT 1994\n", " number of valence electrons: 4.0\n", " maximum angular momentum: d\n", " angular momentum for local part: d\n", " XC correlation: LDA_XC_TETER93\n", " supports spin-orbit: False\n", " radius for non-linear core correction: 1.80626423934776\n", " hint for low accuracy: ecut: 0.0, pawecutdg: 0.0\n", " hint for normal accuracy: ecut: 0.0, pawecutdg: 0.0\n", " hint for high accuracy: ecut: 0.0, pawecutdg: 0.0\n" ] } ], "source": [ "for p in flow[0][0].input.pseudos: \n", " print(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's print the value of `kptopt` for all tasks in our flow with:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, -2]\n" ] } ], "source": [ "print([task.input[\"kptopt\"] for task in flow.iflat_tasks()])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "that, in this particular case, gives the same result as:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, -2]\n" ] } ], "source": [ "print([task.input[\"kptopt\"] for task in flow[0]])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Executing a Flow\n", "[[back to top](#top)]\n", "\n", "The `Flow` can be executed with two different approaches: a programmatic interface based \n", "on `flow.make_scheduler` or the `abirun.py` script. \n", "In this section, we discuss the first approach because it plays well with the jupyter notebook.\n", "Note however that `abirun.py` is highly recommended especially when running non-trivial calculations. " ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[Wed Feb 5 11:04:13 2020] Number of launches: 1\u001b[0m\n", "\n", "Work #0: , Finalized=False\n", "+--------+-------------+------------+--------------+------------+----------+-----------------+----------+-----------+\n", "| Task | Status | Queue | MPI|Omp|Gb | Warn|Com | Class | Sub|Rest|Corr | Time | Node_ID |\n", "+========+=============+============+==============+============+==========+=================+==========+===========+\n", "| w0_t0 | \u001b[34mSubmitted\u001b[0m | 35638@gmac | 2| 1|2.0 | 0| 0 | ScfTask | (1, 0, 0) | 0:00:00Q | 174775 |\n", "+--------+-------------+------------+--------------+------------+----------+-----------------+----------+-----------+\n", "| w0_t1 | Initialized\u001b[0m | None | 1| 1|2.0 | NA|NA | NscfTask | (0, 0, 0) | None | 174776 |\n", "+--------+-------------+------------+--------------+------------+----------+-----------------+----------+-----------+\n", "\n", "\u001b[33m[Wed Feb 5 11:04:14 2020] Number of launches: 1\u001b[0m\n", "\n", "Work #0: , Finalized=False\n", "+--------+-----------+------------+--------------+------------+----------+-----------------+----------+-----------+\n", "| Task | Status | Queue | MPI|Omp|Gb | Warn|Com | Class | Sub|Rest|Corr | Time | Node_ID |\n", "+========+===========+============+==============+============+==========+=================+==========+===========+\n", "| w0_t0 | \u001b[32mCompleted\u001b[0m | 35638@gmac | 2| 1|2.0 | 1| 1 | ScfTask | (1, 0, 0) | 0:00:01R | 174775 |\n", "+--------+-----------+------------+--------------+------------+----------+-----------------+----------+-----------+\n", "| w0_t1 | \u001b[34mSubmitted\u001b[0m | 35647@gmac | 2| 1|2.0 | 0| 0 | NscfTask | (1, 0, 0) | 0:00:00Q | 174776 |\n", "+--------+-----------+------------+--------------+------------+----------+-----------------+----------+-----------+\n", "\n", "\n", "Work #0: , Finalized=\u001b[32mTrue\u001b[0m\n", " Finalized works are not shown. Use verbose > 0 to force output.\n", "\u001b[32m\n", "all_ok reached\n", "\u001b[0m\n", "\n", "Submitted on: Wed Feb 5 11:04:12 2020\n", "Completed on: Wed Feb 5 11:04:16 2020\n", "Elapsed time: 0:00:04.021915\n", "Flow completed successfully\n", "\n", "Calling flow.finalize()...\n" ] }, { "data": { "text/plain": [ "0" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flow.make_scheduler().start()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The flow keeps track of the different actions performed by the python code:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\n", "==================================================================================================================\n", "================= =================\n", "==================================================================================================================\u001b[0m\n", "[Wed Feb 5 11:04:14 2020] In on_ok with sender \n", "[Wed Feb 5 11:04:16 2020] In on_ok with sender \n", "[Wed Feb 5 11:04:16 2020] Finalized set to True\n", "[Wed Feb 5 11:04:16 2020] Work is finalized and broadcasts signal S_OK\n", "[Wed Feb 5 11:04:16 2020] Node broadcasts signal Completed\n", "\u001b[32m\n", "===================================================================================================================\n", "===================== =====================\n", "===================================================================================================================\u001b[0m\n", "[Wed Feb 5 11:04:12 2020] Status changed to Ready. msg: Status set to Ready\n", "[Wed Feb 5 11:04:12 2020] Setting input variables: {'autoparal': 1, 'max_ncpus': 2, 'mem_test': 0}\n", "[Wed Feb 5 11:04:12 2020] Old values: {'autoparal': None, 'max_ncpus': None, 'mem_test': None}\n", "[Wed Feb 5 11:04:13 2020] Setting input variables: {'npimage': 1, 'npkpt': 2, 'npspinor': 1, 'npfft': 1, 'npband': 1, 'bandpp': 1}\n", "[Wed Feb 5 11:04:13 2020] Old values: {'npimage': None, 'npkpt': None, 'npspinor': None, 'npfft': None, 'npband': None, 'bandpp': None}\n", "[Wed Feb 5 11:04:13 2020] Status changed to Initialized. msg: finished autoparal run\n", "[Wed Feb 5 11:04:13 2020] Submitted with MPI=2, Omp=1, Memproc=2.0 [Gb] Submitted to queue \n", "[Wed Feb 5 11:04:14 2020] Task completed status set to OK based on abiout\n", "[Wed Feb 5 11:04:14 2020] Finalized set to True\n", "[Wed Feb 5 11:04:14 2020] Node broadcasts signal Completed\n", "\u001b[32m\n", "==================================================================================================================\n", "==================== ====================\n", "==================================================================================================================\u001b[0m\n", "[Wed Feb 5 11:04:14 2020] Status changed to Ready. msg: Status set to Ready\n", "[Wed Feb 5 11:04:14 2020] Need path /tmp/hello_bands/w0/t0/outdata/out_DEN with ext DEN\n", "[Wed Feb 5 11:04:14 2020] Linking path /tmp/hello_bands/w0/t0/outdata/out_DEN --> /tmp/hello_bands/w0/t1/indata/in_DEN\n", "[Wed Feb 5 11:04:14 2020] Setting input variables: {'ngfft': [18, 18, 18]}\n", "[Wed Feb 5 11:04:14 2020] Old values: {'ngfft': None}\n", "[Wed Feb 5 11:04:14 2020] Adding connecting vars {'irdden': 1}\n", "[Wed Feb 5 11:04:14 2020] Setting input variables: {'irdden': 1}\n", "[Wed Feb 5 11:04:14 2020] Old values: {'irdden': None}\n", "[Wed Feb 5 11:04:14 2020] Setting input variables: {'autoparal': 1, 'max_ncpus': 2, 'mem_test': 0}\n", "[Wed Feb 5 11:04:14 2020] Old values: {'autoparal': None, 'max_ncpus': None, 'mem_test': None}\n", "[Wed Feb 5 11:04:14 2020] Setting input variables: {'npimage': 1, 'npkpt': 2, 'npspinor': 1, 'npfft': 1, 'npband': 1, 'bandpp': 1}\n", "[Wed Feb 5 11:04:14 2020] Old values: {'npimage': None, 'npkpt': None, 'npspinor': None, 'npfft': None, 'npband': None, 'bandpp': None}\n", "[Wed Feb 5 11:04:14 2020] Status changed to Initialized. msg: finished autoparal run\n", "[Wed Feb 5 11:04:14 2020] Submitted with MPI=2, Omp=1, Memproc=2.0 [Gb] Submitted to queue \n", "[Wed Feb 5 11:04:16 2020] Task completed status set to OK based on abiout\n", "[Wed Feb 5 11:04:16 2020] Finalized set to True\n", "[Wed Feb 5 11:04:16 2020] Node broadcasts signal Completed\n", "\u001b[32m\n", "==================================================================================================================\n", "========================= =========================\n", "==================================================================================================================\u001b[0m\n", "[Wed Feb 5 11:04:16 2020] Calling flow.finalize.\n", "[Wed Feb 5 11:04:16 2020] Finalized set to True\n" ] } ], "source": [ "flow.show_history()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you read the logs carefully, you will realize that in the first iteration of the scheduler, \n", "only the `ScfTask` is executed because the second task depends on it. \n", "After the initial submission, the scheduler starts to monitor all the tasks in the flow.\n", "\n", "When the ScfTask completes, the dependency of the NscfTask is fullfilled and \n", "a new submission takes place. Once the second task completes, the scheduler calls `flow.finalize`\n", "to execute (optional) logic that is supposed to be executed to perform some sort of cleanup or final processing.\n", "At this point, all the tasks in the flow are completed and the scheduler exits.\n", "\n", "Now we can have a look at the different output files produced by our flow with:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "directory\n", "\n", "/tmp/hello_bands/w0\n", "\n", "cluster_/tmp/hello_bands/w0\n", "\n", "w0\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/tmpdata\n", "\n", "tmpdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/indata\n", "\n", "indata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/outdata\n", "\n", "outdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1\n", "\n", "t1\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0\n", "\n", "t0\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1/tmpdata\n", "\n", "tmpdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1/indata\n", "\n", "indata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t1/outdata\n", "\n", "outdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0/tmpdata\n", "\n", "tmpdata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0/indata\n", "\n", "indata\n", "\n", "\n", "cluster_/tmp/hello_bands/w0/t0/outdata\n", "\n", "outdata\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.log\n", "\n", "run.log\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.abo\n", "\n", "run.abo\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.abi\n", "\n", "run.abi\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/__startlock__\n", "\n", "__startlock__\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.err\n", "\n", "run.err\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/job.sh\n", "\n", "job.sh\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/autoparal.json\n", "\n", "autoparal.json\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/run.files\n", "\n", "run.files\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/indata/in_DEN\n", "\n", "in_DEN\n", "\n", "\n", "\n", "../../../../../../private/tmp/hello_bands/w0/t0/outdata/out_DEN\n", "\n", "../../../../../../private/tmp/hello_bands/w0/t0/outdata/out_DEN\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/indata/in_DEN->../../../../../../private/tmp/hello_bands/w0/t0/outdata/out_DEN\n", "\n", "\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_EIG.nc\n", "\n", "out_EIG.nc\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_WFK\n", "\n", "out_WFK\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_EBANDS.agr\n", "\n", "out_EBANDS.agr\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_GSR.nc\n", "\n", "out_GSR.nc\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_EIG\n", "\n", "out_EIG\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_DEN\n", "\n", "out_DEN\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t1/outdata/out_OUT.nc\n", "\n", "out_OUT.nc\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.log\n", "\n", "run.log\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.abo\n", "\n", "run.abo\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.abi\n", "\n", "run.abi\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/__startlock__\n", "\n", "__startlock__\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.err\n", "\n", "run.err\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/job.sh\n", "\n", "job.sh\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/autoparal.json\n", "\n", "autoparal.json\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/run.files\n", "\n", "run.files\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_EIG.nc\n", "\n", "out_EIG.nc\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_WFK\n", "\n", "out_WFK\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_EBANDS.agr\n", "\n", "out_EBANDS.agr\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_DDB\n", "\n", "out_DDB\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_GSR.nc\n", "\n", "out_GSR.nc\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_EIG\n", "\n", "out_EIG\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_DEN\n", "\n", "out_DEN\n", "\n", "\n", "\n", "/tmp/hello_bands/w0/t0/outdata/out_OUT.nc\n", "\n", "out_OUT.nc\n", "\n", "\n", "\n", "\n", "\n", "__0:cluster_/tmp/hello_bands/w0->__1:cluster_/tmp/hello_bands/w0/tmpdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__2:cluster_/tmp/hello_bands/w0->__3:cluster_/tmp/hello_bands/w0/indata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__4:cluster_/tmp/hello_bands/w0->__5:cluster_/tmp/hello_bands/w0/outdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__6:cluster_/tmp/hello_bands/w0->__7:cluster_/tmp/hello_bands/w0/t1\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__8:cluster_/tmp/hello_bands/w0->__9:cluster_/tmp/hello_bands/w0/t0\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__10:cluster_/tmp/hello_bands/w0/t1->__11:cluster_/tmp/hello_bands/w0/t1/tmpdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__12:cluster_/tmp/hello_bands/w0/t1->__13:cluster_/tmp/hello_bands/w0/t1/indata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__14:cluster_/tmp/hello_bands/w0/t1->__15:cluster_/tmp/hello_bands/w0/t1/outdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__16:cluster_/tmp/hello_bands/w0/t0->__17:cluster_/tmp/hello_bands/w0/t0/tmpdata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__18:cluster_/tmp/hello_bands/w0/t0->__19:cluster_/tmp/hello_bands/w0/t0/indata\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "__20:cluster_/tmp/hello_bands/w0/t0->__21:cluster_/tmp/hello_bands/w0/t0/outdata\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flow[0].get_graphviz_dirtree()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or list only the files with a given extension:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Found 2 files with extension `GSR.nc` produced by the flow\n", "File Size [Mb] Node_ID Node Class\n", "------------------------------------------------------- ----------- --------- ------------\n", "../../../../../tmp/hello_bands/w0/t0/outdata/out_GSR.nc 0.02 174775 ScfTask\n", "../../../../../tmp/hello_bands/w0/t1/outdata/out_GSR.nc 0.02 174776 NscfTask\n" ] } ], "source": [ "flow.listext(\"GSR.nc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The nice thing about the flow is that the object knows how to locate and interpret the \n", "different input/ouput files produced by Abinit. \n", "As a consequence, it is very easy to expose the AbiPy post-processing tools with a easy-to-use API\n", "in which only tasks/works/flow plus a very few input arguments are required.\n", "\n", "Let's call, for instance, the inspect method to plot the self-consistent cycles:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34mTask does not provide an inspect method\u001b[0m\n" ] } ], "source": [ "flow.inspect(tight_layout=True);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the other AbiPy tutorials, we have explained how to use abiopen to create \n", "python objects from netcdf files. \n", "Well, the same code can be reused with the flow. \n", "It is just a matter of replacing\n", "\n", "```python\n", "with abiopen(filepath) as gsr:\n", "```\n", "\n", "with\n", "\n", "```python\n", "with task.open_gsr() as gsr:\n", "```\n", "\n", "Note that there is no need to specify the file path when you use the task-based API, because \n", "the `Task` knows how to locate its `GSR.nc` output.\n", "Let's do some practice..." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "image/png": "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ubjGcuPGDXnzzTeN0xxVqFBBrl69atI0tBpL1kNq41jmAAOAp8AmoLmI3DadpWWcggULMnjwYBwcHIzB0dExweeUttvY2OT3Xh0a6cDKyor+/fvTv39/jh49yldffcWvv/7Kli1b2LJlC6VLl2bIkCG88cYb1K5d29xyAejQoQOnTp1i48aNTJs2jfPnz9OlSxfat2/P3LlzadCggbklZivR0dF4e3uzevVqduzYQUxMDBYWFgwbNoy5c+dSqlQpc0vUSExKjgN8DFTNSZdLK+TnucLyGnm1xpIct27dkjlz5ki1atUS1HLr168vixYtkgcPHphbopEXL17I/PnzjbPiAjJkyBC5ceOGydIgl9RYbty4IVOmTEnQy8vS0lKGDBli8lpKfLQaS9ZDig2SIjJLRP5WShVQSs1USn0HoJSqopTqnr12p6GRc5QtW5YPP/yQy5cvc+zYMcaOHUvhwoU5c+YMEyZMoEyZMvTu3Ztt27YRFRVlVq12dnZMnjyZgIAAJk+ejI2NDRs2bKBatWq89957PH782Kz6soqIcODAAfr27UulSpWYO3cu9+/fp3r16sydO5fbt2+zfv16qlatam6pGqmQniddPwCRQNPYz7eB2dmmSEPDTCilaNKkCcuWLePu3bv8/PPPdOvWDRHBy8uLvn37UqZMGcaNG4e/v39czd4sFC1alPnz53P16lWGDBlCVFQUCxYswNnZme7du7NmzZoEk5rmBe7du0ffvn1p06YN27Ztw9LSkiFDhuDn58elS5d4//33KV26tLllaqSD9BhLJRGZC0QDiMgLQHtYoZGvsbOzw9PTkz/++IPbt28zf/58ateuzePHj1myZAkNGzakdu3azJs3j7t375pNp5ubG+vXr+fUqVN07twZnU7Hjh07GDFiBKVKlaJz5858//33PHr0KO3IzMiOHTuoVasW27dvx8nJiY8++ojAwEDWr19Ps2bNtOejeYz0GEuUUsoeQxsnSqlKGGowGhovBaVLl2by5MmcPXuW06dP8+6771K8eHEuXrzIlClTcHV1pXPnzixatIjTp0+j0+lyXKOHhwfe3t7cuXOH5cuX06FDB0SE3bt3M2rUKEqXLk3Hjh1ZsWIFDx48yHF9qbF+/Xp69erFkydPePXVV7lw4QKzZs3C2dnZ3NI0MktaD2GAjhi6GT8ENgA3gTY5+SAo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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "with flow[0][0].open_gsr() as gsr:\n", " ebands_kmesh = gsr.ebands\n", " \n", "with flow[0][1].open_gsr() as gsr:\n", " gsr.ebands.plot_with_edos(ebands_kmesh.get_edos(), with_gaps=True);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More on Works, Tasks and dependencies \n", "[[back to top](#top)]\n", "\n", "In the previous example, we have constructed a workflow for band structure calculations\n", "starting from two input files and the magic line\n", "\n", "```python\n", "flow = flowtk.bandstructure_flow(workdir, scf_input, nscf_input)\n", "```\n", "\n", "Now it is the right time to explain in more details the syntax and the API used in AbiPy \n", "to build a flow with dependencies.\n", "Let's try to build a `Flow` from scratch and use graphviz after each step to show what's happening.\n", "We start with an empty flow in the `hello_flow` directory:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174777, workdir=hello_flow\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hello_flow = flowtk.Flow(workdir=\"hello_flow\")\n", "hello_flow.get_graphviz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we add a new `Task` by just passing an `AbinitInput` for SCF calculations:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174777, workdir=hello_flow\n", "\n", "clusterw0\n", "\n", "Work (w0)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "ScfTask\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hello_flow.register_scf_task(scf_input, append=True)\n", "hello_flow.get_graphviz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the tricky part. \n", "We want to register a NSCF calculation that should depend on the `scf_task` in `w0_t0` via the DEN file.\n", "We can use the same API but we **must** specify the dependency between the two steps with the \n", "```{scf_task: \"DEN\"}``` dictionary:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174777, workdir=hello_flow\n", "\n", "clusterw0\n", "\n", "Work (w0)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "ScfTask\n", "\n", "\n", "\n", "w0_t1\n", "\n", "w0_t1\n", "NscfTask\n", "\n", "\n", "\n", "w0_t0->w0_t1\n", "\n", "\n", "DEN\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hello_flow.register_nscf_task(nscf_input, deps={hello_flow[0][0]: \"DEN\"}, append=True)\n", "hello_flow.get_graphviz(engine=\"dot\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Excellent, we managed to build our first AbiPy flow with inter-dependent tasks in just six lines \n", "of code (including the three calls to graphviz).\n", "Now let's assume we want to add a second Nscf calculation (`NscTask`) in which we change one of the input parameters\n", "e.g. the number of bands and that, for some reason, we really want to re-use the output WFK file \n", "produced by `w0_t1` to initialize the eigenvalue solver (obviously we still need a DEN file).\n", "How can we express this with AbiPy? \n", "\n", "Well, the syntax for the new deps, it's just:\n", "\n", "```python\n", "deps = {hello_flow[0][0]: \"DEN\", hello_flow[0][1]: \"WFK\"}\n", "```\n", "\n", "but we should also change the input variable nband in the `nscf_input` before creating\n", "the new `NscTask` (remember that building a `Task` requires an `AbinitInput` object \n", "and a list of dependencies, if any).\n", "\n", "Now there are two ways to increase nband: the **wrong** way and the **correct** one!\n", "Let's start from the *wrong* way because it's always useful to learn from our mistakes.\n", "Let's print some values just for the record:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "nband in the first NscfTask: 8\n" ] } ], "source": [ "t1 = flow[0][1]\n", "print(\"nband in the first NscfTask:\", t1.input[\"nband\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's use the \"recipe\" recommended to us by the FORTRAN guru of our group: \n", "\n", "\"\"" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "nband in the first NscfTask: 1000\n", "nband in the new input: 1000\n" ] } ], "source": [ "# Just copy the previous input and change nband, it's super-easy, the FORTRAN guru said!\n", "new_input = t1.input\n", "new_input[\"nband\"] = 1000\n", "\n", "print(\"nband in the first NscfTask:\", t1.input[\"nband\"])\n", "print(\"nband in the new input:\", new_input[\"nband\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tada! Thanks to the trick of our beloved FORTRAN guru, we ended up with *two* NscfTaks\n", "with the **same number** of bands (1000!). Why?\n", "\n", "Because `AbinitInput` is implemented internally with a dictionary, python dictionaries are **mutable**\n", "and python variables are essentially references (they do not store data, actually they store the address of the data)." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a dict: {'foo': 'bar', 'hello': 'world'}\n", "b dict: {'foo': 'bar', 'hello': 'world'}\n", "c dict: {'foo': 'bar'}\n" ] } ], "source": [ "a = {\"foo\": \"bar\"}\n", "b = a \n", "c = a.copy()\n", "a[\"hello\"] = \"world\"\n", "print(\"a dict:\", a)\n", "print(\"b dict:\", b)\n", "print(\"c dict:\", c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a more techical explanation see [here](http://docs.python-guide.org/en/latest/writing/gotchas/)\n", "\n", "To avoid this mistake, we need to *copy* the object before changing it" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "nband in the first NscfTask: 8\n", "nband in the new input: 1000\n" ] } ], "source": [ "t1.input[\"nband\"] = 8 # back to the old value\n", "\n", "new_input = t1.input.new_with_vars(nband=1000) # Copy and change nband\n", "\n", "print(\"nband in the first NscfTask:\", t1.input[\"nband\"])\n", "print(\"nband in the new input:\", new_input[\"nband\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can finally add the second `NscfTask` with 1000 bands:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174777, workdir=hello_flow\n", "\n", "clusterw0\n", "\n", "Work (w0)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "ScfTask\n", "\n", "\n", "\n", "w0_t1\n", "\n", "w0_t1\n", "NscfTask\n", "\n", "\n", "\n", "w0_t0->w0_t1\n", "\n", "\n", "DEN\n", "\n", "\n", "\n", "w0_t2\n", "\n", "w0_t2\n", "NscfTask\n", "\n", "\n", "\n", "w0_t0->w0_t2\n", "\n", "\n", "DEN\n", "\n", "\n", "\n", "w0_t1->w0_t2\n", "\n", "\n", "WFK\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hello_flow.register_nscf_task(new_input, deps={hello_flow[0][0]: \"DEN\", hello_flow[0][1]: \"WFK\"}, append=True)\n", "hello_flow.get_graphviz(engine=\"dot\")" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[8, 8, 1000]\n" ] } ], "source": [ "print([task.input[\"nband\"] for task in hello_flow.iflat_tasks()])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that AbiPy dependencies can also be fulfilled with external files that are already available\n", "when the flow is constructed. There is no change in the syntax we've used so far.\n", "It is just a matter of using the absolute path to the DEN file as keyword of the dictionary instead of a `Task`.\n", "Let's start with a new `Flow` to avoid confusion and create a `NscfTask` that will start from a pre-computed `DEN` file." ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174782, workdir=flow_with_file\n", "\n", "clusterw0\n", "\n", "Work (w0)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "NscfTask\n", "\n", "\n", "\n", "/Users/gmatteo/git_repos/abipy/abipy/data/refs/si_ebands/si_DEN.nc\n", "\n", "FileNode, node_id=174785, rpath=../../abipy/abipy/data/refs/si_ebands/si_DEN.nc\n", "\n", "\n", "\n", "/Users/gmatteo/git_repos/abipy/abipy/data/refs/si_ebands/si_DEN.nc->w0_t0\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flow_with_file = flowtk.Flow(workdir=\"flow_with_file\")\n", "\n", "den_filepath = abidata.ref_file(\"si_DEN.nc\")\n", "flow_with_file.register_nscf_task(nscf_input, deps={den_filepath: \"DEN\"})\n", "\n", "flow_with_file.get_graphviz(engine=\"dot\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A call to `new_with_vars` inside a python `for` loop is all we need to add other two `NscfTasks`\n", "with different `nband`, all starting from the same DEN file:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[8, 10, 20]\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174782, workdir=flow_with_file\n", "\n", "clusterw0\n", "\n", "Work (w0)\n", "\n", "\n", "clusterw1\n", "\n", "Work (w1)\n", "\n", "\n", "clusterw2\n", "\n", "Work (w2)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "NscfTask\n", "\n", "\n", "\n", "w1_t0\n", "\n", "w1_t0\n", "NscfTask\n", "\n", "\n", "\n", "w2_t0\n", "\n", "w2_t0\n", "NscfTask\n", "\n", "\n", "\n", "/Users/gmatteo/git_repos/abipy/abipy/data/refs/si_ebands/si_DEN.nc\n", "\n", "FileNode, node_id=174785, rpath=../../abipy/abipy/data/refs/si_ebands/si_DEN.nc\n", "\n", "\n", "\n", "/Users/gmatteo/git_repos/abipy/abipy/data/refs/si_ebands/si_DEN.nc->w0_t0\n", "\n", "\n", "\n", "\n", "\n", "/Users/gmatteo/git_repos/abipy/abipy/data/refs/si_ebands/si_DEN.nc->w1_t0\n", "\n", "\n", "\n", "\n", "\n", "/Users/gmatteo/git_repos/abipy/abipy/data/refs/si_ebands/si_DEN.nc->w2_t0\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for nband in [10, 20]:\n", " flow_with_file.register_nscf_task(nscf_input.new_with_vars(nband=nband), \n", " deps={den_filepath: \"DEN\"}, append=False)\n", "\n", "print([task.input[\"nband\"] for task in flow_with_file.iflat_tasks()])\n", "flow_with_file.get_graphviz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At this point, you may ask why we need `Works` since all the examples presented so far \n", "mainly involve the `Flow` object.\n", "\n", "The answer is that `Works` allow us to encapsulate reusable logic in magic boxes \n", "that can perform lot of useful work. \n", "These boxes can then be connected together to generate more complicated workflows.\n", "We have already encountered the `BandStructureWork` at the beginning of this lesson\n", "and now it is time to introduce another fancy animal of the AbiPy zoo, the `PhononWork`." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
class PhononWork(Work, MergeDdb):\n",
       "    """\n",
       "    This work consists of nirred Phonon tasks where nirred is\n",
       "    the number of irreducible atomic perturbations for a given set of q-points.\n",
       "    It provides the callback method (on_all_ok) that calls mrgddb (mrgdv) to merge\n",
       "    all the partial DDB (POT) files produced. The two files are available in the\n",
       "    output directory of the Work.\n",
       "\n",
       "    .. rubric:: Inheritance Diagram\n",
       "    .. inheritance-diagram:: PhononWork\n",
       "    """\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abilab.print_doc(flowtk.PhononWork)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "

\n", "\n", "
    @classmethod\n",
       "    def from_scf_task(cls, scf_task, qpoints, is_ngqpt=False, tolerance=None, with_becs=False,\n",
       "                      ddk_tolerance=None, manager=None):\n",
       "        """\n",
       "        Construct a `PhononWork` from a |ScfTask| object.\n",
       "        The input file for phonons is automatically generated from the input of the ScfTask.\n",
       "        Each phonon task depends on the WFK file produced by the `scf_task`.\n",
       "\n",
       "        Args:\n",
       "            scf_task: |ScfTask| object.\n",
       "            qpoints: q-points in reduced coordinates. Accepts single q-point, list of q-points\n",
       "                or three integers defining the q-mesh if `is_ngqpt`.\n",
       "            is_ngqpt: True if `qpoints` should be interpreted as divisions instead of q-points.\n",
       "            tolerance: dict {"varname": value} with the tolerance to be used in the phonon run.\n",
       "                None to use AbiPy default.\n",
       "            with_becs: Activate calculation of Electric field and Born effective charges.\n",
       "            ddk_tolerance: dict {"varname": value} with the tolerance used in the DDK run if with_becs.\n",
       "                None to use AbiPy default.\n",
       "            manager: |TaskManager| object.\n",
       "        """\n",
       "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abilab.print_doc(flowtk.PhononWork.from_scf_task)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The docstring seems to suggest that if I have a `scf_task`, I can construct a magic box\n", "to compute phonons but wait, I already have such a task! \n", "Actually I already have another magic box to compute the electronic band structure \n", "and it would be really great if I could compute the electronic and vibrational properties in a single flow.\n", "Let's connect the two boxes together with:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174792, workdir=phflow\n", "\n", "clusterw0\n", "\n", "BandStructureWork (w0)\n", "\n", "\n", "clusterw1\n", "\n", "PhononWork (w1)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "ScfTask\n", "\n", "\n", "\n", "w0_t1\n", "\n", "w0_t1\n", "NscfTask\n", "\n", "\n", "\n", "w0_t0->w0_t1\n", "\n", "\n", "DEN\n", "\n", "\n", "\n", "w1_t0\n", "\n", "w1_t0\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t0\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w1_t1\n", "\n", "w1_t1\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t1\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w1_t2\n", "\n", "w1_t2\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t2\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w1_t3\n", "\n", "w1_t3\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t3\n", "\n", "\n", "WFK\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create new flow.\n", "ph_flow = flowtk.Flow(workdir=\"phflow\")\n", "\n", "# Band structure (SCF + NSCF)\n", "bands_work = flowtk.BandStructureWork(scf_input, nscf_input, dos_inputs=None)\n", "ph_flow.register_work(bands_work) \n", " \n", "# Build second work from scf_task.\n", "scf_task = bands_work[0]\n", "ph_work = flowtk.PhononWork.from_scf_task(scf_task, [2, 2, 2], is_ngqpt=True, tolerance=None)\n", "ph_flow.register_work(ph_work) \n", "\n", "ph_flow.get_graphviz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now it turns out that the `PhononWork` merges all the DDB files produced by its `PhononTask`\n", "and put this final output file in its outdir. \n", "So from the AbiPy perspective, a `PhononWork` is not that different from a `ScfTask` that produces e.g. a DEN file.\n", "This means that we can connect other magic boxes to our `PhononWork` e.g. a set of `EPhTasks` that \n", "require a DDB file and another input file with the DFPT potentials \n", "(DVDB, merged by `PhononWork` similarly to what is done for the DDB)." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "flow\n", "\n", "Flow, node_id=174792, workdir=phflow\n", "\n", "clusterw0\n", "\n", "BandStructureWork (w0)\n", "\n", "\n", "clusterw1\n", "\n", "PhononWork (w1)\n", "\n", "\n", "clusterw2\n", "\n", "Work (w2)\n", "\n", "\n", "\n", "w0_t0\n", "\n", "w0_t0\n", "ScfTask\n", "\n", "\n", "\n", "w0_t1\n", "\n", "w0_t1\n", "NscfTask\n", "\n", "\n", "\n", "w0_t0->w0_t1\n", "\n", "\n", "DEN\n", "\n", "\n", "\n", "w1_t0\n", "\n", "w1_t0\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t0\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w1_t1\n", "\n", "w1_t1\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t1\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w1_t2\n", "\n", "w1_t2\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t2\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w1_t3\n", "\n", "w1_t3\n", "PhononTask\n", "\n", "\n", "\n", "w0_t0->w1_t3\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w2_t0\n", "\n", "w2_t0\n", "EphTask\n", "\n", "\n", "\n", "w0_t1->w2_t0\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w2_t1\n", "\n", "w2_t1\n", "EphTask\n", "\n", "\n", "\n", "w0_t1->w2_t1\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "w2_t2\n", "\n", "w2_t2\n", "EphTask\n", "\n", "\n", "\n", "w0_t1->w2_t2\n", "\n", "\n", "WFK\n", "\n", "\n", "\n", "DDB (w1)\n", "\n", "DDB (w1)\n", "\n", "\n", "\n", "DDB (w1)->w2_t0\n", "\n", "\n", "\n", "\n", "\n", "DDB (w1)->w2_t1\n", "\n", "\n", "\n", "\n", "\n", "DDB (w1)->w2_t2\n", "\n", "\n", "\n", "\n", "\n", "DVDB (w1)\n", "\n", "DVDB (w1)\n", "\n", "\n", "\n", "DVDB (w1)->w2_t0\n", "\n", "\n", "\n", "\n", "\n", "DVDB (w1)->w2_t1\n", "\n", "\n", "\n", "\n", "\n", "DVDB (w1)->w2_t2\n", "\n", "\n", "\n", "\n", "\n", "\n", "__0:clusterw1->DDB (w1)\n", "\n", "\n", "\n", "\n", "\n", "\n", "__1:clusterw1->DVDB (w1)\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# EPH tasks require 3 input files (WFK, DDB, DVDB)\n", "eph_deps = {ph_flow[0][1]: \"WFK\", ph_work: [\"DDB\", \"DVDB\"]}\n", "\n", "for i, ecut in enumerate([2, 3, 4]):\n", " ph_flow.register_eph_task(nscf_input.new_with_vars(ecut=ecut), deps=eph_deps, append=(i != 0))\n", " \n", "ph_flow.get_graphviz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This explains why in AbiPy we have this classification in terms of `Tasks/Works/Flows`.\n", "As a consequence, we can implement highly specialized `Works/Tasks` to\n", "solve specific problems and then connect all these nodes together.\n", "Just 11 lines of code to get electrons + phonons + (electrons + phononons)!\n", "\n", "But wait, did you see the gorilla?" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "image/jpeg": "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\n", "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"vJG698U2Mvo\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There's indeed a bug in the last step. The connections among the nodes are OK but we made\n", "a mistake while creating the `EPhTasks` with:\n", "\n", "```python\n", "ph_flow.register_eph_task(nscf_input.new_with_vars(ecut=ecut), ...)\n", "```\n", "\n", "because we passed an input for a standard band structure calculation to something that is supposed\n", "to deal with E-PH interaction.\n", "This essentially to stress that the AbiPy `Flow`, *by design*, does not try to validate your input to make sure\n", "it is consistent with the workflow logic.\n", "This is done on purpose for two reasons:\n", "\n", "- Expert users should be able to customize/tune their input files and validating all the possible cases in python is not trivial\n", "- Only Abinit (and God) knows at run-time if your input file makes sense and we can't reimplement the same logic in python\n", "\n", "At this point, you may wonder why we have so many different Abipy Tasks (`ScfTask`, `NscfTask`, `RelaxTask`, `PhononTask`, `EPHTask` ...) if there's no input validation when we create them...\n", "\n", "The answer is that we need all these subclasses to implement extra logic that is specific to that particular calculation. Abipy, indeed, is not just submitting jobs. It also monitors the evolution of the calculation\n", "and execute pre-defined code to fix run-time problems (and these problems are calculation specific).\n", "An example will help clarify this point.\n", "\n", "Restarting jobs is one of the typical problem encountered in ab-initio calculations\n", "and restarting a `RelaxTask` requires a different logic from e.g. restarting a `ScfTask`.\n", "In the case of a `ScfTask` we only need to use the output WFK (DEN) of the previous execution \n", "as input of the restarted job while a `RelaxTask` must also re-use the (unconverged) final structure \n", "of the previous job to be effective and avoid a possibly infinite loop.\n", "In a nutshell, when you are using a particular `Task/Work` class you are telling AbiPy how to handle possible\n", "problems at run-time and you are also specifying the actions that should be performed \n", "at the beginning/end of the execution." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Abirun.py\n", "[[back to top](#top)]\n", "\n", "Executing \n", "\n", "```python \n", "flow.make_scheduler().start()\n", "``` \n", "\n", "inside a jupyter notebook is handy if you are dealing with small calculations that require few seconds or minutes. \n", "This approach, however, is unpractical when you have large flows or big calculations requiring hours or days, \n", "even on massively parallel machines.\n", "In this case, indeed, one would like to run the scheduler in a separate process in the backgroud \n", "so that the scheduler is not killed when the jupyter server is closed.\n", "\n", "To start the scheduler in a separate process, use the `abirun.py` script.\n", "The syntax is:\n", "\n", " abirun.py flow_workdir COMMAND\n", "\n", "where `flow_workdir` is the directory containing the `Flow` \n", "(the directory with the pickle file) and `command` selects the operation to be performed.\n", "\n", "Typical examples:\n", "\n", " abirun.py /tmp/hello_bands status\n", " \n", "checks the status of the `Flow` and print the results to screen while\n", "\n", " nohup abirun.py /tmp/hello_bands scheduler > sched.log 2> sched.err &\n", " \n", "starts the scheduler in the background redirecting the standard output to file `sched.log`\n", "\n", "
\n", "`nohup` is a standard Unix tool. The command make the scheduler immune \n", "to hangups so that you can close the shell session without killing the scheduler.\n", "
\n", "\n", "This brings us to the last and most crucial question. \n", "How do we configure AbiPy to run Abinit workflows on different architectures ranging from \n", "standard laptops to high-performance supercomputers?\n", "\n", "Unfortunately this notebook is already quite long and these details are best covered \n", "in a technical documentation.\n", "What should be stressed here is that the behaviour can be customized with two Yaml files.\n", "All the information related to your environment (Abinit build, modules, resource managers, shell environment)\n", "are read from the `manager.yml` configuration file, that is usually located in the directory `~/.abinit/abipy/`\n", "The options for the python scheduler responsible for job submission are given in `scheduler.yml`.\n", "\n", "For a more complete description of these configuration options, \n", "please consult the [TaskManager documentation](http://abinit.github.io/abipy/workflows/taskmanager.html).\n", "A list of configuration files for different machines and clusters is available \n", "[here](http://abinit.github.io/abipy/workflows/manager_examples.html)\n", "while the [Flows HOWTO](http://abinit.github.io/abipy/flows_howto.html)\n", "gathers answers to frequently asked questions.\n", "\n", "Last but not least, check out our \n", "[gallery of AbiPy Flows](http://abinit.github.io/abipy/flow_gallery/index.html) for inspiration." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Back to the main [Index](index.ipynb)" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" }, "latex_envs": { "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 0 } }, "nbformat": 4, "nbformat_minor": 4 }