Source code for abipy.flowtk.gwr_works
# coding: utf-8
"""
Works and Flows for GWR calculations (GW with supercells).
NB: An Abinit build with Scalapack is required to run GWR.
"""
from __future__ import annotations
import os
from abipy.abio.inputs import AbinitInput, RUNL, GWR_TASK
from abipy.electrons.gwr import GwrRobot
from abipy.tools.iotools import make_executable
from .nodes import Node
from .tasks import TaskManager
from .works import Work
[docs]
class DirectDiagoWork(Work):
"""
This work performs the direct diagonalization of the KS Hamiltonian
using the density produced by a GS-SCF run and produces a WFK file with
empty states in the outdir of the second task.
.. rubric:: Inheritance Diagram
.. inheritance-diagram:: DirectDiagoWork
"""
[docs]
@classmethod
def from_scf_input(cls, scf_input: AbinitInput, green_nband: int,
manager: TaskManager=None) -> DirectDiagoWork:
"""
Build object from an input representing a GS-SCF calculation.
Args:
scf_input: Input for the GS-SCF calculation.
green_nband: Number of bands to compute in the direct diagonalization.
A negative value activate full diagonalization with nband equal to
the number of PWs.
"""
work = cls(manager=manager)
work.green_nband = green_nband
gwr_task = GWR_TASK.HDIAGO_FULL if green_nband < 0 else GWR_TASK.HDIAGO
work.scf_task = work.register_scf_task(scf_input)
diago_input = scf_input.new_with_vars(optdriver=RUNL.GWR, gwr_task=gwr_task)
work.diago_task = work.register_gwr_task(diago_input, deps={work.scf_task: "DEN"})
return work
class _BaseGWRWork(Work):
@classmethod
def from_varname_values(cls, varname_values: tuple, gwr_template: AbinitInput,
den_node: Node, wfk_node: Node,
manager: TaskManager = None):
"""
Generate the work by changing the values of selected variables in a template for GWR calculations.
Args:
varname_values: Tuple or List of tuples. See examples below.
gwr_template: GWR input to be used as template to generate other inputs.
den_node: The Node who produced the DEN file.
wfk_node: The Node who produced the WFK file.
manager: Abipy Task Manager.
Example:
varname_values = ("nband", [8, 12, 14])
Work.from_varname_values(varname_values, gwr_template, den_node, wfk_node)
or:
varname_values = [
("nband", [8, 12]),
("gwr_ntau", [6, 8]),
]
Work.from_varname_values(varname_values, gwr_template, den_node, wfk_node)
"""
work = cls(manager=manager)
for new_inp in gwr_template.news_varname_values(varname_values):
work.register_gwr_task(new_inp, deps={den_node: "DEN", wfk_node: "WFK"})
return work
[docs]
class GWRSigmaConvWork(_BaseGWRWork):
"""
This work performs multiple QP calculations with the GWR code
and produces `xlsx` files in its `outdata` directory
with the QP results obtained with the different parameters.
.. rubric:: Inheritance Diagram
.. inheritance-diagram:: GWRSigmaConvWork
"""
[docs]
def on_all_ok(self):
"""
Generate `qp_dirgaps.csv` file in the `outdata` directory.
"""
with GwrRobot.from_files(self.get_all_outdata_files_with_ext("_GWR.nc")) as gwr_robot:
dirgaps_df = gwr_robot.get_dirgaps_dataframe()
dirgaps_df.to_csv(self.outdir.path_in("dirgaps.csv"))
qpdata_df = gwr_robot.get_dataframe()
qpdata_df.to_csv(self.outdir.path_in("qpdata.csv"))
with gwr_robot.get_pyscript(self.outdir.path_in("gwr_robot.py")) as script:
script.add_text("""
#robot.plot_selfenergy_conv(spin=0, kpoint=?, band=?, axis="wreal", sortby=None, hue=None)
#robot.plot_qpgaps_convergence(qp_kpoints="all", qp_type="qpz0", sortby=None, hue=None)
""")
return super().on_all_ok()
[docs]
class GWRChiCompareWork(_BaseGWRWork):
"""
This work computes the irreducibile polarizability along the imaginary axis
using the GWR code and the quartic-scaling algorithm using the same minimax mesh
so that one can compare the two quantities.
.. rubric:: Inheritance Diagram
.. inheritance-diagram:: GWRChiCompareConvWork
"""
[docs]
@classmethod
def from_scf_input(cls, scf_input: AbinitInput, gwr_ntau, nband, ecuteps,
den_node: Node, wfk_node: Node,
gwr_kwargs=None, scr_kwargs=None,
manager: TaskManager = None):
"""
Build Work from an input for GS-SCF calculation
Args:
scf_input: input for GS run.
gwr_ntau: Number of points in minimax mesh.
nband: Number of bands to build G and chi.
ecuteps: Cutoff energy for chi.
den_node: The Node who produced the DEN file.
wfk_node: The Node who produced the WFK file.
gwr_kwargs: Extra kwargs used to build the GWR input.
scr_kwargs: Extra kwargs used to build the SCR input.
manager: Abipy Task Manager.
"""
gwr_input = scf_input.make_gwr_qprange_input(gwr_ntau=gwr_ntau, nband=nband,
ecuteps=ecuteps, gwr_task=GWR_TASK.CHI0)
gwr_input.set_vars(prtsuscep=1, iomode=3)
if gwr_kwargs is not None: gwr_input.set_vars(**gwr_kwargs)
chi_input = scf_input.new_with_vars(optdriver=3,
gwcalctyp=1, # Analytic continuation.
nfreqim=gwr_ntau,
ecuteps=ecuteps,
nband=nband,
prtsuscep=1,
iomode=3,
userie=4242, # Magic number to use the minimax mesh in the SCR driver.
# with nfreqim points.
)
if scr_kwargs is not None: chi_input.set_vars(**scr_kwargs)
work = cls(manager=manager)
work.register_scr_task(chi_input, deps={wfk_node: "WFK"})
work.register_gwr_task(gwr_input, deps={den_node: "DEN", wfk_node: "WFK"})
return work
[docs]
def on_all_ok(self):
"""
Write python script to compare chi0 matrix elements.
"""
sus_path = self[0].outdir.path_in("out_SUS.nc")
tchi_path = self[1].outdir.path_in("out_TCHIM.nc")
py_text = f"""\
#!/usr/bin/env python
import seaborn as sns
sns.set(context="paper", style='darkgrid', palette='deep',
font='sans-serif', font_scale=0.8, color_codes=False, rc=None)
from abipy.electrons.gwr import TchimVsSus
o = TchimVsSus("{tchi_path}", "{sus_path}")
gpairs = [
((0, 0, 0), (0, 0, 0)),
((0, 0, 0), (1, 0, 0)),
((1, 0, 0), (1, 0, 0)),
((1, 0, 0), (0, 1, 0)),
((0, 0, 0), (2, 0, 0)),
]
qpoint_list = [
[0, 0, 0],
[0.5, 0, 0],
]
o.expose_qpoints_gpairs(qpoint_list, gpairs, exposer="mpl")
#o.plot_matdiff(qpoint=0, iw_index=0)
"""
py_path = os.path.join(self.workdir, "plot_tchi_sus.py")
with open(py_path, "wt") as fh:
fh.write(py_text)
make_executable(py_path)
return super().on_all_ok()
[docs]
class GWRRPAConvWork(_BaseGWRWork):
"""
This work computes the RPA correlated energy for different number
of points in the minimax mesh.
"""
[docs]
@classmethod
def from_scf_input_ntaus(cls, scf_input: AbinitInput, gwr_ntau_list, nband, ecuteps,
den_node: Node, wfk_node: Node,
gwr_kwargs=None, manager: TaskManager=None):
"""
Build Work from an input for GS-SCF calculation
Args:
scf_input: input for GS run.
gwr_ntau_list: List with number of points in minimax mesh.
nband: Number of bands to build G and chi.
ecuteps: Cutoff energy for chi.
den_node: The Node who produced the DEN file.
wfk_node: The Node who produced the WFK file.
gwr_kwargs: Extra kwargs used to build the GWR input.
manager: Abipy Task Manager.
"""
work = cls(manager=manager)
for gwr_ntau in gwr_ntau_list:
gwr_input = scf_input.make_gwr_qprange_input(gwr_ntau=gwr_ntau, nband=nband,
ecuteps=ecuteps, gwr_task=GWR_TASK.RPA_ENERGY)
if gwr_kwargs is not None: gwr_input.set_vars(**gwr_kwargs)
work.register_gwr_task(gwr_input, deps={den_node: "DEN", wfk_node: "WFK"})
return work
[docs]
def on_all_ok(self):
"""
Generate `gwr_robot.py` script in the `outdata` directory.
"""
with GwrRobot.from_files(self.get_all_outdata_files_with_ext("_GWR.nc")) as gwr_robot:
with gwr_robot.get_pyscript(self.outdir.path_in("gwr_robot.py")) as script:
script.add_text("""
df = robot.get_rpa_ene_dataframe()
print(df)
""")
return super().on_all_ok()