"""Per-code parallelization settings.
The top-level ``parallelization`` block maps each code (``pw``, ``kcp``, …)
to a small config of MPI-rank count (``ntasks``), k-point-pool count
(``npool``), a pencil-decomposition switch (``pd``), and a per-rank
OpenMP/BLAS thread count (``omp``). ``ntasks`` becomes the scheduler's
``tot_num_mpiprocs``; ``npool`` becomes ``-npool`` and ``pd`` becomes
``-pd true`` on the QE command line; ``omp`` sets the ``OMP_NUM_THREADS`` /
``OPENBLAS_NUM_THREADS`` / ``MKL_NUM_THREADS`` per rank, defaulting to the
localhost computer's pin of one thread. See
:func:`koopmans.aiida.conversion.code_parallelization` for the translation
into AiiDA ``metadata.options`` / ``settings.cmdline``.
"""
from __future__ import annotations
from typing import Self, cast
from aiida_koopmans.parallelization import CODE_NAMES, ParallelizationDict
from pydantic import Field, model_validator
from koopmans.base import BaseModel
# Every code the parallelization block recognises. Sourced from the single
# ``aiida_koopmans.parallelization`` vocabulary (``CodeName``) rather than duplicated here.
ALL_CODES: tuple[str, ...] = CODE_NAMES
# Codes that accept ``-npool`` (k-point pools) and ``-pd`` (pencil
# decomposition) on their command line. Source-verified against Quantum
# ESPRESSO (``Modules/command_line_options.f90`` parses both flags globally for
# the modern binaries; the koopmans-kcp fork behind kcp.x / wann2kcp.x reads no
# CLI flags, and wannier90 has no pool/pd concept). ``kcw`` accepts pools for
# its wann2kc / screen steps but not its ham step — a per-step distinction the
# workgraph makes; at the schema level ``kcw`` counts as pool-supporting.
POOL_SUPPORTING_CODES: frozenset[str] = frozenset({"pw", "ph", "projwfc", "pw2wannier90", "kcw"})
PD_SUPPORTING_CODES: frozenset[str] = frozenset({"pw", "ph", "projwfc", "pw2wannier90", "kcw"})
__all__ = ["CodeParallelization", "ParallelizationInput"]
# NOTE: keep this Pydantic model (and the per-code fields it validates) in
# sync with the ``CodeParallelization`` TypedDict in ``aiida_koopmans.parallelization``
# — the TypedDict is the runtime shape the graphs consume; this model is the
# user-facing validated view of the same data.
class CodeParallelization(BaseModel):
"""Parallelization settings for a single code."""
ntasks: int | None = Field(
default=None,
ge=1,
description="number of MPI ranks to run the code with (becomes the scheduler's "
"``tot_num_mpiprocs``)",
)
npool: int | None = Field(
default=None,
ge=1,
description="number of k-point pools to distribute the calculation over "
"(becomes ``-npool`` on the command line; should be commensurate with the "
"k-point grid). Only valid for pw, ph, projwfc, pw2wannier90, and kcw.",
)
pd: bool | None = Field(
default=None,
description="use pencil decomposition of the FFT grid (becomes ``-pd true`` on "
"the command line). Only valid for pw, ph, projwfc, pw2wannier90, and kcw.",
)
omp: int | None = Field(
default=None,
ge=1,
description="number of OpenMP / BLAS threads to run each MPI rank with (sets "
"``OMP_NUM_THREADS`` / ``OPENBLAS_NUM_THREADS`` / ``MKL_NUM_THREADS`` per rank). "
"Valid for every code; the default is the localhost computer's pin of one thread "
"per rank, which stops the threaded BLAS builds oversubscribing the allocation.",
)