Source code for aiida_wannier90_workflows.workflows.base.projwfc
"""Wrapper workchain for ProjwfcCalculation to automatically handle several errors."""
import pathlib
import typing as ty
from aiida import orm
from aiida.common.lang import type_check
from aiida.engine import process_handler
from aiida.engine.processes.builder import ProcessBuilder
from aiida_quantumespresso.calculations.projwfc import ProjwfcCalculation
from aiida_quantumespresso.workflows.protocols.utils import ProtocolMixin
from .qebaserestart import QeBaseRestartWorkChain
__all__ = [
"ProjwfcBaseWorkChain",
]
[docs]class ProjwfcBaseWorkChain(ProtocolMixin, QeBaseRestartWorkChain):
"""Workchain to run a projwfc.x calculation with automated error handling and restarts."""
_process_class = ProjwfcCalculation
_inputs_namespace = "projwfc"
@classmethod
def get_protocol_filepath(cls) -> pathlib.Path:
"""Return the ``pathlib.Path`` to the ``.yaml`` file that defines the protocols."""
from importlib_resources import files
from .. import protocols
return files(protocols) / "base" / "projwfc.yaml"
@classmethod
def get_builder_from_protocol(
cls,
code: ty.Union[orm.Code, str, int],
*,
protocol: str = None,
overrides: dict = None,
) -> ProcessBuilder:
"""Return a builder prepopulated with inputs selected according to the chosen protocol.
:param code: [description]
:type code: ty.Union[orm.Code, str, int]
:param protocol: [description], defaults to None
:type protocol: str, optional
:param overrides: [description], defaults to None
:type overrides: dict, optional
:return: [description]
:rtype: ProcessBuilder
"""
from aiida_quantumespresso.workflows.protocols.utils import recursive_merge
if isinstance(code, (int, str)):
code = orm.load_code(code)
type_check(code, orm.Code)
# Update the parameters based on the protocol inputs
inputs = cls.get_protocol_inputs(protocol, overrides)
parameters = inputs[cls._inputs_namespace]["parameters"]
metadata = inputs[cls._inputs_namespace]["metadata"]
# If overrides are provided, they take precedence over default protocol
if overrides:
parameter_overrides = overrides.get(cls._inputs_namespace, {}).get(
"parameters", {}
)
parameters = recursive_merge(parameters, parameter_overrides)
metadata_overrides = overrides.get(cls._inputs_namespace, {}).get(
"metadata", {}
)
metadata = recursive_merge(metadata, metadata_overrides)
# pylint: disable=no-member
builder = cls.get_builder()
builder[cls._inputs_namespace]["code"] = code
builder[cls._inputs_namespace]["parameters"] = orm.Dict(parameters)
builder[cls._inputs_namespace]["metadata"] = metadata
if "settings" in inputs[cls._inputs_namespace]:
builder[cls._inputs_namespace]["settings"] = orm.Dict(
dict=inputs[cls._inputs_namespace]["settings"]
)
if "settings" in inputs:
builder["settings"] = orm.Dict(inputs["settings"])
builder.clean_workdir = orm.Bool(inputs["clean_workdir"])
# pylint: enable=no-member
return builder
@process_handler(
exit_codes=[
_process_class.exit_codes.ERROR_OUTPUT_STDOUT_INCOMPLETE
] # pylint: disable=no-member
)
def handle_output_stdout_incomplete(self, calculation):
"""Overide parent function."""
return super().handle_output_stdout_incomplete(calculation)