├── LICENSE ├── README.md ├── clean ├── example ├── AlN_abs.txt ├── create_workflow.ipynb ├── input.yaml └── postprocessing.ipynb ├── pyGWBSE ├── config.py ├── inputset.py ├── inputset.yaml ├── make_wflow.py ├── out2db.py ├── run_calc.py ├── tasks.py ├── wannier_tasks.py └── wflows.py ├── requirements.txt ├── setup.py └── sphinx ├── Makefile ├── README ├── README.md ├── _static ├── github.png └── orcid.jpg ├── clean ├── compile ├── conf.py ├── example ├── AlN_abs.txt ├── create_workflow.ipynb ├── input.yaml └── postprocessing.ipynb ├── index.rst ├── make.bat ├── pyGWBSE ├── config.py ├── inputset.py ├── inputset.yaml ├── make_wflow.py ├── out2db.py ├── run_calc.py ├── tasks.py ├── wannier_tasks.py └── wflows.py ├── requirement.txt ├── rst ├── modules.rst ├── project │ ├── gwbse_wf │ │ ├── getfromdb.rst │ │ ├── inputset.rst │ │ ├── modules.rst │ │ ├── out2db.rst │ │ ├── run_calc.rst │ │ ├── tasks.rst │ │ ├── wannier_tasks.rst │ │ └── wflows.rst │ ├── make_wf.rst │ └── modules.rst └── project_intro │ ├── installation.rst │ ├── introduction.rst │ ├── modules.rst │ ├── references.rst │ └── team.rst └── setup.py /README.md: -------------------------------------------------------------------------------- 1 | # *py*GWBSE 2 | *py*GWBSE is a high-throughtput python workflow package designed to perform automtaed GW-BSE (Bethe-Salpeter Equation) calculation. The *py*GWBSE package leverages well known computational tools: *pymatgen, atomate, fireworks* and first principles software such as: *VASP* and *Wannier90* to perform high-throughput GW-BSE calculations. The workflow creates, computes, analyzes and stores all relevant simulation parameters and results in a queryable MongoDB database that can be accessed through our API. Check out our [documentation](https://cmdlab.github.io/pyGWBSE/) or the [paper](https://arxiv.org/abs/2210.00152)! 3 | 4 | ## Package Description 5 | *py*GWBSE package takes input structure of materials and performs GW-BSE simulations for studying excited state properties. It performs automated convergence calculations required to obtain accurate results from such simulations. *py*GWBSE uses widely used *VASP* software to perform first-principles calculations. It uses *Wannier90* software to obtain quasiparticle (QP) bandstructure (both the one-shot G0W0 and partially self-consistent GW0 level) using maximally localized wannier functions. The electron and hole effective masses are computed using Sumo package. *py*GWBSE is also capable of solving BSE, which calculates absorption spectra of materials that incorporates excitonic effects and is accurate enough to comapre with experimental spectra. In addition to performing excited state property simulations, *py*GWBSE also computes several key electronic structure properties of materials such as, orbital resolved density of states (both at DFT and QP level), real and imaginary part of the dielectric function (with and without incorporating electron-hole interaction), the exciton energies, and their corresponding oscillator strengths, band-edges, static dielectric tensors etc. 6 | 7 | 8 | ## Installation Instructions for *py*GWBSE 9 | IMPORTANT NOTE: Atomate and FireWorks do not run on Windows OS. You need a unix-based OS (Mac or Linux) in order for these packages to run. As such, all setup instructions are given for Unix systems. 10 | 11 | 1. Download the repo from the green code icon or via github's clone method. 12 | - ``git clone https://github.com/cmdlab/pyGWBSE.git`` 13 | 2. Install *py*GWBSE in a clean enviromnent using python=3.9. I suggest using Anaconda3 to manange environments. 14 | - ``conda create --name pygwbse python=3.9`` 15 | 3. Activate the *py*GWBSE environment and run the line below in the *py*GWBSE directory to install: 16 | - ``pip install -r requirements.txt`` 17 | 4. After installation, *py*GWBSE needs to be added to your python path. This can be done by running the first line below **OR** by adding the 2nd line listed below to your *.bashrc* file. Only necessary if python cannot find the package or the setup.py failed for some reason. 18 | - ``python setup.py develop`` or ``python setup.py install`` 19 | - ``export PYTHONPATH="$HOME/path_to_package/pyGWBSE:$PYTHONPATH"`` 20 | 5. If this is your first time installing the package dependencies listed below, please ensure you have followed the respective setup instructions: 21 | - [atomate](https://atomate.org/) 22 | - [FireWorks](https://materialsproject.github.io/fireworks/installation.html) 23 | - [pymatgen](https://pymatgen.org/installation.html) 24 | 6. To run jupyter notebooks on various resources the ipykernel has to be installed. Sometimes this isn't enough and you need explicitly add the kernel to the list of environments. Via the command line: 25 | - Activate your environment ``conda activate pygwbse`` 26 | - Install ipykernel ``python -m pip install ipykernel`` 27 | - Add pygwbse kernel ``python -m ipykernel install --user --name pygwbse`` 28 | 29 | ## Setting up dependancies 30 | The *py*GWBSE package dependancies have a lot of documentation to look over. I will highlight the essential documentation to get started as quickly as possible. 31 | 1. *atomate* requires the most set up. Mainly, creating a directory scaffold and writing the 5 required files to connect to the database and run jobs. (MongoDB or free Atlas MongoDB is required) 32 | 2. *pymatgen* has a command line tool installed to set up default directory paths called pmg. There are 2 essential commands you have to run to use *py*GWBSE on any system. 33 | - Reference directory for the VASP POTCARs. You need to have the POTCARs from VASP yourself. 34 | - `pmg config -p ` 35 | - Default pseudopotential files from VASP 36 | - `pmg config --add PMG_DEFAULT_FUNCTIONAL PBE_54` 37 | 3. *VASP* should be installed with Wannier90 support (for more information visit [here](https://www.vasp.at/wiki/index.php/LWANNIER90)). We have tested our code with VASP.5.4.4. The VASP execution command should be specified in atomate config file my_fworker.yaml as, 38 | - `vasp_cmd: "srun --mpi=pmi2 [location of VASP executable] > vasp.log"` 39 | 5. *Wannier90* version 3.1.0 should be installed (for more information visit [here](http://www.wannier.org/)). The Wannier90 execution command should be specified in the atomate config file my_fworker.yaml as, 40 | - wannier_cmd: "[location of Wannier90 executable] > wannier90" 41 | 7. *Sumo* version 2.2.5 should be installed (for more information visit [here](https://smtg-ucl.github.io/sumo/index.html)). The Sumo execution command should be specified in the atomate config file my_fworker.yaml as, 42 | - sumo_cmd: "sumo-bandstats" 43 | 44 | ## Examples 45 | To get started using *py*GWBSE, various tutorials and examples have been created using Jupyter Notebooks. These notebooks demonstrate the basic functionality of *py*GWBSE to enable users to quickly learn how to use the various modules within this package. These can be found under pyGWBSE/examples. 46 | 47 | ## Issues Installing 48 | 1. If you have a new install you likely do not have the gcc compiler that pymatgen requires. In that case run 49 | - `sudo apt install build-essential` 50 | - `sudo apt-get install manpages-dev` 51 | 52 | ## How to cite *py*GWBSE 53 | If you use *py*GWBSE in your research, please consider citing the paper! 54 | 55 | > Tathagata Biswas, Arunima K. Singh. *pyGWBSE: A high throughput workflow package for GW-BSE calculations*. [https://doi.org/10.1038/s41524-023-00976-y](https://doi.org/10.1038/s41524-023-00976-y) 56 | 57 | -------------------------------------------------------------------------------- /clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf build/ dist/ pyGWBSE.egg-info/ __pycache__/ 3 | rm -rf pyGWBSE/__init__.py pyGWBSE/__pycache__/ 4 | -------------------------------------------------------------------------------- /example/AlN_abs.txt: -------------------------------------------------------------------------------- 1 | 6.15789 0.430108 0 0 0 0 2 | 6.17895 0.55914 0 0 0 0 3 | 6.15789 0.924731 0 0 0 0 4 | 6.17895 1.5914 0 0 0 0 5 | 6.22105 2.04301 0 0 0 0 6 | 6.28421 2.43011 0 0 0 0 7 | 6.32632 2.47312 0 0 0 0 8 | 6.51579 2.34409 0 0 0 0 9 | 6.57895 2.36559 0 0 0 0 10 | 6.74737 2.45161 0 0 0 0 11 | 6.97895 2.66667 0 0 0 0 12 | 7.06316 2.94624 0 0 0 0 13 | 7.14737 3.24731 0 0 0 0 14 | 7.23158 3.5914 0 0 0 0 15 | 7.29474 3.87097 0 0 0 0 16 | 7.33684 4.25806 0 0 0 0 17 | 7.42105 4.7957 0 0 0 0 18 | 7.50526 5.50538 0 0 0 0 19 | 7.54737 6.15054 0 0 0 0 20 | 7.58947 6.7957 0 0 0 0 21 | 7.63158 7.33333 0 0 0 0 22 | 7.65263 7.65591 0 0 0 0 23 | 7.69474 8 0 0 0 0 24 | 7.73684 8.8172 0 0 0 0 25 | 7.75789 9.22581 0 0 0 0 26 | 7.8 9.5914 0 0 0 0 27 | 7.84211 9.97849 0 0 0 0 28 | 7.98947 9.5914 0 0 0 0 29 | 8.07368 9.26882 0 0 0 0 30 | 8.26316 8.88172 0 0 0 0 31 | 8.49474 8.53763 0 0 0 0 32 | 8.6 8.47312 0 0 0 0 33 | 8.74737 8.58065 0 0 0 0 34 | 8.87368 8.62366 0 0 0 0 35 | 9.04211 8.53763 0 0 0 0 36 | 9.14737 8.15054 0 0 0 0 37 | 9.23158 7.87097 0 0 0 0 38 | 9.31579 7.65591 0 0 0 0 39 | 9.42105 7.22581 0 0 0 0 40 | 9.48421 6.90323 0 0 0 0 41 | 9.58947 6.36559 0 0 0 0 42 | 9.67368 5.87097 0 0 0 0 43 | 9.73684 5.52688 0 0 0 0 44 | -------------------------------------------------------------------------------- /example/create_workflow.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "These examples show how to create GW-BSE workflow using $py$GWBSE\n", 8 | "package. We will show how to compute QP bandstructure for wurtzite-AlN\n", 9 | "at the partial self-consistent (GW$_0$) level by obtaining input \n", 10 | "structure from Material Project (MP) database. We will also compute the \n", 11 | "absorption spectra of wurtzite-AlN by solving Bethe-Salpeter equation (BSE)." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 1, 17 | "metadata": { 18 | "scrolled": true 19 | }, 20 | "outputs": [ 21 | { 22 | "name": "stderr", 23 | "output_type": "stream", 24 | "text": [ 25 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/pymatgen/analysis/phase_diagram.py:26: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", 26 | " from tqdm.autonotebook import tqdm\n", 27 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/atomate/vasp/drones.py:46: FutureWarning: which is deprecated; use which in shutil instead.\n", 28 | "shutil.which has been available since Python 3.3. This will be removed in v2023.\n", 29 | " BADER_EXE_EXISTS = which(\"bader\") or which(\"bader.exe\")\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "#First let's load the required libraries such as pymatgen and Fireworks\n", 35 | "import sys\n", 36 | "from pyGWBSE.make_wflow import read_input, create_wfs\n", 37 | "from fireworks import LaunchPad" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 2, 43 | "metadata": { 44 | "scrolled": false 45 | }, 46 | "outputs": [ 47 | { 48 | "name": "stdout", 49 | "output_type": "stream", 50 | "text": [ 51 | "PARAMS:\r\n", 52 | " kpar: 8 \r\n", 53 | " # 'KPAR' tag to be used in VASP simulations\r\n", 54 | " \r\n", 55 | " ppn: 13 \r\n", 56 | " # NPROCS/KPAR ; NPROCS: number of total processors to be used in VASP simulations \r\n", 57 | " \r\n", 58 | " reciprocal_density: 200 \r\n", 59 | " # reciprocal density that determines the k-grid using 'automatic_density_by_vol' method of pymatgen\r\n", 60 | " \r\n", 61 | " encutgw: 100 \r\n", 62 | " # ENCUTGW to be used in VASP simulations\r\n", 63 | " \r\n", 64 | " nbgwfactor: 5 \r\n", 65 | " # NBANDS=nbgwfactor x nocc'; nocc' is the smallest multiple of ppn which is larger than number of occupied bands\r\n", 66 | " \r\n", 67 | " nomegagw: 80 \r\n", 68 | " # NOMEGAGW to be used in VASP simulations\r\n", 69 | " \r\n", 70 | " convparam: NBANDS \r\n", 71 | " # NBANDS/ENCUTGW/NOMEGA parameter to run convergence test for \r\n", 72 | " \r\n", 73 | " convsteps: 2 \r\n", 74 | " # steps to be used for convergence test\r\n", 75 | " \r\n", 76 | " conviter: 5 \r\n", 77 | " # maximum number of iteration in convergence test \r\n", 78 | " \r\n", 79 | " enwinbse: 3.0 \r\n", 80 | " # energy window in BSE calculations\r\n", 81 | "\r\n", 82 | "\r\n", 83 | "\r\n", 84 | "STRUCTURE:\r\n", 85 | " \r\n", 86 | " source: MID \r\n", 87 | " # MID/POSCAR MID:get structure from MP database, POSCAR: structure from a file\r\n", 88 | " \r\n", 89 | " mat_name: NEW_MAT \r\n", 90 | " # unique identifier in the database when source=POSCAR\r\n", 91 | " \r\n", 92 | " material_id: mp-661 \r\n", 93 | " # material_id of the input structure in MP database\r\n", 94 | " \r\n", 95 | " \r\n", 96 | " \r\n", 97 | "WFLOW_DESIGN:\r\n", 98 | " \r\n", 99 | " skip_emc: false \r\n", 100 | " # set true to skip effective mass calculation \r\n", 101 | " \r\n", 102 | " skip_wannier: false \r\n", 103 | " # set true to skip wannier bandstructure interpolation\r\n", 104 | " \r\n", 105 | " skip_conv: false \r\n", 106 | " # set true to skip convergence test\r\n", 107 | " \r\n", 108 | " skip_gw: false \r\n", 109 | " # set true to skip GW calculation\r\n", 110 | " \r\n", 111 | " scgw: true \r\n", 112 | " # set true to perform self-consistent GW instead of G0W0\r\n", 113 | " \r\n", 114 | " skip_bse: false \r\n", 115 | " # set true to skip BSE calculation\r\n" 116 | ] 117 | } 118 | ], 119 | "source": [ 120 | "#Now let's check the content of the 'input.yaml' file.\n", 121 | "!cat 'input.yaml'" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 3, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "name": "stderr", 131 | "output_type": "stream", 132 | "text": [ 133 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/pymatgen/ext/matproj.py:182: UserWarning: You are using the legacy MPRester. This version of the MPRester will no longer be updated. To access the latest data with the new MPRester, obtain a new API key from https://materialsproject.org/api and consult the docs at https://docs.materialsproject.org/ for more information.\n", 134 | " warnings.warn(\n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "\"\"\"\n", 140 | " 'read_input' function reads input parameters from input.yaml file.\n", 141 | " \n", 142 | " Returns:\n", 143 | " \n", 144 | " structure: pymatgen structure object for the input structure\n", 145 | " input_dict: a dictionary of all the input paramters\n", 146 | " \n", 147 | "\"\"\"\n", 148 | "\n", 149 | "structure, input_dict = read_input()\n", 150 | "#To obtain one go to https://materialsproject.org/api" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 4, 156 | "metadata": { 157 | "scrolled": false 158 | }, 159 | "outputs": [ 160 | { 161 | "name": "stdout", 162 | "output_type": "stream", 163 | "text": [ 164 | "-------------------------------------------\n", 165 | "material: mp-661\n", 166 | "Information for efficient parallelization\n", 167 | "You have 8 occupied bands\n", 168 | "You have 76 kpoints\n", 169 | "You have [[12, 12, 7]] k-grid\n", 170 | "Will perform convergence test for: NBANDS\n", 171 | "Values that will be used for convergence test: 65 91 117 143 169 \n", 172 | "KPAR= 8\n", 173 | "reciprocal_density= 200\n", 174 | "BSE calculation will include bands in the energy window (eV)= 3.0\n", 175 | "-------------------------------------------\n" 176 | ] 177 | }, 178 | { 179 | "name": "stderr", 180 | "output_type": "stream", 181 | "text": [ 182 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/pymatgen/io/vasp/sets.py:419: BadInputSetWarning: Overriding the POTCAR functional is generally not recommended as it significantly affect the results of calculations and compatibility with other calculations done with the same input set. Note that some POTCAR symbols specified in the configuration file may not be available in the selected functional.\n", 183 | " warnings.warn(\n", 184 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/pymatgen/io/vasp/inputs.py:1822: UnknownPotcarWarning: POTCAR with symbol Al_GW has metadata that does not match any VASP POTCAR known to pymatgen. The data in this POTCAR is known to match the following functionals: ['PBE_54', 'PBE_52', 'unvie_PBE_52']\n", 185 | " warnings.warn(\n", 186 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/pymatgen/io/vasp/inputs.py:1822: UnknownPotcarWarning: POTCAR with symbol N_GW has metadata that does not match any VASP POTCAR known to pymatgen. The data in this POTCAR is known to match the following functionals: ['PBE_54', 'PBE_52', 'unvie_PBE_52']\n", 187 | " warnings.warn(\n" 188 | ] 189 | } 190 | ], 191 | "source": [ 192 | "\"\"\"\n", 193 | " 'create_wfs' function creates the GW-BSE workflow based on input specification.\n", 194 | " \n", 195 | " Args:\n", 196 | " \n", 197 | " structure: pymatgen structure object for the input structure\n", 198 | " input_dict: a dictionary of all the input paramters\n", 199 | " \n", 200 | " Returns:\n", 201 | " \n", 202 | " wf_gwbse: GW-BSE workflow as a Fireworks workflow object.\n", 203 | " \n", 204 | "\"\"\"\n", 205 | "\n", 206 | "wf_gwbse=create_wfs(structure, input_dict)" 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "metadata": {}, 212 | "source": [ 213 | "The error message \"Overriding the POTCAR functional is generally not ...\" is due to changing default POTCAR symbols to GW POTCAR files. One can choose other POTCARs by modifying inputset.yaml file. " 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 5, 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [ 222 | "#Load the Fireworks Launchpad \n", 223 | "lpad = LaunchPad.auto_load() " 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": 6, 229 | "metadata": {}, 230 | "outputs": [ 231 | { 232 | "name": "stdout", 233 | "output_type": "stream", 234 | "text": [ 235 | "2022-10-04 11:55:19,394 INFO Added a workflow. id_map: {-7: 1, -6: 2, -5: 3, -4: 4, -3: 5, -2: 6, -1: 7}\n" 236 | ] 237 | }, 238 | { 239 | "data": { 240 | "text/plain": [ 241 | "{-7: 1, -6: 2, -5: 3, -4: 4, -3: 5, -2: 6, -1: 7}" 242 | ] 243 | }, 244 | "execution_count": 6, 245 | "metadata": {}, 246 | "output_type": "execute_result" 247 | } 248 | ], 249 | "source": [ 250 | "#Add the workflow you just created\n", 251 | "lpad.add_wf(wf_gwbse)" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": 7, 257 | "metadata": { 258 | "scrolled": false 259 | }, 260 | "outputs": [ 261 | { 262 | "name": "stdout", 263 | "output_type": "stream", 264 | "text": [ 265 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/atomate/vasp/drones.py:46: FutureWarning: which is deprecated; use which in shutil instead.\n", 266 | "shutil.which has been available since Python 3.3. This will be removed in v2023.\n", 267 | " BADER_EXE_EXISTS = which(\"bader\") or which(\"bader.exe\")\n", 268 | "/home/tatha/anaconda3/envs/pygwbse/lib/python3.9/site-packages/pymatgen/io/vasp/sets.py:419: BadInputSetWarning: Overriding the POTCAR functional is generally not recommended as it significantly affect the results of calculations and compatibility with other calculations done with the same input set. Note that some POTCAR symbols specified in the configuration file may not be available in the selected functional.\n", 269 | " warnings.warn(\n", 270 | "[\n", 271 | " {\n", 272 | " \"fw_id\": 1,\n", 273 | " \"created_on\": \"2022-10-04T18:55:18.450316\",\n", 274 | " \"updated_on\": \"2022-10-04T18:55:18.450319\",\n", 275 | " \"state\": \"PAUSED\",\n", 276 | " \"name\": \"mp-661-BSE\"\n", 277 | " },\n", 278 | " {\n", 279 | " \"fw_id\": 2,\n", 280 | " \"created_on\": \"2022-10-04T18:55:18.450282\",\n", 281 | " \"updated_on\": \"2022-10-04T18:55:18.450283\",\n", 282 | " \"name\": \"mp-661-WANNIER\",\n", 283 | " \"state\": \"WAITING\"\n", 284 | " },\n", 285 | " {\n", 286 | " \"fw_id\": 3,\n", 287 | " \"created_on\": \"2022-10-04T18:55:18.450243\",\n", 288 | " \"updated_on\": \"2022-10-04T18:55:18.450248\",\n", 289 | " \"name\": \"mp-661-GW\",\n", 290 | " \"state\": \"WAITING\"\n", 291 | " },\n", 292 | " {\n", 293 | " \"fw_id\": 4,\n", 294 | " \"created_on\": \"2022-10-04T18:55:18.450060\",\n", 295 | " \"updated_on\": \"2022-10-04T18:55:18.450062\",\n", 296 | " \"name\": \"mp-661-CONV\",\n", 297 | " \"state\": \"WAITING\"\n", 298 | " },\n", 299 | " {\n", 300 | " \"fw_id\": 5,\n", 301 | " \"created_on\": \"2022-10-04T18:55:18.436622\",\n", 302 | " \"updated_on\": \"2022-10-04T18:55:18.436623\",\n", 303 | " \"name\": \"mp-661-WANNIER_CHECK\",\n", 304 | " \"state\": \"WAITING\"\n", 305 | " },\n", 306 | " {\n", 307 | " \"fw_id\": 6,\n", 308 | " \"created_on\": \"2022-10-04T18:55:18.435151\",\n", 309 | " \"updated_on\": \"2022-10-04T18:55:18.435152\",\n", 310 | " \"name\": \"mp-661-EMC\",\n", 311 | " \"state\": \"WAITING\"\n", 312 | " },\n", 313 | " {\n", 314 | " \"fw_id\": 7,\n", 315 | " \"created_on\": \"2022-10-04T18:55:18.433728\",\n", 316 | " \"updated_on\": \"2022-10-04T18:55:18.501427\",\n", 317 | " \"state\": \"READY\",\n", 318 | " \"name\": \"mp-661-SCF\"\n", 319 | " }\n", 320 | "]\n" 321 | ] 322 | } 323 | ], 324 | "source": [ 325 | "#Check the Fireworks loaded to the Launchpad\n", 326 | "lp='lpad get_fws'\n", 327 | "!{lp}" 328 | ] 329 | }, 330 | { 331 | "cell_type": "markdown", 332 | "metadata": {}, 333 | "source": [ 334 | "As you can see there are 7 fireworks with prefix `mp-661` were loaded to the Launchpad. \n", 335 | "Also one should note that the BSE Firework is in a `PAUSED` state by default. This is \n", 336 | "because, the k-point parallelization is not implemented for BSE calculation in VASP. \n", 337 | "Therefore, to make the number of bands in the WAVEDER file a multiple of number of \n", 338 | "processor used (requirement for VASP, otherwise it will change the NBANDS value) we \n", 339 | "need to run the BSE workflow on NPROCS=NPROCS$'$/KPAR, where NPROCS$'$ is the number \n", 340 | "of processors used for the `fw_id: 2-7`. Now that we have all the Fireworks in the \n", 341 | "Launchpad we can run them and use the postprocessing scripts to analyze the results once \n", 342 | "they are `COMPLETED`." 343 | ] 344 | } 345 | ], 346 | "metadata": { 347 | "kernelspec": { 348 | "display_name": "pygwbse", 349 | "language": "python", 350 | "name": "pygwbse" 351 | }, 352 | "language_info": { 353 | "codemirror_mode": { 354 | "name": "ipython", 355 | "version": 3 356 | }, 357 | "file_extension": ".py", 358 | "mimetype": "text/x-python", 359 | "name": "python", 360 | "nbconvert_exporter": "python", 361 | "pygments_lexer": "ipython3", 362 | "version": "3.9.13" 363 | } 364 | }, 365 | "nbformat": 4, 366 | "nbformat_minor": 4 367 | } 368 | -------------------------------------------------------------------------------- /example/input.yaml: -------------------------------------------------------------------------------- 1 | PARAMS: 2 | kpar: 4 3 | # 'KPAR' tag to be used in VASP simulations 4 | 5 | ppn: 13 6 | # NPROCS/KPAR ; NPROCS: number of total processors to be used in VASP simulations 7 | 8 | reciprocal_density: 50 9 | # reciprocal density that determines the k-grid using 'automatic_density_by_vol' method of pymatgen 10 | 11 | encutgw: 100 12 | # ENCUTGW to be used in VASP simulations 13 | 14 | nbgwfactor: 2 15 | # NBANDS=nbgwfactor x nocc'; nocc' is the smallest multiple of ppn which is larger than number of occupied bands 16 | 17 | nomegagw: 50 18 | # NOMEGAGW to be used in VASP simulations 19 | 20 | convsteps: [50, 0, 0] 21 | # percentage increments to be used for convergence tests of NBANDS, ENCUTGW, NOMEGA 22 | 23 | conviter: 5 24 | # maximum number of iteration in convergence test 25 | 26 | enwinbse: 3.0 27 | # energy window in BSE calculations 28 | 29 | 30 | 31 | STRUCTURE: 32 | 33 | source: MID 34 | # MID/POSCAR MID:get structure from MP database, POSCAR: structure from a file 35 | 36 | mat_name: NEW_MAT 37 | # unique identifier in the database when source=POSCAR 38 | 39 | material_id: mp-149 40 | # material_id of the input structure in MP database 41 | 42 | 43 | 44 | WFLOW_DESIGN: 45 | 46 | skip_emc: true 47 | # set true to skip effective mass calculation 48 | 49 | skip_wannier: true 50 | # set true to skip wannier bandstructure interpolation 51 | 52 | skip_conv: false 53 | # set true to skip convergence test 54 | 55 | skip_gw: true 56 | # set true to skip GW calculation 57 | 58 | scgw: true 59 | # set true to perform self-consistent GW instead of G0W0 60 | 61 | skip_bse: true 62 | # set true to skip BSE calculation 63 | -------------------------------------------------------------------------------- /pyGWBSE/config.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Tathagata Biswas ' 2 | 3 | # TODO: @computron should be able to load from YAML -computron 4 | 5 | VASP_CMD = ">>vasp_cmd<<" 6 | SUMO_CMD = ">>sumo_cmd<<" 7 | WANNIER_CMD = ">>wannier_cmd<<" 8 | DB_FILE = ">>db_file<<" 9 | 10 | -------------------------------------------------------------------------------- /pyGWBSE/inputset.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # Copyright (c) Pymatgen Development Team. 3 | # Distributed under the terms of the MIT License. 4 | 5 | import os 6 | 7 | from monty.serialization import loadfn 8 | from pymatgen.io.vasp.inputs import Incar, Kpoints 9 | from pymatgen.io.vasp.sets import DictSet 10 | from pymatgen.symmetry.bandstructure import HighSymmKpath 11 | 12 | MODULE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | 14 | class CreateInputs(DictSet): 15 | """ 16 | Your Comments Here 17 | """ 18 | CONFIG = loadfn(os.path.join(MODULE_DIR, "inputset.yaml")) 19 | 20 | SUPPORTED_MODES = ("DIAG", "GW", "STATIC", "BSE", "CONV", "EMC") 21 | 22 | def __init__(self, structure, prev_incar=None, nbands=None, nomegagw=None, encutgw=None, 23 | potcar_functional="PBE_54", reciprocal_density=100, kpoints_line_density = 100, kpar=None, nbandsgw=None, 24 | mode="STATIC", copy_wavecar=True, nbands_factor=5, ncores=16,nbandso=None, nbandsv=None, wannier_fw=None, 25 | **kwargs): 26 | super().__init__(structure, CreateInputs.CONFIG, **kwargs) 27 | self.prev_incar = prev_incar 28 | self.nbands = nbands 29 | self.encutgw = encutgw 30 | self.nomegagw = nomegagw 31 | self.potcar_functional = potcar_functional 32 | self.reciprocal_density = reciprocal_density 33 | self.kpoints_line_density = kpoints_line_density 34 | self.mode = mode.upper() 35 | if self.mode not in CreateInputs.SUPPORTED_MODES: 36 | raise ValueError("%s not one of the support modes : %s" % 37 | (self.mode, CreateInputs.SUPPORTED_MODES)) 38 | self.kwargs = kwargs 39 | self.copy_wavecar = copy_wavecar 40 | self.nbands_factor = nbands_factor 41 | self.ncores = ncores 42 | self.kpar = kpar 43 | self.nbandsgw = nbandsgw 44 | self.nbandso = nbandso 45 | self.nbandsv = nbandsv 46 | self.wannier_fw = wannier_fw 47 | 48 | @property 49 | def kpoints(self): 50 | """ 51 | Generate gamma center k-points mesh grid for GW calc, 52 | which is requested by GW calculation. 53 | """ 54 | if self.mode == "EMC": 55 | kpath = HighSymmKpath(self.structure) 56 | frac_k_points, k_points_labels = kpath.get_kpoints( 57 | line_density=self.kpoints_line_density, 58 | coords_are_cartesian=False) 59 | kpoints = Kpoints( 60 | comment="Non SCF run along symmetry lines", 61 | style=Kpoints.supported_modes.Reciprocal, 62 | num_kpts=len(frac_k_points), 63 | kpts=frac_k_points, labels=k_points_labels, 64 | kpts_weights=[1] * len(frac_k_points)) 65 | 66 | return kpoints 67 | 68 | else: 69 | 70 | kpoints=Kpoints.automatic_density_by_vol(self.structure, 71 | self.reciprocal_density, force_gamma=True) 72 | 73 | return kpoints 74 | 75 | @property 76 | def incar(self): 77 | """ 78 | Your Comments Here 79 | """ 80 | parent_incar = super().incar 81 | incar = Incar(self.prev_incar) if self.prev_incar is not None else \ 82 | Incar(parent_incar) 83 | if self.wannier_fw == True: 84 | incar.update({ 85 | "LWANNIER90": True 86 | }) 87 | if self.mode == "EMC": 88 | incar.update({ 89 | "IBRION": -1, 90 | "ISMEAR": 0, 91 | "SIGMA": 0.001, 92 | "LCHARG": False, 93 | "LORBIT": 11, 94 | "LWAVE": False, 95 | "NSW": 0, 96 | "ISYM": 0, 97 | "ICHARG": 11 98 | }) 99 | incar.pop("LWANNIER90", None) 100 | incar.pop("LEPSILON", None) 101 | if self.mode == "DIAG": 102 | # Default parameters for diagonalization calculation. 103 | incar.update({ 104 | "ALGO": "Exact", 105 | "NELM": 1, 106 | "LOPTICS": True, 107 | "LPEAD": True 108 | }) 109 | incar.pop("LEPSILON", None) 110 | incar.pop("LWANNIER90", None) 111 | elif self.mode == "GW": 112 | # Default parameters for GW calculation. 113 | incar.update({ 114 | "ALGO": "GW", 115 | "NELM": 1, 116 | "NOMEGA": self.nomegagw, 117 | "ENCUTGW": self.encutgw, 118 | "NBANDSGW": self.nbandsgw, 119 | "LWAVE": True 120 | }) 121 | if self.wannier_fw == True: 122 | incar.update({ 123 | "LWANNIER90": True 124 | }) 125 | incar.pop("EDIFF", None) 126 | incar.pop("LOPTICS", None) 127 | incar.pop("LPEAD", None) 128 | incar.pop("LEPSILON", None) 129 | elif self.mode == "CONV": 130 | # Default parameters for GW calculation. 131 | incar.update({ 132 | "ALGO": "GW0", 133 | "NELM": 1, 134 | "NOMEGA": self.nomegagw, 135 | "ENCUTGW": self.encutgw, 136 | "NBANDSGW": self.nbandsgw, 137 | "LWAVE": False 138 | }) 139 | incar.pop("EDIFF", None) 140 | incar.pop("LOPTICS", None) 141 | incar.pop("LEPSILON", None) 142 | incar.pop("LPEAD", None) 143 | incar.pop("LWANNIER90", None) 144 | elif self.mode == "BSE": 145 | # Default parameters for BSE calculation. 146 | incar.update({ 147 | "ALGO": "BSE", 148 | "ANTIRES": 0, 149 | "NBANDSO": self.nbandso, 150 | "NBANDSV": self.nbandsv, 151 | "KPAR": 1, 152 | "CSHIFT": 0.2 153 | }) 154 | incar.pop("LEPSILON", None) 155 | incar.pop("LWANNIER90", None) 156 | if self.nbands: 157 | incar["NBANDS"] = self.nbands 158 | 159 | if self.kpar: 160 | incar["KPAR"] = self.kpar 161 | 162 | rd=self.reciprocal_density 163 | 164 | incar["SYSTEM"] = 'reciprocal density: '+str(rd) 165 | 166 | # Respect user set INCAR. 167 | incar.update(self.kwargs.get("user_incar_settings", {})) 168 | 169 | return incar 170 | 171 | -------------------------------------------------------------------------------- /pyGWBSE/inputset.yaml: -------------------------------------------------------------------------------- 1 | # Default VASP settings for GW calculations used by the Materials Virtual Lab. 2 | INCAR: 3 | ALGO: Normal 4 | ENCUT: 500 5 | EDIFF: 1.0e-8 6 | ISMEAR: 0 7 | LREAL: AUTO 8 | ISPIN: 1 9 | LWAVE: true 10 | NELM: 100 11 | PREC: Accurate 12 | SIGMA: 0.01 13 | LEPSILON: true 14 | LVHAR: false 15 | LOPTICS: true 16 | LPEAD: false 17 | LORBIT: 11 18 | KPOINTS: 19 | reciprocal_density: 100 20 | POTCAR: 21 | Ac: Ac 22 | Ag: Ag_sv_GW 23 | Al: Al_GW 24 | Ar: Ar_GW 25 | As: As_GW 26 | At: At_d_GW 27 | Au: Au_sv_GW 28 | B: B_GW 29 | Ba: Ba_sv_GW 30 | Be: Be_sv_GW 31 | Bi: Bi_d_GW 32 | Br: Br_GW 33 | C: C_GW 34 | Ca: Ca_sv_GW 35 | Cd: Cd_sv_GW 36 | Ce: Ce_GW 37 | Cl: Cl_GW 38 | Co: Co_sv_GW 39 | Cr: Cr_sv_GW 40 | Cs: Cs_sv_GW 41 | Cu: Cu_sv_GW 42 | Dy: Dy_3 43 | Er: Er_3 44 | Eu: Eu 45 | F: F_GW 46 | Fe: Fe_sv_GW 47 | Ga: Ga_d_GW 48 | Gd: Gd 49 | Ge: Ge_d_GW 50 | H: H_GW 51 | He: He_GW 52 | Hf: Hf_sv_GW 53 | Hg: Hg_sv_GW 54 | Ho: Ho_3 55 | I: I_GW 56 | In: In_d_GW 57 | Ir: Ir_sv_GW 58 | K: K_sv_GW 59 | Kr: Kr_GW 60 | La: La_GW 61 | Li: Li_sv_GW 62 | Lu: Lu_3 63 | Mg: Mg_sv_GW 64 | Mn: Mn_sv_GW 65 | Mo: Mo_sv_GW 66 | N: N_GW 67 | Na: Na_sv_GW 68 | Nb: Nb_sv_GW 69 | Nd: Nd_3 70 | Ne: Ne_GW 71 | Ni: Ni_sv_GW 72 | Np: Np 73 | O: O_GW 74 | Os: Os_sv_GW 75 | P: P_GW 76 | Pa: Pa 77 | Pb: Pb_d_GW 78 | Pd: Pd_sv_GW 79 | Pm: Pm_3 80 | Po: Po_d_GW 81 | Pr: Pr_3 82 | Pt: Pt_sv_GW 83 | Pu: Pu 84 | Rb: Rb_sv_GW 85 | Re: Re_sv_GW 86 | Rh: Rh_sv_GW 87 | Rn: Rn_d_GW 88 | Ru: Ru_sv_GW 89 | S: S_GW 90 | Sb: Sb_d_GW 91 | Sc: Sc_sv_GW 92 | Se: Se_GW 93 | Si: Si_GW 94 | Sm: Sm_3 95 | Sn: Sn_d_GW 96 | Sr: Sr_sv_GW 97 | Ta: Ta_sv_GW 98 | Tb: Tb_3 99 | Tc: Tc_sv_GW 100 | Te: Te_GW 101 | Th: Th 102 | Ti: Ti_sv_GW 103 | Tl: Tl_d_GW 104 | Tm: Tm_3 105 | U: U 106 | V: V_sv_GW 107 | W: W_sv_GW 108 | Xe: Xe_GW 109 | Y: Y_sv_GW 110 | Yb: Yb_2 111 | Zn: Zn_sv_GW 112 | Zr: Zr_sv_GW 113 | -------------------------------------------------------------------------------- /pyGWBSE/make_wflow.py: -------------------------------------------------------------------------------- 1 | #This code is to create the workflow based on inputs from input.yaml file 2 | 3 | from fireworks import Firework, Workflow 4 | from pyGWBSE.wflows import ScfFW, convFW, BseFW, GwFW, EmcFW, WannierCheckFW, WannierFW 5 | from pyGWBSE.inputset import CreateInputs 6 | from pymatgen.core import Structure 7 | from fireworks import LaunchPad 8 | from pyGWBSE.config import VASP_CMD, DB_FILE, SUMO_CMD, WANNIER_CMD 9 | from pymatgen.symmetry.analyzer import SpacegroupAnalyzer 10 | from pymatgen.io.vasp.inputs import Kpoints 11 | from pymatgen.ext.matproj import MPRester 12 | import numpy as np 13 | from pymongo import MongoClient 14 | import yaml 15 | import sys 16 | 17 | 18 | #Function to find the kgrid and number of symmtery reduced kpoints based on symmetry of the structure and the reciprocal density 19 | def num_ir_kpts(struct,reciprocal_density): 20 | spg=SpacegroupAnalyzer(struct, symprec=0.01, angle_tolerance=5) 21 | Kpts=Kpoints.automatic_density_by_vol(struct,reciprocal_density,force_gamma=True) 22 | kpts=spg.get_ir_reciprocal_mesh(mesh=Kpts.kpts, is_shift=(0, 0, 0)) 23 | return Kpts.kpts,len(kpts) 24 | 25 | 26 | #Function to find the number of occupied bands from the input structure 27 | def num_occ_bands(struct): 28 | vasp_input_set = CreateInputs(struct) 29 | nel=vasp_input_set.nelect 30 | nocc=int(nel/2) 31 | return nocc 32 | 33 | 34 | #Function to read the input.yaml file 35 | def read_input(mp_key): 36 | 37 | yaml_file = open("input.yaml") 38 | input_dict = yaml.load(yaml_file, Loader=yaml.FullLoader) 39 | struc_src=input_dict["STRUCTURE"]["source"] 40 | 41 | if struc_src=='POSCAR': 42 | struct=Structure.from_file('POSCAR') 43 | mat_name=input_dict["STRUCTURE"]["mat_name"] 44 | elif struc_src=='MID': 45 | material_id=input_dict["STRUCTURE"]["material_id"] 46 | mat_name=material_id 47 | with MPRester(mp_key) as m: 48 | struct = m.get_structure_by_material_id(material_id,conventional_unit_cell=False) 49 | else: 50 | sys.exit('Error: use MID/POSCAR as structure source .... Exiting NOW') 51 | input_dict["PARAMS"]["mat_name"]=mat_name 52 | return struct, input_dict 53 | 54 | #Function to create the workflow 55 | def create_wfs(struct, params_dict, vasp_cmd=None, sumo_cmd=None, wannier_cmd=None, db_file=None, c=None): 56 | 57 | c = c or {} 58 | vasp_cmd = c.get("VASP_CMD", VASP_CMD) 59 | sumo_cmd = c.get("SUMO_CMD", SUMO_CMD) 60 | wannier_cmd = c.get("WANNIER_CMD", WANNIER_CMD) 61 | db_file = c.get("DB_FILE", DB_FILE) 62 | 63 | params=params_dict["PARAMS"] 64 | mat_name=params["mat_name"] 65 | nocc=num_occ_bands(struct) 66 | kpar=params["kpar"] 67 | ppn=params["ppn"] 68 | rd=params["reciprocal_density"] 69 | nbgwfactor=params["nbgwfactor"] 70 | encutgw=params["encutgw"] 71 | nomegagw=params["nomegagw"] 72 | convsteps=params["convsteps"] 73 | conviter=params["conviter"] 74 | enwinbse=params["enwinbse"] 75 | skip_emc=params_dict["WFLOW_DESIGN"]["skip_emc"] 76 | skip_wannier=params_dict["WFLOW_DESIGN"]["skip_wannier"] 77 | skip_conv=params_dict["WFLOW_DESIGN"]["skip_conv"] 78 | skip_gw=params_dict["WFLOW_DESIGN"]["skip_gw"] 79 | scgw=params_dict["WFLOW_DESIGN"]["scgw"] 80 | skip_bse=params_dict["WFLOW_DESIGN"]["skip_bse"] 81 | 82 | mesh,nkpt=num_ir_kpts(struct,rd) 83 | nbands=(int(nocc/ppn)+1)*ppn 84 | nbandsgw=nocc+10 85 | 86 | print("-------------------------------------------") 87 | print("material: ",mat_name) 88 | print("Information for efficient parallelization") 89 | print("You have ",nocc,"occupied bands") 90 | print("You have ",nkpt,"kpoints") 91 | print("You have ",mesh,"k-grid") 92 | print("KPAR=",kpar) 93 | print("reciprocal_density=",rd) 94 | if not(skip_bse): 95 | print("BSE calculation will include bands in the energy window (eV)=", enwinbse) 96 | print("-------------------------------------------") 97 | 98 | if scgw==True: 99 | gw_tag='GW0' 100 | else: 101 | gw_tag='G0W0' 102 | 103 | ifw=0 104 | 105 | fws = [ScfFW(structure=struct, mat_name=mat_name, nbands=nbands, vasp_cmd=vasp_cmd,db_file=db_file,kpar=kpar,reciprocal_density=rd,wannier_fw=not(skip_wannier))] 106 | 107 | if skip_emc==False: 108 | ifw=ifw+1 109 | parents = fws[0] 110 | fw = EmcFW(structure=struct, mat_name=mat_name, vasp_cmd=vasp_cmd, sumo_cmd=sumo_cmd, db_file=db_file,kpar=kpar,reciprocal_density=rd, steps=0.001,parents=parents) 111 | fws.append(fw) 112 | 113 | if skip_wannier==False: 114 | ifw=ifw+1 115 | parents = fws[0] 116 | fw = WannierCheckFW(structure=struct, mat_name=mat_name, kpar=kpar, ppn=ppn,vasp_cmd=vasp_cmd,wannier_cmd=wannier_cmd,db_file=db_file,parents=parents,reciprocal_density=rd) 117 | fws.append(fw) 118 | 119 | ifw=ifw+1 120 | parents = fws[0] 121 | fw = convFW(structure=struct, mat_name=mat_name, nbands=nbands, nbgwfactor=nbgwfactor, encutgw=encutgw, nomegagw=nomegagw, convsteps=convsteps, conviter=conviter, 122 | tolerence=0.1, no_conv=skip_conv, vasp_cmd=vasp_cmd,db_file=db_file,parents=parents,kpar=kpar,nbandsgw=nbandsgw,reciprocal_density=rd) 123 | fws.append(fw) 124 | 125 | if skip_gw==False: 126 | ifw=ifw+1 127 | parents = fws[ifw-1] 128 | fw = GwFW(structure=struct, mat_name=mat_name, tolerence=0.1, no_conv=not(scgw), 129 | vasp_cmd=vasp_cmd,db_file=db_file,parents=parents,reciprocal_density=rd, nbandsgw=nbandsgw, wannier_fw=not(skip_wannier), job_tag=gw_tag) 130 | fws.append(fw) 131 | 132 | if skip_wannier==False and skip_gw==False: 133 | ifw=ifw+1 134 | parents = fws[ifw-1] 135 | fw = WannierFW(structure=struct,mat_name=mat_name, wannier_cmd=wannier_cmd,db_file=db_file,parents=parents) 136 | fws.append(fw) 137 | 138 | if skip_bse==False and skip_gw==True: 139 | sys.exit('Error: Need QP energies from GW calculation to perform BSE .... Exiting NOW') 140 | 141 | if skip_bse==False and skip_gw==False: 142 | ifw=ifw+1 143 | if skip_wannier==False: 144 | parents = fws[ifw-2] 145 | else: 146 | parents = fws[ifw-1] 147 | fw = BseFW(structure=struct, mat_name=mat_name, 148 | vasp_cmd=vasp_cmd,db_file=db_file,parents=parents,reciprocal_density=rd,enwinbse=enwinbse, job_tag=gw_tag+'-BSE') 149 | fws.append(fw) 150 | 151 | 152 | wf_gwbse = Workflow(fws) 153 | 154 | return wf_gwbse 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /pyGWBSE/out2db.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import glob 4 | import os 5 | 6 | from atomate.utils.utils import env_chk 7 | from atomate.vasp.database import VaspCalcDb 8 | from fireworks import explicit_serialize, FiretaskBase, FWAction 9 | from monty.json import jsanitize 10 | from pymatgen.io.vasp.outputs import Vasprun, Outcar 11 | 12 | from pyGWBSE.tasks import read_emcpyout, read_epsilon, get_gap_from_dict, read_vac_level 13 | from pyGWBSE.wannier_tasks import read_vbm, read_wannier, read_vasp, read_special_kpts 14 | 15 | 16 | @explicit_serialize 17 | class gw2db(FiretaskBase): 18 | """ 19 | Insert quasi-particle energies into the database for a GW calculation. 20 | """ 21 | required_params = ["structure", "task_label", "db_file", "mat_name"] 22 | optional_params = ["job_tag", "defuse_unsuccessful"] 23 | 24 | def run_task(self, fw_spec): 25 | """ 26 | Your Comments Here 27 | """ 28 | # get adddtional tags to parse the directory for 29 | db_file = env_chk(self.get('db_file'), fw_spec) 30 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 31 | ifconv = fw_spec["ifconv"] 32 | structure = self["structure"] 33 | task_label = self["task_label"] 34 | if "job_tag" in self: 35 | job_tag = self["job_tag"] 36 | else: 37 | job_tag = None 38 | mat_name = self["mat_name"] 39 | task_collection = 'QP_Results' 40 | dir_name = os.getcwd() 41 | file = glob.glob('vasprun.xml*')[-1] 42 | vasprun = Vasprun(file) 43 | file = glob.glob('OUTCAR*')[-1] 44 | outcar = Outcar(file) 45 | run_stats=outcar.run_stats 46 | qp_energies = vasprun.eigenvalues 47 | en, eps1, eps2 = vasprun.dielectric 48 | igap, dgap = get_gap_from_dict(qp_energies) 49 | incar = vasprun.incar 50 | parameters = vasprun.parameters 51 | bgap, cbm, vbm, is_band_gap_direct = vasprun.eigenvalue_band_properties 52 | kpts_dict = vasprun.kpoints.as_dict() 53 | # dictionary to update the database with 54 | d = {"structure": structure.as_dict(), 55 | "formula_pretty": structure.composition.reduced_formula, 56 | "material_id": mat_name, "run_stats": run_stats, 57 | "run_directory": dir_name, 'direct_gap': dgap, 'indirect_gap': igap, 58 | "qp_energies": qp_energies, "task_label": task_label, 59 | "frequency": en, "epsilon_1": eps1, "epsilon_2": eps2, 60 | "job_tag": job_tag, "ifconv": ifconv, "vbm": vbm, "cbm": cbm, 61 | "incar": incar, "parameters": parameters, "kpoints": kpts_dict} 62 | d = jsanitize(d) 63 | coll = mmdb.db[task_collection] 64 | coll.insert_one(d) 65 | 66 | return FWAction(update_spec={"gw_gaps": [igap, dgap]}) 67 | 68 | 69 | @explicit_serialize 70 | class bse2db(FiretaskBase): 71 | """ 72 | Insert exciton energies, oscillator strength and dielectric function into the database for a BSE calculation. 73 | """ 74 | required_params = ["structure", "task_label", "db_file", "mat_name"] 75 | optional_params = ["job_tag", "defuse_unsuccessful"] 76 | 77 | def run_task(self, fw_spec): 78 | """ 79 | Your Comments Here 80 | """ 81 | # get adddtional tags to parse the directory for 82 | db_file = env_chk(self.get('db_file'), fw_spec) 83 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 84 | structure = self["structure"] 85 | task_label = self["task_label"] 86 | job_tag = self["job_tag"] 87 | mat_name = self["mat_name"] 88 | igap = fw_spec["gw_gaps"][0] 89 | dgap = fw_spec["gw_gaps"][1] 90 | task_collection = 'BSE_Results' 91 | dir_name = os.getcwd() 92 | filename = glob.glob('vasprun.xml*')[-1] 93 | if "job_tag" in self: 94 | job_tag = self["job_tag"] 95 | else: 96 | job_tag = None 97 | with open(filename, "a") as file: 98 | file.write("") 99 | vasprun = Vasprun(filename) 100 | incar = vasprun.incar 101 | parameters = vasprun.parameters 102 | optical_transition = vasprun.optical_transition 103 | en, eps1, eps2 = vasprun.dielectric 104 | kpts_dict = vasprun.kpoints.as_dict() 105 | file = glob.glob('OUTCAR*')[-1] 106 | outcar = Outcar(file) 107 | run_stats=outcar.run_stats 108 | d = {"structure": structure.as_dict(), 109 | "formula_pretty": structure.composition.reduced_formula, 110 | "material_id": mat_name, "run_directory": dir_name, 111 | "frequency": en, "epsilon_1": eps1, "epsilon_2": eps2, 112 | 'direct_gap': dgap, 'indirect_gap': igap, "run_stats": run_stats, 113 | "optical_transition": optical_transition, "task_label": task_label, "job_tag": job_tag, 114 | "incar": incar, "parameters": parameters, "kpoints": kpts_dict} 115 | d = jsanitize(d) 116 | coll = mmdb.db[task_collection] 117 | coll.insert_one(d) 118 | 119 | @explicit_serialize 120 | class rpa2db(FiretaskBase): 121 | """ 122 | Insert exciton energies, oscillator strength and dielectric function into the database for a BSE calculation. 123 | """ 124 | required_params = ["structure", "task_label", "db_file", "mat_name"] 125 | optional_params = ["defuse_unsuccessful"] 126 | 127 | def run_task(self, fw_spec): 128 | """ 129 | Your Comments Here 130 | """ 131 | # get adddtional tags to parse the directory for 132 | db_file = env_chk(self.get('db_file'), fw_spec) 133 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 134 | structure = self["structure"] 135 | task_label = self["task_label"] 136 | mat_name = self["mat_name"] 137 | task_collection = 'RPA_Results' 138 | dir_name = os.getcwd() 139 | filename = glob.glob('vasprun.xml*')[-1] 140 | vasprun = Vasprun(filename) 141 | incar = vasprun.incar 142 | parameters = vasprun.parameters 143 | dft_energies = vasprun.eigenvalues 144 | en, eps1, eps2 = vasprun.dielectric 145 | kpts_dict = vasprun.kpoints.as_dict() 146 | file = glob.glob('OUTCAR*')[-1] 147 | outcar = Outcar(file) 148 | run_stats=outcar.run_stats 149 | d = {"structure": structure.as_dict(), 150 | "formula_pretty": structure.composition.reduced_formula, 151 | "material_id": mat_name, "run_directory": dir_name, 152 | "dft_energies": dft_energies, "run_stats": run_stats, 153 | "frequency": en, "epsilon_1": eps1, "epsilon_2": eps2, "task_label": task_label, 154 | "incar": incar, "parameters": parameters, "kpoints": kpts_dict} 155 | d = jsanitize(d) 156 | coll = mmdb.db[task_collection] 157 | coll.insert_one(d) 158 | 159 | @explicit_serialize 160 | class emc2db(FiretaskBase): 161 | """ 162 | Insert effective masses for a SUMO-BANDSTATS calculation. 163 | """ 164 | required_params = ["structure", "db_file", "mat_name"] 165 | optional_params = ["defuse_unsuccessful"] 166 | 167 | def run_task(self, fw_spec): 168 | """ 169 | Your Comments Here 170 | """ 171 | # get adddtional tags to parse the directory for 172 | db_file = env_chk(self.get('db_file'), fw_spec) 173 | dir_name = os.getcwd() 174 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 175 | structure = self["structure"] 176 | mat_name = self["mat_name"] 177 | task_collection = 'EMC_Results' 178 | filename = glob.glob('sumo-bandstats.log*')[-1] 179 | hmass, emass = read_emcpyout(filename) 180 | # dictionary to update the database with 181 | d = {"structure": structure.as_dict(), 182 | "formula_pretty": structure.composition.reduced_formula, 183 | "material_id": mat_name, "run_directory": dir_name, 184 | "hole_effective_mass": hmass, "electron_effective_mass": emass} 185 | d = jsanitize(d) 186 | coll = mmdb.db[task_collection] 187 | coll.insert_one(d) 188 | 189 | @explicit_serialize 190 | class eps2db(FiretaskBase): 191 | """ 192 | Insert macroscopic dielectric constants for LEPSILON=TRUE calculation. 193 | """ 194 | required_params = ["structure", "db_file", "mat_name"] 195 | optional_params = ["defuse_unsuccessful"] 196 | 197 | def run_task(self, fw_spec): 198 | """ 199 | Your Comments Here 200 | """ 201 | # get additional tags to parse the directory for 202 | db_file = env_chk(self.get('db_file'), fw_spec) 203 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 204 | dir_name = os.getcwd() 205 | structure = self["structure"] 206 | mat_name = self["mat_name"] 207 | task_collection = 'EPS_Results' 208 | filename = glob.glob('vasprun.xml*')[-1] 209 | try: 210 | locpot_fname = glob.glob('LOCPOT*')[-1] 211 | zvac, evac, delta_evac=read_vac_level(locpot_fname, filename) 212 | ifvac=True 213 | except: 214 | ifvac=False 215 | epsilon = read_epsilon(filename) 216 | vrun = Vasprun(filename, parse_projected_eigen=True) 217 | ks_energies = vrun.eigenvalues 218 | proj_eigs=vrun.projected_eigenvalues 219 | kwgs=vrun.actual_kpoints_weights 220 | file = glob.glob('OUTCAR*')[-1] 221 | outcar = Outcar(file) 222 | run_stats=outcar.run_stats 223 | igap, dgap = get_gap_from_dict(ks_energies) 224 | bgap, cbm, vbm, is_band_gap_direct = vrun.eigenvalue_band_properties 225 | # dictionary to update the database with 226 | d = {"structure": structure.as_dict(), 227 | "formula_pretty": structure.composition.reduced_formula, 228 | "material_id": mat_name, "dielectric constant": epsilon, 229 | "run_stats": run_stats, "run_directory": dir_name, 230 | 'direct_gap': dgap, 'indirect_gap': igap, 231 | "kpoint_weights": kwgs, "cbm": cbm, "vbm": vbm, 232 | "projected_eigs": proj_eigs, "ks_energies": ks_energies} 233 | if ifvac: 234 | d.update({"z_vacuum": zvac, "e_vacuum": evac, "delta_e_vacuum": delta_evac}) 235 | d = jsanitize(d) 236 | coll = mmdb.db[task_collection] 237 | coll.insert_one(d) 238 | 239 | 240 | 241 | @explicit_serialize 242 | class Wannier2DB(FiretaskBase): 243 | """ 244 | Insert a optical transition and quasi-particle energies 245 | into the database for a GW and BSE calculation. 246 | 247 | Args: 248 | db_file (str): path to file containing the database credentials. 249 | Supports env_chk. Default: write data to JSON file. 250 | task_collection (str): The name of the task collection you 251 | want to push the data to. 252 | wf_name (str): The name of the workflow that this analysis is part of. 253 | """ 254 | 255 | required_params = ["structure", "task_label", "db_file", "compare_vasp", "mat_name"] 256 | optional_params = ["defuse_unsuccessful"] 257 | 258 | def run_task(self, fw_spec): 259 | """ 260 | Your Comments Here 261 | """ 262 | # get adddtional tags to parse the directory for 263 | db_file = env_chk(self.get('db_file'), fw_spec) 264 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 265 | structure = self["structure"] 266 | task_label = self["task_label"] 267 | compare_vasp = self["compare_vasp"] 268 | mat_name = self["mat_name"] 269 | task_collection = 'WANNIER_Results' 270 | dir_name = os.getcwd() 271 | fname_band = glob.glob('wannier90_band.dat*')[-1] 272 | fname_kpt = glob.glob('wannier90_band.kpt*')[-1] 273 | fname_gnu = glob.glob('wannier90_band.gnu*')[-1] 274 | fname_vasp = glob.glob('vasprun.xml*')[-1] 275 | gap, vbm = read_vbm(fname_vasp) 276 | kpts, eigs_wann = read_wannier(fname_band, fname_kpt, vbm) 277 | spkptl, spkptc = read_special_kpts(fname_gnu) 278 | if compare_vasp: 279 | kpt_vasp, eigs_vasp = read_vasp(fname_vasp, vbm) 280 | d = {"structure": structure.as_dict(), 281 | "formula_pretty": structure.composition.reduced_formula, 282 | "material_id": mat_name, 283 | "run_directory": dir_name, 284 | "wannier_kpoints": kpts, "wannier_eigenvalues": eigs_wann, 285 | "actual_kpoints": kpt_vasp, "actual_eigenvalues": eigs_vasp, 286 | "special_kpoint_labels": spkptl, 287 | "special_kpoint_coordinates": spkptc, 288 | "task_label": task_label} 289 | else: 290 | d = {"structure": structure.as_dict(), 291 | "formula_pretty": structure.composition.reduced_formula, 292 | "material_id": mat_name, 293 | "run_directory": dir_name, 294 | "wannier_kpoints": kpts, "wannier_eigenvalues": eigs_wann, 295 | "special_kpoint_labels": spkptl, 296 | "special_kpoint_coordinates": spkptc, 297 | "task_label": task_label} 298 | d = jsanitize(d) 299 | coll = mmdb.db[task_collection] 300 | coll.insert_one(d) 301 | -------------------------------------------------------------------------------- /pyGWBSE/run_calc.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | This module defines tasks that support running vasp in various ways. 5 | """ 6 | 7 | import os 8 | import subprocess 9 | 10 | from atomate.utils.utils import env_chk, get_logger 11 | from fireworks import explicit_serialize, FiretaskBase 12 | 13 | __author__ = 'Anubhav Jain ' 14 | __credits__ = 'Shyue Ping Ong ' 15 | 16 | logger = get_logger(__name__) 17 | 18 | 19 | @explicit_serialize 20 | class Run_Vasp(FiretaskBase): 21 | """ 22 | Execute a command directly (no custodian). 23 | 24 | Args: 25 | cmd (str): the name of the full executable to run. Supports env_chk. 26 | 27 | Other Parameters: 28 | expand_vars (str): Set to true to expand variable names in the cmd. 29 | """ 30 | 31 | required_params = ["vasp_cmd"] 32 | optional_params = ["expand_vars"] 33 | 34 | def run_task(self, fw_spec): 35 | """ 36 | Your Comments Here 37 | """ 38 | cmd = env_chk(self["vasp_cmd"], fw_spec) 39 | if self.get("expand_vars", False): 40 | cmd = os.path.expandvars(cmd) 41 | 42 | logger.info("Running command: {}".format(cmd)) 43 | return_code = subprocess.call(cmd, shell=True) 44 | logger.info("Command {} finished running with returncode: {}".format(cmd, return_code)) 45 | 46 | 47 | @explicit_serialize 48 | class Run_Sumo(FiretaskBase): 49 | """ 50 | Your Comments Here 51 | """ 52 | required_params = ["sumo_cmd"] 53 | 54 | def run_task(self, fw_spec): 55 | """ 56 | Your Comments Here 57 | """ 58 | cmd = env_chk(self["sumo_cmd"], fw_spec) 59 | logger.info("Running command: {}".format(cmd)) 60 | return_code = subprocess.call(cmd, shell=True) 61 | logger.info("Command {} finished running with returncode: {}".format(cmd, return_code)) 62 | 63 | 64 | @explicit_serialize 65 | class Run_Wannier(FiretaskBase): 66 | """ 67 | Your Comments Here 68 | """ 69 | required_params = ["wannier_cmd"] 70 | 71 | def run_task(self, fw_spec): 72 | """ 73 | Your Comments Here 74 | """ 75 | cmd = env_chk(self["wannier_cmd"], fw_spec) 76 | logger.info("Running command: {}".format(cmd)) 77 | return_code = subprocess.call(cmd, shell=True) 78 | logger.info("Command {} finished running with returncode: {}".format(cmd, return_code)) 79 | -------------------------------------------------------------------------------- /pyGWBSE/tasks.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import glob 4 | import gzip 5 | import os 6 | import re 7 | from atomate.common.firetasks.glue_tasks import CopyFiles, get_calc_loc 8 | from atomate.utils.utils import env_chk, get_logger 9 | from fireworks import explicit_serialize, FiretaskBase, FWAction 10 | from pymatgen.io.vasp import Vasprun, Locpot 11 | from pymatgen.io.vasp.inputs import Incar 12 | from pymatgen.core import Structure 13 | 14 | from pyGWBSE.inputset import CreateInputs 15 | 16 | """ 17 | This module defines tasks that acts as a glue between other vasp Firetasks to allow communication 18 | between different Firetasks and Fireworks. This module also contains tasks that affect the control 19 | flow of the workflow, e.g. tasks to check stability or the gap is within a certain range. 20 | """ 21 | 22 | logger = get_logger(__name__) 23 | 24 | __author__ = 'Anubhav Jain, Kiran Mathew' 25 | __email__ = 'ajain@lbl.gov, kmathew@lbl.gov' 26 | 27 | 28 | @explicit_serialize 29 | class CheckBeConv(FiretaskBase): 30 | """ 31 | Your Comments Here 32 | """ 33 | required_params = ["niter", "tolerence", "no_conv"] 34 | 35 | def run_task(self, fw_spec): 36 | """ 37 | Your Comments Here 38 | """ 39 | niter = self["niter"] 40 | conv = self["no_conv"] 41 | tol = self["tolerence"] 42 | filename = str(os.getcwd()) + '/vasprun.xml' 43 | vasprun = Vasprun(filename) 44 | gap, cbm, vbm, is_direct = vasprun.eigenvalue_band_properties 45 | print() 46 | print('=================================================') 47 | print('Iteration:', niter) 48 | print("band gap:", ("%10.4f" % gap)) 49 | print("CBM:", ("%10.4f" % cbm)) 50 | print("VBM:", ("%10.4f" % vbm)) 51 | print("Is the gap direct:", is_direct) 52 | if niter > 1: 53 | old_val = fw_spec["conval"] 54 | new_val = gap 55 | diff = abs(old_val - new_val) 56 | print("Difference:", ("%10.4f" % diff)) 57 | print('=================================================') 58 | print() 59 | if diff < tol: 60 | conv = True 61 | return FWAction(update_spec={"ifconv": conv, "conval": gap}) 62 | 63 | 64 | @explicit_serialize 65 | class MakeWFilesList(FiretaskBase): 66 | 67 | def run_task(self, fw_spec): 68 | files2copy = glob.glob("W*.tmp") 69 | return FWAction(update_spec={"wfiles": files2copy}) 70 | 71 | @explicit_serialize 72 | class SaveNbandsov(FiretaskBase): 73 | 74 | required_params = ["enwinbse"] 75 | 76 | def run_task(self, fw_spec): 77 | 78 | enwinbse = self["enwinbse"] 79 | filename = str(os.getcwd()) + '/vasprun.xml' 80 | vasprun = Vasprun(filename) 81 | qpe=vasprun.eigenvalues 82 | gap, cbm, vbm, is_direct = vasprun.eigenvalue_band_properties 83 | nbandso,nbandsv=get_nbandsov(qpe,vbm,cbm,enwinbse) 84 | 85 | return FWAction(update_spec={"nbandso": nbandso, "nbandsv": nbandsv}) 86 | 87 | @explicit_serialize 88 | class SaveConvParams(FiretaskBase): 89 | 90 | required_params = ["nomegagw","encutgw","nbands"] 91 | 92 | def run_task(self, fw_spec): 93 | nomegagw=self["nomegagw"] 94 | encutgw=self["encutgw"] 95 | nbands=self["nbands"] 96 | return FWAction(update_spec={"nomegagw": nomegagw, "encutgw": encutgw, "nbands": nbands}) 97 | 98 | @explicit_serialize 99 | class StopIfConverged(FiretaskBase): 100 | """ 101 | Your Comments Here 102 | """ 103 | def run_task(self, fw_spec): 104 | """ 105 | Your Comments Here 106 | """ 107 | ifconv = fw_spec["ifconv"] 108 | if ifconv: 109 | return FWAction(exit=True) 110 | 111 | 112 | @explicit_serialize 113 | class PasscalClocsCond(FiretaskBase): 114 | """ 115 | Your Comments Here 116 | """ 117 | required_params = ["name"] 118 | optional_params = ["filesystem", "path"] 119 | 120 | def run_task(self, fw_spec): 121 | """ 122 | Your Comments Here 123 | """ 124 | calc_locs = list(fw_spec.get("calc_locs", [])) 125 | calc_locs.append({"name": self["name"], 126 | "filesystem": env_chk(self.get('filesystem', None), fw_spec), 127 | "path": self.get("path", os.getcwd())}) 128 | ifconv = fw_spec["ifconv"] 129 | if ifconv: 130 | return FWAction(mod_spec=[{'_push_all': {'calc_locs': calc_locs}}]) 131 | 132 | 133 | @explicit_serialize 134 | class WriteBSEInput(FiretaskBase): 135 | """ 136 | Your Comments Here 137 | """ 138 | required_params = ["structure", "reciprocal_density"] 139 | 140 | def run_task(self, fw_spec): 141 | """ 142 | Your Comments Here 143 | """ 144 | f_incar = str(os.getcwd()) + '/INCAR' 145 | structure = self["structure"] 146 | reciprocal_density = self["reciprocal_density"] 147 | nbandso = fw_spec["nbandso"] 148 | nbandsv = fw_spec["nbandsv"] 149 | prev_incar = Incar.from_file(f_incar) 150 | vis = CreateInputs(structure, mode='BSE', prev_incar=prev_incar, reciprocal_density=reciprocal_density, 151 | nbandso=nbandso, nbandsv=nbandsv) 152 | vis.write_input(".") 153 | 154 | 155 | @explicit_serialize 156 | class WriteGWInput(FiretaskBase): 157 | """ 158 | Your Comments Here 159 | """ 160 | required_params = ["structure", "reciprocal_density", "nbandsgw", "wannier_fw"] 161 | 162 | def run_task(self, fw_spec): 163 | """ 164 | Your Comments Here 165 | """ 166 | f_incar = str(os.getcwd()) + '/INCAR' 167 | prev_incar = Incar.from_file(f_incar) 168 | structure = self["structure"] 169 | nbandsgw = self["nbandsgw"] 170 | wannier_fw = self["wannier_fw"] 171 | reciprocal_density = self["reciprocal_density"] 172 | encutgw=fw_spec["encutgw"] 173 | nomegagw=fw_spec["nomegagw"] 174 | nbands=fw_spec["nbands"] 175 | vis = CreateInputs(structure, mode='GW', prev_incar=prev_incar, reciprocal_density=reciprocal_density, 176 | encutgw=encutgw, nomegagw=nomegagw, nbands=nbands, nbandsgw=nbandsgw, wannier_fw=wannier_fw) 177 | vis.write_input(".") 178 | 179 | 180 | def read_emcpyout(fname): 181 | f = open(fname) 182 | contents = f.readlines() 183 | f.close() 184 | ne=0 185 | nh=0 186 | h_res={} 187 | e_res={} 188 | for content in contents: 189 | if "m_h:" in content: 190 | nh=nh+1 191 | lines = str.split(content) 192 | hmass=eval(lines[1]) 193 | hibnd=eval(lines[4]) 194 | inda=lines.index('->') 195 | if inda==10: 196 | hdir1=lines[9] 197 | hdir2=lines[14] 198 | else: 199 | hdir1='Intermediate' 200 | hdir2=lines[13] 201 | 202 | h_res['mass'+str(nh)+': '+str(hibnd)+', '+hdir1+', '+hdir2]=hmass 203 | 204 | if "m_e:" in content: 205 | ne=ne+1 206 | lines = str.split(content) 207 | emass=eval(lines[1]) 208 | eibnd=eval(lines[4]) 209 | inda=lines.index('->') 210 | if inda==10: 211 | edir1=lines[9] 212 | edir2=lines[14] 213 | else: 214 | edir1='Intermediate' 215 | edir2=lines[13] 216 | 217 | 218 | e_res['mass'+str(ne)+': '+str(eibnd)+', '+edir1+', '+edir2]=emass 219 | 220 | return h_res, e_res 221 | 222 | def read_epsilon(fname): 223 | vasprun = Vasprun(fname) 224 | try: 225 | epsilon = vasprun.epsilon_static_wolfe 226 | except: 227 | epsilon = None 228 | return epsilon 229 | 230 | 231 | def calc_delta_evac(x,y,n0): 232 | dx1=x[n0+1]-x[n0] 233 | dy1=y[n0+1]-y[n0] 234 | dx2=x[n0]-x[n0-1] 235 | dy2=y[n0]-y[n0-1] 236 | f1=dy1/dx1 237 | f2=dy2/dx2 238 | return (f1+f2)/2 239 | 240 | 241 | 242 | def read_vac_level(locpot_fname,fname): 243 | lpot=Locpot.from_file(locpot_fname) 244 | vrun=Vasprun(fname) 245 | vrun_d=vrun.as_dict() 246 | struct=Structure.from_dict(vrun_d["input"]["crystal"]) 247 | latt_c=struct.lattice.c 248 | y=lpot.get_average_along_axis(2) 249 | zarr=lpot.get_axis_grid(2) 250 | 251 | dist_z0=0. 252 | z0=0. 253 | 254 | for n,z in enumerate(zarr): 255 | dist=[] 256 | for site in struct.sites: 257 | pos_z=site.coords[2] 258 | if pos_z<0: 259 | pos_z=pos_z+latt_c 260 | dist.append(abs(pos_z-z)) 261 | dist.append(abs(pos_z+latt_c-z)) 262 | dist_z=min(dist) 263 | if dist_z>dist_z0: 264 | dist_z0=dist_z 265 | z0=z 266 | n0=n 267 | 268 | evac=y[n0] 269 | zvac=zarr[n0] 270 | delta_evac=calc_delta_evac(zarr,y,n0) 271 | 272 | return zvac,evac,delta_evac 273 | 274 | def get_gap_from_dict(qp_energies): 275 | 276 | tol=1e-5 277 | vbm = -float("inf") 278 | cbm = float("inf") 279 | for spin, d in qp_energies.items(): 280 | for k, val in enumerate(d): 281 | for (eigenval, occu) in val: 282 | if occu > tol and eigenval > vbm: 283 | vbm = eigenval 284 | elif occu <= tol and eigenval < cbm: 285 | cbm = eigenval 286 | igap=max(cbm-vbm,0) 287 | 288 | gap = [] 289 | filled = 1.0 290 | tol=1e-5 291 | vbm=0 292 | cbm=0 293 | for spin, d in qp_energies.items(): 294 | for k, val in enumerate(d): 295 | for (eigenval, occu) in val: 296 | if abs(occu-filled)<=tol: 297 | vbm=eigenval 298 | else: 299 | cbm=eigenval 300 | gap.append(cbm-vbm) 301 | break 302 | dgap=min(gap) 303 | return igap,dgap 304 | 305 | def get_nbandsov(qp_energies,vbm,cbm,enwinbse): 306 | 307 | tol=1e-5 308 | nvb=[] 309 | ncb=[] 310 | for spin, d in qp_energies.items(): 311 | for k, val in enumerate(d): 312 | for ibnd,(eigenval, occ) in enumerate(val): 313 | if abs(occ-1.0) 9: 404 | raise ValueError( 405 | "CopyVaspOutputs doesn't properly handle >9 relaxations!") 406 | m = re.search('\.relax\d*', relax_paths[-1]) 407 | relax_ext = m.group(0) 408 | 409 | # detect .gz extension if needed - note that monty zpath() did not seem useful here 410 | gz_ext = "" 411 | if not (f + relax_ext) in all_files: 412 | for possible_ext in [".gz", ".GZ"]: 413 | if (f + relax_ext + possible_ext) in all_files: 414 | gz_ext = possible_ext 415 | 416 | if not (f + relax_ext + gz_ext) in all_files: 417 | raise ValueError("Cannot find file: {}".format(f)) 418 | 419 | # copy the file (minus the relaxation extension) 420 | self.fileclient.copy(prev_path_full + relax_ext + gz_ext, 421 | dest_path + gz_ext) 422 | 423 | # unzip the .gz if needed 424 | if gz_ext in ['.gz', ".GZ"]: 425 | # unzip dest file 426 | f = gzip.open(dest_path + gz_ext, 'rt') 427 | file_content = f.read() 428 | with open(dest_path, 'w') as f_out: 429 | f_out.writelines(file_content) 430 | f.close() 431 | os.remove(dest_path + gz_ext) 432 | -------------------------------------------------------------------------------- /pyGWBSE/wannier_tasks.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | This module defines tasks for WANNIER90 calculation 5 | """ 6 | 7 | import os 8 | 9 | import numpy as np 10 | from atomate.utils.utils import get_logger 11 | from fireworks import explicit_serialize, FiretaskBase 12 | from pymatgen.core import Structure 13 | from pymatgen.io.vasp import Vasprun 14 | from pymatgen.io.vasp.inputs import Incar, Potcar, PotcarSingle 15 | from pymatgen.symmetry.analyzer import SpacegroupAnalyzer 16 | from pymatgen.symmetry.bandstructure import HighSymmKpath 17 | 18 | from pyGWBSE.inputset import CreateInputs 19 | 20 | logger = get_logger(__name__) 21 | 22 | __author__ = 'Tathagata Biswas' 23 | __email__ = 'tbiswas3@asu.edu' 24 | 25 | 26 | @explicit_serialize 27 | class WriteWannierInputForGW(FiretaskBase): 28 | """ 29 | Your Comments Here 30 | """ 31 | required_params = ["structure", "reciprocal_density", "nbandsgw"] 32 | 33 | def run_task(self, fw_spec): 34 | """ 35 | Your Comments Here 36 | """ 37 | f_incar = str(os.getcwd()) + '/INCAR' 38 | structure = self["structure"] 39 | nbandsgw = self["nbandsgw"] 40 | reciprocal_density = self["reciprocal_density"] 41 | prev_incar = Incar.from_file(f_incar) 42 | wann_inp = str(os.getcwd()) + '/wannier90.win' 43 | vasprunfile = str(os.getcwd()) + '/vasprun.xml' 44 | poscarfile = str(os.getcwd()) + '/POSCAR' 45 | potcarfile = str(os.getcwd()) + '/POTCAR' 46 | vasprun = Vasprun(vasprunfile) 47 | incar = vasprun.incar 48 | nbands = incar["NBANDS"] 49 | elements = read_potcar(potcarfile, poscarfile) 50 | labels, kpts = kpath_finder(poscarfile) 51 | numwan = 0 52 | for element in elements: 53 | numwan = numwan + element[5] 54 | if numwan > nbandsgw: 55 | nbandsgw = numwan 56 | encutgw=fw_spec["encutgw"] 57 | nomegagw=fw_spec["nomegagw"] 58 | nbands=fw_spec["nbands"] 59 | vis = CreateInputs(structure, mode='GW', reciprocal_density=reciprocal_density, 60 | prev_incar=prev_incar, encutgw=encutgw, nomegagw=nomegagw, nbands=nbands, nbandsgw=nbandsgw) 61 | vis.write_input(".") 62 | labels, kpts = kpath_finder(poscarfile) 63 | write_wannier_input(numwan, nbands, labels, kpts, wann_inp, elements,False) 64 | 65 | 66 | @explicit_serialize 67 | class WriteWannierInputForDFT(FiretaskBase): 68 | """ 69 | Your Comments Here 70 | """ 71 | required_params = ["structure", "reciprocal_density", "ppn", "write_hr"] 72 | 73 | def run_task(self, fw_spec): 74 | """ 75 | Your Comments Here 76 | """ 77 | f_incar = str(os.getcwd()) + '/INCAR' 78 | structure = self["structure"] 79 | reciprocal_density = self["reciprocal_density"] 80 | ppn = self["ppn"] 81 | write_hr = self["write_hr"] 82 | prev_incar = Incar.from_file(f_incar) 83 | wann_inp = str(os.getcwd()) + '/wannier90.win' 84 | vasprunfile = str(os.getcwd()) + '/vasprun.xml' 85 | poscarfile = str(os.getcwd()) + '/POSCAR' 86 | potcarfile = str(os.getcwd()) + '/POTCAR' 87 | vasprun = Vasprun(vasprunfile) 88 | incar = vasprun.incar 89 | nbands = incar["NBANDS"] 90 | elements = read_potcar(potcarfile, poscarfile) 91 | numwan = 0 92 | for element in elements: 93 | numwan = numwan + element[5] 94 | print(numwan, nbands) 95 | if numwan > nbands: 96 | nbands = (int(numwan / ppn) + 1) * ppn 97 | vis = CreateInputs(structure, mode='STATIC', prev_incar=prev_incar, reciprocal_density=reciprocal_density, 98 | nbands=nbands) 99 | vis.write_input(".") 100 | labels, kpts = kpath_finder(poscarfile) 101 | write_wannier_input(numwan, nbands, labels, kpts, wann_inp, elements,write_hr) 102 | 103 | 104 | @explicit_serialize 105 | class CopyKptsWan2vasp(FiretaskBase): 106 | """ 107 | Your Comments Here 108 | """ 109 | 110 | def run_task(self, fw_spec): 111 | """ 112 | Your Comments Here 113 | """ 114 | f_wannkpt = str(os.getcwd()) + '/wannier90_band.kpt' 115 | f_vaspkpt = str(os.getcwd()) + '/KPOINTS' 116 | f = open(f_wannkpt) 117 | contents = f.readlines() 118 | f.close() 119 | lines = str.split(contents[0]) 120 | nkpts = eval(lines[0]) 121 | f = open(f_vaspkpt, 'w') 122 | f.write('kpoints file generated from wannier90_band.kpt' + '\n') 123 | f.write(str(nkpts) + '\n') 124 | f.write('Reciprocal' + '\n') 125 | for ik in range(nkpts): 126 | f.write(contents[ik + 1]) 127 | f.close() 128 | 129 | 130 | def write_wannier_input(numwan, nbands, labels, kpts, wann_inp, elements,write_hr): 131 | """ 132 | Your Comments Here 133 | """ 134 | if write_hr: 135 | f = open(wann_inp, 'a') 136 | f.write("write_hr = true" + "\n") 137 | f.close() 138 | else: 139 | f = open(wann_inp, 'w') 140 | f.write("num_wann = " + str(numwan) + "\n") 141 | if numwan < nbands: 142 | f.write("exclude_bands " + str(numwan + 1) + "-" + str(nbands) + "\n") 143 | if numwan == nbands - 1: 144 | f.write("exclude_bands " + str(numwan + 1) + "\n") 145 | f.write("bands_plot = true" + "\n") 146 | f.write("begin kpoint_path" + "\n") 147 | for i in range(len(labels)): 148 | for j in range(len(labels[i])-1): 149 | label1=labels[i][j] 150 | label2=labels[i][j+1] 151 | string = write_kpath_lines(kpts[label1], label1, kpts[label2], label2) 152 | f.write(string) 153 | f.write("end kpoint_path" + "\n") 154 | f.write("bands_num_points 40" + "\n") 155 | f.write("bands_plot_format gnuplot" + "\n") 156 | f.write("Begin Projections" + "\n") 157 | f.write("random" + "\n") 158 | for element in elements: 159 | f.write(element[0] + ':') 160 | for l in range(4): 161 | if element[l + 1] > 0: 162 | if l == 0: 163 | f.write('l=' + str(l)) 164 | else: 165 | f.write(';' + 'l=' + str(l)) 166 | f.write('\n') 167 | f.write("End Projections" + "\n") 168 | f.write("num_iter = 500" + "\n") 169 | f.close() 170 | 171 | 172 | def write_kpath_lines(kpt1, label1, kpt2, label2): 173 | """ 174 | Your Comments Here 175 | """ 176 | string = label1 + " " + "%10.5f" % kpt1[0] + "%10.5f" % kpt1[1] + "%10.5f" % kpt1[ 177 | 2] + " " + label2 + " " + "%10.5f" % kpt2[0] + "%10.5f" % kpt2[1] + "%10.5f" % kpt2[2] + "\n" 178 | return string 179 | 180 | 181 | def kpath_finder(filename): 182 | """ 183 | Your Comments Here 184 | """ 185 | struct = Structure.from_file(filename) 186 | spcg = SpacegroupAnalyzer(struct) 187 | pstruct = spcg.get_primitive_standard_structure(international_monoclinic=False) 188 | hskp = HighSymmKpath(pstruct) 189 | kpts = hskp.kpath["kpoints"] 190 | labels = hskp.kpath["path"] 191 | return labels, kpts 192 | 193 | 194 | def read_potcar(potcarfile, poscarfile): 195 | """ 196 | Your Comments Here 197 | """ 198 | struct = Structure.from_file(poscarfile) 199 | potcar = Potcar.from_file(potcarfile) 200 | sites = struct.species 201 | specs = potcar.spec 202 | wan_info = [] 203 | for spec in specs: 204 | single = PotcarSingle.from_symbol_and_functional(symbol=spec['symbol'], functional='PBE_54') 205 | orbitals = single.electron_configuration 206 | element = single.element 207 | nat = str(sites).count(single.element) 208 | spdf = [] 209 | for orbital in orbitals: 210 | spdf.append(orbital[1]) 211 | scnt = spdf.count('s') 212 | pcnt = spdf.count('p') 213 | dcnt = spdf.count('d') 214 | fcnt = spdf.count('f') 215 | numwan = nat * (scnt * 1 + pcnt * 3 + dcnt * 5 + fcnt * 7) 216 | wan_info.append([element, scnt, pcnt, dcnt, fcnt, numwan]) 217 | return wan_info 218 | 219 | 220 | def read_vbm(fname): 221 | """ 222 | Your Comments Here 223 | """ 224 | vasprun = Vasprun(fname, parse_potcar_file=False) 225 | gap, cbm, vbm, is_direct = vasprun.eigenvalue_band_properties 226 | return gap, vbm 227 | 228 | 229 | def read_wannier(fname_band, fname_kpt, vbm): 230 | """ 231 | Your Comments Here 232 | """ 233 | f = open(fname_band) 234 | contents = f.readlines() 235 | f.close() 236 | 237 | kvals = [] 238 | evals = [] 239 | 240 | for content in contents: 241 | lines = str.split(content) 242 | if len(lines) != 0: 243 | kvals.append(eval(lines[0])) 244 | evals.append(eval(lines[1])) 245 | with open(fname_kpt) as f: 246 | first_line = f.readline() 247 | nkpt = eval(str.split(first_line)[0]) 248 | nband = int(len(evals) / nkpt) 249 | kpts_flat = np.array(kvals) 250 | eigs_flat = np.array(evals) - vbm 251 | kpts = kpts_flat.reshape(nband, nkpt) 252 | eigs = eigs_flat.reshape(nband, nkpt) 253 | 254 | return kpts, eigs 255 | 256 | 257 | def read_vasp(fname, vbm): 258 | """ 259 | Your Comments Here 260 | """ 261 | vasprun = Vasprun(fname) 262 | eigs = vasprun.eigenvalues 263 | nkpt = len(vasprun.actual_kpoints) 264 | kptvasp = vasprun.actual_kpoints 265 | out = [] 266 | for spin, d in eigs.items(): 267 | for k, val in enumerate(d): 268 | for n, eigenval in enumerate(val): 269 | out.append(eigenval[0] - vbm) 270 | nbands = int(len(out) / nkpt) 271 | eigvasp = np.reshape(out, (nkpt, nbands)) 272 | 273 | return kptvasp, eigvasp 274 | 275 | 276 | def read_special_kpts(fname): 277 | """ 278 | Your Comments Here 279 | """ 280 | f = open(fname) 281 | contents = f.readlines() 282 | f.close() 283 | spkptl = [] 284 | spkptc = [] 285 | for content in contents: 286 | if 'set xtics' in content: 287 | lines = str.split(content,sep='"') 288 | for n, words in enumerate(lines): 289 | if n!=0 and n%2!=0: 290 | spkptl.append(words) 291 | elif n!=0: 292 | spkptc.append(eval(words[:9])) 293 | 294 | return spkptl,spkptc 295 | 296 | -------------------------------------------------------------------------------- /pyGWBSE/wflows.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | """ 5 | Defines standardized Fireworks that can be chained easily to perform various 6 | sequences of VASP calculations. 7 | """ 8 | import numpy as np 9 | from atomate.common.firetasks.glue_tasks import PassCalcLocs 10 | from atomate.vasp.firetasks.write_inputs import WriteVaspFromIOSet 11 | from fireworks import Firework, Tracker 12 | 13 | 14 | from pyGWBSE.inputset import CreateInputs 15 | from pyGWBSE.out2db import gw2db, bse2db, emc2db, eps2db, Wannier2DB, rpa2db 16 | from pyGWBSE.run_calc import Run_Vasp, Run_Sumo, Run_Wannier 17 | from pyGWBSE.tasks import CopyOutputFiles, CheckBeConv, StopIfConverged, PasscalClocsCond, WriteBSEInput, \ 18 | WriteGWInput, MakeWFilesList, SaveNbandsov, SaveConvParams 19 | from pyGWBSE.wannier_tasks import WriteWannierInputForDFT, WriteWannierInputForGW, CopyKptsWan2vasp 20 | 21 | 22 | class ScfFW(Firework): 23 | def __init__(self, mat_name=None, structure=None, nbands=None, kpar=None, reciprocal_density=None, 24 | vasp_input_set=None, vasp_input_params=None, 25 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, wannier_fw=None, 26 | vasptodb_kwargs={}, **kwargs): 27 | """ 28 | Your Comments Here 29 | """ 30 | t = [] 31 | vasp_input_set = CreateInputs(structure, kpar=kpar, reciprocal_density=reciprocal_density, nbands=nbands, 32 | wannier_fw=wannier_fw) 33 | name = 'SCF' 34 | fw_name = "{}-{}".format(mat_name, name) 35 | t.append(WriteVaspFromIOSet(structure=structure, 36 | vasp_input_set=vasp_input_set, 37 | vasp_input_params=vasp_input_params)) 38 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 39 | t.append(eps2db(structure=structure, mat_name=mat_name, db_file=db_file, defuse_unsuccessful=False)) 40 | t.append(rpa2db(structure=structure, mat_name=mat_name, task_label=name, db_file=db_file, defuse_unsuccessful=False)) 41 | t.append(PassCalcLocs(name=name)) 42 | super(ScfFW, self).__init__(t, name=fw_name, **kwargs) 43 | 44 | 45 | class convFW(Firework): 46 | 47 | def __init__(self, mat_name=None, structure=None, tolerence=None, no_conv=None, nbands=None, 48 | nbgwfactor=None, encutgw=None, nomegagw=None, convsteps=None, conviter=None, 49 | kpar=None, nbandsgw=None, reciprocal_density=None, vasp_input_set=None, vasp_input_params=None, 50 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, vasptodb_kwargs={}, parents=None, **kwargs): 51 | t = [] 52 | name = "CONV" 53 | fw_name = "{}-{}".format(mat_name, name) 54 | niter = 0 55 | nocc=nbands 56 | convsteps=np.array(convsteps)*0.01 57 | for niter in range(conviter): 58 | niter = niter + 1 59 | files2copy = ['WAVECAR'] 60 | task_label = 'Convergence_Iteration: ' + str(niter) 61 | 62 | hviter=np.heaviside((niter-1),0) 63 | 64 | nbgwfactor = nbgwfactor + nbgwfactor*hviter*convsteps[0] 65 | encutgw = encutgw + encutgw*hviter*convsteps[1] 66 | nomegagw = nomegagw + nomegagw*hviter*convsteps[2] 67 | 68 | nbands=round(nocc*nbgwfactor) 69 | encutgw=round(encutgw) 70 | nomegagw=round(nomegagw) 71 | 72 | if no_conv==False: 73 | if hviter==0: 74 | print('Convergence test will be performed using following values') 75 | print('Iteration, NBANDS, ENCUTGW, NOMEGA') 76 | print('%10i' %niter, '%7i' %nbands, '%8i' %encutgw, '%6i' %nomegagw) 77 | else: 78 | if hviter==0: 79 | print('values of follwing parameters will be used') 80 | print('NBANDS, ENCUTGW, NOMEGA') 81 | print('%7i' %nbands, '%8i' %encutgw, '%6i' %nomegagw) 82 | 83 | if prev_calc_dir: 84 | t.append(CopyOutputFiles(additional_files=files2copy, calc_dir=prev_calc_dir, contcar_to_poscar=True)) 85 | elif parents: 86 | if prev_calc_loc: 87 | t.append( 88 | CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 89 | vasp_input_set = CreateInputs(structure, mode='DIAG', nbands=nbands, kpar=kpar, 90 | reciprocal_density=reciprocal_density) 91 | t.append(WriteVaspFromIOSet(structure=structure, 92 | vasp_input_set=vasp_input_set, 93 | vasp_input_params=vasp_input_params)) 94 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 95 | vasp_input_set = CreateInputs(structure,mode='CONV',nbands=nbands,encutgw=encutgw,nomegagw=nomegagw,kpar=kpar,reciprocal_density=reciprocal_density,nbandsgw=nbandsgw) 96 | t.append(WriteVaspFromIOSet(structure=structure, 97 | vasp_input_set=vasp_input_set, 98 | vasp_input_params=vasp_input_params)) 99 | if no_conv==False: 100 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 101 | t.append(SaveConvParams(nbands=nbands, encutgw=encutgw, nomegagw=nomegagw)) 102 | t.append(CheckBeConv(niter=niter, tolerence=tolerence, no_conv=no_conv)) 103 | t.append(PasscalClocsCond(name=name)) 104 | if no_conv==False: 105 | t.append(gw2db(structure=structure, mat_name=mat_name, task_label=task_label, db_file=db_file, defuse_unsuccessful=False)) 106 | t.append(StopIfConverged()) 107 | tracker = Tracker('vasp.log', nlines=100) 108 | super(convFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 109 | 110 | 111 | class GwFW(Firework): 112 | def __init__(self, mat_name=None, structure=None, tolerence=None, no_conv=None, reciprocal_density=None, 113 | vasp_input_set=None, vasp_input_params=None, nbandso=None, nbandsv=None, nbandsgw=None, 114 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, wannier_fw=None, 115 | vasptodb_kwargs={}, job_tag=None, parents=None, **kwargs): 116 | """ 117 | Your Comments Here 118 | """ 119 | t = [] 120 | name = "GW" 121 | fw_name = "{}-{}".format(mat_name, name) 122 | files2copy = ['WAVECAR', 'WAVEDER'] 123 | if prev_calc_dir: 124 | t.append(CopyOutputFiles(additional_files=files2copy, calc_dir=prev_calc_dir, contcar_to_poscar=True)) 125 | elif parents: 126 | if prev_calc_loc: 127 | t.append(CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 128 | t.append(WriteGWInput(structure=structure, reciprocal_density=reciprocal_density, nbandsgw=nbandsgw, 129 | wannier_fw=wannier_fw)) 130 | for niter in range(1, 10): 131 | task_label = 'scGW_Iteration: ' + str(niter) 132 | if wannier_fw: 133 | t.append(WriteWannierInputForGW(structure=structure, reciprocal_density=reciprocal_density,nbandsgw=nbandsgw)) 134 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 135 | t.append(CheckBeConv(niter=niter, tolerence=tolerence, no_conv=no_conv)) 136 | t.append(PasscalClocsCond(name=name)) 137 | t.append(MakeWFilesList()) 138 | t.append( 139 | gw2db(structure=structure, mat_name=mat_name, task_label=task_label, job_tag=job_tag, db_file=db_file, 140 | defuse_unsuccessful=False)) 141 | t.append(StopIfConverged()) 142 | tracker = Tracker('vasp.log', nlines=100) 143 | 144 | super(GwFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 145 | 146 | 147 | class BseFW(Firework): 148 | def __init__(self, mat_name=None, structure=None, reciprocal_density=None, vasp_input_set=None, 149 | vasp_input_params=None, enwinbse=None, 150 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, vasptodb_kwargs={}, 151 | job_tag=None, parents=None, **kwargs): 152 | """ 153 | Your Comments Here 154 | """ 155 | t = [] 156 | name = "BSE" 157 | fw_name = "{}-{}".format(mat_name, name) 158 | files2copy = ['WAVECAR', 'WAVEDER'] 159 | if prev_calc_dir: 160 | t.append(CopyOutputFiles(additional_files=files2copy, calc_dir=prev_calc_dir, contcar_to_poscar=True)) 161 | elif parents: 162 | if prev_calc_loc: 163 | t.append(CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 164 | t.append(SaveNbandsov(enwinbse=enwinbse)) 165 | t.append(WriteBSEInput(structure=structure, reciprocal_density=reciprocal_density)) 166 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 167 | t.append(bse2db(structure=structure, mat_name=mat_name, task_label=name, job_tag=job_tag, db_file=db_file, 168 | defuse_unsuccessful=False)) 169 | tracker = Tracker('vasp.log', nlines=100) 170 | 171 | super(BseFW, self).__init__(t, parents=parents, name=fw_name, state='PAUSED', spec={"_trackers": [tracker]}, 172 | **kwargs) 173 | 174 | 175 | class EmcFW(Firework): 176 | def __init__(self, mat_name=None, structure=None, nbands=None, kpar=None, reciprocal_density=None, steps=None, 177 | vasp_input_set=None, vasp_input_params=None, 178 | vasp_cmd="vasp", sumo_cmd='sumo', prev_calc_loc=True, prev_calc_dir=None, db_file=None, 179 | vasptodb_kwargs={}, parents=None, **kwargs): 180 | """ 181 | Your Comments Here 182 | """ 183 | t = [] 184 | 185 | vasp_input_set = CreateInputs(structure, mode='EMC', kpar=kpar, reciprocal_density=reciprocal_density, 186 | nbands=nbands) 187 | name = 'EMC' 188 | fw_name = "{}-{}".format(mat_name, name) 189 | if prev_calc_dir: 190 | t.append(CopyOutputFiles(calc_dir=prev_calc_dir, additional_files=["CHGCAR"])) 191 | elif parents: 192 | t.append(CopyOutputFiles(calc_loc=True, additional_files=["CHGCAR"])) 193 | else: 194 | raise ValueError("Must specify previous calculation for NonScfFW") 195 | t.append(WriteVaspFromIOSet(structure=structure, 196 | vasp_input_set=vasp_input_set, 197 | vasp_input_params=vasp_input_params)) 198 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 199 | t.append(Run_Sumo(sumo_cmd=sumo_cmd)) 200 | t.append(emc2db(structure=structure, mat_name=mat_name, db_file=db_file, defuse_unsuccessful=False)) 201 | super(EmcFW, self).__init__(t, parents=parents, name=fw_name, **kwargs) 202 | 203 | 204 | class WannierCheckFW(Firework): 205 | def __init__(self, ppn=None, kpar=None, mat_name=None, structure=None, reciprocal_density=None, vasp_input_set=None, 206 | vasp_input_params=None, 207 | vasp_cmd="vasp", wannier_cmd=None, prev_calc_loc=True, prev_calc_dir=None, db_file=None, 208 | vasptodb_kwargs={}, parents=None, **kwargs): 209 | """ 210 | Your Comments Here 211 | """ 212 | t = [] 213 | name = "WANNIER_CHECK" 214 | fw_name = "{}-{}".format(mat_name, name) 215 | t.append(CopyOutputFiles(calc_loc=prev_calc_loc, contcar_to_poscar=True)) 216 | t.append(WriteWannierInputForDFT(structure=structure, reciprocal_density=reciprocal_density, ppn=ppn, write_hr=False)) 217 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 218 | t.append(WriteWannierInputForDFT(structure=structure, reciprocal_density=reciprocal_density, ppn=ppn, write_hr=True)) 219 | t.append(Run_Wannier(wannier_cmd=wannier_cmd)) 220 | vasp_input_set = CreateInputs(structure, mode='EMC', kpar=kpar, reciprocal_density=reciprocal_density) 221 | t.append(WriteVaspFromIOSet(structure=structure, 222 | vasp_input_set=vasp_input_set, 223 | vasp_input_params=vasp_input_params)) 224 | t.append(CopyKptsWan2vasp()) 225 | t.append(Run_Vasp(vasp_cmd=vasp_cmd)) 226 | t.append(Wannier2DB(structure=structure, mat_name=mat_name, task_label='CHECK_WANNIER_INTERPOLATION', 227 | db_file=db_file, compare_vasp=True, defuse_unsuccessful=False)) 228 | tracker = Tracker('vasp.log', nlines=100) 229 | 230 | super(WannierCheckFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 231 | 232 | 233 | class WannierFW(Firework): 234 | def __init__(self, structure=None, mat_name=None, wannier_cmd=None, prev_calc_loc=True, prev_calc_dir=None, 235 | db_file=None, parents=None, **kwargs): 236 | """ 237 | Your Comments Here 238 | """ 239 | t = [] 240 | name = "WANNIER" 241 | fw_name = "{}-{}".format(mat_name, name) 242 | files2copy = ['wannier90.win', 'wannier90.mmn', 'wannier90.amn', 'wannier90.eig'] 243 | t.append(CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 244 | t.append(Run_Wannier(wannier_cmd=wannier_cmd)) 245 | t.append(Wannier2DB(structure=structure, mat_name=mat_name, task_label='GW_BANDSTRUCTURE', db_file=db_file, 246 | compare_vasp=False, defuse_unsuccessful=False)) 247 | tracker = Tracker('wannier90.wout', nlines=100) 248 | 249 | super(WannierFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 250 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | atomate==1.0.3 2 | FireWorks==2.0.3 3 | pymatgen==2022.9.21 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | setup( 5 | name='pyGWBSE', 6 | version='1.0', 7 | description='python workflow for GW-BSE calculation', 8 | author='Tathagata Biswas', 9 | author_email='tbiswas3@asu.edu', 10 | packages=['pyGWBSE'], 11 | install_requires=['FireWorks>=2.0.3', 'pymatgen>=2022.9.21', 12 | 'atomate>=1.0.3'], 13 | package_data={"pyGWBSE": ["inputset.yaml"]} 14 | 15 | ) 16 | -------------------------------------------------------------------------------- /sphinx/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /sphinx/README: -------------------------------------------------------------------------------- 1 | TO INSTALL run the "compile" script 2 | "input.yaml is a sample input file" 3 | Run make_wf.py to crate a workflow based on "input.yaml" 4 | 5 | 6 | You will need wannier90, sumo-bandstats, pymatgen, fireworks and atomate to run the code. 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /sphinx/README.md: -------------------------------------------------------------------------------- 1 | # pyGWBSE 2 | python workflow for GW-BSE calculation 3 | -------------------------------------------------------------------------------- /sphinx/_static/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmdlab/pyGWBSE/110d0b47f96d7676ae224fc75a76e7e37c8922bd/sphinx/_static/github.png -------------------------------------------------------------------------------- /sphinx/_static/orcid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmdlab/pyGWBSE/110d0b47f96d7676ae224fc75a76e7e37c8922bd/sphinx/_static/orcid.jpg -------------------------------------------------------------------------------- /sphinx/clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf build/ dist/ pyGWBSE.egg-info/ __pycache__/ 3 | rm -rf pyGWBSE/__init__.py pyGWBSE/__pycache__/ 4 | -------------------------------------------------------------------------------- /sphinx/compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python setup.py install 3 | -------------------------------------------------------------------------------- /sphinx/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('.')) 16 | sys.path.insert(0, os.path.abspath('../')) 17 | sys.path.insert(0, os.path.abspath('../gwbse_wf')) 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = 'WFGWBSE' 22 | copyright = '2021, Tathagata Biswas' 23 | author = 'Tathagata Biswas' 24 | 25 | # The full version, including alpha/beta/rc tags 26 | release = '0.1' 27 | 28 | 29 | # -- General configuration --------------------------------------------------- 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = [ 35 | 'sphinx.ext.autodoc', 36 | 'sphinx.ext.napoleon' 37 | ] 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ['_templates'] 41 | 42 | # List of patterns, relative to source directory, that match files and 43 | # directories to ignore when looking for source files. 44 | # This pattern also affects html_static_path and html_extra_path. 45 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 46 | 47 | 48 | # -- Options for HTML output ------------------------------------------------- 49 | 50 | # The theme to use for HTML and HTML Help pages. See the documentation for 51 | # a list of builtin themes. 52 | 53 | html_theme = 'sphinx_rtd_theme' 54 | autodoc_member_order = 'bysource' 55 | autodoc_mock_imports = ["fireworks", "atomate", "pymatgen", "monty", "pydash", "pymongo"] 56 | autoclass_content = 'both' 57 | autodoc_default_flags = ['members', 'undoc-members', 'private-members', 'special-members', 'inherited-members', 'show-inheritance'] 58 | 59 | 60 | # Add any paths that contain custom static files (such as style sheets) here, 61 | # relative to this directory. They are copied after the builtin static files, 62 | # so a file named "default.css" will overwrite the builtin "default.css". 63 | html_static_path = ['_static'] -------------------------------------------------------------------------------- /sphinx/example/AlN_abs.txt: -------------------------------------------------------------------------------- 1 | 6.15789 0.430108 0 0 0 0 2 | 6.17895 0.55914 0 0 0 0 3 | 6.15789 0.924731 0 0 0 0 4 | 6.17895 1.5914 0 0 0 0 5 | 6.22105 2.04301 0 0 0 0 6 | 6.28421 2.43011 0 0 0 0 7 | 6.32632 2.47312 0 0 0 0 8 | 6.51579 2.34409 0 0 0 0 9 | 6.57895 2.36559 0 0 0 0 10 | 6.74737 2.45161 0 0 0 0 11 | 6.97895 2.66667 0 0 0 0 12 | 7.06316 2.94624 0 0 0 0 13 | 7.14737 3.24731 0 0 0 0 14 | 7.23158 3.5914 0 0 0 0 15 | 7.29474 3.87097 0 0 0 0 16 | 7.33684 4.25806 0 0 0 0 17 | 7.42105 4.7957 0 0 0 0 18 | 7.50526 5.50538 0 0 0 0 19 | 7.54737 6.15054 0 0 0 0 20 | 7.58947 6.7957 0 0 0 0 21 | 7.63158 7.33333 0 0 0 0 22 | 7.65263 7.65591 0 0 0 0 23 | 7.69474 8 0 0 0 0 24 | 7.73684 8.8172 0 0 0 0 25 | 7.75789 9.22581 0 0 0 0 26 | 7.8 9.5914 0 0 0 0 27 | 7.84211 9.97849 0 0 0 0 28 | 7.98947 9.5914 0 0 0 0 29 | 8.07368 9.26882 0 0 0 0 30 | 8.26316 8.88172 0 0 0 0 31 | 8.49474 8.53763 0 0 0 0 32 | 8.6 8.47312 0 0 0 0 33 | 8.74737 8.58065 0 0 0 0 34 | 8.87368 8.62366 0 0 0 0 35 | 9.04211 8.53763 0 0 0 0 36 | 9.14737 8.15054 0 0 0 0 37 | 9.23158 7.87097 0 0 0 0 38 | 9.31579 7.65591 0 0 0 0 39 | 9.42105 7.22581 0 0 0 0 40 | 9.48421 6.90323 0 0 0 0 41 | 9.58947 6.36559 0 0 0 0 42 | 9.67368 5.87097 0 0 0 0 43 | 9.73684 5.52688 0 0 0 0 44 | -------------------------------------------------------------------------------- /sphinx/example/create_workflow.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "These examples show how to create GW-BSE workflow using $py$GWBSE\n", 8 | "package. We will show how to compute QP bandstructure for wurtzite-AlN\n", 9 | "at the partial self-consistent (GW$_0$) level by obtaining input \n", 10 | "structure from Material Project (MP) database. We will also compute the \n", 11 | "absorption spectra of wurtzite-AlN by solving Bethe-Salpeter equation (BSE)." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 1, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "#First let's load the required libraries such as pymatgen and Fireworks\n", 21 | "import sys\n", 22 | "from pyGWBSE.make_wflow import read_input, create_wfs\n", 23 | "from fireworks import LaunchPad\n", 24 | "from pymatgen.ext.matproj import MPRester\n", 25 | "from pymatgen import Structure" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 9, 31 | "metadata": { 32 | "scrolled": false 33 | }, 34 | "outputs": [ 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "PARAMS:\r\n", 40 | " kpar: 8 \r\n", 41 | " # 'KPAR' tag to be used in VASP simulations\r\n", 42 | " \r\n", 43 | " ppn: 13 \r\n", 44 | " # NPROCS/KPAR ; NPROCS: number of total processors to be used in VASP simulations \r\n", 45 | " \r\n", 46 | " reciprocal_density: 200 \r\n", 47 | " # reciprocal density that determines the k-grid using 'automatic_density_by_vol' method of pymatgen\r\n", 48 | " \r\n", 49 | " encutgw: 100 \r\n", 50 | " # ENCUTGW to be used in VASP simulations\r\n", 51 | " \r\n", 52 | " nbgwfactor: 3 \r\n", 53 | " # NBANDS=nbgwfactor x nocc'; nocc' is the smallest multiple of ppn which is larger than number of occupied bands\r\n", 54 | " \r\n", 55 | " nomegagw: 80 \r\n", 56 | " # NOMEGAGW to be used in VASP simulations\r\n", 57 | " \r\n", 58 | " convparam: NBANDS \r\n", 59 | " # NBANDS/ENCUTGW/NOMEGA parameter to run convergence test for \r\n", 60 | " \r\n", 61 | " convsteps: 2 \r\n", 62 | " # steps to be used for convergence test\r\n", 63 | " \r\n", 64 | " conviter: 5 \r\n", 65 | " # maximum number of iteration in convergence test \r\n", 66 | " \r\n", 67 | " enwinbse: 3.0 \r\n", 68 | " # energy window in BSE calculations\r\n", 69 | "\r\n", 70 | "\r\n", 71 | "\r\n", 72 | "STRUCTURE:\r\n", 73 | " \r\n", 74 | " source: MID \r\n", 75 | " # MID/POSCAR MID:get structure from MP database, POSCAR: structure from a file \r\n", 76 | " \r\n", 77 | " mat_name: NEW_MAT \r\n", 78 | " # unique identifier in the database when source=POSCAR\r\n", 79 | " \r\n", 80 | " material_id: mp-661 \r\n", 81 | " # material_id of the input structure in MP database\r\n", 82 | " \r\n", 83 | " \r\n", 84 | " \r\n", 85 | "WFLOW_DESIGN:\r\n", 86 | " \r\n", 87 | " skip_emc: false \r\n", 88 | " # set true to skip effective mass calculation \r\n", 89 | " \r\n", 90 | " skip_wannier: false \r\n", 91 | " # set true to skip wannier bandstructure interpolation\r\n", 92 | " \r\n", 93 | " skip_conv: false \r\n", 94 | " # set true to skip convergence test\r\n", 95 | " \r\n", 96 | " skip_gw: false \r\n", 97 | " # set true to skip GW calculation\r\n", 98 | " \r\n", 99 | " scgw: true \r\n", 100 | " # set true to perform self-consistent GW instead of G0W0\r\n", 101 | " \r\n", 102 | " skip_bse: false \r\n", 103 | " # set true to skip BSE calculation\r\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "#Now let's check the content of the 'input.yaml' file.\n", 109 | "!cat 'input.yaml'" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 3, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "\"\"\"\n", 119 | " 'read_input' function reads input parameters from input.yaml file.\n", 120 | " \n", 121 | " Returns:\n", 122 | " \n", 123 | " structure: pymatgen structure object for the input structure\n", 124 | " input_dict: a dictionary of all the input paramters\n", 125 | " \n", 126 | "\"\"\"\n", 127 | "\n", 128 | "structure, input_dict = read_input()" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 4, 134 | "metadata": { 135 | "scrolled": true 136 | }, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "-------------------------------------------\n", 143 | "material: mp-661\n", 144 | "Information for efficient parallelization\n", 145 | "You have 8 occupied bands\n", 146 | "You have 76 kpoints\n", 147 | "You have [[12, 12, 7]] k-grid\n", 148 | "Will perform convergence test for: NBANDS\n", 149 | "Values that will be used for convergence test: 39 65 91 117 143 \n", 150 | "KPAR= 8\n", 151 | "reciprocal_density= 200\n", 152 | "BSE calculation will include bands in the energy window (eV)= 3.0\n", 153 | "-------------------------------------------\n" 154 | ] 155 | }, 156 | { 157 | "name": "stderr", 158 | "output_type": "stream", 159 | "text": [ 160 | "/home/tatha/anaconda3/envs/cms/lib/python3.6/site-packages/pymatgen/io/vasp/sets.py:447: BadInputSetWarning:\n", 161 | "\n", 162 | "Overriding the POTCAR functional is generally not recommended as it significantly affect the results of calculations and compatibility with other calculations done with the same input set. Note that some POTCAR symbols specified in the configuration file may not be available in the selected functional.\n", 163 | "\n" 164 | ] 165 | } 166 | ], 167 | "source": [ 168 | "\"\"\"\n", 169 | " 'create_wfs' function creates the GW-BSE workflow based on input specification.\n", 170 | " \n", 171 | " Args:\n", 172 | " \n", 173 | " structure: pymatgen structure object for the input structure\n", 174 | " input_dict: a dictionary of all the input paramters\n", 175 | " \n", 176 | " Returns:\n", 177 | " \n", 178 | " wf_gwbse: GW-BSE workflow as a Fireworks workflow object.\n", 179 | " \n", 180 | "\"\"\"\n", 181 | "\n", 182 | "wf_gwbse=create_wfs(structure, input_dict)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "The error message \"Overriding the POTCAR functional is generally not ...\" is due to changing default POTCAR symbols to GW POTCAR files. One can choose other POTCARs by modifying inputset.yaml file. " 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 5, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "#Load the Fireworks Launchpad \n", 199 | "lpad = LaunchPad.auto_load() " 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 6, 205 | "metadata": {}, 206 | "outputs": [ 207 | { 208 | "name": "stdout", 209 | "output_type": "stream", 210 | "text": [ 211 | "2022-09-14 14:27:54,737 INFO Added a workflow. id_map: {-7: 1, -6: 2, -5: 3, -4: 4, -3: 5, -2: 6, -1: 7}\n" 212 | ] 213 | }, 214 | { 215 | "data": { 216 | "text/plain": [ 217 | "{-7: 1, -6: 2, -5: 3, -4: 4, -3: 5, -2: 6, -1: 7}" 218 | ] 219 | }, 220 | "execution_count": 6, 221 | "metadata": {}, 222 | "output_type": "execute_result" 223 | } 224 | ], 225 | "source": [ 226 | "#Add the workflow you just created\n", 227 | "lpad.add_wf(wf_gwbse)" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 7, 233 | "metadata": { 234 | "scrolled": false 235 | }, 236 | "outputs": [ 237 | { 238 | "name": "stdout", 239 | "output_type": "stream", 240 | "text": [ 241 | "/home/tatha/anaconda3/envs/cms/lib/python3.6/site-packages/pymatgen/io/vasp/sets.py:447: BadInputSetWarning:\n", 242 | "\n", 243 | "Overriding the POTCAR functional is generally not recommended as it significantly affect the results of calculations and compatibility with other calculations done with the same input set. Note that some POTCAR symbols specified in the configuration file may not be available in the selected functional.\n", 244 | "\n", 245 | "[\n", 246 | " {\n", 247 | " \"fw_id\": 1,\n", 248 | " \"created_on\": \"2022-09-14T21:27:54.144377\",\n", 249 | " \"updated_on\": \"2022-09-14T21:27:54.144378\",\n", 250 | " \"state\": \"PAUSED\",\n", 251 | " \"name\": \"mp-661-BSE\"\n", 252 | " },\n", 253 | " {\n", 254 | " \"fw_id\": 2,\n", 255 | " \"created_on\": \"2022-09-14T21:27:54.144357\",\n", 256 | " \"updated_on\": \"2022-09-14T21:27:54.144358\",\n", 257 | " \"name\": \"mp-661-WANNIER\",\n", 258 | " \"state\": \"WAITING\"\n", 259 | " },\n", 260 | " {\n", 261 | " \"fw_id\": 3,\n", 262 | " \"created_on\": \"2022-09-14T21:27:54.144341\",\n", 263 | " \"updated_on\": \"2022-09-14T21:27:54.144341\",\n", 264 | " \"name\": \"mp-661-GW\",\n", 265 | " \"state\": \"WAITING\"\n", 266 | " },\n", 267 | " {\n", 268 | " \"fw_id\": 4,\n", 269 | " \"created_on\": \"2022-09-14T21:27:54.144271\",\n", 270 | " \"updated_on\": \"2022-09-14T21:27:54.144272\",\n", 271 | " \"name\": \"mp-661-CONV\",\n", 272 | " \"state\": \"WAITING\"\n", 273 | " },\n", 274 | " {\n", 275 | " \"fw_id\": 5,\n", 276 | " \"created_on\": \"2022-09-14T21:27:54.141887\",\n", 277 | " \"updated_on\": \"2022-09-14T21:27:54.141888\",\n", 278 | " \"name\": \"mp-661-WANNIER_CHECK\",\n", 279 | " \"state\": \"WAITING\"\n", 280 | " },\n", 281 | " {\n", 282 | " \"fw_id\": 6,\n", 283 | " \"created_on\": \"2022-09-14T21:27:54.141655\",\n", 284 | " \"updated_on\": \"2022-09-14T21:27:54.141656\",\n", 285 | " \"name\": \"mp-661-EMC\",\n", 286 | " \"state\": \"WAITING\"\n", 287 | " },\n", 288 | " {\n", 289 | " \"fw_id\": 7,\n", 290 | " \"created_on\": \"2022-09-14T21:27:54.141378\",\n", 291 | " \"updated_on\": \"2022-09-14T21:27:54.531247\",\n", 292 | " \"state\": \"READY\",\n", 293 | " \"name\": \"mp-661-SCF\"\n", 294 | " }\n", 295 | "]\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "#Check the Fireworks loaded to the Launchpad\n", 301 | "lp='lpad get_fws'\n", 302 | "!{lp}" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": {}, 308 | "source": [ 309 | "As you can see there are 7 fireworks with prefix `mp-661` were loaded to the Launchpad. \n", 310 | "Also one should note that the BSE Firework is in a `PAUSED` state by default. This is \n", 311 | "because, the k-point parallelization is not implemented for BSE calculation in VASP. \n", 312 | "Therefore, to make the number of bands in the WAVEDER file a multiple of number of \n", 313 | "processor used (requirement for VASP, otherwise it will change the NBANDS value) we \n", 314 | "need to run the BSE workflow on NPROCS=NPROCS$'$/KPAR, where NPROCS$'$ is the number \n", 315 | "of processors used for the `fw_id: 2-7`. Now that we have all the Fireworks in the \n", 316 | "Launchpad we can run them and use the postprocessing scripts to analyze the results once \n", 317 | "they are `COMPLETED`." 318 | ] 319 | } 320 | ], 321 | "metadata": { 322 | "kernelspec": { 323 | "display_name": "cms", 324 | "language": "python", 325 | "name": "cms" 326 | }, 327 | "language_info": { 328 | "codemirror_mode": { 329 | "name": "ipython", 330 | "version": 3 331 | }, 332 | "file_extension": ".py", 333 | "mimetype": "text/x-python", 334 | "name": "python", 335 | "nbconvert_exporter": "python", 336 | "pygments_lexer": "ipython3", 337 | "version": "3.6.13" 338 | } 339 | }, 340 | "nbformat": 4, 341 | "nbformat_minor": 4 342 | } 343 | -------------------------------------------------------------------------------- /sphinx/example/input.yaml: -------------------------------------------------------------------------------- 1 | PARAMS: 2 | kpar: 8 3 | # 'KPAR' tag to be used in VASP simulations 4 | 5 | ppn: 13 6 | # NPROCS/KPAR ; NPROCS: number of total processors to be used in VASP simulations 7 | 8 | reciprocal_density: 200 9 | # reciprocal density that determines the k-grid using 'automatic_density_by_vol' method of pymatgen 10 | 11 | encutgw: 100 12 | # ENCUTGW to be used in VASP simulations 13 | 14 | nbgwfactor: 5 15 | # NBANDS=nbgwfactor x nocc'; nocc' is the smallest multiple of ppn which is larger than number of occupied bands 16 | 17 | nomegagw: 80 18 | # NOMEGAGW to be used in VASP simulations 19 | 20 | convparam: NBANDS 21 | # NBANDS/ENCUTGW/NOMEGA parameter to run convergence test for 22 | 23 | convsteps: 2 24 | # steps to be used for convergence test 25 | 26 | conviter: 5 27 | # maximum number of iteration in convergence test 28 | 29 | enwinbse: 3.0 30 | # energy window in BSE calculations 31 | 32 | 33 | 34 | STRUCTURE: 35 | 36 | source: MID 37 | # MID/POSCAR MID:get structure from MP database, POSCAR: structure from a file 38 | 39 | mat_name: NEW_MAT 40 | # unique identifier in the database when source=POSCAR 41 | 42 | material_id: mp-661 43 | # material_id of the input structure in MP database 44 | 45 | 46 | 47 | WFLOW_DESIGN: 48 | 49 | skip_emc: false 50 | # set true to skip effective mass calculation 51 | 52 | skip_wannier: false 53 | # set true to skip wannier bandstructure interpolation 54 | 55 | skip_conv: false 56 | # set true to skip convergence test 57 | 58 | skip_gw: false 59 | # set true to skip GW calculation 60 | 61 | scgw: true 62 | # set true to perform self-consistent GW instead of G0W0 63 | 64 | skip_bse: false 65 | # set true to skip BSE calculation 66 | -------------------------------------------------------------------------------- /sphinx/index.rst: -------------------------------------------------------------------------------- 1 | .. WFGWBSE documentation master file, created by 2 | sphinx-quickstart on Fri Aug 6 11:21:48 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to WFGWBSE's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | rst/modules 14 | 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /sphinx/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/config.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Tathagata Biswas ' 2 | 3 | # TODO: @computron should be able to load from YAML -computron 4 | 5 | VASP_CMD = ">>vasp_cmd<<" 6 | SUMO_CMD = ">>sumo_cmd<<" 7 | WANNIER_CMD = ">>wannier_cmd<<" 8 | DB_FILE = ">>db_file<<" 9 | 10 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/inputset.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # Copyright (c) Pymatgen Development Team. 3 | # Distributed under the terms of the MIT License. 4 | 5 | import os 6 | 7 | from monty.serialization import loadfn 8 | from pymatgen.io.vasp.inputs import Incar, Kpoints 9 | from pymatgen.io.vasp.sets import DictSet 10 | from pymatgen.symmetry.bandstructure import HighSymmKpath 11 | 12 | MODULE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | 14 | class CreateInputs(DictSet): 15 | """ 16 | Your Comments Here 17 | """ 18 | CONFIG = loadfn(os.path.join(MODULE_DIR, "inputset.yaml")) 19 | 20 | SUPPORTED_MODES = ("DIAG", "GW", "STATIC", "BSE", "CONV", "EMC") 21 | 22 | def __init__(self, structure, prev_incar=None, nbands=None, nomegagw=None, encutgw=None, 23 | potcar_functional="PBE_54", reciprocal_density=100, kpoints_line_density = 100, kpar=None, nbandsgw=None, 24 | mode="STATIC", copy_wavecar=True, nbands_factor=5, ncores=16,nbandso=None, nbandsv=None, wannier_fw=None, 25 | **kwargs): 26 | super().__init__(structure, CreateInputs.CONFIG, **kwargs) 27 | self.prev_incar = prev_incar 28 | self.nbands = nbands 29 | self.encutgw = encutgw 30 | self.nomegagw = nomegagw 31 | self.potcar_functional = potcar_functional 32 | self.reciprocal_density = reciprocal_density 33 | self.kpoints_line_density = kpoints_line_density 34 | self.mode = mode.upper() 35 | if self.mode not in CreateInputs.SUPPORTED_MODES: 36 | raise ValueError("%s not one of the support modes : %s" % 37 | (self.mode, CreateInputs.SUPPORTED_MODES)) 38 | self.kwargs = kwargs 39 | self.copy_wavecar = copy_wavecar 40 | self.nbands_factor = nbands_factor 41 | self.ncores = ncores 42 | self.kpar = kpar 43 | self.nbandsgw = nbandsgw 44 | self.nbandso = nbandso 45 | self.nbandsv = nbandsv 46 | self.wannier_fw = wannier_fw 47 | 48 | @property 49 | def kpoints(self): 50 | """ 51 | Generate gamma center k-points mesh grid for GW calc, 52 | which is requested by GW calculation. 53 | """ 54 | if self.mode == "EMC": 55 | kpath = HighSymmKpath(self.structure) 56 | frac_k_points, k_points_labels = kpath.get_kpoints( 57 | line_density=self.kpoints_line_density, 58 | coords_are_cartesian=False) 59 | kpoints = Kpoints( 60 | comment="Non SCF run along symmetry lines", 61 | style=Kpoints.supported_modes.Reciprocal, 62 | num_kpts=len(frac_k_points), 63 | kpts=frac_k_points, labels=k_points_labels, 64 | kpts_weights=[1] * len(frac_k_points)) 65 | 66 | return kpoints 67 | 68 | else: 69 | 70 | kpoints=Kpoints.automatic_density_by_vol(self.structure, 71 | self.reciprocal_density, force_gamma=True) 72 | 73 | return kpoints 74 | 75 | @property 76 | def incar(self): 77 | """ 78 | Your Comments Here 79 | """ 80 | parent_incar = super().incar 81 | incar = Incar(self.prev_incar) if self.prev_incar is not None else \ 82 | Incar(parent_incar) 83 | if self.wannier_fw == True: 84 | incar.update({ 85 | "LWANNIER90": True 86 | }) 87 | if self.mode == "EMC": 88 | incar.update({ 89 | "IBRION": -1, 90 | "ISMEAR": 0, 91 | "SIGMA": 0.001, 92 | "LCHARG": False, 93 | "LORBIT": 11, 94 | "LWAVE": False, 95 | "NSW": 0, 96 | "ISYM": 0, 97 | "ICHARG": 11 98 | }) 99 | incar.pop("LWANNIER90", None) 100 | incar.pop("LEPSILON", None) 101 | if self.mode == "DIAG": 102 | # Default parameters for diagonalization calculation. 103 | incar.update({ 104 | "ALGO": "Exact", 105 | "NELM": 1, 106 | "LOPTICS": True, 107 | "LPEAD": True 108 | }) 109 | incar.pop("LEPSILON", None) 110 | incar.pop("LWANNIER90", None) 111 | elif self.mode == "GW": 112 | # Default parameters for GW calculation. 113 | incar.update({ 114 | "ALGO": "GW", 115 | "NELM": 1, 116 | "NOMEGA": self.nomegagw, 117 | "ENCUTGW": self.encutgw, 118 | "NBANDSGW": self.nbandsgw, 119 | "LWAVE": True 120 | }) 121 | if self.wannier_fw == True: 122 | incar.update({ 123 | "LWANNIER90": True 124 | }) 125 | incar.pop("EDIFF", None) 126 | incar.pop("LOPTICS", None) 127 | incar.pop("LPEAD", None) 128 | incar.pop("LEPSILON", None) 129 | elif self.mode == "CONV": 130 | # Default parameters for GW calculation. 131 | incar.update({ 132 | "ALGO": "GW0", 133 | "NELM": 1, 134 | "NOMEGA": self.nomegagw, 135 | "ENCUTGW": self.encutgw, 136 | "NBANDSGW": self.nbandsgw, 137 | "LWAVE": False 138 | }) 139 | incar.pop("EDIFF", None) 140 | incar.pop("LOPTICS", None) 141 | incar.pop("LEPSILON", None) 142 | incar.pop("LPEAD", None) 143 | incar.pop("LWANNIER90", None) 144 | elif self.mode == "BSE": 145 | # Default parameters for BSE calculation. 146 | incar.update({ 147 | "ALGO": "BSE", 148 | "ANTIRES": 0, 149 | "NBANDSO": self.nbandso, 150 | "NBANDSV": self.nbandsv, 151 | "KPAR": 1, 152 | "CSHIFT": 0.2 153 | }) 154 | incar.pop("LEPSILON", None) 155 | incar.pop("LWANNIER90", None) 156 | if self.nbands: 157 | incar["NBANDS"] = self.nbands 158 | 159 | if self.kpar: 160 | incar["KPAR"] = self.kpar 161 | 162 | rd=self.reciprocal_density 163 | 164 | incar["SYSTEM"] = 'reciprocal density: '+str(rd) 165 | 166 | # Respect user set INCAR. 167 | incar.update(self.kwargs.get("user_incar_settings", {})) 168 | 169 | return incar 170 | 171 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/inputset.yaml: -------------------------------------------------------------------------------- 1 | # Default VASP settings for GW calculations used by the Materials Virtual Lab. 2 | INCAR: 3 | ALGO: Normal 4 | ENCUT: 500 5 | EDIFF: 1.0e-8 6 | ISMEAR: 0 7 | LREAL: AUTO 8 | ISPIN: 1 9 | LWAVE: true 10 | NELM: 100 11 | PREC: Accurate 12 | SIGMA: 0.01 13 | LEPSILON: true 14 | LVHAR: false 15 | LOPTICS: true 16 | LPEAD: false 17 | LORBIT: 11 18 | KPOINTS: 19 | reciprocal_density: 100 20 | POTCAR: 21 | Ac: Ac 22 | Ag: Ag_sv_GW 23 | Al: Al_GW 24 | Ar: Ar_GW 25 | As: As_GW 26 | At: At_d_GW 27 | Au: Au_sv_GW 28 | B: B_GW 29 | Ba: Ba_sv_GW 30 | Be: Be_sv_GW 31 | Bi: Bi_d_GW 32 | Br: Br_GW 33 | C: C_GW 34 | Ca: Ca_sv_GW 35 | Cd: Cd_sv_GW 36 | Ce: Ce_GW 37 | Cl: Cl_GW 38 | Co: Co_sv_GW 39 | Cr: Cr_sv_GW 40 | Cs: Cs_sv_GW 41 | Cu: Cu_sv_GW 42 | Dy: Dy_3 43 | Er: Er_3 44 | Eu: Eu 45 | F: F_GW 46 | Fe: Fe_sv_GW 47 | Ga: Ga_d_GW 48 | Gd: Gd 49 | Ge: Ge_d_GW 50 | H: H_GW 51 | He: He_GW 52 | Hf: Hf_sv_GW 53 | Hg: Hg_sv_GW 54 | Ho: Ho_3 55 | I: I_GW 56 | In: In_d_GW 57 | Ir: Ir_sv_GW 58 | K: K_sv_GW 59 | Kr: Kr_GW 60 | La: La_GW 61 | Li: Li_sv_GW 62 | Lu: Lu_3 63 | Mg: Mg_sv_GW 64 | Mn: Mn_sv_GW 65 | Mo: Mo_sv_GW 66 | N: N_GW 67 | Na: Na_sv_GW 68 | Nb: Nb_sv_GW 69 | Nd: Nd_3 70 | Ne: Ne_GW 71 | Ni: Ni_sv_GW 72 | Np: Np 73 | O: O_GW 74 | Os: Os_sv_GW 75 | P: P_GW 76 | Pa: Pa 77 | Pb: Pb_d_GW 78 | Pd: Pd_sv_GW 79 | Pm: Pm_3 80 | Po: Po_d_GW 81 | Pr: Pr_3 82 | Pt: Pt_sv_GW 83 | Pu: Pu 84 | Rb: Rb_sv_GW 85 | Re: Re_sv_GW 86 | Rh: Rh_sv_GW 87 | Rn: Rn_d_GW 88 | Ru: Ru_sv_GW 89 | S: S_GW 90 | Sb: Sb_d_GW 91 | Sc: Sc_sv_GW 92 | Se: Se_GW 93 | Si: Si_GW 94 | Sm: Sm_3 95 | Sn: Sn_d_GW 96 | Sr: Sr_sv_GW 97 | Ta: Ta_sv_GW 98 | Tb: Tb_3 99 | Tc: Tc_sv_GW 100 | Te: Te_GW 101 | Th: Th 102 | Ti: Ti_sv_GW 103 | Tl: Tl_d_GW 104 | Tm: Tm_3 105 | U: U 106 | V: V_sv_GW 107 | W: W_sv_GW 108 | Xe: Xe_GW 109 | Y: Y_sv_GW 110 | Yb: Yb_2 111 | Zn: Zn_sv_GW 112 | Zr: Zr_sv_GW 113 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/make_wflow.py: -------------------------------------------------------------------------------- 1 | #This code is to create the workflow based on inputs from input.yaml file 2 | 3 | from fireworks import Firework, Workflow 4 | from pyGWBSE.wflows import ScfFW, convFW, BseFW, GwFW, EmcFW, WannierCheckFW, WannierFW 5 | from pyGWBSE.inputset import CreateInputs 6 | from pymatgen import Structure 7 | from fireworks import LaunchPad 8 | from pyGWBSE.config import VASP_CMD, DB_FILE, SUMO_CMD, WANNIER_CMD 9 | from pymatgen.symmetry.analyzer import SpacegroupAnalyzer 10 | from pymatgen.io.vasp.inputs import Kpoints 11 | from pymatgen.ext.matproj import MPRester 12 | import numpy as np 13 | from pymongo import MongoClient 14 | import yaml 15 | import sys 16 | 17 | 18 | #Function to find the kgrid and number of symmtery reduced kpoints based on symmetry of the structure and the reciprocal density 19 | def num_ir_kpts(struct,reciprocal_density): 20 | spg=SpacegroupAnalyzer(struct, symprec=0.01, angle_tolerance=5) 21 | Kpts=Kpoints.automatic_density_by_vol(struct,reciprocal_density,force_gamma=True) 22 | kpts=spg.get_ir_reciprocal_mesh(mesh=Kpts.kpts, is_shift=(0, 0, 0)) 23 | return Kpts.kpts,len(kpts) 24 | 25 | 26 | #Function to find the number of occupied bands from the input structure 27 | def num_occ_bands(struct): 28 | vasp_input_set = CreateInputs(struct) 29 | nel=vasp_input_set.nelect 30 | nocc=int(nel/2) 31 | return nocc 32 | 33 | 34 | #Function to read the input.yaml file 35 | def read_input(): 36 | yaml_file = open("input.yaml") 37 | input_dict = yaml.load(yaml_file, Loader=yaml.FullLoader) 38 | 39 | struc_src=input_dict["STRUCTURE"]["source"] 40 | if struc_src=='POSCAR': 41 | struct=Structure.from_file('POSCAR') 42 | mat_name=input_dict["STRUCTURE"]["mat_name"] 43 | elif struc_src=='MID': 44 | material_id=input_dict["STRUCTURE"]["material_id"] 45 | mat_name=material_id 46 | with MPRester("b62Ts1xuKP9ahZmX") as m: 47 | struct = m.get_structure_by_material_id(material_id,conventional_unit_cell=False) 48 | else: 49 | sys.exit('Error: use MID/POSCAR as structure source .... Exiting NOW') 50 | input_dict["PARAMS"]["mat_name"]=mat_name 51 | return struct, input_dict 52 | 53 | #Function to create the workflow 54 | def create_wfs(struct, params_dict, vasp_cmd=None, sumo_cmd=None, wannier_cmd=None, db_file=None, c=None): 55 | 56 | c = c or {} 57 | vasp_cmd = c.get("VASP_CMD", VASP_CMD) 58 | sumo_cmd = c.get("SUMO_CMD", SUMO_CMD) 59 | wannier_cmd = c.get("WANNIER_CMD", WANNIER_CMD) 60 | db_file = c.get("DB_FILE", DB_FILE) 61 | 62 | params=params_dict["PARAMS"] 63 | mat_name=params["mat_name"] 64 | nocc=num_occ_bands(struct) 65 | kpar=params["kpar"] 66 | ppn=params["ppn"] 67 | rd=params["reciprocal_density"] 68 | nbgwfactor=params["nbgwfactor"] 69 | encutgw=params["encutgw"] 70 | nomegagw=params["nomegagw"] 71 | convparam=params["convparam"] 72 | convsteps=params["convsteps"] 73 | conviter=params["conviter"] 74 | enwinbse=params["enwinbse"] 75 | skip_emc=params_dict["WFLOW_DESIGN"]["skip_emc"] 76 | skip_wannier=params_dict["WFLOW_DESIGN"]["skip_wannier"] 77 | skip_conv=params_dict["WFLOW_DESIGN"]["skip_conv"] 78 | skip_gw=params_dict["WFLOW_DESIGN"]["skip_gw"] 79 | scgw=params_dict["WFLOW_DESIGN"]["scgw"] 80 | skip_bse=params_dict["WFLOW_DESIGN"]["skip_bse"] 81 | 82 | mesh,nkpt=num_ir_kpts(struct,rd) 83 | nbands=(int(nocc/ppn)+1)*ppn 84 | nbandsgw=nocc+10 85 | 86 | print("-------------------------------------------") 87 | print("material: ",mat_name) 88 | print("Information for efficient parallelization") 89 | print("You have ",nocc,"occupied bands") 90 | print("You have ",nkpt,"kpoints") 91 | print("You have ",mesh,"k-grid") 92 | if not(skip_conv): 93 | print("Will perform convergence test for: ",convparam) 94 | print("Values that will be used for convergence test: ",end='') 95 | if convparam=='NOMEGA': 96 | initparam=nomegagw 97 | if convparam=='NBANDS': 98 | initparam=nbgwfactor 99 | if convparam=='ENCUTGW': 100 | initparam=encutgw 101 | for citer in range(conviter): 102 | if convparam=='NBANDS': 103 | print(nbands*(initparam+citer*convsteps),end=' ') 104 | else: 105 | print(initparam+citer*convsteps,end=' ') 106 | print( ) 107 | print("KPAR=",kpar) 108 | print("reciprocal_density=",rd) 109 | if not(skip_bse): 110 | print("BSE calculation will include bands in the energy window (eV)=", enwinbse) 111 | print("-------------------------------------------") 112 | 113 | if scgw==True: 114 | gw_tag='GW0' 115 | else: 116 | gw_tag='G0W0' 117 | 118 | ifw=0 119 | 120 | fws = [ScfFW(structure=struct, mat_name=mat_name, nbands=nbands, vasp_cmd=vasp_cmd,db_file=db_file,kpar=kpar,reciprocal_density=rd,wannier_fw=not(skip_wannier))] 121 | 122 | if skip_emc==False: 123 | ifw=ifw+1 124 | parents = fws[0] 125 | fw = EmcFW(structure=struct, mat_name=mat_name, vasp_cmd=vasp_cmd, sumo_cmd=sumo_cmd, db_file=db_file,kpar=kpar,reciprocal_density=rd, steps=0.001,parents=parents) 126 | fws.append(fw) 127 | 128 | if skip_wannier==False: 129 | ifw=ifw+1 130 | parents = fws[0] 131 | fw = WannierCheckFW(structure=struct, mat_name=mat_name, kpar=kpar, ppn=ppn,vasp_cmd=vasp_cmd,wannier_cmd=wannier_cmd,db_file=db_file,parents=parents,reciprocal_density=rd) 132 | fws.append(fw) 133 | 134 | ifw=ifw+1 135 | parents = fws[0] 136 | fw = convFW(structure=struct, mat_name=mat_name, nbands=nbands, nbgwfactor=nbgwfactor, encutgw=encutgw, nomegagw=nomegagw, convparam=convparam, convsteps=convsteps, conviter=conviter, 137 | tolerence=0.1, no_conv=skip_conv, vasp_cmd=vasp_cmd,db_file=db_file,parents=parents,kpar=kpar,nbandsgw=nbandsgw,reciprocal_density=rd) 138 | fws.append(fw) 139 | 140 | if skip_gw==False: 141 | ifw=ifw+1 142 | parents = fws[ifw-1] 143 | fw = GwFW(structure=struct, mat_name=mat_name, tolerence=0.1, no_conv=not(scgw), 144 | vasp_cmd=vasp_cmd,db_file=db_file,parents=parents,reciprocal_density=rd, nbandsgw=nbandsgw, wannier_fw=not(skip_wannier), job_tag=gw_tag) 145 | fws.append(fw) 146 | 147 | if skip_wannier==False and skip_gw==False: 148 | ifw=ifw+1 149 | parents = fws[ifw-1] 150 | fw = WannierFW(structure=struct,mat_name=mat_name, wannier_cmd=wannier_cmd,db_file=db_file,parents=parents) 151 | fws.append(fw) 152 | 153 | if skip_bse==False and skip_gw==True: 154 | sys.exit('Error: Need QP energies from GW calculation to perform BSE .... Exiting NOW') 155 | 156 | if skip_bse==False and skip_gw==False: 157 | ifw=ifw+1 158 | if skip_wannier==False: 159 | parents = fws[ifw-2] 160 | else: 161 | parents = fws[ifw-1] 162 | fw = BseFW(structure=struct, mat_name=mat_name, 163 | vasp_cmd=vasp_cmd,db_file=db_file,parents=parents,reciprocal_density=rd,enwinbse=enwinbse, job_tag=gw_tag+'-BSE') 164 | fws.append(fw) 165 | 166 | 167 | wf_gwbse = Workflow(fws) 168 | 169 | return wf_gwbse 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/out2db.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import glob 4 | import os 5 | 6 | from atomate.utils.utils import env_chk 7 | from atomate.vasp.database import VaspCalcDb 8 | from fireworks import explicit_serialize, FiretaskBase, FWAction 9 | from monty.json import jsanitize 10 | from pymatgen.io.vasp.outputs import Vasprun, Outcar 11 | 12 | from pyGWBSE.tasks import read_emcpyout, read_epsilon, get_gap_from_dict, read_vac_level 13 | from pyGWBSE.wannier_tasks import read_vbm, read_wannier, read_vasp, read_special_kpts 14 | 15 | 16 | @explicit_serialize 17 | class gw2db(FiretaskBase): 18 | """ 19 | Insert quasi-particle energies into the database for a GW calculation. 20 | """ 21 | required_params = ["structure", "task_label", "db_file", "mat_name"] 22 | optional_params = ["job_tag"] 23 | 24 | def run_task(self, fw_spec): 25 | """ 26 | Your Comments Here 27 | """ 28 | # get adddtional tags to parse the directory for 29 | db_file = env_chk(self.get('db_file'), fw_spec) 30 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 31 | ifconv = fw_spec["ifconv"] 32 | structure = self["structure"] 33 | task_label = self["task_label"] 34 | if "job_tag" in self: 35 | job_tag = self["job_tag"] 36 | else: 37 | job_tag = None 38 | mat_name = self["mat_name"] 39 | task_collection = 'QP_Results' 40 | dir_name = os.getcwd() 41 | file = glob.glob('vasprun.xml*')[-1] 42 | vasprun = Vasprun(file) 43 | file = glob.glob('OUTCAR*')[-1] 44 | outcar = Outcar(file) 45 | run_stats=outcar.run_stats 46 | qp_energies = vasprun.eigenvalues 47 | en, eps1, eps2 = vasprun.dielectric 48 | igap, dgap = get_gap_from_dict(qp_energies) 49 | incar = vasprun.incar 50 | parameters = vasprun.parameters 51 | bgap, cbm, vbm, is_band_gap_direct = vasprun.eigenvalue_band_properties 52 | kpts_dict = vasprun.kpoints.as_dict() 53 | # dictionary to update the database with 54 | d = {"structure": structure.as_dict(), 55 | "formula_pretty": structure.composition.reduced_formula, 56 | "material_id": mat_name, "run_stats": run_stats, 57 | "run_directory": dir_name, 'direct_gap': dgap, 'indirect_gap': igap, 58 | "qp_energies": qp_energies, "task_label": task_label, 59 | "frequency": en, "epsilon_1": eps1, "epsilon_2": eps2, 60 | "job_tag": job_tag, "ifconv": ifconv, "vbm": vbm, "cbm": cbm, 61 | "incar": incar, "parameters": parameters, "kpoints": kpts_dict} 62 | d = jsanitize(d) 63 | coll = mmdb.db[task_collection] 64 | coll.insert_one(d) 65 | 66 | return FWAction(update_spec={"gw_gaps": [igap, dgap]}) 67 | 68 | 69 | @explicit_serialize 70 | class bse2db(FiretaskBase): 71 | """ 72 | Insert exciton energies, oscillator strength and dielectric function into the database for a BSE calculation. 73 | """ 74 | required_params = ["structure", "task_label", "db_file", "mat_name"] 75 | optional_params = ["job_tag"] 76 | 77 | def run_task(self, fw_spec): 78 | """ 79 | Your Comments Here 80 | """ 81 | # get adddtional tags to parse the directory for 82 | db_file = env_chk(self.get('db_file'), fw_spec) 83 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 84 | structure = self["structure"] 85 | task_label = self["task_label"] 86 | job_tag = self["job_tag"] 87 | mat_name = self["mat_name"] 88 | igap = fw_spec["gw_gaps"][0] 89 | dgap = fw_spec["gw_gaps"][1] 90 | task_collection = 'BSE_Results' 91 | dir_name = os.getcwd() 92 | filename = glob.glob('vasprun.xml*')[-1] 93 | if "job_tag" in self: 94 | job_tag = self["job_tag"] 95 | else: 96 | job_tag = None 97 | with open(filename, "a") as file: 98 | file.write("") 99 | vasprun = Vasprun(filename) 100 | incar = vasprun.incar 101 | parameters = vasprun.parameters 102 | optical_transition = vasprun.optical_transition 103 | en, eps1, eps2 = vasprun.dielectric 104 | kpts_dict = vasprun.kpoints.as_dict() 105 | file = glob.glob('OUTCAR*')[-1] 106 | outcar = Outcar(file) 107 | run_stats=outcar.run_stats 108 | d = {"structure": structure.as_dict(), 109 | "formula_pretty": structure.composition.reduced_formula, 110 | "material_id": mat_name, "run_directory": dir_name, 111 | "frequency": en, "epsilon_1": eps1, "epsilon_2": eps2, 112 | 'direct_gap': dgap, 'indirect_gap': igap, "run_stats": run_stats, 113 | "optical_transition": optical_transition, "task_label": task_label, "job_tag": job_tag, 114 | "incar": incar, "parameters": parameters, "kpoints": kpts_dict} 115 | d = jsanitize(d) 116 | coll = mmdb.db[task_collection] 117 | coll.insert_one(d) 118 | 119 | @explicit_serialize 120 | class rpa2db(FiretaskBase): 121 | """ 122 | Insert exciton energies, oscillator strength and dielectric function into the database for a BSE calculation. 123 | """ 124 | required_params = ["structure", "task_label", "db_file", "mat_name"] 125 | 126 | def run_task(self, fw_spec): 127 | """ 128 | Your Comments Here 129 | """ 130 | # get adddtional tags to parse the directory for 131 | db_file = env_chk(self.get('db_file'), fw_spec) 132 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 133 | structure = self["structure"] 134 | task_label = self["task_label"] 135 | mat_name = self["mat_name"] 136 | task_collection = 'RPA_Results' 137 | dir_name = os.getcwd() 138 | filename = glob.glob('vasprun.xml*')[-1] 139 | vasprun = Vasprun(filename) 140 | incar = vasprun.incar 141 | parameters = vasprun.parameters 142 | dft_energies = vasprun.eigenvalues 143 | en, eps1, eps2 = vasprun.dielectric 144 | kpts_dict = vasprun.kpoints.as_dict() 145 | file = glob.glob('OUTCAR*')[-1] 146 | outcar = Outcar(file) 147 | run_stats=outcar.run_stats 148 | d = {"structure": structure.as_dict(), 149 | "formula_pretty": structure.composition.reduced_formula, 150 | "material_id": mat_name, "run_directory": dir_name, 151 | "dft_energies": dft_energies, "run_stats": run_stats, 152 | "frequency": en, "epsilon_1": eps1, "epsilon_2": eps2, "task_label": task_label, 153 | "incar": incar, "parameters": parameters, "kpoints": kpts_dict} 154 | d = jsanitize(d) 155 | coll = mmdb.db[task_collection] 156 | coll.insert_one(d) 157 | 158 | @explicit_serialize 159 | class emc2db(FiretaskBase): 160 | """ 161 | Insert effective masses for a SUMO-BANDSTATS calculation. 162 | """ 163 | required_params = ["structure", "db_file", "mat_name"] 164 | 165 | def run_task(self, fw_spec): 166 | """ 167 | Your Comments Here 168 | """ 169 | # get adddtional tags to parse the directory for 170 | db_file = env_chk(self.get('db_file'), fw_spec) 171 | dir_name = os.getcwd() 172 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 173 | structure = self["structure"] 174 | mat_name = self["mat_name"] 175 | task_collection = 'EMC_Results' 176 | filename = glob.glob('sumo-bandstats.log*')[-1] 177 | hmass, emass = read_emcpyout(filename) 178 | # dictionary to update the database with 179 | d = {"structure": structure.as_dict(), 180 | "formula_pretty": structure.composition.reduced_formula, 181 | "material_id": mat_name, "run_directory": dir_name, 182 | "hole_effective_mass": hmass, "electron_effective_mass": emass} 183 | d = jsanitize(d) 184 | coll = mmdb.db[task_collection] 185 | coll.insert_one(d) 186 | 187 | @explicit_serialize 188 | class eps2db(FiretaskBase): 189 | """ 190 | Insert macroscopic dielectric constants for LEPSILON=TRUE calculation. 191 | """ 192 | required_params = ["structure", "db_file", "mat_name"] 193 | 194 | def run_task(self, fw_spec): 195 | """ 196 | Your Comments Here 197 | """ 198 | # get additional tags to parse the directory for 199 | db_file = env_chk(self.get('db_file'), fw_spec) 200 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 201 | dir_name = os.getcwd() 202 | structure = self["structure"] 203 | mat_name = self["mat_name"] 204 | task_collection = 'EPS_Results' 205 | filename = glob.glob('vasprun.xml*')[-1] 206 | try: 207 | locpot_fname = glob.glob('LOCPOT*')[-1] 208 | zvac, evac, delta_evac=read_vac_level(locpot_fname, filename) 209 | ifvac=True 210 | except: 211 | ifvac=False 212 | epsilon = read_epsilon(filename) 213 | vrun = Vasprun(filename, parse_projected_eigen=True) 214 | ks_energies = vrun.eigenvalues 215 | proj_eigs=vrun.projected_eigenvalues 216 | kwgs=vrun.actual_kpoints_weights 217 | file = glob.glob('OUTCAR*')[-1] 218 | outcar = Outcar(file) 219 | run_stats=outcar.run_stats 220 | igap, dgap = get_gap_from_dict(ks_energies) 221 | bgap, cbm, vbm, is_band_gap_direct = vrun.eigenvalue_band_properties 222 | # dictionary to update the database with 223 | d = {"structure": structure.as_dict(), 224 | "formula_pretty": structure.composition.reduced_formula, 225 | "material_id": mat_name, "dielectric constant": epsilon, 226 | "run_stats": run_stats, "run_directory": dir_name, 227 | 'direct_gap': dgap, 'indirect_gap': igap, 228 | "kpoint_weights": kwgs, "cbm": cbm, "vbm": vbm, 229 | "projected_eigs": proj_eigs, "ks_energies": ks_energies} 230 | if ifvac: 231 | d.update({"z_vacuum": zvac, "e_vacuum": evac, "delta_e_vacuum": delta_evac}) 232 | d = jsanitize(d) 233 | coll = mmdb.db[task_collection] 234 | coll.insert_one(d) 235 | 236 | 237 | 238 | @explicit_serialize 239 | class Wannier2DB(FiretaskBase): 240 | """ 241 | Insert a optical transition and quasi-particle energies 242 | into the database for a GW and BSE calculation. 243 | 244 | Args: 245 | db_file (str): path to file containing the database credentials. 246 | Supports env_chk. Default: write data to JSON file. 247 | task_collection (str): The name of the task collection you 248 | want to push the data to. 249 | wf_name (str): The name of the workflow that this analysis is part of. 250 | """ 251 | 252 | required_params = ["structure", "task_label", "db_file", "compare_vasp", "mat_name"] 253 | 254 | def run_task(self, fw_spec): 255 | """ 256 | Your Comments Here 257 | """ 258 | # get adddtional tags to parse the directory for 259 | db_file = env_chk(self.get('db_file'), fw_spec) 260 | mmdb = VaspCalcDb.from_db_file(db_file, admin=True) 261 | structure = self["structure"] 262 | task_label = self["task_label"] 263 | compare_vasp = self["compare_vasp"] 264 | mat_name = self["mat_name"] 265 | task_collection = 'WANNIER_Results' 266 | dir_name = os.getcwd() 267 | fname_band = glob.glob('wannier90_band.dat*')[-1] 268 | fname_kpt = glob.glob('wannier90_band.kpt*')[-1] 269 | fname_gnu = glob.glob('wannier90_band.gnu*')[-1] 270 | fname_vasp = glob.glob('vasprun.xml*')[-1] 271 | gap, vbm = read_vbm(fname_vasp) 272 | kpts, eigs_wann = read_wannier(fname_band, fname_kpt, vbm) 273 | spkptl, spkptc = read_special_kpts(fname_gnu) 274 | if compare_vasp: 275 | kpt_vasp, eigs_vasp = read_vasp(fname_vasp, vbm) 276 | d = {"structure": structure.as_dict(), 277 | "formula_pretty": structure.composition.reduced_formula, 278 | "material_id": mat_name, 279 | "run_directory": dir_name, 280 | "wannier_kpoints": kpts, "wannier_eigenvalues": eigs_wann, 281 | "actual_kpoints": kpt_vasp, "actual_eigenvalues": eigs_vasp, 282 | "special_kpoint_labels": spkptl, 283 | "special_kpoint_coordinates": spkptc, 284 | "task_label": task_label} 285 | else: 286 | d = {"structure": structure.as_dict(), 287 | "formula_pretty": structure.composition.reduced_formula, 288 | "material_id": mat_name, 289 | "run_directory": dir_name, 290 | "wannier_kpoints": kpts, "wannier_eigenvalues": eigs_wann, 291 | "special_kpoint_labels": spkptl, 292 | "special_kpoint_coordinates": spkptc, 293 | "task_label": task_label} 294 | d = jsanitize(d) 295 | coll = mmdb.db[task_collection] 296 | coll.insert_one(d) 297 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/run_calc.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | This module defines tasks that support running vasp in various ways. 5 | """ 6 | 7 | import os 8 | import subprocess 9 | 10 | from atomate.utils.utils import env_chk, get_logger 11 | from fireworks import explicit_serialize, FiretaskBase 12 | 13 | __author__ = 'Anubhav Jain ' 14 | __credits__ = 'Shyue Ping Ong ' 15 | 16 | logger = get_logger(__name__) 17 | 18 | 19 | @explicit_serialize 20 | class Run_Vasp(FiretaskBase): 21 | """ 22 | Execute a command directly (no custodian). 23 | 24 | Args: 25 | cmd (str): the name of the full executable to run. Supports env_chk. 26 | 27 | Other Parameters: 28 | expand_vars (str): Set to true to expand variable names in the cmd. 29 | """ 30 | 31 | required_params = ["vasp_cmd"] 32 | optional_params = ["expand_vars"] 33 | 34 | def run_task(self, fw_spec): 35 | """ 36 | Your Comments Here 37 | """ 38 | cmd = env_chk(self["vasp_cmd"], fw_spec) 39 | if self.get("expand_vars", False): 40 | cmd = os.path.expandvars(cmd) 41 | 42 | logger.info("Running command: {}".format(cmd)) 43 | return_code = subprocess.call(cmd, shell=True) 44 | logger.info("Command {} finished running with returncode: {}".format(cmd, return_code)) 45 | 46 | 47 | @explicit_serialize 48 | class Run_Sumo(FiretaskBase): 49 | """ 50 | Your Comments Here 51 | """ 52 | required_params = ["sumo_cmd"] 53 | 54 | def run_task(self, fw_spec): 55 | """ 56 | Your Comments Here 57 | """ 58 | cmd = env_chk(self["sumo_cmd"], fw_spec) 59 | logger.info("Running command: {}".format(cmd)) 60 | return_code = subprocess.call(cmd, shell=True) 61 | logger.info("Command {} finished running with returncode: {}".format(cmd, return_code)) 62 | 63 | 64 | @explicit_serialize 65 | class Run_Wannier(FiretaskBase): 66 | """ 67 | Your Comments Here 68 | """ 69 | required_params = ["wannier_cmd"] 70 | 71 | def run_task(self, fw_spec): 72 | """ 73 | Your Comments Here 74 | """ 75 | cmd = env_chk(self["wannier_cmd"], fw_spec) 76 | logger.info("Running command: {}".format(cmd)) 77 | return_code = subprocess.call(cmd, shell=True) 78 | logger.info("Command {} finished running with returncode: {}".format(cmd, return_code)) 79 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/tasks.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import glob 4 | import gzip 5 | import os 6 | import re 7 | from atomate.common.firetasks.glue_tasks import CopyFiles, get_calc_loc 8 | from atomate.utils.utils import env_chk, get_logger 9 | from fireworks import explicit_serialize, FiretaskBase, FWAction 10 | from pymatgen.io.vasp import Vasprun, Locpot 11 | from pymatgen.io.vasp.inputs import Incar 12 | from pymatgen.core import Structure 13 | 14 | from pyGWBSE.inputset import CreateInputs 15 | 16 | """ 17 | This module defines tasks that acts as a glue between other vasp Firetasks to allow communication 18 | between different Firetasks and Fireworks. This module also contains tasks that affect the control 19 | flow of the workflow, e.g. tasks to check stability or the gap is within a certain range. 20 | """ 21 | 22 | logger = get_logger(__name__) 23 | 24 | __author__ = 'Anubhav Jain, Kiran Mathew' 25 | __email__ = 'ajain@lbl.gov, kmathew@lbl.gov' 26 | 27 | 28 | @explicit_serialize 29 | class CheckBeConv(FiretaskBase): 30 | """ 31 | Your Comments Here 32 | """ 33 | required_params = ["niter", "tolerence", "no_conv"] 34 | 35 | def run_task(self, fw_spec): 36 | """ 37 | Your Comments Here 38 | """ 39 | niter = self["niter"] 40 | conv = self["no_conv"] 41 | tol = self["tolerence"] 42 | filename = str(os.getcwd()) + '/vasprun.xml' 43 | vasprun = Vasprun(filename) 44 | gap, cbm, vbm, is_direct = vasprun.eigenvalue_band_properties 45 | print() 46 | print('=================================================') 47 | print('Iteration:', niter) 48 | print("band gap:", ("%10.4f" % gap)) 49 | print("CBM:", ("%10.4f" % cbm)) 50 | print("VBM:", ("%10.4f" % vbm)) 51 | print("Is the gap direct:", is_direct) 52 | if niter > 1: 53 | old_val = fw_spec["conval"] 54 | new_val = gap 55 | diff = abs(old_val - new_val) 56 | print("Difference:", ("%10.4f" % diff)) 57 | print('=================================================') 58 | print() 59 | if diff < tol: 60 | conv = True 61 | return FWAction(update_spec={"ifconv": conv, "conval": gap}) 62 | 63 | 64 | @explicit_serialize 65 | class MakeWFilesList(FiretaskBase): 66 | 67 | def run_task(self, fw_spec): 68 | files2copy = glob.glob("W*.tmp") 69 | return FWAction(update_spec={"wfiles": files2copy}) 70 | 71 | @explicit_serialize 72 | class SaveNbandsov(FiretaskBase): 73 | 74 | required_params = ["enwinbse"] 75 | 76 | def run_task(self, fw_spec): 77 | 78 | enwinbse = self["enwinbse"] 79 | filename = str(os.getcwd()) + '/vasprun.xml' 80 | vasprun = Vasprun(filename) 81 | qpe=vasprun.eigenvalues 82 | gap, cbm, vbm, is_direct = vasprun.eigenvalue_band_properties 83 | nbandso,nbandsv=get_nbandsov(qpe,vbm,cbm,enwinbse) 84 | 85 | return FWAction(update_spec={"nbandso": nbandso, "nbandsv": nbandsv}) 86 | 87 | @explicit_serialize 88 | class SaveConvParams(FiretaskBase): 89 | 90 | required_params = ["nomegagw","encutgw","nbands"] 91 | 92 | def run_task(self, fw_spec): 93 | nomegagw=self["nomegagw"] 94 | encutgw=self["encutgw"] 95 | nbands=self["nbands"] 96 | return FWAction(update_spec={"nomegagw": nomegagw, "encutgw": encutgw, "nbands": nbands}) 97 | 98 | @explicit_serialize 99 | class StopIfConverged(FiretaskBase): 100 | """ 101 | Your Comments Here 102 | """ 103 | def run_task(self, fw_spec): 104 | """ 105 | Your Comments Here 106 | """ 107 | ifconv = fw_spec["ifconv"] 108 | if ifconv: 109 | return FWAction(exit=True) 110 | 111 | 112 | @explicit_serialize 113 | class PasscalClocsCond(FiretaskBase): 114 | """ 115 | Your Comments Here 116 | """ 117 | required_params = ["name"] 118 | optional_params = ["filesystem", "path"] 119 | 120 | def run_task(self, fw_spec): 121 | """ 122 | Your Comments Here 123 | """ 124 | calc_locs = list(fw_spec.get("calc_locs", [])) 125 | calc_locs.append({"name": self["name"], 126 | "filesystem": env_chk(self.get('filesystem', None), fw_spec), 127 | "path": self.get("path", os.getcwd())}) 128 | ifconv = fw_spec["ifconv"] 129 | if ifconv: 130 | return FWAction(mod_spec=[{'_push_all': {'calc_locs': calc_locs}}]) 131 | 132 | 133 | @explicit_serialize 134 | class WriteBSEInput(FiretaskBase): 135 | """ 136 | Your Comments Here 137 | """ 138 | required_params = ["structure", "reciprocal_density"] 139 | 140 | def run_task(self, fw_spec): 141 | """ 142 | Your Comments Here 143 | """ 144 | f_incar = str(os.getcwd()) + '/INCAR' 145 | structure = self["structure"] 146 | reciprocal_density = self["reciprocal_density"] 147 | nbandso = fw_spec["nbandso"] 148 | nbandsv = fw_spec["nbandsv"] 149 | prev_incar = Incar.from_file(f_incar) 150 | vis = CreateInputs(structure, mode='BSE', prev_incar=prev_incar, reciprocal_density=reciprocal_density, 151 | nbandso=nbandso, nbandsv=nbandsv) 152 | vis.write_input(".") 153 | 154 | 155 | @explicit_serialize 156 | class WriteGWInput(FiretaskBase): 157 | """ 158 | Your Comments Here 159 | """ 160 | required_params = ["structure", "reciprocal_density", "nbandsgw", "wannier_fw"] 161 | 162 | def run_task(self, fw_spec): 163 | """ 164 | Your Comments Here 165 | """ 166 | f_incar = str(os.getcwd()) + '/INCAR' 167 | prev_incar = Incar.from_file(f_incar) 168 | structure = self["structure"] 169 | nbandsgw = self["nbandsgw"] 170 | wannier_fw = self["wannier_fw"] 171 | reciprocal_density = self["reciprocal_density"] 172 | encutgw=fw_spec["encutgw"] 173 | nomegagw=fw_spec["nomegagw"] 174 | nbands=fw_spec["nbands"] 175 | vis = CreateInputs(structure, mode='GW', prev_incar=prev_incar, reciprocal_density=reciprocal_density, 176 | encutgw=encutgw, nomegagw=nomegagw, nbands=nbands, nbandsgw=nbandsgw, wannier_fw=wannier_fw) 177 | vis.write_input(".") 178 | 179 | 180 | def read_emcpyout(fname): 181 | f = open(fname) 182 | contents = f.readlines() 183 | f.close() 184 | ne=0 185 | nh=0 186 | h_res={} 187 | e_res={} 188 | for content in contents: 189 | if "m_h:" in content: 190 | nh=nh+1 191 | lines = str.split(content) 192 | hmass=eval(lines[1]) 193 | hibnd=eval(lines[4]) 194 | inda=lines.index('->') 195 | if inda==10: 196 | hdir1=lines[9] 197 | hdir2=lines[14] 198 | else: 199 | hdir1='Intermediate' 200 | hdir2=lines[13] 201 | 202 | h_res['mass'+str(nh)+': '+str(hibnd)+', '+hdir1+', '+hdir2]=hmass 203 | 204 | if "m_e:" in content: 205 | ne=ne+1 206 | lines = str.split(content) 207 | emass=eval(lines[1]) 208 | eibnd=eval(lines[4]) 209 | inda=lines.index('->') 210 | if inda==10: 211 | edir1=lines[9] 212 | edir2=lines[14] 213 | else: 214 | edir1='Intermediate' 215 | edir2=lines[13] 216 | 217 | 218 | e_res['mass'+str(ne)+': '+str(eibnd)+', '+edir1+', '+edir2]=emass 219 | 220 | return h_res, e_res 221 | 222 | def read_epsilon(fname): 223 | vasprun = Vasprun(fname) 224 | try: 225 | epsilon = vasprun.epsilon_static_wolfe 226 | except: 227 | epsilon = None 228 | return epsilon 229 | 230 | 231 | def calc_delta_evac(x,y,n0): 232 | dx1=x[n0+1]-x[n0] 233 | dy1=y[n0+1]-y[n0] 234 | dx2=x[n0]-x[n0-1] 235 | dy2=y[n0]-y[n0-1] 236 | f1=dy1/dx1 237 | f2=dy2/dx2 238 | return (f1+f2)/2 239 | 240 | 241 | 242 | def read_vac_level(locpot_fname,fname): 243 | lpot=Locpot.from_file(locpot_fname) 244 | vrun=Vasprun(fname) 245 | vrun_d=vrun.as_dict() 246 | struct=Structure.from_dict(vrun_d["input"]["crystal"]) 247 | latt_c=struct.lattice.c 248 | y=lpot.get_average_along_axis(2) 249 | zarr=lpot.get_axis_grid(2) 250 | 251 | dist_z0=0. 252 | z0=0. 253 | 254 | for n,z in enumerate(zarr): 255 | dist=[] 256 | for site in struct.sites: 257 | pos_z=site.coords[2] 258 | if pos_z<0: 259 | pos_z=pos_z+latt_c 260 | dist.append(abs(pos_z-z)) 261 | dist.append(abs(pos_z+latt_c-z)) 262 | dist_z=min(dist) 263 | if dist_z>dist_z0: 264 | dist_z0=dist_z 265 | z0=z 266 | n0=n 267 | 268 | evac=y[n0] 269 | zvac=zarr[n0] 270 | delta_evac=calc_delta_evac(zarr,y,n0) 271 | 272 | return zvac,evac,delta_evac 273 | 274 | def get_gap_from_dict(qp_energies): 275 | 276 | tol=1e-5 277 | vbm = -float("inf") 278 | cbm = float("inf") 279 | for spin, d in qp_energies.items(): 280 | for k, val in enumerate(d): 281 | for (eigenval, occu) in val: 282 | if occu > tol and eigenval > vbm: 283 | vbm = eigenval 284 | elif occu <= tol and eigenval < cbm: 285 | cbm = eigenval 286 | igap=max(cbm-vbm,0) 287 | 288 | gap = [] 289 | filled = 1.0 290 | tol=1e-5 291 | vbm=0 292 | cbm=0 293 | for spin, d in qp_energies.items(): 294 | for k, val in enumerate(d): 295 | for (eigenval, occu) in val: 296 | if abs(occu-filled)<=tol: 297 | vbm=eigenval 298 | else: 299 | cbm=eigenval 300 | gap.append(cbm-vbm) 301 | break 302 | dgap=min(gap) 303 | return igap,dgap 304 | 305 | def get_nbandsov(qp_energies,vbm,cbm,enwinbse): 306 | 307 | tol=1e-5 308 | nvb=[] 309 | ncb=[] 310 | for spin, d in qp_energies.items(): 311 | for k, val in enumerate(d): 312 | for ibnd,(eigenval, occ) in enumerate(val): 313 | if abs(occ-1.0) 9: 404 | raise ValueError( 405 | "CopyVaspOutputs doesn't properly handle >9 relaxations!") 406 | m = re.search('\.relax\d*', relax_paths[-1]) 407 | relax_ext = m.group(0) 408 | 409 | # detect .gz extension if needed - note that monty zpath() did not seem useful here 410 | gz_ext = "" 411 | if not (f + relax_ext) in all_files: 412 | for possible_ext in [".gz", ".GZ"]: 413 | if (f + relax_ext + possible_ext) in all_files: 414 | gz_ext = possible_ext 415 | 416 | if not (f + relax_ext + gz_ext) in all_files: 417 | raise ValueError("Cannot find file: {}".format(f)) 418 | 419 | # copy the file (minus the relaxation extension) 420 | self.fileclient.copy(prev_path_full + relax_ext + gz_ext, 421 | dest_path + gz_ext) 422 | 423 | # unzip the .gz if needed 424 | if gz_ext in ['.gz', ".GZ"]: 425 | # unzip dest file 426 | f = gzip.open(dest_path + gz_ext, 'rt') 427 | file_content = f.read() 428 | with open(dest_path, 'w') as f_out: 429 | f_out.writelines(file_content) 430 | f.close() 431 | os.remove(dest_path + gz_ext) 432 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/wannier_tasks.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | This module defines tasks for WANNIER90 calculation 5 | """ 6 | 7 | import os 8 | 9 | import numpy as np 10 | from atomate.utils.utils import get_logger 11 | from fireworks import explicit_serialize, FiretaskBase 12 | from pymatgen import Structure 13 | from pymatgen.io.vasp import Vasprun 14 | from pymatgen.io.vasp.inputs import Incar, Potcar, PotcarSingle 15 | from pymatgen.symmetry.analyzer import SpacegroupAnalyzer 16 | from pymatgen.symmetry.bandstructure import HighSymmKpath 17 | 18 | from pyGWBSE.inputset import CreateInputs 19 | 20 | logger = get_logger(__name__) 21 | 22 | __author__ = 'Tathagata Biswas' 23 | __email__ = 'tbiswas3@asu.edu' 24 | 25 | 26 | @explicit_serialize 27 | class WriteWannierInputForGW(FiretaskBase): 28 | """ 29 | Your Comments Here 30 | """ 31 | required_params = ["structure", "reciprocal_density", "nbandsgw"] 32 | 33 | def run_task(self, fw_spec): 34 | """ 35 | Your Comments Here 36 | """ 37 | f_incar = str(os.getcwd()) + '/INCAR' 38 | structure = self["structure"] 39 | nbandsgw = self["nbandsgw"] 40 | reciprocal_density = self["reciprocal_density"] 41 | prev_incar = Incar.from_file(f_incar) 42 | wann_inp = str(os.getcwd()) + '/wannier90.win' 43 | vasprunfile = str(os.getcwd()) + '/vasprun.xml' 44 | poscarfile = str(os.getcwd()) + '/POSCAR' 45 | potcarfile = str(os.getcwd()) + '/POTCAR' 46 | vasprun = Vasprun(vasprunfile) 47 | incar = vasprun.incar 48 | nbands = incar["NBANDS"] 49 | elements = read_potcar(potcarfile, poscarfile) 50 | labels, kpts = kpath_finder(poscarfile) 51 | numwan = 0 52 | for element in elements: 53 | numwan = numwan + element[5] 54 | if numwan > nbandsgw: 55 | nbandsgw = numwan 56 | encutgw=fw_spec["encutgw"] 57 | nomegagw=fw_spec["nomegagw"] 58 | nbands=fw_spec["nbands"] 59 | vis = CreateInputs(structure, mode='GW', reciprocal_density=reciprocal_density, 60 | prev_incar=prev_incar, encutgw=encutgw, nomegagw=nomegagw, nbands=nbands, nbandsgw=nbandsgw) 61 | vis.write_input(".") 62 | labels, kpts = kpath_finder(poscarfile) 63 | write_wannier_input(numwan, nbands, labels, kpts, wann_inp, elements,False) 64 | 65 | 66 | @explicit_serialize 67 | class WriteWannierInputForDFT(FiretaskBase): 68 | """ 69 | Your Comments Here 70 | """ 71 | required_params = ["structure", "reciprocal_density", "ppn", "write_hr"] 72 | 73 | def run_task(self, fw_spec): 74 | """ 75 | Your Comments Here 76 | """ 77 | f_incar = str(os.getcwd()) + '/INCAR' 78 | structure = self["structure"] 79 | reciprocal_density = self["reciprocal_density"] 80 | ppn = self["ppn"] 81 | write_hr = self["write_hr"] 82 | prev_incar = Incar.from_file(f_incar) 83 | wann_inp = str(os.getcwd()) + '/wannier90.win' 84 | vasprunfile = str(os.getcwd()) + '/vasprun.xml' 85 | poscarfile = str(os.getcwd()) + '/POSCAR' 86 | potcarfile = str(os.getcwd()) + '/POTCAR' 87 | vasprun = Vasprun(vasprunfile) 88 | incar = vasprun.incar 89 | nbands = incar["NBANDS"] 90 | elements = read_potcar(potcarfile, poscarfile) 91 | numwan = 0 92 | for element in elements: 93 | numwan = numwan + element[5] 94 | print(numwan, nbands) 95 | if numwan > nbands: 96 | nbands = (int(numwan / ppn) + 1) * ppn 97 | vis = CreateInputs(structure, mode='STATIC', prev_incar=prev_incar, reciprocal_density=reciprocal_density, 98 | nbands=nbands) 99 | vis.write_input(".") 100 | labels, kpts = kpath_finder(poscarfile) 101 | write_wannier_input(numwan, nbands, labels, kpts, wann_inp, elements,write_hr) 102 | 103 | 104 | @explicit_serialize 105 | class CopyKptsWan2vasp(FiretaskBase): 106 | """ 107 | Your Comments Here 108 | """ 109 | 110 | def run_task(self, fw_spec): 111 | """ 112 | Your Comments Here 113 | """ 114 | f_wannkpt = str(os.getcwd()) + '/wannier90_band.kpt' 115 | f_vaspkpt = str(os.getcwd()) + '/KPOINTS' 116 | f = open(f_wannkpt) 117 | contents = f.readlines() 118 | f.close() 119 | lines = str.split(contents[0]) 120 | nkpts = eval(lines[0]) 121 | f = open(f_vaspkpt, 'w') 122 | f.write('kpoints file generated from wannier90_band.kpt' + '\n') 123 | f.write(str(nkpts) + '\n') 124 | f.write('Reciprocal' + '\n') 125 | for ik in range(nkpts): 126 | f.write(contents[ik + 1]) 127 | f.close() 128 | 129 | 130 | def write_wannier_input(numwan, nbands, labels, kpts, wann_inp, elements,write_hr): 131 | """ 132 | Your Comments Here 133 | """ 134 | if write_hr: 135 | f = open(wann_inp, 'a') 136 | f.write("write_hr = true" + "\n") 137 | f.close() 138 | else: 139 | f = open(wann_inp, 'w') 140 | f.write("num_wann = " + str(numwan) + "\n") 141 | if numwan < nbands: 142 | f.write("exclude_bands " + str(numwan + 1) + "-" + str(nbands) + "\n") 143 | if numwan == nbands - 1: 144 | f.write("exclude_bands " + str(numwan + 1) + "\n") 145 | f.write("bands_plot = true" + "\n") 146 | f.write("begin kpoint_path" + "\n") 147 | for i in range(len(labels)): 148 | for j in range(len(labels[i])-1): 149 | label1=labels[i][j] 150 | label2=labels[i][j+1] 151 | string = write_kpath_lines(kpts[label1], label1, kpts[label2], label2) 152 | f.write(string) 153 | f.write("end kpoint_path" + "\n") 154 | f.write("bands_num_points 40" + "\n") 155 | f.write("bands_plot_format gnuplot" + "\n") 156 | f.write("Begin Projections" + "\n") 157 | f.write("random" + "\n") 158 | for element in elements: 159 | f.write(element[0] + ':') 160 | for l in range(4): 161 | if element[l + 1] > 0: 162 | if l == 0: 163 | f.write('l=' + str(l)) 164 | else: 165 | f.write(';' + 'l=' + str(l)) 166 | f.write('\n') 167 | f.write("End Projections" + "\n") 168 | f.write("num_iter = 500" + "\n") 169 | f.close() 170 | 171 | 172 | def write_kpath_lines(kpt1, label1, kpt2, label2): 173 | """ 174 | Your Comments Here 175 | """ 176 | string = label1 + " " + "%10.5f" % kpt1[0] + "%10.5f" % kpt1[1] + "%10.5f" % kpt1[ 177 | 2] + " " + label2 + " " + "%10.5f" % kpt2[0] + "%10.5f" % kpt2[1] + "%10.5f" % kpt2[2] + "\n" 178 | return string 179 | 180 | 181 | def kpath_finder(filename): 182 | """ 183 | Your Comments Here 184 | """ 185 | struct = Structure.from_file(filename) 186 | spcg = SpacegroupAnalyzer(struct) 187 | pstruct = spcg.get_primitive_standard_structure(international_monoclinic=False) 188 | hskp = HighSymmKpath(pstruct) 189 | kpts = hskp.kpath["kpoints"] 190 | labels = hskp.kpath["path"] 191 | return labels, kpts 192 | 193 | 194 | def read_potcar(potcarfile, poscarfile): 195 | """ 196 | Your Comments Here 197 | """ 198 | struct = Structure.from_file(poscarfile) 199 | potcar = Potcar.from_file(potcarfile) 200 | sites = struct.species 201 | specs = potcar.spec 202 | wan_info = [] 203 | for spec in specs: 204 | single = PotcarSingle.from_symbol_and_functional(symbol=spec['symbol'], functional='PBE_54') 205 | orbitals = single.electron_configuration 206 | element = single.element 207 | nat = str(sites).count(single.element) 208 | spdf = [] 209 | for orbital in orbitals: 210 | spdf.append(orbital[1]) 211 | scnt = spdf.count('s') 212 | pcnt = spdf.count('p') 213 | dcnt = spdf.count('d') 214 | fcnt = spdf.count('f') 215 | numwan = nat * (scnt * 1 + pcnt * 3 + dcnt * 5 + fcnt * 7) 216 | wan_info.append([element, scnt, pcnt, dcnt, fcnt, numwan]) 217 | return wan_info 218 | 219 | 220 | def read_vbm(fname): 221 | """ 222 | Your Comments Here 223 | """ 224 | vasprun = Vasprun(fname, parse_potcar_file=False) 225 | gap, cbm, vbm, is_direct = vasprun.eigenvalue_band_properties 226 | return gap, vbm 227 | 228 | 229 | def read_wannier(fname_band, fname_kpt, vbm): 230 | """ 231 | Your Comments Here 232 | """ 233 | f = open(fname_band) 234 | contents = f.readlines() 235 | f.close() 236 | 237 | kvals = [] 238 | evals = [] 239 | 240 | for content in contents: 241 | lines = str.split(content) 242 | if len(lines) != 0: 243 | kvals.append(eval(lines[0])) 244 | evals.append(eval(lines[1])) 245 | with open(fname_kpt) as f: 246 | first_line = f.readline() 247 | nkpt = eval(str.split(first_line)[0]) 248 | nband = int(len(evals) / nkpt) 249 | kpts_flat = np.array(kvals) 250 | eigs_flat = np.array(evals) - vbm 251 | kpts = kpts_flat.reshape(nband, nkpt) 252 | eigs = eigs_flat.reshape(nband, nkpt) 253 | 254 | return kpts, eigs 255 | 256 | 257 | def read_vasp(fname, vbm): 258 | """ 259 | Your Comments Here 260 | """ 261 | vasprun = Vasprun(fname) 262 | eigs = vasprun.eigenvalues 263 | nkpt = len(vasprun.actual_kpoints) 264 | kptvasp = vasprun.actual_kpoints 265 | out = [] 266 | for spin, d in eigs.items(): 267 | for k, val in enumerate(d): 268 | for n, eigenval in enumerate(val): 269 | out.append(eigenval[0] - vbm) 270 | nbands = int(len(out) / nkpt) 271 | eigvasp = np.reshape(out, (nkpt, nbands)) 272 | 273 | return kptvasp, eigvasp 274 | 275 | 276 | def read_special_kpts(fname): 277 | """ 278 | Your Comments Here 279 | """ 280 | f = open(fname) 281 | contents = f.readlines() 282 | f.close() 283 | spkptl = [] 284 | spkptc = [] 285 | for content in contents: 286 | if 'set xtics' in content: 287 | lines = str.split(content,sep='"') 288 | for n, words in enumerate(lines): 289 | if n!=0 and n%2!=0: 290 | spkptl.append(words) 291 | elif n!=0: 292 | spkptc.append(eval(words[:9])) 293 | 294 | return spkptl,spkptc 295 | 296 | -------------------------------------------------------------------------------- /sphinx/pyGWBSE/wflows.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | """ 5 | Defines standardized Fireworks that can be chained easily to perform various 6 | sequences of VASP calculations. 7 | """ 8 | 9 | from atomate.common.firetasks.glue_tasks import PassCalcLocs 10 | from atomate.vasp.firetasks.write_inputs import WriteVaspFromIOSet 11 | from fireworks import Firework, Tracker 12 | 13 | 14 | from pyGWBSE.inputset import CreateInputs 15 | from pyGWBSE.out2db import gw2db, bse2db, emc2db, eps2db, Wannier2DB, rpa2db 16 | from pyGWBSE.run_calc import Run_Vasp, Run_Sumo, Run_Wannier 17 | from pyGWBSE.tasks import CopyOutputFiles, CheckBeConv, StopIfConverged, PasscalClocsCond, WriteBSEInput, \ 18 | WriteGWInput, MakeWFilesList, SaveNbandsov, SaveConvParams 19 | from pyGWBSE.wannier_tasks import WriteWannierInputForDFT, WriteWannierInputForGW, CopyKptsWan2vasp 20 | 21 | 22 | class ScfFW(Firework): 23 | def __init__(self, mat_name=None, structure=None, nbands=None, kpar=None, reciprocal_density=None, 24 | vasp_input_set=None, vasp_input_set_params=None, 25 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, wannier_fw=None, 26 | vasptodb_kwargs={}, **kwargs): 27 | """ 28 | Your Comments Here 29 | """ 30 | t = [] 31 | vasp_input_set = CreateInputs(structure, kpar=kpar, reciprocal_density=reciprocal_density, nbands=nbands, 32 | wannier_fw=wannier_fw) 33 | name = 'SCF' 34 | fw_name = "{}-{}".format(mat_name, name) 35 | t.append(WriteVaspFromIOSet(structure=structure, 36 | vasp_input_set=vasp_input_set, 37 | vasp_input_set_params=vasp_input_set_params)) 38 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 39 | t.append(eps2db(structure=structure, mat_name=mat_name, db_file=db_file, defuse_unsuccessful=False)) 40 | t.append(rpa2db(structure=structure, mat_name=mat_name, task_label=name, db_file=db_file, defuse_unsuccessful=False)) 41 | t.append(PassCalcLocs(name=name)) 42 | super(ScfFW, self).__init__(t, name=fw_name, **kwargs) 43 | 44 | 45 | class convFW(Firework): 46 | 47 | def __init__(self, mat_name=None, structure=None, tolerence=None, no_conv=None, nbands=None, 48 | nbgwfactor=None, encutgw=None, nomegagw=None, convparam=None, convsteps=None, conviter=None, 49 | kpar=None, nbandsgw=None, reciprocal_density=None, vasp_input_set=None, vasp_input_set_params=None, 50 | vasp_cmd="vasp", 51 | prev_calc_loc=True, prev_calc_dir=None, db_file=None, vasptodb_kwargs={}, parents=None, **kwargs): 52 | t = [] 53 | name = "CONV" 54 | fw_name = "{}-{}".format(mat_name, name) 55 | niter = 0 56 | for niter in range(conviter): 57 | niter = niter + 1 58 | files2copy = ['WAVECAR'] 59 | task_label = 'Convergence_Iteration: ' + str(niter) 60 | if convparam == 'NBANDS': 61 | nbgwfactor = nbgwfactor + (niter - 1) * convsteps 62 | if convparam == 'ENCUTGW': 63 | encutgw = encutgw + (niter - 1) * convsteps 64 | if convparam == 'NOMEGA': 65 | nomegagw = nomegagw + (niter - 1) * convsteps 66 | if prev_calc_dir: 67 | t.append(CopyOutputFiles(additional_files=files2copy, calc_dir=prev_calc_dir, contcar_to_poscar=True)) 68 | elif parents: 69 | if prev_calc_loc: 70 | t.append( 71 | CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 72 | vasp_input_set = CreateInputs(structure, mode='DIAG', nbands=nbands * nbgwfactor, kpar=kpar, 73 | reciprocal_density=reciprocal_density) 74 | t.append(WriteVaspFromIOSet(structure=structure, 75 | vasp_input_set=vasp_input_set, 76 | vasp_input_set_params=vasp_input_set_params)) 77 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 78 | vasp_input_set = CreateInputs(structure,mode='CONV',nbands=nbands*nbgwfactor,encutgw=encutgw,nomegagw=nomegagw,kpar=kpar,reciprocal_density=reciprocal_density,nbandsgw=nbandsgw) 79 | t.append(WriteVaspFromIOSet(structure=structure, 80 | vasp_input_set=vasp_input_set, 81 | vasp_input_set_params=vasp_input_set_params)) 82 | if no_conv==False: 83 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 84 | t.append(SaveConvParams(nbands=nbands*nbgwfactor, encutgw=encutgw, nomegagw=nomegagw)) 85 | t.append(CheckBeConv(niter=niter, tolerence=tolerence, no_conv=no_conv)) 86 | t.append(PasscalClocsCond(name=name)) 87 | if no_conv==False: 88 | t.append(gw2db(structure=structure, mat_name=mat_name, task_label=task_label, db_file=db_file, 89 | defuse_unsuccessful=False)) 90 | t.append(StopIfConverged()) 91 | tracker = Tracker('vasp.log', nlines=100) 92 | super(convFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 93 | 94 | 95 | class GwFW(Firework): 96 | def __init__(self, mat_name=None, structure=None, tolerence=None, no_conv=None, reciprocal_density=None, 97 | vasp_input_set=None, vasp_input_set_params=None, nbandso=None, nbandsv=None, nbandsgw=None, 98 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, wannier_fw=None, 99 | vasptodb_kwargs={}, job_tag=None, parents=None, **kwargs): 100 | """ 101 | Your Comments Here 102 | """ 103 | t = [] 104 | name = "GW" 105 | fw_name = "{}-{}".format(mat_name, name) 106 | files2copy = ['WAVECAR', 'WAVEDER'] 107 | if prev_calc_dir: 108 | t.append(CopyOutputFiles(additional_files=files2copy, calc_dir=prev_calc_dir, contcar_to_poscar=True)) 109 | elif parents: 110 | if prev_calc_loc: 111 | t.append(CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 112 | t.append(WriteGWInput(structure=structure, reciprocal_density=reciprocal_density, nbandsgw=nbandsgw, 113 | wannier_fw=wannier_fw)) 114 | for niter in range(1, 10): 115 | task_label = 'scGW_Iteration: ' + str(niter) 116 | if wannier_fw: 117 | t.append(WriteWannierInputForGW(structure=structure, reciprocal_density=reciprocal_density,nbandsgw=nbandsgw)) 118 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 119 | t.append(CheckBeConv(niter=niter, tolerence=tolerence, no_conv=no_conv)) 120 | t.append(PasscalClocsCond(name=name)) 121 | t.append(MakeWFilesList()) 122 | t.append( 123 | gw2db(structure=structure, mat_name=mat_name, task_label=task_label, job_tag=job_tag, db_file=db_file, 124 | defuse_unsuccessful=False)) 125 | t.append(StopIfConverged()) 126 | tracker = Tracker('vasp.log', nlines=100) 127 | 128 | super(GwFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 129 | 130 | 131 | class BseFW(Firework): 132 | def __init__(self, mat_name=None, structure=None, reciprocal_density=None, vasp_input_set=None, 133 | vasp_input_set_params=None, enwinbse=None, 134 | vasp_cmd="vasp", prev_calc_loc=True, prev_calc_dir=None, db_file=None, vasptodb_kwargs={}, 135 | job_tag=None, parents=None, **kwargs): 136 | """ 137 | Your Comments Here 138 | """ 139 | t = [] 140 | name = "BSE" 141 | fw_name = "{}-{}".format(mat_name, name) 142 | files2copy = ['WAVECAR', 'WAVEDER'] 143 | if prev_calc_dir: 144 | t.append(CopyOutputFiles(additional_files=files2copy, calc_dir=prev_calc_dir, contcar_to_poscar=True)) 145 | elif parents: 146 | if prev_calc_loc: 147 | t.append(CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 148 | t.append(SaveNbandsov(enwinbse=enwinbse)) 149 | t.append(WriteBSEInput(structure=structure, reciprocal_density=reciprocal_density)) 150 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 151 | t.append(bse2db(structure=structure, mat_name=mat_name, task_label=name, job_tag=job_tag, db_file=db_file, 152 | defuse_unsuccessful=False)) 153 | tracker = Tracker('vasp.log', nlines=100) 154 | 155 | super(BseFW, self).__init__(t, parents=parents, name=fw_name, state='PAUSED', spec={"_trackers": [tracker]}, 156 | **kwargs) 157 | 158 | 159 | class EmcFW(Firework): 160 | def __init__(self, mat_name=None, structure=None, nbands=None, kpar=None, reciprocal_density=None, steps=None, 161 | vasp_input_set=None, vasp_input_set_params=None, 162 | vasp_cmd="vasp", sumo_cmd='sumo', prev_calc_loc=True, prev_calc_dir=None, db_file=None, 163 | vasptodb_kwargs={}, parents=None, **kwargs): 164 | """ 165 | Your Comments Here 166 | """ 167 | t = [] 168 | 169 | vasp_input_set = CreateInputs(structure, mode='EMC', kpar=kpar, reciprocal_density=reciprocal_density, 170 | nbands=nbands) 171 | name = 'EMC' 172 | fw_name = "{}-{}".format(mat_name, name) 173 | if prev_calc_dir: 174 | t.append(CopyOutputFiles(calc_dir=prev_calc_dir, additional_files=["CHGCAR"])) 175 | elif parents: 176 | t.append(CopyOutputFiles(calc_loc=True, additional_files=["CHGCAR"])) 177 | else: 178 | raise ValueError("Must specify previous calculation for NonScfFW") 179 | t.append(WriteVaspFromIOSet(structure=structure, 180 | vasp_input_set=vasp_input_set, 181 | vasp_input_set_params=vasp_input_set_params)) 182 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 183 | t.append(Run_Sumo(sumo_cmd=sumo_cmd)) 184 | t.append(emc2db(structure=structure, mat_name=mat_name, db_file=db_file, defuse_unsuccessful=False)) 185 | super(EmcFW, self).__init__(t, parents=parents, name=fw_name, **kwargs) 186 | 187 | 188 | class WannierCheckFW(Firework): 189 | def __init__(self, ppn=None, kpar=None, mat_name=None, structure=None, reciprocal_density=None, vasp_input_set=None, 190 | vasp_input_set_params=None, 191 | vasp_cmd="vasp", wannier_cmd=None, prev_calc_loc=True, prev_calc_dir=None, db_file=None, 192 | vasptodb_kwargs={}, parents=None, **kwargs): 193 | """ 194 | Your Comments Here 195 | """ 196 | t = [] 197 | name = "WANNIER_CHECK" 198 | fw_name = "{}-{}".format(mat_name, name) 199 | t.append(CopyOutputFiles(calc_loc=prev_calc_loc, contcar_to_poscar=True)) 200 | t.append(WriteWannierInputForDFT(structure=structure, reciprocal_density=reciprocal_density, ppn=ppn, write_hr=False)) 201 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 202 | t.append(WriteWannierInputForDFT(structure=structure, reciprocal_density=reciprocal_density, ppn=ppn, write_hr=True)) 203 | t.append(Run_Wannier(wannier_cmd=wannier_cmd)) 204 | vasp_input_set = CreateInputs(structure, mode='EMC', kpar=kpar, reciprocal_density=reciprocal_density) 205 | t.append(WriteVaspFromIOSet(structure=structure, 206 | vasp_input_set=vasp_input_set, 207 | vasp_input_set_params=vasp_input_set_params)) 208 | t.append(CopyKptsWan2vasp()) 209 | t.append(Run_Vasp(vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<")) 210 | t.append(Wannier2DB(structure=structure, mat_name=mat_name, task_label='CHECK_WANNIER_INTERPOLATION', 211 | db_file=db_file, compare_vasp=True, defuse_unsuccessful=False)) 212 | tracker = Tracker('vasp.log', nlines=100) 213 | 214 | super(WannierCheckFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 215 | 216 | 217 | class WannierFW(Firework): 218 | def __init__(self, structure=None, mat_name=None, wannier_cmd=None, prev_calc_loc=True, prev_calc_dir=None, 219 | db_file=None, parents=None, **kwargs): 220 | """ 221 | Your Comments Here 222 | """ 223 | t = [] 224 | name = "WANNIER" 225 | fw_name = "{}-{}".format(mat_name, name) 226 | files2copy = ['wannier90.win', 'wannier90.mmn', 'wannier90.amn', 'wannier90.eig'] 227 | t.append(CopyOutputFiles(additional_files=files2copy, calc_loc=prev_calc_loc, contcar_to_poscar=True)) 228 | t.append(Run_Wannier(wannier_cmd=wannier_cmd)) 229 | t.append(Wannier2DB(structure=structure, mat_name=mat_name, task_label='GW_BANDSTRUCTURE', db_file=db_file, 230 | compare_vasp=False, defuse_unsuccessful=False)) 231 | tracker = Tracker('wannier90.wout', nlines=100) 232 | 233 | super(WannierFW, self).__init__(t, parents=parents, name=fw_name, spec={"_trackers": [tracker]}, **kwargs) 234 | -------------------------------------------------------------------------------- /sphinx/requirement.txt: -------------------------------------------------------------------------------- 1 | numpy==1.16.0 2 | FireWorks==1.8.1 3 | pymatgen==2018.11.30 4 | atomate==0.8.4 5 | monty==1.0.3 6 | sphinx==3.0.1 7 | sphinx-rtd-theme==0.5.2 8 | setuptools==57.4.0 9 | pybtex==0.24.0 -------------------------------------------------------------------------------- /sphinx/rst/modules.rst: -------------------------------------------------------------------------------- 1 | WFGWBSE 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | project_intro/modules 8 | Documentation 9 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/getfromdb.rst: -------------------------------------------------------------------------------- 1 | getfromdb module 2 | ================ 3 | 4 | .. automodule:: getfromdb 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/inputset.rst: -------------------------------------------------------------------------------- 1 | inputset module 2 | =============== 3 | 4 | .. automodule:: inputset 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/modules.rst: -------------------------------------------------------------------------------- 1 | gwbse_wf 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | getfromdb 8 | inputset 9 | out2db 10 | run_calc 11 | tasks 12 | wannier_tasks 13 | wflows 14 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/out2db.rst: -------------------------------------------------------------------------------- 1 | out2db module 2 | ============= 3 | 4 | .. automodule:: out2db 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/run_calc.rst: -------------------------------------------------------------------------------- 1 | run\_calc module 2 | ================ 3 | 4 | .. automodule:: run_calc 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/tasks.rst: -------------------------------------------------------------------------------- 1 | tasks module 2 | ============ 3 | 4 | .. automodule:: tasks 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/wannier_tasks.rst: -------------------------------------------------------------------------------- 1 | wannier\_tasks module 2 | ===================== 3 | 4 | .. automodule:: wannier_tasks 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/gwbse_wf/wflows.rst: -------------------------------------------------------------------------------- 1 | wflows module 2 | ============= 3 | 4 | .. automodule:: wflows 5 | :members: 6 | :undoc-members: 7 | :special-members: '__init__' 8 | :show-inheritance: 9 | -------------------------------------------------------------------------------- /sphinx/rst/project/make_wf.rst: -------------------------------------------------------------------------------- 1 | make\_wf module 2 | =============== 3 | 4 | .. automodule:: make_wf 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /sphinx/rst/project/modules.rst: -------------------------------------------------------------------------------- 1 | WFGWBSE 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | make_wf 8 | gwbse_wf/modules -------------------------------------------------------------------------------- /sphinx/rst/project_intro/installation.rst: -------------------------------------------------------------------------------- 1 | Installing WFGWBSE 2 | ================== 3 | 4 | ""Your Comments Here"" 5 | 6 | -------------------------------------------------------------------------------- /sphinx/rst/project_intro/introduction.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Introduction 3 | ============ 4 | 5 | ""Your Comments Here"" 6 | 7 | Package Description 8 | =================== 9 | 10 | ""Your Comments Here"" 11 | 12 | Examples 13 | ======== 14 | 15 | ""Your Comments Here"" 16 | 17 | How to cite 2dSynth 18 | =================== 19 | 20 | If you use 2dSynth in your research, please consider citing the following work: 21 | 22 | **add later** 23 | 24 | License 25 | ======= 26 | 27 | ""Your Comments Here"" 28 | 29 | About the Team 30 | ============== 31 | 32 | ""Your Comments Here"" 33 | 34 | Copyright Policy 35 | ================ 36 | 37 | ""Your Comments Here"" 38 | 39 | # Copyright (c) CMD Lab Development Team. 40 | # Distributed under the terms of the GNU License. -------------------------------------------------------------------------------- /sphinx/rst/project_intro/modules.rst: -------------------------------------------------------------------------------- 1 | Project Intro 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | introduction 8 | installation 9 | team 10 | references 11 | -------------------------------------------------------------------------------- /sphinx/rst/project_intro/references.rst: -------------------------------------------------------------------------------- 1 | References 2 | ========== 3 | 4 | ""Your Comments Here"" -------------------------------------------------------------------------------- /sphinx/rst/project_intro/team.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | Development Team 3 | ================ 4 | 5 | Lead Maintainers 6 | ================ 7 | 8 | | **Arunima K. Singh** |as2362| |0000-0002-7212-6310| 9 | | Assistant Professor, Department of Physics 10 | | Arizona State University, Tempe 11 | 12 | .. |as2362| image:: ../../_static/github.png 13 | :target: https://github.com/as2362 14 | :width: 26 15 | :height: 26 16 | :alt: GitHub profile for as2362 17 | 18 | .. |0000-0002-7212-6310| image:: ../../_static/orcid.jpg 19 | :target: https://orcid.org/0000-0002-7212-6310 20 | :width: 26 21 | :height: 26 22 | :alt: ORCID profile for 0000-0002-7212-6310 23 | 24 | | Tathagata Biswas 25 | | XYZ 26 | | Arizona State University, Tempe 27 | 28 | List of Developers (A-Z) 29 | ======================== 30 | 31 | 32 | -------------------------------------------------------------------------------- /sphinx/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | setup( 5 | name='pyGWBSE', 6 | version='1.0', 7 | description='python workflow for GW-BSE calculation', 8 | author='Tathagata Biswas', 9 | author_email='tbiswas3@asu.edu', 10 | packages=['pyGWBSE'], 11 | install_requires=['FireWorks>=1.4.0', 'pymatgen>=2018.6.11', 12 | 'monty>=1.0.2', 'atomate>=0.8.4'], 13 | package_data={"pyGWBSE": ["inputset.yaml"]} 14 | 15 | ) 16 | --------------------------------------------------------------------------------