Source code for atomate2.vasp.flows.lobster

"""Flows for Lobster computations."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING

from jobflow import Flow, Maker
from monty.dev import requires

from atomate2.lobster.jobs import LobsterMaker
from atomate2.vasp.flows.core import DoubleRelaxMaker, UniformBandStructureMaker
from atomate2.vasp.jobs.core import NonSCFMaker, RelaxMaker, StaticMaker
from atomate2.vasp.jobs.lobster import (
    delete_lobster_wavecar,
    get_basis_infos,
    get_lobster_jobs,
    update_user_incar_settings_maker,
)
from atomate2.vasp.sets.core import NonSCFSetGenerator, StaticSetGenerator

try:
    import ijson
    from lobsterpy.cohp.analyze import Analysis
    from lobsterpy.cohp.describe import Description
except ImportError:
    ijson = None
    Analysis = None
    Description = None

if TYPE_CHECKING:
    from pathlib import Path

    from pymatgen.core import Structure

    from atomate2.vasp.jobs.base import BaseVaspMaker


LOBSTER_UNIFORM_MAKER = UniformBandStructureMaker(
    name="uniform lobster structure",
    static_maker=StaticMaker(
        input_set_generator=StaticSetGenerator(
            user_kpoints_settings={"reciprocal_density": 100},
            user_incar_settings={
                "EDIFF": 1e-7,
                "LAECHG": False,
                "LVTOT": False,
                "LREAL": False,
                "ALGO": "Normal",
                "LWAVE": False,
            },
        )
    ),
    bs_maker=NonSCFMaker(
        input_set_generator=NonSCFSetGenerator(
            user_kpoints_settings={"reciprocal_density": 400},
            user_incar_settings={
                "LWAVE": True,
                "ISYM": 0,
            },
        ),
        task_document_kwargs={"parse_dos": False, "parse_bandstructure": False},
    ),
)


[docs] @dataclass class VaspLobsterMaker(Maker): """ Maker to perform a Lobster computation. The calculations performed are: 1. Optional optimization. 2. Static calculation with ISYM=0. 3. Several Lobster computations testing several basis sets are performed. .. Note:: The basis sets can only be changed with yaml files. Parameters ---------- name : str Name of the flows produced by this maker. relax_maker : .BaseVaspMaker or None A maker to perform a relaxation on the bulk. Set to ``None`` to skip the bulk relaxation. lobster_static_maker : .BaseVaspMaker A maker to perform the computation of the wavefunction before the static run. Cannot be skipped. It can be LOBSTERUNIFORM or LobsterStaticMaker() lobster_maker : .LobsterMaker A maker to perform the Lobster run. delete_wavecars : bool If true, all WAVECARs will be deleted after the run. address_min_basis : str A path to a yaml file including basis set information. address_max_basis : str A path to a yaml file including basis set information. """ name: str = "lobster" relax_maker: BaseVaspMaker | None = field( default_factory=lambda: DoubleRelaxMaker.from_relax_maker(RelaxMaker()) ) lobster_static_maker: BaseVaspMaker = field( default_factory=lambda: LOBSTER_UNIFORM_MAKER ) lobster_maker: LobsterMaker | None = field(default_factory=LobsterMaker) delete_wavecars: bool = True address_min_basis: str | None = None address_max_basis: str | None = None
[docs] @requires( Analysis, "This flow requires lobsterpy and ijson to function properly. " "Please reinstall atomate2 using atomate2[lobster]", ) def make( self, structure: Structure, prev_dir: str | Path | None = None, ) -> Flow: """Make flow to calculate bonding properties. Parameters ---------- structure : .Structure A pymatgen structure. Please start with a structure that is nearly fully optimized as the internal optimizers have very strict settings! prev_dir : str or Path or None A previous vasp calculation directory to use for copying outputs. """ jobs = [] # optionally relax the structure optimization_dir = None optimization_uuid = None if self.relax_maker is not None: optimization = self.relax_maker.make(structure, prev_dir=prev_dir) jobs.append(optimization) structure = optimization.output.structure optimization_dir = optimization.output.dir_name optimization_uuid = optimization.output.uuid prev_dir = optimization_dir # Information about the basis is collected basis_infos = get_basis_infos( structure=structure, vasp_maker=self.lobster_static_maker, address_min_basis=self.address_min_basis, address_max_basis=self.address_max_basis, ) jobs.append(basis_infos) # Maker needs to be updated here. If the job itself is updated, no further # updates on the job are possible lobster_static = update_user_incar_settings_maker( self.lobster_static_maker, basis_infos.output["nbands"], structure, prev_dir, ) jobs.append(lobster_static) lobster_static_dir = lobster_static.output.dir_name lobster_static_uuid = lobster_static.output.uuid lobster_jobs = get_lobster_jobs( lobster_maker=self.lobster_maker, basis_dict=basis_infos.output["basis_dict"], optimization_dir=optimization_dir, optimization_uuid=optimization_uuid, static_dir=lobster_static_dir, static_uuid=lobster_static_uuid, ) jobs.append(lobster_jobs) # delete all WAVECARs that have been copied # TODO: this has to be adapted as well if self.delete_wavecars: delete_wavecars = delete_lobster_wavecar( dirs=lobster_jobs.output["lobster_dirs"], lobster_static_dir=lobster_static.output.dir_name, ) jobs.append(delete_wavecars) return Flow(jobs, output=lobster_jobs.output)