Skip to content

espresso

Custom Espresso calculator and template.

LOGGER module-attribute

LOGGER = getLogger(__name__)

Espresso

Espresso(
    input_atoms: Atoms | None = None,
    preset: str | Path | None = None,
    template: EspressoTemplate | None = None,
    **kwargs
)

Bases: GenericFileIOCalculator

A wrapper around the ASE Espresso calculator that adjusts input_data parameters and allows for the use of presets. Templates are used to set the binary and input/output file names.

Parameters:

  • input_atoms (Atoms | None, default: None ) –

    The input Atoms object to be used for the calculation.

  • preset (str | Path | None, default: None ) –

    A YAML file containing a list of parameters to use as a "preset" for the calculator. If preset has a .yml or .yaml file extension, the path to this file will be used directly. If preset is a string without an extension, the corresponding YAML file will be assumed to be in the ESPRESSO_PRESET_DIR. Any user-supplied calculator **kwargs will override any corresponding preset values.

  • template (EspressoTemplate | None, default: None ) –

    ASE calculator templace which can be used to specify which espresso binary will be used in the calculation. This is taken care of by recipe in most cases.

  • **kwargs

    Additional arguments to be passed to the Espresso calculator. Takes all valid ASE calculator arguments, such as input_data and kpts. Refer to ase.calculators.espresso.Espresso for details. Note that the full input must be described; use {"system":{"ecutwfc": 60}} and not the {"ecutwfc": 60} short-hand.

Returns:

  • None
Source code in quacc/calculators/espresso/espresso.py
def __init__(
    self,
    input_atoms: Atoms | None = None,
    preset: str | Path | None = None,
    template: EspressoTemplate | None = None,
    **kwargs,
) -> None:
    """
    Initialize the Espresso calculator.

    Parameters
    ----------
    input_atoms
        The input Atoms object to be used for the calculation.
    preset
        A YAML file containing a list of parameters to use as a "preset"
        for the calculator. If `preset` has a .yml or .yaml file extension, the
        path to this file will be used directly. If `preset` is a string without
        an extension, the corresponding YAML file will be assumed to be in the
        `ESPRESSO_PRESET_DIR`. Any user-supplied calculator **kwargs will
        override any corresponding preset values.
    template
        ASE calculator templace which can be used to specify which espresso
        binary will be used in the calculation. This is taken care of by recipe
        in most cases.
    **kwargs
        Additional arguments to be passed to the Espresso calculator. Takes all valid
        ASE calculator arguments, such as `input_data` and `kpts`. Refer to
        [ase.calculators.espresso.Espresso][] for details. Note that the full input
        must be described; use `{"system":{"ecutwfc": 60}}` and not the `{"ecutwfc": 60}`
        short-hand.

    Returns
    -------
    None
    """
    self.input_atoms = input_atoms or Atoms()
    self.preset = preset
    self.kwargs = kwargs
    self.user_calc_params = {}
    self._settings = get_settings()
    template = template or EspressoTemplate("pw")
    self._binary = template.binary
    full_path = Path(
        self._settings.ESPRESSO_BIN_DIR,
        self._settings.ESPRESSO_BINARIES[self._binary],
    )
    self._bin_path = str(full_path)

    if template._ase_known_binary:
        self._cleanup_params()
    else:
        LOGGER.warning(
            f"The binary you requested, `{self._binary}`, is not supported by ASE. This means that presets and usual checks will not be carried out, your `input_data` must be provided in nested format."
        )

        self.kwargs["input_data"] = Namelist(self.kwargs.get("input_data"))
        self.user_calc_params = self.kwargs

    self._pseudo_path = (
        self.user_calc_params.get("input_data", {})
        .get("control", {})
        .get("pseudo_dir", str(self._settings.ESPRESSO_PSEUDO))
    )

    cmd_prefix = os.environ.get(
        "PARSL_MPI_PREFIX", self._settings.ESPRESSO_PARALLEL_CMD[0]
    )
    cmd_suffix = self._settings.ESPRESSO_PARALLEL_CMD[1]

    profile = EspressoProfile(
        f"{cmd_prefix} {self._bin_path} {cmd_suffix}", self._pseudo_path
    )

    super().__init__(
        template=template,
        profile=profile,
        directory=".",
        parameters=self.user_calc_params,
    )

input_atoms instance-attribute

input_atoms = input_atoms or Atoms()

kwargs instance-attribute

kwargs = kwargs

preset instance-attribute

preset = preset

user_calc_params instance-attribute

user_calc_params = {}

EspressoTemplate

EspressoTemplate(
    binary: str = "pw",
    test_run: bool = False,
    autorestart: bool = False,
    outdir: str | Path | None = None,
)

Bases: EspressoTemplate

A wrapper around the ASE Espresso template that allows for the use of other binaries such as pw.x, ph.x, cp.x, etc.

Parameters:

  • binary (str, default: 'pw' ) –

    The name of the espresso binary to use. This is used to set the input/output file names. By default we fall back to "pw".

  • test_run (bool, default: False ) –

    If True, a test run is performed to check that the calculation input_data is correct or to generate some files/info if needed.

  • autorestart (bool, default: False ) –

    If True, the calculation will automatically switch to 'restart' if this calculator performs more than one run. (ASE-relax/MD/NEB)

  • outdir (str | Path | None, default: None ) –

    The directory that will be used as outdir in the input_data. If None, the directory will be set to the current working directory.

Returns:

  • None
Source code in quacc/calculators/espresso/espresso.py
def __init__(
    self,
    binary: str = "pw",
    test_run: bool = False,
    autorestart: bool = False,
    outdir: str | Path | None = None,
) -> None:
    """
    Initialize the Espresso template.

    Parameters
    ----------
    binary
        The name of the espresso binary to use. This is used to set the
        input/output file names. By default we fall back to "pw".
    test_run
        If True, a test run is performed to check that the calculation
        input_data is correct or to generate some files/info if needed.
    autorestart
        If True, the calculation will automatically switch to 'restart'
        if this calculator performs more than one run. (ASE-relax/MD/NEB)
    outdir
        The directory that will be used as `outdir` in the input_data. If
        None, the directory will be set to the current working directory.

    Returns
    -------
    None
    """
    super().__init__()

    self.inputname = f"{binary}.in"
    self.outputname = f"{binary}.out"
    self.errorname = f"{binary}.err"
    self.binary = binary
    self._ase_known_binary = self.binary in ALL_KEYS
    self.test_run = test_run
    self.nruns = 0
    self.autorestart = autorestart
    self.outdir = outdir

autorestart instance-attribute

autorestart = autorestart

binary instance-attribute

binary = binary

errorname instance-attribute

errorname = f'{binary}.err'

inputname instance-attribute

inputname = f'{binary}.in'

nruns instance-attribute

nruns = 0

outdir instance-attribute

outdir = outdir

outputname instance-attribute

outputname = f'{binary}.out'

test_run instance-attribute

test_run = test_run

execute

execute(*args: Any, **kwargs: Any) -> None
Source code in quacc/calculators/espresso/espresso.py
def execute(self, *args: Any, **kwargs: Any) -> None:
    super().execute(*args, **kwargs)
    self.nruns += 1

read_results

read_results(directory: PathLike) -> dict[str, Any]

The function that should be used instead of the one in ASE EspressoTemplate to read the output file. It calls a customly defined read function. It also adds the "energy" key to the results dictionnary if it is not present. This is needed if the calculation is not made with pw.x.

Parameters:

  • directory (PathLike) –

    The directory in which to read the output file.

Returns:

  • dict

    The results dictionnary

Source code in quacc/calculators/espresso/espresso.py
def read_results(self, directory: os.PathLike) -> dict[str, Any]:
    """
    The function that should be used instead of the one in ASE EspressoTemplate to
    read the output file. It calls a customly defined read function. It also adds
    the "energy" key to the results dictionnary if it is not present. This is needed
    if the calculation is not made with pw.x.

    Parameters
    ----------
    directory
        The directory in which to read the output file.

    Returns
    -------
    dict
        The results dictionnary
    """
    results = {}
    if self.binary == "pw":
        atoms = read(Path(directory) / self.outputname, format="espresso-out")
        results = dict(atoms.calc.properties())
    elif self.binary in ["ph", "phcg"]:
        with Path(directory, self.outputname).open() as fd:
            results = read_espresso_ph(fd)
    elif self.binary == "dos":
        with Path(directory, "pwscf.dos").open() as fd:
            lines = fd.readlines()
            match = re.search(r"-?\d+\.?\d*", lines[0])
            fermi = float(match.group(0)) if match else None
            dos = np.loadtxt(lines[1:])
        results = {"dos_results": {"dos": dos, "fermi": fermi}}
    elif self.binary == "projwfc":
        with Path(directory, "pwscf.pdos_tot").open() as fd:
            lines = np.loadtxt(fd.readlines())
            energy = lines[1:, 0]
            dos = lines[1:, 1]
            pdos = lines[1:, 2]
        results = {"projwfc_results": {"energy": energy, "dos": dos, "pdos": pdos}}
    elif self.binary == "matdyn":
        fldos = Path(directory, "matdyn.dos")
        if fldos.exists():
            phonon_dos = np.loadtxt(fldos)
            results = {"matdyn_results": {"phonon_dos": phonon_dos}}

    if "energy" not in results:
        results["energy"] = None

    return results

write_input

write_input(
    profile: EspressoProfile,
    directory: Path | str,
    atoms: Atoms,
    parameters: dict[str, Any],
    properties: Any,
) -> None

The function that should be used instead of the one in ASE EspressoTemplate to write the input file. It calls a customly defined write function.

Parameters:

  • profile (EspressoProfile) –

    The profile to use.

  • directory (Path | str) –

    The directory in which to write the input file.

  • atoms (Atoms) –

    The atoms object to use.

  • parameters (dict[str, Any]) –

    The parameters to use.

  • properties (Any) –

    Special ASE properties

Returns:

  • None
Source code in quacc/calculators/espresso/espresso.py
def write_input(
    self,
    profile: EspressoProfile,
    directory: Path | str,
    atoms: Atoms,
    parameters: dict[str, Any],
    properties: Any,
) -> None:
    """
    The function that should be used instead of the one in ASE EspressoTemplate to
    write the input file. It calls a customly defined write function.

    Parameters
    ----------
    profile
        The profile to use.
    directory
        The directory in which to write the input file.
    atoms
        The atoms object to use.
    parameters
        The parameters to use.
    properties
        Special ASE properties

    Returns
    -------
    None
    """
    directory = Path(directory)
    self._output_handler(parameters, directory)
    parameters = self._sanity_checks(parameters)

    if self.outdir:
        safe_decompress_dir(self.outdir)

    if self.test_run:
        self._test_run(parameters, directory)

    if self.binary == "pw":
        if self.autorestart and self.nruns > 0:
            parameters["input_data"]["electrons"]["startingpot"] = "file"
            parameters["input_data"]["electrons"]["startingwfc"] = "file"
        write(
            directory / self.inputname,
            atoms,
            format="espresso-in",
            pseudo_dir=str(profile.pseudo_dir),
            properties=properties,
            **parameters,
        )
    elif self.binary in ["ph", "phcg"]:
        with Path(directory, self.inputname).open(mode="w") as fd:
            write_espresso_ph(fd=fd, properties=properties, **parameters)
    else:
        with Path(directory, self.inputname).open(mode="w") as fd:
            write_fortran_namelist(
                fd,
                binary=self.binary if self._ase_known_binary else None,
                properties=properties,
                **parameters,
            )