Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Absorption #726

Merged
merged 6 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions atomate/vasp/drones.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,11 @@ def generate_doc(self, dir_name, vasprun_files, outcar_files):
for k in ["optical_absorption_coeff", "dielectric"]:
d["output"][k] = d_calc_final["output"][k]

# store optical data, overwrites the LOPTICS data
if d["input"]["incar"].get("ALGO") == 'CHI':
for k in ["optical_absorption_coeff", "dielectric"]:
d["output"][k] = d_calc_final["output"][k]

d["state"] = (
"successful" if d_calc["has_vasp_completed"] else "unsuccessful"
)
Expand Down Expand Up @@ -586,6 +591,14 @@ def process_vasprun(self, dir_name, taskname, filename):
)
d["output"]["optical_absorption_coeff"] = vrun.optical_absorption_coeff

# parse output from response function
if vrun.incar.get("ALGO") == 'CHI':
dielectric = vrun.dielectric
d["output"]["dielectric"] = dict(
energy=dielectric[0], real=dielectric[1], imag=dielectric[2]
)
d["output"]["optical_absorption_coeff"] = vrun.optical_absorption_coeff

return d

def process_bandstructure(self, vrun):
Expand Down
56 changes: 56 additions & 0 deletions atomate/vasp/firetasks/absorption_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
from importlib import import_module

import numpy as np

from monty.serialization import dumpfn
from fireworks import FiretaskBase, explicit_serialize
from fireworks.utilities.dict_mods import apply_mod
from pymatgen.core.structure import Structure
from pymatgen.io.vasp import Incar, Poscar, Potcar, PotcarSingle, Kpoints
from pymatgen.io.vasp.sets import MPAbsorptionSet
from pymatgen.io.vasp.outputs import Vasprun
from atomate.utils.utils import env_chk, load_class

@explicit_serialize
class WriteVaspAbsorptionFromPrev(FiretaskBase):
"""
Writes input files for an LOPTICS absorption run. Assumes that output files (WAVECAR) from an
scf job can be accessed.
Optional params:
"prev_calc_dir",
"mode", either "IPA" or "RPA"
"reciprocal_density",
"other_params",
"potcar_spec"

"""
optional_params = [
"prev_calc_dir",
"structure",
"mode",
"copy_wavecar",
"nbands",
"nbands_factor",
"reciprocal_density",
"nkred",
"ncores",
"nedos",
"potcar_spec",
"other_params"
]

def run_task(self, fw_spec):
vis = MPAbsorptionSet.from_prev_calc(
prev_calc_dir=self.get("prev_calc_dir", "."),
mode=self.get("mode", "IPA"),
copy_wavecar=self.get("copy_wavecar", True),
nbands=self.get("nbands", None),
nbands_factor=self.get("nbands_factor", 2),
reciprocal_density=self.get("reciprocal_density", 200),
nkred=self.get("nkred", None),
nedos=self.get("nedos", 2001),
**self.get("other_params", {})
)
potcar_spec = self.get("potcar_spec", False)
vis.write_input(".", potcar_spec=potcar_spec)
230 changes: 230 additions & 0 deletions atomate/vasp/fireworks/absorption.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
from atomate.vasp.config import (
VASP_CMD,
DB_FILE,
)
from fireworks import Firework
from pymatgen.io.vasp.sets import MPStaticSet, MPAbsorptionSet
from atomate.common.firetasks.glue_tasks import (
PassCalcLocs,
CopyFiles,
DeleteFiles,
GzipDir,
CreateFolder,
PassCalcLocs
)
from atomate.vasp.firetasks import (
CheckBandgap,
CopyVaspOutputs,
ModifyIncar,
RunVaspCustodian,
VaspToDb,
)
from atomate.vasp.firetasks.write_inputs import WriteVaspFromIOSet, WriteVaspStaticFromPrev
from atomate.vasp.firetasks.absorption_tasks import WriteVaspAbsorptionFromPrev


class AbsorptionFW(Firework):
def __init__(
self,
structure,
name="frequency dependent dielectrics",
mode='STATIC',
nbands=None,
nbands_factor=2,
reciprocal_density=200,
nkred=None,
nedos=2001,
vasp_cmd=VASP_CMD,
prev_calc_dir=None,
db_file=DB_FILE,
vasptodb_kwargs=None,
parents=None,
vasp_input_set_params=None,
**kwargs,
):
"""
FW that calculates frequency dependent dielectric function within
indenpendent-particle-approxiamtion. A previous ground state calculation
with the output WAVECAR is required by specifying mode = 'static'; in the case of no
parent, a PBE functional ground state calculation will be performed and
the WAVECAR will be saved. Then, perform another calculation with 'ALGO = EXACT, LOPTICS = True'
with variable NBANDS by specifying MODE = "IPA". This calculation will save the
WAVECAR and WAVEDER in case one wants to run RPA level absorption
spectra. For RPA-DFT absorption spectrum, run another mode = 'RPA' calculation
with the WAVECAR, WAVEDER saved from previous IPA calc.
Args:
structure (Structure): Input structure. For an interpolation, this
is a dummy structure. See interpolate arg description.
name (str): Name for the FireWork.
mode: 'STATIC', 'IPA', or 'RPA'.
nbands: number of bands to use, leave to None, and use nbands_factor instead
nbands_factor: the multiplication of the number of bands
reciprocal_density: k-point density
nkred: reduced number of k-points, for RPA calculation use only, reduces the computing time
nedos: energy mesh for DOS
vasp_cmd (str): Command to run vasp.
prev_calc_loc (bool or str): If true (default), copies outputs from previous calc. If
a str value, retrieves a previous calculation output by name.
vasp_input_set (str): string name for the VASP input set (e.g.,
"MPAbsorptionSet").
db_file (str): Path to file specifying db credentials.
parents (Firework): Parents of this particular Firework. FW or list
of FWS.
vasp_input_set_params (dict): Dict of vasp_input_set_kwargs.
prev_calc_dir (str): Path to a previous calculation to copy from
vasptodb_kwargs (dict): kwargs to pass to VaspToDb
**kwargs: Other kwargs that are passed to Firework.__init__.

"""
t = []

vasp_input_set_params = vasp_input_set_params or {}
vasptodb_kwargs = vasptodb_kwargs or {}
if "additional_fields" not in vasptodb_kwargs:
vasptodb_kwargs["additional_fields"] = {}
vasptodb_kwargs["additional_fields"]["task_label"] = name

fw_name = "{}-{}-{}".format(
structure.composition.reduced_formula if structure else "unknown", name, mode
)

# define what wavecars to copy from the previous run
if mode == "STATIC":
wavecars = []
elif mode == "IPA":
wavecars = ["WAVECAR"]
elif mode == "RPA":
wavecars = ["WAVECAR", "WAVEDER"]
else:
raise Exception("Mode has to be from 'STATIC', 'IPA' or 'RPA'. ")

# "IPA" or "RPA" run
if mode == "IPA" or mode == "RPA":
if prev_calc_dir:
# Copy the WAVECAR from previous calc directory
t.append(CopyVaspOutputs(
calc_dir=prev_calc_dir,
contcar_to_poscar=True,
additional_files=wavecars)
)

t.append(
WriteVaspAbsorptionFromPrev(
prev_calc_dir=".",
structure=structure, # The structure will only be useful for the FW name
mode=mode,
copy_wavecar=True,
nbands=None,
nbands_factor=nbands_factor,
reciprocal_density=reciprocal_density,
nkred=nkred,
nedos=nedos,
**vasp_input_set_params
)
)

elif parents:
# Copy the WAVECAR from previous calc location
t.append(
CopyVaspOutputs(
calc_loc=True,
contcar_to_poscar=True,
additional_files=wavecars
)
)

t.append(
WriteVaspAbsorptionFromPrev(
prev_calc_dir=".",
structure=structure, # The structure will only be useful for the FW name
mode=mode,
copy_wavecar=True,
nbands=None,
nbands_factor=nbands_factor,
reciprocal_density=reciprocal_density,
nkred=nkred,
nedos=nedos,
**vasp_input_set_params
)
)

else:
raise ValueError("Must specify previous calculation for {}".format(mode))

# when mode = "static"
elif mode == "STATIC":
static_incar={"LWAVE": True,
"ENCUT": 500,
"ISMEAR": 0,
"SIGMA": 0.01,
"LREAL": False,
"GGA": "PE",
"LELF": False,
"LAECHG": False,
"LASPH": False,
"LVHAR": False,
"LVTOT": False,
"METAGGA": "None",
"LMIXTAU": False}

if prev_calc_dir:
# Copy only the CONTCAR from previous calc directory (often a relaxation run)
t.append(
CopyVaspOutputs(
calc_dir=prev_calc_dir,
contcar_to_poscar=True,
additional_files=wavecars
)
)

t.append(
WriteVaspStaticFromPrev(reciprocal_density=reciprocal_density,
other_params={"user_incar_settings": static_incar})
)

elif parents:
# Copy only the CONTCAR from previous calc
t.append(CopyVaspOutputs(calc_loc=True,
additional_files=wavecars,
contcar_to_poscar=True)
)

t.append(
WriteVaspStaticFromPrev(reciprocal_density=reciprocal_density,
other_params={"user_incar_settings": static_incar})
)

elif structure:
static_input_set = MPStaticSet(structure=structure,
reciprocal_density=reciprocal_density,
user_incar_settings=static_incar)

t.append(WriteVaspFromIOSet(structure=structure, vasp_input_set=static_input_set)
)

else:
raise ValueError("Must specify structure or previous calculation for static calculation")

else:
raise ValueError("Must specify a mode from 'STATIC', 'IPA', or 'RPA'")

# use the 'default' custodian handler group
handler_group = "default"

# Run VASP
t.append(
RunVaspCustodian(
vasp_cmd=vasp_cmd,
auto_npar=">>auto_npar<<",
handler_group=handler_group
)
)
t.append(PassCalcLocs(name=name))
# Parse
t.append(VaspToDb(db_file=db_file,
additional_fields={
"task_label": structure.composition.reduced_formula + " " + name + " " + mode}))

super().__init__(t, parents=parents, name=fw_name, **kwargs)