From c4650051ec413ba9b40abc3e49afd041db8c0e0e Mon Sep 17 00:00:00 2001 From: Guaxixi Date: Fri, 3 Dec 2021 15:11:39 -0800 Subject: [PATCH 1/6] add absorption --- atomate/vasp/drones.py | 13 ++ atomate/vasp/firetasks/absorption_tasks.py | 56 ++++++ atomate/vasp/fireworks/absorption.py | 217 +++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 atomate/vasp/firetasks/absorption_tasks.py create mode 100644 atomate/vasp/fireworks/absorption.py diff --git a/atomate/vasp/drones.py b/atomate/vasp/drones.py index c7cb95835..b6de26d58 100644 --- a/atomate/vasp/drones.py +++ b/atomate/vasp/drones.py @@ -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" ) @@ -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): diff --git a/atomate/vasp/firetasks/absorption_tasks.py b/atomate/vasp/firetasks/absorption_tasks.py new file mode 100644 index 000000000..1a5e989c7 --- /dev/null +++ b/atomate/vasp/firetasks/absorption_tasks.py @@ -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) diff --git a/atomate/vasp/fireworks/absorption.py b/atomate/vasp/fireworks/absorption.py new file mode 100644 index 000000000..177a8aff8 --- /dev/null +++ b/atomate/vasp/fireworks/absorption.py @@ -0,0 +1,217 @@ +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={}, + **kwargs, + ): + """ + FW that calculates frequency dpendent dielectric function within + indenpendent-particle-approxiamtion. A previous ground state calculation + with 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 another calculation with 'ALGO = EXACT, LOPTICS = True' + with variable NBANDS will be performed (MODE = "IPA"). This calculation + can 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 polarization FireWork. + static_name (str): Name for the SCF run to be used in PassCalcLoc + if copy_vasp_outputs != True. + mode: 'STATIC', 'IPA', or 'RPA'. Default is 'IPA' + vasp_cmd (str): Command to run vasp. + vasp_input_set (str): string name for the VASP input set (e.g., + "MPAbsorptionSet"). + vasp_input_set_params (dict): Dict of vasp_input_set_kwargs. + db_file (str): Path to file specifying db credentials. + parents (Firework): Parents of this particular Firework. FW or list + of FWS. + 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. If False/None, will create + new SCAN calculation using the provided structure. + prev_calc_dir (str): Path to a previous calculation to copy from + db_file (str): Path to file specifying db credentials. + parents (Firework): Parents of this particular Firework. FW or list of FWs. + 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 + ) + + has_previous_calc = False + + # 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": + if prev_calc_dir: + # Copy only the CONTCAR from previous calc directory + t.append(CopyVaspOutputs( + calc_dir=prev_calc_dir, + contcar_to_poscar=True, + additional_files=wavecars) + ) + + t.append(WriteVaspStaticFromPrev(user_incar_settings={"LWAVE": "TRUE"})) + + elif parents: + # Copy only the CONTCAR from previous calc + t.append( + CopyVaspOutputs( + calc_loc=True, + contcar_to_poscar=True, + additional_files=wavecars + ) + ) + + t.append(WriteVaspStaticFromPrev(user_incar_settings={"LWAVE": "TRUE"})) + + elif structure: + vasp_input_set = MPStaticSet( + structure, user_incar_settings={"LWAVE": "TRUE"} + ) + t.append( + WriteVaspFromIOSet(structure=structure, vasp_input_set=vasp_input_set) + ) + + else: + raise ValueError("Must specify structure or previous calculation for Static calculation") + + else: + raise ValueEroor("Must specify 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, + gzip_output=False, + ) + ) + t.append(PassCalcLocs(name=name)) + # Parse + t.append(VaspToDb(db_file=db_file, + additional_fields={ + "task_label": structure.composition.reduced_formula + " " + name + " " + mode})) + # zip the output (don't rely on custodian to do it) + t.append(GzipDir()) + + super().__init__(t, parents=parents, name=fw_name, **kwargs) + + From 8e58aedf7f813dfe8317b43a04fafaf246c0bcf0 Mon Sep 17 00:00:00 2001 From: yang-ruoxi Date: Tue, 7 Dec 2021 20:24:11 -0800 Subject: [PATCH 2/6] add absorptionFW --- atomate/vasp/fireworks/absorption.py | 46 +++++++++++++--------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/atomate/vasp/fireworks/absorption.py b/atomate/vasp/fireworks/absorption.py index 177a8aff8..edca23685 100644 --- a/atomate/vasp/fireworks/absorption.py +++ b/atomate/vasp/fireworks/absorption.py @@ -39,40 +39,39 @@ def __init__( db_file=DB_FILE, vasptodb_kwargs=None, parents=None, - vasp_input_set_params={}, + vasp_input_set_params=None, **kwargs, ): """ - FW that calculates frequency dpendent dielectric function within + FW that calculates frequency dependent dielectric function within indenpendent-particle-approxiamtion. A previous ground state calculation - with WAVECAR is required by specifying mode = 'static'; in the case of no + 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 another calculation with 'ALGO = EXACT, LOPTICS = True' - with variable NBANDS will be performed (MODE = "IPA"). This calculation - can save the WAVECAR and WAVEDER in case one wants to run RPA level absorption + 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 polarization FireWork. - static_name (str): Name for the SCF run to be used in PassCalcLoc - if copy_vasp_outputs != True. - mode: 'STATIC', 'IPA', or 'RPA'. Default is 'IPA' + 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"). - vasp_input_set_params (dict): Dict of vasp_input_set_kwargs. db_file (str): Path to file specifying db credentials. parents (Firework): Parents of this particular Firework. FW or list of FWS. - 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. If False/None, will create - new SCAN calculation using the provided structure. + vasp_input_set_params (dict): Dict of vasp_input_set_kwargs. prev_calc_dir (str): Path to a previous calculation to copy from - db_file (str): Path to file specifying db credentials. - parents (Firework): Parents of this particular Firework. FW or list of FWs. vasptodb_kwargs (dict): kwargs to pass to VaspToDb **kwargs: Other kwargs that are passed to Firework.__init__. @@ -89,8 +88,6 @@ def __init__( structure.composition.reduced_formula if structure else "unknown", name, mode ) - has_previous_calc = False - # define what wavecars to copy from the previous run if mode == "STATIC": wavecars = [] @@ -157,14 +154,14 @@ def __init__( # when mode = "static" elif mode == "STATIC": if prev_calc_dir: - # Copy only the CONTCAR from previous calc directory + # 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(user_incar_settings={"LWAVE": "TRUE"})) + t.append(WriteVaspStaticFromPrev(other_params = {"user_incar_settings": {"LWAVE": "TRUE"}})) elif parents: # Copy only the CONTCAR from previous calc @@ -176,7 +173,8 @@ def __init__( ) ) - t.append(WriteVaspStaticFromPrev(user_incar_settings={"LWAVE": "TRUE"})) + t.append( + WriteVaspStaticFromPrev(other_params = {"user_incar_settings": {"LWAVE": "TRUE"}})) elif structure: vasp_input_set = MPStaticSet( @@ -187,10 +185,10 @@ def __init__( ) else: - raise ValueError("Must specify structure or previous calculation for Static calculation") + raise ValueError("Must specify structure or previous calculation for static calculation") else: - raise ValueEroor("Must specify mode from 'STATIC', 'IPA', or 'RPA'") + raise ValueEroor("Must specify a mode from 'STATIC', 'IPA', or 'RPA'") # use the 'default' custodian handler group handler_group = "default" From 2ae34cbbacba0338e50d2808b2d59ae001e3a461 Mon Sep 17 00:00:00 2001 From: yang-ruoxi Date: Mon, 20 Dec 2021 16:26:46 -0800 Subject: [PATCH 3/6] modified WriteVaspStaticFromPrev --- atomate/vasp/fireworks/absorption.py | 53 ++++++++++++++++++---------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/atomate/vasp/fireworks/absorption.py b/atomate/vasp/fireworks/absorption.py index edca23685..e81650d1f 100644 --- a/atomate/vasp/fireworks/absorption.py +++ b/atomate/vasp/fireworks/absorption.py @@ -153,42 +153,59 @@ def __init__( # when mode = "static" elif mode == "STATIC": + static_incar={"LWAVE": True, + "ENCUT": 500, + "ISMEAR": 0, + "SIGMA": 0.01, + "LREAL": False, + "GGA": "PE", + "LCHARG": False, + "LAECHG": 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(other_params = {"user_incar_settings": {"LWAVE": "TRUE"}})) - - elif parents: - # Copy only the CONTCAR from previous calc t.append( CopyVaspOutputs( - calc_loc=True, + calc_dir=prev_calc_dir, contcar_to_poscar=True, additional_files=wavecars ) ) t.append( - WriteVaspStaticFromPrev(other_params = {"user_incar_settings": {"LWAVE": "TRUE"}})) - - elif structure: - vasp_input_set = MPStaticSet( - structure, user_incar_settings={"LWAVE": "TRUE"} + WriteVaspStaticFromPrev(structure=structure, + 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( - WriteVaspFromIOSet(structure=structure, vasp_input_set=vasp_input_set) + WriteVaspStaticFromPrev(structure=structure, + 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 ValueEroor("Must specify a mode from 'STATIC', 'IPA', or 'RPA'") + raise ValueError("Must specify a mode from 'STATIC', 'IPA', or 'RPA'") # use the 'default' custodian handler group handler_group = "default" From 99ea3dc14fe5c8510c53f343c181c08932792097 Mon Sep 17 00:00:00 2001 From: yang-ruoxi Date: Mon, 20 Dec 2021 16:44:04 -0800 Subject: [PATCH 4/6] modified WriteVaspStaticFromPrev --- atomate/vasp/fireworks/absorption.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/atomate/vasp/fireworks/absorption.py b/atomate/vasp/fireworks/absorption.py index e81650d1f..0e76c8533 100644 --- a/atomate/vasp/fireworks/absorption.py +++ b/atomate/vasp/fireworks/absorption.py @@ -175,8 +175,7 @@ def __init__( ) t.append( - WriteVaspStaticFromPrev(structure=structure, - reciprocal_density=reciprocal_density, + WriteVaspStaticFromPrev(reciprocal_density=reciprocal_density, other_params={"user_incar_settings": static_incar}) ) @@ -188,15 +187,14 @@ def __init__( ) t.append( - WriteVaspStaticFromPrev(structure=structure, - reciprocal_density=reciprocal_density, + 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) + reciprocal_density=reciprocal_density, + user_incar_settings=static_incar) t.append(WriteVaspFromIOSet(structure=structure, vasp_input_set=static_input_set) ) From 6d881a8e44fd7319d6b3d13a852074613b1ad1c8 Mon Sep 17 00:00:00 2001 From: yang-ruoxi Date: Wed, 12 Jan 2022 13:16:49 -0800 Subject: [PATCH 5/6] incar edit --- atomate/vasp/fireworks/absorption.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/atomate/vasp/fireworks/absorption.py b/atomate/vasp/fireworks/absorption.py index 0e76c8533..b88be9a4f 100644 --- a/atomate/vasp/fireworks/absorption.py +++ b/atomate/vasp/fireworks/absorption.py @@ -160,7 +160,11 @@ def __init__( "LREAL": False, "GGA": "PE", "LCHARG": False, + "LELF": False, "LAECHG": False, + "LASPH": False, + "LVHAR": False, + "LVTOT": False, "METAGGA": "None", "LMIXTAU": False} @@ -213,8 +217,7 @@ def __init__( RunVaspCustodian( vasp_cmd=vasp_cmd, auto_npar=">>auto_npar<<", - handler_group=handler_group, - gzip_output=False, + handler_group=handler_group ) ) t.append(PassCalcLocs(name=name)) @@ -222,8 +225,6 @@ def __init__( t.append(VaspToDb(db_file=db_file, additional_fields={ "task_label": structure.composition.reduced_formula + " " + name + " " + mode})) - # zip the output (don't rely on custodian to do it) - t.append(GzipDir()) super().__init__(t, parents=parents, name=fw_name, **kwargs) From 1403c693b22d3a499836b4f95e68576bf62f5aa8 Mon Sep 17 00:00:00 2001 From: yang-ruoxi Date: Wed, 2 Feb 2022 09:56:56 -0800 Subject: [PATCH 6/6] cleanup --- atomate/vasp/fireworks/absorption.py | 1 - 1 file changed, 1 deletion(-) diff --git a/atomate/vasp/fireworks/absorption.py b/atomate/vasp/fireworks/absorption.py index b88be9a4f..d78ef3a46 100644 --- a/atomate/vasp/fireworks/absorption.py +++ b/atomate/vasp/fireworks/absorption.py @@ -159,7 +159,6 @@ def __init__( "SIGMA": 0.01, "LREAL": False, "GGA": "PE", - "LCHARG": False, "LELF": False, "LAECHG": False, "LASPH": False,