# SPDX-FileCopyrightText: 2025-2026 Julian Peil <julian.peil@tuwien.ac.at>
# SPDX-License-Identifier: MIT
#
# DGAmore — Multi-Orbital Ladder Dynamical Vertex Approximation (LDGA) &
# Eliashberg Equation Solver for Strongly Correlated Electron Systems
"""
Global configuration singleton. This module holds the process-wide mutable state of a DGAmore run as module-level
instances of the ``*Config`` classes (``box``, ``lattice``, ``sys``, ``dmft``, ``eliashberg``,
``lambda_correction``, ``self_consistency``, ``self_energy_interpolation``, ``output``, ``memory``, ``ana_cont``,
and the ``logger``). :class:`ConfigParser` populates these from a YAML file on rank 0, after which they are
broadcast to all MPI ranks; most modules read their parameters directly off this module rather than receiving them
as arguments, so mutating a field changes behavior everywhere. Each ``*Config`` class documents its fields; the
example YAML config is ``dgamore/dga_config.yaml``.
"""
import numpy as np
import dgamore.brillouin_zone as bz
from dgamore.dga_logger import DgaLogger
from dgamore.hamiltonian import Hamiltonian
[docs]
class InteractionConfig:
r"""
Stores the interaction parameters. Currently only ``udd``, ``vdd``, ``jdd`` are used (local and Kanamori-type
interactions); the remaining parameters are reserved for future use.
:ivar float udd: Intra-orbital Hubbard interaction :math:`U_{dd}` on the d orbitals.
:ivar float udp: Inter-orbital d-p Hubbard interaction.
:ivar float upp: Intra-orbital Hubbard interaction :math:`U_{pp}` on the p orbitals.
:ivar float uppod: Off-diagonal p-p Hubbard interaction.
:ivar float jdd: Hund's exchange :math:`J_{dd}` on the d orbitals.
:ivar float jdp: Inter-orbital d-p exchange.
:ivar float jpp: Hund's exchange :math:`J_{pp}` on the p orbitals.
:ivar float jppod: Off-diagonal p-p exchange.
:ivar float vdd: Inter-orbital interaction :math:`V_{dd}` on the d orbitals.
:ivar float vpp: Inter-orbital interaction :math:`V_{pp}` on the p orbitals.
"""
def __init__(self):
self.udd: float = 0.0
self.udp: float = 0.0
self.upp: float = 0.0
self.uppod: float = 0.0
self.jdd: float = 0.0
self.jdp: float = 0.0
self.jpp: float = 0.0
self.jppod: float = 0.0
self.vdd: float = 0.0
self.vpp: float = 0.0
[docs]
class BoxConfig:
r"""
Stores the Matsubara frequency box sizes. The main quantities live in the core region; explicit asymptotics
correct it with shell-region quantities. The full region is the sum of core and shell and exists for convenience.
:ivar int niw_core: Number of positive bosonic core frequencies :math:`\omega`.
:ivar int niv_core: Number of positive fermionic core frequencies :math:`\nu`.
:ivar int niv_shell: Number of positive fermionic shell frequencies (asymptotic correction region).
:ivar int niv_full: Number of positive fermionic full-region frequencies (core + shell).
:ivar int niv_dmft: Number of positive fermionic frequencies available in the DMFT 1-particle input.
"""
def __init__(self):
self.niw_core: int = -1
self.niv_core: int = -1
self.niv_shell: int = 0
self.niv_full: int = 0
self.niv_dmft: int = 0
[docs]
class LatticeConfig:
"""
Stores the lattice parameters: the symmetries, lattice type, input Hamiltonian and input interaction. The k and
q grids are built from the number of k/q points and the lattice symmetries. See ``dga_config.yaml`` or the
author's master's thesis for details.
:ivar list symmetries: The lattice symmetries (a list of :class:`KnownSymmetries` or the auto sentinel).
:ivar str type: How the kinetic Hamiltonian is provided (e.g. ``"from_wannier90"``).
:ivar er_input: Path(s) to the hopping input.
:vartype er_input: str | list
:ivar str interaction_type: How the interaction is provided (e.g. ``"one_band_from_dmft"``).
:ivar interaction_input: Path(s) to the interaction input.
:vartype interaction_input: str | list
:ivar tuple nk: Number of k-points per spatial direction.
:ivar tuple nq: Number of q-points per spatial direction (defaults to ``nk``).
:ivar InteractionConfig interaction: The :class:`InteractionConfig`.
:ivar Hamiltonian hamiltonian: The :class:`Hamiltonian` instance.
:ivar KGrid k_grid: The k-space :class:`KGrid`.
:ivar KGrid q_grid: The q-space :class:`KGrid`.
"""
def __init__(self):
self.symmetries: list[bz.KnownSymmetries] = bz.two_dimensional_square_symmetries()
self.type: str = "from_wannier90"
self.er_input: str | list = "/path/to/file"
self.interaction_type: str = "one_band_from_dmft"
self.interaction_input: str | list = ""
self.nk: tuple[int, int, int] = (16, 16, 1)
self.nq: tuple[int, int, int] = self.nk
self.interaction: InteractionConfig = InteractionConfig()
self.hamiltonian: Hamiltonian = Hamiltonian()
self.k_grid: bz.KGrid = bz.KGrid(self.nk, self.symmetries)
self.q_grid: bz.KGrid = bz.KGrid(self.nq, self.symmetries)
[docs]
class SelfConsistencyConfig:
r"""
Stores the self-consistency-loop parameters: the maximum iteration count, the convergence criterion, the mixing
parameter/scheme and continuation options. If ``previous_sc_path`` is set, the loop resumes from a previous run.
The mixing scheme can be ``"linear"``, ``"pulay"`` or ``"anderson"`` (the latter two use an iteration history).
:ivar int max_iter: Maximum number of self-consistency iterations.
:ivar float epsilon: Relative-residual convergence threshold on the self-energy.
:ivar float mixing: The mixing parameter :math:`\alpha`.
:ivar str mixing_strategy: The mixing scheme (``"linear"``, ``"pulay"`` or ``"anderson"``).
:ivar int mixing_history_length: Number of past iterations used by the accelerated mixing schemes.
:ivar str previous_sc_path: Path to a previous self-consistency run to resume from (empty to start fresh).
:ivar bool use_interpolated_sigma: Whether to resume from the interpolated rather than the raw self-energy.
:ivar bool use_lambda_correction: Whether the self-consistency loop applies the lambda correction.
:ivar bool restrict_chi_phys: Whether to restrict the physical susceptibility to positive values.
:ivar anderson_prev_res: Cached previous Anderson residual (internal use).
:vartype anderson_prev_res: float | None
"""
def __init__(self):
self.max_iter: int = 20
self.epsilon: float = 1e-4
self.mixing: float = 0.2
self.mixing_strategy: str = "linear"
self.mixing_history_length: int = 3
self.previous_sc_path: str = ""
self.use_interpolated_sigma: bool = False
self.use_lambda_correction: bool = False
self.restrict_chi_phys: bool = False
self.anderson_prev_res: float | None = None
[docs]
class EliashbergConfig:
"""
Stores the Eliashberg-step configuration: whether to run it, power-iteration settings, and saving options for the
pairing/full vertex in pp notation.
:ivar bool perform_eliashberg: Whether to solve the Eliashberg equation.
:ivar bool save_pairing_vertex: Whether to save the singlet/triplet pairing vertices.
:ivar bool save_fq: Whether to save the full ladder vertex (in ph notation) in the irreducible BZ.
:ivar bool construct_fq_cheap: Whether to build the full vertex on the smaller pp frequency box (cheaper).
:ivar int n_eig: Number of leading eigenvalues/gap functions to compute per channel.
:ivar float epsilon: Convergence tolerance for the Lanczos eigensolver.
:ivar str symmetry: Initial gap-function symmetry (``"d-wave"``, ``"p-wave-x"``, ``"p-wave-y"``, or ``"random"``).
:ivar bool include_local_part: Whether to add the local reducible pp diagrams to the pairing vertex.
:ivar str subfolder_name: Output subfolder name for Eliashberg results.
"""
def __init__(self):
self.perform_eliashberg: bool = False
self.save_pairing_vertex: bool = False
self.save_fq: bool = False
self.construct_fq_cheap: bool = False
self.n_eig: int = 4
self.epsilon: float = 1e-6
self.symmetry: str = "random"
self.include_local_part: bool = True
self.subfolder_name: str = "Eliashberg"
[docs]
class LambdaCorrectionConfig:
"""
Stores the lambda-correction configuration.
:ivar bool perform_lambda_correction: Whether to apply the Moriya lambda correction.
:ivar str type: Correction type: ``"sp"`` (magnetic channel only) or ``"spch"`` (density and magnetic channels).
"""
def __init__(self):
self.perform_lambda_correction: bool = False
self.type: str = "spch"
[docs]
class DmftConfig:
r"""
Stores the DMFT input-file parameters: the input path, the 1- and 2-particle data filenames, symmetrization
options and the inequivalent-atom structure.
:ivar str type: DMFT solver/format of the input (e.g. ``"w2dyn"``).
:ivar str input_path: Directory containing the DMFT input files.
:ivar str fname_1p: Filename of the 1-particle data.
:ivar str fname_2p: Filename of the 2-particle data.
:ivar bool do_sym_v_vp: Whether to symmetrize the 2-particle data with respect to :math:`(\nu, \nu')`.
:ivar list symmetrize_orbitals: 1-based orbital indices to symmetrize over (empty for none).
:ivar int n_ineq: Number of inequivalent atoms.
:ivar list ineq_ordering: Ordering of the inequivalent atoms.
:ivar list n_bands_per_ineq: Number of bands per inequivalent atom.
"""
def __init__(self):
self.type: str = "w2dyn"
self.input_path: str = "./"
self.fname_1p: str = "1p-data.hdf5"
self.fname_2p: str = "g4iw_sym.hdf5"
self.do_sym_v_vp: bool = True
self.symmetrize_orbitals: list = []
self.n_ineq: int = 1
self.ineq_ordering: list[int] = [1]
self.n_bands_per_ineq = []
[docs]
class SystemConfig:
r"""
Stores the physical system parameters and derived quantities updated during the run.
:ivar float beta: Inverse temperature :math:`\beta`.
:ivar float mu: Chemical potential :math:`\mu` (updated during self-consistency).
:ivar float mu_dmft: Chemical potential of the DMFT input.
:ivar float n: Total filling :math:`n`.
:ivar int n_bands: Number of bands.
:ivar numpy.ndarray occ: Local (k-averaged) occupation matrix.
:ivar numpy.ndarray occ_k: Full (k-resolved) occupation matrix.
:ivar numpy.ndarray occ_dmft: Local occupation matrix from the DMFT input.
:ivar list occ_dmft_per_ineq: DMFT occupation matrices per inequivalent atom.
"""
def __init__(self):
self.beta: float = 0.0
self.mu: float = 0.0
self.mu_dmft: float = 0.0
self.n: float = 0.0
self.n_bands: int = 0
self.occ: np.ndarray = np.ndarray(0)
self.occ_k: np.ndarray = np.ndarray(0)
self.occ_dmft: np.ndarray = np.ndarray(0)
self.occ_dmft_per_ineq: list[np.ndarray] = []
[docs]
class SelfEnergyInterpolationConfig:
r"""
Stores the self-energy interpolation parameters (re-gridding to a different temperature/frequency box).
:ivar bool do_interpolation: Whether to additionally save an interpolated self-energy each iteration.
:ivar float beta_target: Target inverse temperature :math:`\beta` of the interpolation.
:ivar int niv_target: Target number of positive fermionic frequencies of the interpolation.
"""
def __init__(self):
self.do_interpolation: bool = False
self.beta_target: float = 1.0
self.niv_target: int = 10
[docs]
class OutputConfig:
"""
Stores the output paths.
:ivar str output_path: Directory where the main results are written.
:ivar bool do_plotting: Whether to produce plots (rank 0 only).
:ivar str plotting_path: Directory where plots are written.
:ivar str plotting_subfolder_name: Subfolder name (under ``plotting_path``) for the plots.
:ivar str eliashberg_path: Directory where Eliashberg results are written.
"""
def __init__(self):
self.output_path: str = ""
self.do_plotting: bool = True
self.plotting_path: str = "./Plots/"
self.plotting_subfolder_name: str = "Plots"
self.eliashberg_path: str = "./Eliashberg/"
[docs]
class MemoryConfig:
"""
Stores the speed-vs-memory trade-off switches. Each flag, when True, selects a slower but more memory-lean code
path for the corresponding quantity.
:ivar bool save_memory_for_chi0q: Use the per-q einsum bubble instead of the FFT bubble.
:ivar bool save_memory_for_chiq_aux: Use the per-q auxiliary-susceptibility path and per-rank BZ mapping.
:ivar bool save_memory_for_sde: Use the q-loop self-energy contraction instead of the FFT one.
:ivar bool save_memory_for_fq: Use the per-q full-vertex construction in the Eliashberg step.
:ivar bool save_memory_for_lanczos: Use the frequency-distributed Lanczos solver.
"""
def __init__(self):
self.save_memory_for_chi0q: bool = False
self.save_memory_for_chiq_aux: bool = False
self.save_memory_for_sde: bool = False
self.save_memory_for_fq: bool = False
self.save_memory_for_lanczos: bool = False
[docs]
class AnaContConfig:
"""
Stores the analytic-continuation (maximum-entropy) configuration.
:ivar bool do_spectrum_dga: Whether to continue the DGA Green's function to real frequencies.
:ivar bool do_spectrum_dmft: Whether to continue the DMFT Green's function to real frequencies.
:ivar int w_count: Number of real-frequency points.
:ivar bool plot_spectrum: Whether to plot the resulting spectral function.
:ivar list k_path: The k-path (list of ``(kx, ky, kz, label)`` tuples) for the spectral function.
:ivar tuple energy_window: The real-frequency window ``(w_min, w_max)``.
"""
def __init__(self):
self.do_spectrum_dga: bool = False
self.do_spectrum_dmft: bool = False
self.w_count: int = 1001
self.plot_spectrum: bool = False
self.k_path: list[tuple[float, float, float, str]] = [
(0.0, 0.0, 0.0, "Gamma"), # default for cubic, must be in primitive k-space
(0.0, 0.5, 0.0, "X"),
(0.5, 0.5, 0.0, "M"),
(0.0, 0.0, 0.0, "Gamma"),
]
self.energy_window: tuple[float, float] = (-2, 3)
logger: DgaLogger
box: BoxConfig = BoxConfig()
lattice: LatticeConfig = LatticeConfig()
lambda_correction: LambdaCorrectionConfig = LambdaCorrectionConfig()
dmft: DmftConfig = DmftConfig()
sys: SystemConfig = SystemConfig()
output: OutputConfig = OutputConfig()
self_energy_interpolation: SelfEnergyInterpolationConfig = SelfEnergyInterpolationConfig()
self_consistency: SelfConsistencyConfig = SelfConsistencyConfig()
eliashberg: EliashbergConfig = EliashbergConfig()
memory: MemoryConfig = MemoryConfig()
ana_cont: AnaContConfig = AnaContConfig()