{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# useful to autoreload the module without restarting the kernel\n", "%load_ext autoreload\n", "%autoreload 2" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from mppi import InputFiles as I, Calculators as C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial for the QeCalculator class" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This tutorial describes the usage of the QeCalculator class, that manages the run of (many) calculations in\n", "parallel with the QuantumESPRESSO package." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "run_dir = 'QeCalculator_test'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Perform (many) scf computations for silicon" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We init the PwInput object using an exsisting input file. Then we define 4 inputs with the associated names by\n", "considering different values for the energy cutoff of the wave-functions" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "enegy_cutoffs = [40,50,60,70]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "from copy import deepcopy\n", "\n", "inp = I.PwInput(file='IO_files/si_scf.in')\n", "inp.set_kpoints(points = [6,6,6])\n", "\n", "inputs = []\n", "names = []\n", "\n", "for e in enegy_cutoffs: \n", " prefix = 'ecut_%s'%e\n", " inp.set_prefix(prefix)\n", " inp.set_energy_cutoff(e)\n", " inputs.append(deepcopy(inp))\n", " names.append(prefix)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['ecut_40', 'ecut_50', 'ecut_60', 'ecut_70']" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "names" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we have chosen the value of the prefix of the input object as the name of the file. In this way the inp, log and xml file created by QuantumESPRESSO\n", "have the same name of the prefix folder." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we define an intance of the QeCalculator. For this example we use a direct scheduler, so the computations are runned in parallel using the python\n", "multiprocessing module" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mInit signature:\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mQeCalculator\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0momp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpi\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpi_run\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'mpirun -np'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexecutable\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'pw.x'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mscheduler\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'direct'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmultiTask\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mskip\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mverbose\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIO_time\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m \n", "Manage (multiple) QuantumESPRESSO calculations performed in parallel. Computations\n", "are managed by a scheduler that, in the actual implementation of the class, can\n", "be `direct` or `slurm`.\n", "\n", "Parameters:\n", " omp (:py:class:`int`) : value of the OMP_NUM_THREADS variable\n", " mpi (:py:class:`int`) : number of mpi processes\n", " mpi_run (:py:class:`string`) : command for the execution of mpirun, e.g. 'mpirun -np' or 'mpiexec -np'\n", " executable (:py:class:`string`) : set the executable (pw.x, ph.x, ..) of the QuantumESPRESSO package\n", " scheduler (:py:class:`string`) : choose the scheduler used to submit the job, actually the choices implemented are\n", " 'direct' that runs the computation using the python multiprocessing package and 'slurm' that creates a slurm script\n", " multiTask (:py:class:`bool`) : if true a single run_script is built and all the computations are performed in parallel,\n", " otherwise an independent script is built for each elements of inputs and the computations are performed sequentially\n", " skip (:py:class:`bool`) : if True evaluate if one (or many) computations can be skipped.\n", " This is done by checking if the file $name.xml is present in the prefix folder,\n", " for each name in names\n", " verbose (:py:class:`bool`) : set the amount of information provided on terminal\n", " IO_time (int) : time step (in second) used by the wait method to check that the job is completed\n", " kwargs : other parameters that are stored in the _global_options dictionary. For instance the variable\n", " sbatch_options = [option1,option2,....] allows the user to include further options in the slurm script\n", "\n", "Example:\n", " >>> code = calculator(omp=1,mpi=4,mpi_run='mpirun -np',skip=True,verbose=True,scheduler='direct')\n", " >>> code.run(inputs = [...], run_dir = ...,names = [...], source_dir = ..., **kwargs)\n", "\n", " where the arguments of the run method are:\n", "\n", "Args:\n", " run_dir (:py:class:`string`) : the folder in which the simulation is performed\n", " inputs (:py:class:`list`) : list with the instances of the :class:`PwInput` class\n", " that define the input objects\n", " names (:py:class:`list`) : list with the names associated to the input files,\n", " given in the same order of the inputs list.\n", " Usually you can set the name equal to the prefix of the input object so\n", " the name of the input file and the prefix folder built by QuantumESPRESSO\n", " are equal\n", " source_dir (:py:class:`string`) : location of the scf source folder for a nscf computation.\n", " If present the class copies this folder in the run_dir with the name $prefix.save\n", " kwargs : other parameters that are stored in the run_options dictionary\n", "\u001b[0;31mFile:\u001b[0m ~/Applications/MPPI/mppi/Calculators/QeCalculator.py\n", "\u001b[0;31mType:\u001b[0m type\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "C.QeCalculator?" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Initialize a parallel QuantumESPRESSO calculator with scheduler direct\n" ] }, { "data": { "text/plain": [ "{'omp': 1,\n", " 'mpi': 2,\n", " 'mpi_run': 'mpirun -np',\n", " 'executable': 'pw.x',\n", " 'scheduler': 'direct',\n", " 'multiTask': True,\n", " 'skip': True,\n", " 'verbose': True,\n", " 'IO_time': 5}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "code = C.QeCalculator(mpi=2)\n", "code.global_options()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We run the computation(s) passing the list with the inputs object and the associated names to the run method of the \n", "calculator" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "delete log file: QeCalculator_test/ecut_40.log\n", "delete xml file: QeCalculator_test/ecut_40.xml\n", "delete folder: QeCalculator_test/ecut_40.save\n", "delete log file: QeCalculator_test/ecut_50.log\n", "delete xml file: QeCalculator_test/ecut_50.xml\n", "delete folder: QeCalculator_test/ecut_50.save\n", "delete log file: QeCalculator_test/ecut_60.log\n", "delete xml file: QeCalculator_test/ecut_60.xml\n", "delete folder: QeCalculator_test/ecut_60.save\n", "delete log file: QeCalculator_test/ecut_70.log\n", "delete xml file: QeCalculator_test/ecut_70.xml\n", "delete folder: QeCalculator_test/ecut_70.save\n", "run 0 command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_40.in > ecut_40.log\n", "run 1 command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_50.in > ecut_50.log\n", "run 2 command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_60.in > ecut_60.log\n", "run 3 command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_70.in > ecut_70.log\n", "run0_is_running: True run1_is_running: True run2_is_running: True run3_is_running: True \n", "run0_is_running: True run1_is_running: True run2_is_running: True run3_is_running: True \n", "run0_is_running: False run1_is_running: False run2_is_running: False run3_is_running: True \n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/ecut_40.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_50.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_60.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_70.save/data-file-schema.xml']}" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(run_dir=run_dir,inputs=inputs,names=names,other_variable = 1,skip=False)\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After the run all the parameters passed to the calculator are written in the run_options attribute" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "#code.run_options" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We observe that, if the run of the simulation does not crash the output of the run method is a list with the the data-file-schema.xml (including their relative path) for subsequent parsing.\n", "The elements of the list are ordered as the input objects in the inputs list. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead, let see what happens if the simulation fails. For instance if we provide an empty input to code" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "inp2 = I.PwInput()" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'control': {'prefix': \"'si_scf_test2'\"},\n", " 'system': {},\n", " 'electrons': {},\n", " 'ions': {},\n", " 'cell': {},\n", " 'atomic_species': {},\n", " 'atomic_positions': {},\n", " 'kpoints': {},\n", " 'cell_parameters': {}}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prefix = 'si_scf_test2'\n", "inp2.set_prefix(prefix)\n", "inp2" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "run 0 command: cd QeCalculator_test; mpirun -np 2 pw.x -inp si_scf_test2.in > si_scf_test2.log\n", "run0_is_running: True \n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': [None]}" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result2 = code.run(inputs = [inp2], run_dir = run_dir,names=[prefix]) \n", "result2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case the output of the run method is None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Usage of the skip parameter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we repeat a calculation that has been already performed and skip = True the class skip its computation, for instance" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Skip the computation for input ecut_40\n", "Skip the computation for input ecut_50\n", "Skip the computation for input ecut_60\n", "Skip the computation for input ecut_70\n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/ecut_40.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_50.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_60.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_70.save/data-file-schema.xml']}" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(run_dir=run_dir,inputs=inputs,names=names, skip = True)\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we add one element to inputs and run again onlty the new element is computed" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "e = 80\n", "prefix = 'ecut_%s'%e\n", "inp.set_prefix(prefix)\n", "inp.set_energy_cutoff(e)\n", "inputs.append(deepcopy(inp))\n", "names.append(prefix)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Skip the computation for input ecut_40\n", "Skip the computation for input ecut_50\n", "Skip the computation for input ecut_60\n", "Skip the computation for input ecut_70\n", "Skip the computation for input ecut_80\n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/ecut_40.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_50.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_60.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_70.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_80.save/data-file-schema.xml']}" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(run_dir=run_dir,inputs=inputs,names=names, skip = True)\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead if skip = False the class clean the run_dir before performing the computation, for istance" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "delete log file: QeCalculator_test/ecut_40.log\n", "delete xml file: QeCalculator_test/ecut_40.xml\n", "delete folder: QeCalculator_test/ecut_40.save\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_40.in > ecut_40.log\n", "run0_is_running:True \n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/ecut_40.save/data-file-schema.xml']}" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(run_dir=run_dir,inputs=inputs[0:1],names=names[0:1], skip = False)\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Usage of the multiTask feature" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default the calculator runs in parallel all the computations. However if the multiTask = False option\n", "is used the the computations are performed in sequence." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "delete log file: QeCalculator_test/ecut_40.log\n", "delete xml file: QeCalculator_test/ecut_40.xml\n", "delete folder: QeCalculator_test/ecut_40.save\n", "delete log file: QeCalculator_test/ecut_50.log\n", "delete xml file: QeCalculator_test/ecut_50.xml\n", "delete folder: QeCalculator_test/ecut_50.save\n", "delete log file: QeCalculator_test/ecut_60.log\n", "delete xml file: QeCalculator_test/ecut_60.xml\n", "delete folder: QeCalculator_test/ecut_60.save\n", "delete log file: QeCalculator_test/ecut_70.log\n", "delete xml file: QeCalculator_test/ecut_70.xml\n", "delete folder: QeCalculator_test/ecut_70.save\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_40.in > ecut_40.log\n", "run0_is_running:True \n", "Job completed\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_50.in > ecut_50.log\n", "run0_is_running:True \n", "Job completed\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_60.in > ecut_60.log\n", "run0_is_running:True \n", "Job completed\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp ecut_70.in > ecut_70.log\n", "run0_is_running:True \n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/ecut_40.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_50.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_60.save/data-file-schema.xml',\n", " 'QeCalculator_test/ecut_70.save/data-file-schema.xml']}" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(run_dir=run_dir,inputs=inputs[0:4],names=names[0:4], skip = False, multiTask = False)\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Test of the slurm scheduler" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the `slurm` scheduler is chosen the calculator prepare the slurm script and submit it. The effects of skip and\n", "multiTask parameters can be tested" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "results = code.run(run_dir=run_dir,inputs=inputs,names=names, scheduler = 'slurm', skip = False, multiTask = True)\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The slurm script is written in the run_dir. The execution of the run requires that the slurm scheduler is installed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Perform a nscf computation for silicon. Usage of the source_dir option" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We show how to perform a pw nscf calculation using the results of the first scf run as an input.\n", "\n", "We observe that source_dir is unique, so we can run in parallel only runs that use the same directory\n", "as source scf input.\n", "\n", "For instance we consider two nscf computations" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'QeCalculator_test'" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "run_dir" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "num_bands = [8,12]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "inputs = []\n", "names = []\n", "\n", "for n in num_bands:\n", " inp.set_nscf(n,force_symmorphic=True)\n", " prefix = 'bands_%s'%n\n", " inp.set_prefix(prefix)\n", " inp.set_energy_cutoff(40)\n", " inputs.append(deepcopy(inp))\n", " names.append(prefix)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The folder QeCalculator_test/bands_8.save already exsists. Source folder QeCalculator_test/ecut_40.save not copied\n", "The folder QeCalculator_test/bands_12.save already exsists. Source folder QeCalculator_test/ecut_40.save not copied\n", "Skip the run of bands_8\n", "Skip the run of bands_12\n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/bands_8.save/data-file-schema.xml',\n", " 'QeCalculator_test/bands_12.save/data-file-schema.xml']}" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(inputs=inputs,run_dir=run_dir,names=names,source_dir='QeCalculator_test/ecut_40.save')\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead, if skip = False the class delete the existing output files before running the computation again. " ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "delete log file: QeCalculator_test/bands_8.log\n", "delete xml file: QeCalculator_test/bands_8.xml\n", "delete folder: QeCalculator_test/bands_8.save\n", "delete log file: QeCalculator_test/bands_12.log\n", "delete xml file: QeCalculator_test/bands_12.xml\n", "delete folder: QeCalculator_test/bands_12.save\n", "Copy source_dir QeCalculator_test/ecut_40.save in the QeCalculator_test/bands_8.save\n", "Copy source_dir QeCalculator_test/ecut_40.save in the QeCalculator_test/bands_12.save\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp bands_8.in > bands_8.log\n", "Executing command: cd QeCalculator_test; mpirun -np 2 pw.x -inp bands_12.in > bands_12.log\n", "run0_is_running:True run1_is_running:True \n", "Job completed\n" ] }, { "data": { "text/plain": [ "{'output': ['QeCalculator_test/bands_8.save/data-file-schema.xml',\n", " 'QeCalculator_test/bands_12.save/data-file-schema.xml']}" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results = code.run(inputs=inputs,run_dir=run_dir,names=names,source_dir='QeCalculator_test/ecut_40.save',skip=False)\n", "results" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "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.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }