From bf56e782f0888e2ae5685587c20d3f30a45e7785 Mon Sep 17 00:00:00 2001 From: julpe Date: Mon, 29 Jun 2026 18:30:15 +0200 Subject: [PATCH] Refined docs to be more consistent --- dgamore/DGAmore.py | 10 +++--- dgamore/brillouin_zone.py | 49 +++++++++++++-------------- dgamore/bubble_gen.py | 8 ++--- dgamore/config.py | 10 +++--- dgamore/config_parser.py | 2 +- dgamore/dga_io.py | 4 +-- dgamore/dga_logger.py | 6 ++-- dgamore/dmft_interface.py | 30 ++++++++--------- dgamore/eliashberg_solver.py | 46 ++++++++++++------------- dgamore/four_point.py | 18 +++++----- dgamore/gap_function.py | 8 ++--- dgamore/greens_function.py | 28 +++++++-------- dgamore/hamiltonian.py | 50 ++++++++++++++------------- dgamore/interaction.py | 12 +++---- dgamore/local_four_point.py | 15 ++++----- dgamore/local_n_point.py | 3 +- dgamore/local_sde.py | 32 +++++++++--------- dgamore/matsubara_frequencies.py | 2 +- dgamore/memory_estimator.py | 6 ++-- dgamore/mpi_utils.py | 20 +++++------ dgamore/n_point_base.py | 15 +++++---- dgamore/nonlocal_sde.py | 58 +++++++++++++++++--------------- dgamore/plotting.py | 12 +++---- dgamore/self_energy.py | 8 ++--- tests/test_brillouin_zone.py | 23 ++++++++++--- tests/test_nonlocal_sde.py | 10 +++--- 26 files changed, 251 insertions(+), 234 deletions(-) diff --git a/dgamore/DGAmore.py b/dgamore/DGAmore.py index f8fb75b4..5e31a821 100644 --- a/dgamore/DGAmore.py +++ b/dgamore/DGAmore.py @@ -633,10 +633,10 @@ def fits_everywhere(distributed: float, single: float) -> bool: def setup_lambda_correction_settings(comm: MPI.Comm) -> None: """ Sets up the lambda correction settings based on the configuration provided by the user. If the user has enabled - the lambda correction in the self-consistency settings, it will be enabled in the lambda correction settings as well. - If the user has enabled the lambda correction in the lambda correction settings, but not in the self-consistency settings, - the self-consistency will be set to a single iteration with full mixing. Will raise an error if the user tries to enable - the lambda correction for multi-band systems. + the lambda correction in the self-consistency settings, it will be enabled in the lambda correction settings + as well. If the user has enabled the lambda correction in the lambda correction settings, but not in the + self-consistency settings, the self-consistency will be set to a single iteration with full mixing. Will raise + an error if the user tries to enable the lambda correction for multi-band systems. :param comm: The MPI communicator (only rank 0 validates the multi-band restriction). :return: None. @@ -679,7 +679,7 @@ def setup_lambda_correction_settings(comm: MPI.Comm) -> None: def configure_matplotlib(): """ Configures matplotlib to use the Euler font for mathematical expressions if it is available on the system. This is - done because The Euler font is the default math font in my thesis. + done because the Euler font is the default math font in my thesis. :return: None. """ diff --git a/dgamore/brillouin_zone.py b/dgamore/brillouin_zone.py index 904110bb..75f7bcec 100644 --- a/dgamore/brillouin_zone.py +++ b/dgamore/brillouin_zone.py @@ -183,8 +183,8 @@ def simultaneous_x_y_inversion() -> list[KnownSymmetries]: def inv_sym(mat: np.ndarray, axis) -> None: - """ - Applies an inversion symmetry along ``axis`` to ``mat`` in place, assuming the grid runs over :math:`[0, 2\\pi)` + r""" + Applies an inversion symmetry along ``axis`` to ``mat`` in place, assuming the grid runs over :math:`[0, 2\pi)` so that the zero point does not map. :param mat: The (at least 3D) array to symmetrize in place; the leading three axes are the momentum axes. @@ -308,12 +308,11 @@ def apply_symmetries(mat: np.ndarray, symmetries: list[KnownSymmetries]) -> None def get_lattice_symmetries_from_string(symmetry_string: str | tuple | list) -> list[KnownSymmetries]: """ - Return the lattice symmetries from a string. + Returns the lattice symmetries from a string. - The special string "auto" signals that symmetries should be auto-detected - from a Hamiltonian H(k) at runtime via KGrid.specify_auto_symmetries(hk). - In that case an empty list is returned here, but a marker is set so that - the KGrid defers building fbz2irrk until specify_auto_symmetries is called. + The special string ``"auto"`` signals that symmetries should be auto-detected from a Hamiltonian ``H(k)`` at + runtime via :meth:`specify_auto_symmetries`. In that case an empty list is returned here, but a marker is set so + that the KGrid defers building ``fbz2irrk`` until :meth:`specify_auto_symmetries` is called. :param symmetry_string: A named preset (e.g. ``"two_dimensional_square"``), the special ``"auto"``, an empty string/``"none"``, or a list/tuple (or its string repr) of :class:`KnownSymmetries` values. @@ -408,13 +407,11 @@ class KGrid: """ Class to build the k-grid for the Brillouin zone. - The ``symmetries`` argument accepts the usual list of ``KnownSymmetries`` - *and* the special "auto" mode (passed as the ``AUTO_SYMMETRIES_SENTINEL``, - typically obtained from ``get_lattice_symmetries_from_string("auto")``). - In auto mode the symmetry group is discovered from a Hamiltonian H(k) at - runtime: instantiate the grid with the sentinel, then call - :meth:`specify_auto_symmetries` with the Hamiltonian. Until that call the - grid behaves as if no symmetries were applied (full BZ = IBZ). + The ``symmetries`` argument accepts the usual list of ``KnownSymmetries`` *and* the special "auto" mode (passed as + the ``AUTO_SYMMETRIES_SENTINEL``, typically obtained from ``get_lattice_symmetries_from_string("auto")``). In auto + mode the symmetry group is discovered from a Hamiltonian ``H(k)`` at runtime: instantiate the grid with the + sentinel, then call :meth:`specify_auto_symmetries` with the Hamiltonian. Until that call the grid behaves as if + no symmetries were applied (full BZ = IBZ). """ def __init__(self, nk: tuple = None, symmetries: list[KnownSymmetries] = None): @@ -480,8 +477,8 @@ def specify_auto_symmetries( verbose: bool = False, include_antiunitary: bool = False, ) -> None: - """ - Auto-detect the symmetry group of the Hamiltonian ``hk`` and replay + r""" + Auto-detects the symmetry group of the Hamiltonian ``hk`` and replay the IBZ reduction onto this grid. Only applicable when this ``KGrid`` was constructed in auto mode @@ -684,8 +681,8 @@ def kmesh_list(self): return self.kmesh.reshape((3, -1)) def set_k_axes(self) -> None: - """ - Builds the three k-axis arrays spanning :math:`[0, 2\\pi)` for the full BZ. + r""" + Builds the three k-axis arrays spanning :math:`[0, 2\pi)` for the full BZ. :return: None. """ @@ -713,18 +710,18 @@ def get_irrq_list(self) -> np.ndarray: class KPath: """ Object to generate paths in the Brillouin zone. - Currently assumed that the BZ grid is from (0,2*pi). + It is currently assumed that the BZ grid is from (0,2*pi). """ def __init__(self, nk, path, kx=None, ky=None, kz=None, path_deliminator="-"): - """ + r""" Builds the k-axes and the discretized path (and its k-points) from the path string. :param nk: Number of k-points per spatial direction, as a tuple ``(nx, ny, nz)``. :param path: The desired path through the BZ as a delimiter-separated string of corner-point labels. - :param kx: Optional explicit kx-axis array; a :math:`[0, 2\\pi)` grid is built if None. - :param ky: Optional explicit ky-axis array; a :math:`[0, 2\\pi)` grid is built if None. - :param kz: Optional explicit kz-axis array; a :math:`[0, 2\\pi)` grid is built if None. + :param kx: Optional explicit kx-axis array; a :math:`[0, 2\pi)` grid is built if None. + :param ky: Optional explicit ky-axis array; a :math:`[0, 2\pi)` grid is built if None. + :param kz: Optional explicit kz-axis array; a :math:`[0, 2\pi)` grid is built if None. :param path_deliminator: The delimiter separating corner-point labels in ``path``. """ self.path_deliminator = path_deliminator @@ -748,12 +745,12 @@ def get_kpath_val(self): :return: The k-axis values along the path as a list ``[kx_vals, ky_vals, kz_vals]``. """ - k = [self.kx[self.kpts[:, 0]], self.kx[self.kpts[:, 1]], self.kx[self.kpts[:, 2]]] + k = [self.kx[self.kpts[:, 0]], self.ky[self.kpts[:, 1]], self.kz[self.kpts[:, 2]]] return k def set_kgrid(self, k_in, nk): - """ - Returns an explicit k-axis if given, otherwise builds a :math:`[0, 2\\pi)` grid of ``nk`` points. + r""" + Returns an explicit k-axis if given, otherwise builds a :math:`[0, 2\pi)` grid of ``nk`` points. :param k_in: Explicit k-axis array, or None to build a default grid. :param nk: Number of points in the default grid. diff --git a/dgamore/bubble_gen.py b/dgamore/bubble_gen.py index 5297c057..cbec3614 100644 --- a/dgamore/bubble_gen.py +++ b/dgamore/bubble_gen.py @@ -124,7 +124,7 @@ def create_generalized_chi0_q_fft_auto( beta: float, logger: DgaLogger, ): - """ + r""" Dispatches :meth:`create_generalized_chi0_q_fft` to the GPU when CuPy and a usable CUDA device are available (assigning one GPU per MPI rank round-robin), otherwise falls back to the CPU. @@ -133,7 +133,7 @@ def create_generalized_chi0_q_fft_auto( :param niw: Number of positive bosonic frequencies. :param niv: Number of positive fermionic frequencies. :param k_grid: The :class:`KGrid` over which the BZ sum/FFT is performed. - :param beta: Inverse temperature :math:`\\beta`. + :param beta: Inverse temperature :math:`\beta`. :param logger: Logger used to report whether GPU acceleration is used. :return: The bubble as a :class:`FourPoint` over the irreducible BZ. """ @@ -239,7 +239,7 @@ def create_generalized_chi0_q_auto( beta: float, logger: DgaLogger, ): - """ + r""" Dispatches :meth:`create_generalized_chi0_q` to the GPU when CuPy and a usable CUDA device are available (assigning one GPU per MPI rank round-robin), otherwise falls back to the CPU. @@ -249,7 +249,7 @@ def create_generalized_chi0_q_auto( :param niv: Number of positive fermionic frequencies. :param q_list: Array of integer q-point index triplets to compute. :param q_grid: The :class:`KGrid` providing the momentum normalization. - :param beta: Inverse temperature :math:`\\beta`. + :param beta: Inverse temperature :math:`\beta`. :param logger: Logger used to report whether GPU acceleration is used. :return: The bubble as a :class:`FourPoint` over the given q-points. """ diff --git a/dgamore/config.py b/dgamore/config.py index efe5fb01..8745d6f4 100644 --- a/dgamore/config.py +++ b/dgamore/config.py @@ -26,11 +26,11 @@ class InteractionConfig: 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: d-p inter-orbital Hubbard interaction. + :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: d-p exchange. + :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. @@ -107,14 +107,14 @@ def __init__(self): 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 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). @@ -217,7 +217,7 @@ class SystemConfig: :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: k-resolved 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. """ diff --git a/dgamore/config_parser.py b/dgamore/config_parser.py index 8d13a137..dc040ae1 100644 --- a/dgamore/config_parser.py +++ b/dgamore/config_parser.py @@ -23,7 +23,7 @@ class ConfigParser: """ - Parses the config file and builds the DgaConfig singleton class. The Configuration is then broadcasted to all + Parses the config file and builds the global ``dgamore.config`` singletons (``box``, ``lattice``, ``dmft``, ...). The configuration is then broadcast to all processes. The config file location can be specified with the path and/or name arguments when executing the main Python file. """ diff --git a/dgamore/dga_io.py b/dgamore/dga_io.py index 2f3aba82..a8561279 100644 --- a/dgamore/dga_io.py +++ b/dgamore/dga_io.py @@ -44,11 +44,11 @@ def uniquify_path(path: str = None): def load_from_dmft_file_and_update_config() -> ( tuple[list[GreensFunction], list[SelfEnergy], list[LocalFourPoint], list[LocalFourPoint]] ): - """ + r""" Loads the per-inequivalent-atom DMFT quantities (1- and 2-particle) and updates the global config: inverse temperature, interaction parameters, chemical potential, filling, frequency boxes, band count, Hamiltonian and output paths. Also cuts the two-particle Green's functions to the core box and applies the requested orbital and - :math:`(\\nu, \\nu')` symmetrizations. + :math:`(\nu, \nu')` symmetrizations. :return: A tuple of per-inequivalent-atom lists ``(g_per_ineq, sigma_per_ineq, g2_dens_per_ineq, g2_magn_per_ineq)`` of Green's functions, self-energies and density/magnetic two-particle Green's functions. diff --git a/dgamore/dga_logger.py b/dgamore/dga_logger.py index 258369c2..5cc6036e 100644 --- a/dgamore/dga_logger.py +++ b/dgamore/dga_logger.py @@ -17,8 +17,7 @@ class DgaLogger: """ - A logger class that handles logging messages in a distributed environment using MPI. Currently, it logs messages - to the stdout and can also be extended to log to a file. + Handles logging messages in a distributed environment using MPI. Currently, it logs messages to stdout. """ def __init__(self, comm: MPI.Comm, output_path: str = "./", filename: str = "dga.log"): @@ -94,7 +93,8 @@ def _log(self, message: str, level: int, allowed_ranks: tuple | int = (0,)): def debug(self, message: str, allowed_ranks: tuple = (0,)): """ - Logs a debug message. This is intended for detailed debugging information that is not usually needed in production. + Logs a debug message. This is intended for detailed debugging information that is not usually needed in + production. :param message: The message to log. :param allowed_ranks: The MPI rank(s) permitted to emit this message. diff --git a/dgamore/dmft_interface.py b/dgamore/dmft_interface.py index e4030532..06162121 100644 --- a/dgamore/dmft_interface.py +++ b/dgamore/dmft_interface.py @@ -27,24 +27,24 @@ class DMFTInterface(ABC): """ - Abstract interface for DMFT calculations. Reads the necessary quantities which are needed for a DGA calculation + Abstract interface for DMFT calculations. Reads the quantities needed for a DGA calculation from the output files. """ def get_beta(self) -> float: - """ + r""" Returns the inverse temperature from the DMFT calculation. - :return: The inverse temperature :math:`\\beta` from the DMFT calculation. + :return: The inverse temperature :math:`\beta` from the DMFT calculation. :raises NotImplementedError: In the abstract base class. """ raise NotImplementedError() def get_mu(self) -> float: - """ + r""" Returns the chemical potential from the DMFT calculation. - :return: The chemical potential :math:`\\mu` from the DMFT calculation. + :return: The chemical potential :math:`\mu` from the DMFT calculation. :raises NotImplementedError: In the abstract base class. """ raise NotImplementedError() @@ -79,7 +79,7 @@ def get_occ(self, ineq: int = 1) -> np.ndarray: raise NotImplementedError() def get_udd(self, ineq: int = 1) -> float: - """ + r""" Returns the density-density interaction :math:`U` for the interacting d-orbitals (used both for plain density-density and Kanamori interactions). @@ -90,7 +90,7 @@ def get_udd(self, ineq: int = 1) -> float: raise NotImplementedError() def get_jdd(self, ineq: int = 1) -> float: - """ + r""" Returns the Hund's coupling :math:`J` for the interacting d-orbitals (nonzero only for Kanamori interactions). :param ineq: The index of the inequivalent atom (for multi-site DMFT). @@ -100,7 +100,7 @@ def get_jdd(self, ineq: int = 1) -> float: raise NotImplementedError() def get_vdd(self, ineq: int = 1) -> float: - """ + r""" Returns the inter-orbital repulsion :math:`V` (often :math:`U'`) for the interacting d-orbitals (nonzero only for Kanamori interactions). @@ -169,19 +169,19 @@ def __init__(self): self._open() def get_beta(self) -> float: - """ + r""" Reads the inverse temperature from the w2dynamics config. - :return: The inverse temperature :math:`\\beta` from the DMFT calculation. + :return: The inverse temperature :math:`\beta` from the DMFT calculation. """ return self.file_1p[".config"].attrs["general.beta"] def get_mu(self, dmft_iter: str = "dmft-last") -> float: - """ + r""" Reads the chemical potential from the w2dynamics output. :param dmft_iter: The DMFT iteration to read from. - :return: The chemical potential :math:`\\mu`. + :return: The chemical potential :math:`\mu`. """ return self.file_1p[dmft_iter + "/mu/value"][()] @@ -215,7 +215,7 @@ def get_occ(self, ineq: int = 1, dmft_iter: str = "dmft-last") -> np.ndarray: return 2 * np.mean(rho1, axis=(1, 3)) def get_udd(self, ineq: int = 1) -> float: - """ + r""" Reads the density-density interaction from the w2dynamics config. :param ineq: The index of the inequivalent atom (for multi-site DMFT). @@ -224,7 +224,7 @@ def get_udd(self, ineq: int = 1) -> float: return self._from_ineq_config("udd", ineq=ineq) def get_jdd(self, ineq: int = 1) -> float: - """ + r""" Reads the Hund's coupling from the w2dynamics config. :param ineq: The index of the inequivalent atom (for multi-site DMFT). @@ -233,7 +233,7 @@ def get_jdd(self, ineq: int = 1) -> float: return self._from_ineq_config("jdd", ineq=ineq) def get_vdd(self, ineq: int = 1) -> float: - """ + r""" Reads the inter-orbital repulsion from the w2dynamics config. :param ineq: The index of the inequivalent atom (for multi-site DMFT). diff --git a/dgamore/eliashberg_solver.py b/dgamore/eliashberg_solver.py index e5ba77f8..32c22cfd 100644 --- a/dgamore/eliashberg_solver.py +++ b/dgamore/eliashberg_solver.py @@ -7,7 +7,7 @@ Linearized Eliashberg equation solver. Starting from the ladder-DGA full vertex (saved per channel by the non-local SDE step), this module assembles the particle-particle pairing vertex in the singlet/triplet channels at :math:`\omega = 0`, optionally adds the local reducible diagrams, and power-iterates the linearized gap equation -:math:`\lambda \Delta = -\frac{1}{\beta N_q}\, \Gamma^{pp}\, \chi_0^{pp}\, \Delta` via an ARPACK/Lanczos +:math:`\lambda \Delta = \pm\frac{1}{2\beta N_q}\, \Gamma^{pp}\, \chi_0^{pp}\, \Delta` via an ARPACK/Lanczos eigensolver (two variants: an in-memory one and a memory-lean frequency-distributed one). The leading eigenvalue :math:`\lambda` signals the pairing instability and the eigenvector is the gap function :math:`\Delta(k, \nu)`. Requires ``nq == nk``. Equation numbers refer to the author's master's thesis (Chapter 4). @@ -77,8 +77,8 @@ def _transform_vertex_frequencies_w0(vertex: LocalFourPoint | FourPoint, niv_pp: def transform_vertex_loc_frequencies_w0(f_r_loc: LocalFourPoint, niv_pp: int) -> LocalFourPoint: - """ - Transforms a local vertex from particle-hole to the modified particle-particle notation at :math:`\\omega' = 0` + r""" + Transforms a local vertex from particle-hole to the modified particle-particle notation at :math:`\omega' = 0` (see :func:`_transform_vertex_frequencies_w0`). :param f_r_loc: The local vertex :math:`F` in ph notation. @@ -90,9 +90,9 @@ def transform_vertex_loc_frequencies_w0(f_r_loc: LocalFourPoint, niv_pp: int) -> def transform_vertex_q_frequencies_w0(f_q_r: FourPoint, niv_pp: int) -> FourPoint: - """ + r""" Transforms a momentum-dependent vertex from particle-hole to the modified particle-particle notation at - :math:`\\omega' = 0` (see :func:`_transform_vertex_frequencies_w0`). + :math:`\omega' = 0` (see :func:`_transform_vertex_frequencies_w0`). :param f_q_r: The momentum-dependent vertex :math:`F^{q}` in ph notation. :param niv_pp: Number of positive fermionic frequencies of the pp vertex. @@ -106,14 +106,14 @@ def transform_vertex_q_frequencies_w0(f_q_r: FourPoint, niv_pp: int) -> FourPoin def create_full_vertex_q_r( u_loc: LocalInteraction, v_nonloc: Interaction, gamma_r: LocalFourPoint, niv_pp: int, mpi_dist: MpiDistributor ) -> FourPoint: - """ + r""" Calculates the momentum-dependent full ladder vertex in the given channel (density or magnetic) from the saved intermediates (inverse bubble, three-leg vertex, summed auxiliary susceptibility), and transforms it to pp notation unless ``save_fq`` requests keeping the ph form. Deletes the consumed intermediate files afterwards. :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}`. - :param gamma_r: The local irreducible vertex :math:`\\Gamma_{r}` for this channel. + :param gamma_r: The local irreducible vertex :math:`\Gamma_{r}` for this channel. :param niv_pp: Number of positive fermionic frequencies of the pp vertex. :param mpi_dist: MPI distributor over the irreducible BZ q-points (see :class:`MpiDistributor`). :return: The full ladder vertex :math:`F^{q}_{r}` as a :class:`FourPoint`. @@ -187,13 +187,13 @@ def create_full_vertex_q_r( def create_full_vertex_q_r_pp_w0( u_loc: LocalInteraction, v_nonloc: Interaction, gamma_r: LocalFourPoint, niv_pp: int, mpi_dist_irrk: MpiDistributor ): - """ + r""" Builds the full ladder vertex (see :func:`create_full_vertex_q_r`), optionally gathers and saves it in ph - notation in the irreducible BZ, and returns it transformed to pp notation at :math:`\\omega' = 0`. + notation in the irreducible BZ, and returns it transformed to pp notation at :math:`\omega' = 0`. :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}`. - :param gamma_r: The local irreducible vertex :math:`\\Gamma_{r}` for this channel. + :param gamma_r: The local irreducible vertex :math:`\Gamma_{r}` for this channel. :param niv_pp: Number of positive fermionic frequencies of the pp vertex. :param mpi_dist_irrk: MPI distributor over the irreducible BZ q-points (see :class:`MpiDistributor`). :return: The full ladder vertex :math:`F^{q}_{r}` in pp notation as a :class:`FourPoint`. @@ -231,16 +231,16 @@ def create_full_vertex_q_r_v2( niv_pp: int, q_index: int, ) -> FourPoint: - """ + r""" Calculates the full ladder vertex for a single q-point (memory-lean per-q variant of :func:`create_full_vertex_q_r`), transforming it to pp notation unless ``save_fq`` keeps the ph form. :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}`. - :param gamma_r: The local irreducible vertex :math:`\\Gamma_{r}` for this channel. - :param gchi0_q_inv: The inverse bare bubble :math:`(\\chi_0^q)^{-1}` over all rank-local q-points. - :param vrg_q_r: The momentum-dependent three-leg vertex :math:`\\gamma^q_{r}`. - :param gchi_aux_q_r_sum: The summed auxiliary susceptibility :math:`\\sum_{\\nu'}\\chi^{*;q}_{r}`. + :param gamma_r: The local irreducible vertex :math:`\Gamma_{r}` for this channel. + :param gchi0_q_inv: The inverse bare bubble :math:`(\chi_0^q)^{-1}` over all rank-local q-points. + :param vrg_q_r: The momentum-dependent three-leg vertex :math:`\gamma^q_{r}`. + :param gchi_aux_q_r_sum: The summed auxiliary susceptibility :math:`\sum_{\nu'}\chi^{*;q}_{r}`. :param niv_pp: Number of positive fermionic frequencies of the pp vertex. :param q_index: Index of the q-point (into the rank-local list) to compute. :return: The full ladder vertex :math:`F^{q}_{r}` for that q-point as a :class:`FourPoint`. @@ -272,14 +272,14 @@ def create_full_vertex_q_r_v2( def create_full_vertex_q_r_pp_w0_v2( u_loc: LocalInteraction, v_nonloc: Interaction, gamma_r: LocalFourPoint, niv_pp: int, mpi_dist_irrk: MpiDistributor ): - """ - Memory-lean variant of :func:`create_full_vertex_q_r_pp_w0`: loops over the rank-local q-points (see - :func:`create_full_vertex_q_r_v2`), assembles the full ladder vertex, optionally saves it in ph notation, and - returns it in pp notation at :math:`\\omega' = 0`. + r""" + Builds the full ladder vertex as a memory-lean variant of :func:`create_full_vertex_q_r_pp_w0`, looping over the + rank-local q-points (see :func:`create_full_vertex_q_r_v2`), optionally saving it in ph notation, and returning it + in pp notation at :math:`\omega' = 0`. :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}`. - :param gamma_r: The local irreducible vertex :math:`\\Gamma_{r}` for this channel. + :param gamma_r: The local irreducible vertex :math:`\Gamma_{r}` for this channel. :param niv_pp: Number of positive fermionic frequencies of the pp vertex. :param mpi_dist_irrk: MPI distributor over the irreducible BZ q-points (see :class:`MpiDistributor`). :return: The full ladder vertex :math:`F^{q}_{r}` in pp notation as a :class:`FourPoint`. @@ -779,8 +779,8 @@ def mv(gap: np.ndarray): def solve( giwk_dga: GreensFunction, g_dmft: GreensFunction, u_loc: LocalInteraction, v_nonloc: Interaction, comm: MPI.Comm ): - """ - Top-level driver of the Eliashberg step: assembles the singlet and triplet pairing vertices from the saved + r""" + Drives the Eliashberg step: assembles the singlet and triplet pairing vertices from the saved ladder-DGA full vertices (optionally adding the local reducible diagrams), then solves the linearized gap equation for each channel and returns the leading eigenvalues and gap functions. Dispatches between the in-memory and the memory-lean Lanczos solvers depending on the memory configuration. @@ -806,7 +806,7 @@ def solve( niv_pp = min(config.box.niw_core // 2, config.box.niv_core // 2) def dispatch_full_vertex_calculation(channel, u, v, niv, mpi_dist) -> FourPoint: - """ + r""" Loads the local irreducible vertex for ``channel`` and builds the full ladder pp vertex, dispatching between the memory-lean and the regular construction routine based on the memory configuration. diff --git a/dgamore/four_point.py b/dgamore/four_point.py index c771585f..ee8acc9a 100644 --- a/dgamore/four_point.py +++ b/dgamore/four_point.py @@ -196,7 +196,7 @@ def sum_over_orbitals(self, orbital_contraction: str = "abcd->ad") -> "FourPoint def to_compound_indices(self) -> "FourPoint": r""" - Converts the indices of the LocalFourPoint object :math:`F^{wvv'}_{lmm'l'}` to compound indices :math:`F^{w}_{c_1, c_2}` + Converts the indices of the FourPoint object :math:`F^{wvv'}_{lmm'l'}` to compound indices :math:`F^{w}_{c_1, c_2}` by transposing the object to [q, w, o1, o2, v, o4, o3, v'] (if the object has any fermionic frequency dimension, otherwise the compound indices are built from orbital dimensions only) and grouping {o1, o2, v} and {o4, o3, v'} to the new compound index. Always returns the object with a compressed momentum dimension and in the same niw @@ -275,9 +275,9 @@ def to_full_indices(self, shape: tuple = None) -> "FourPoint": """ Converts an object stored with compound indices to an object that has unraveled momentum, orbital and frequency axes. Always returns the object with a compressed momentum dimension. This is the inverse - transformation as `to_compound_indices`. Will make use of the `original_shape` the object was created or last - modified with. If the `original_shape` is not set or is hard to obtain, the `shape` argument can be used to - specify the original shape of the object. + transformation of :meth:`to_compound_indices`. Will make use of the ``original_shape`` the object was + created or last modified with. If the ``original_shape`` is not set or is hard to obtain, the ``shape`` + argument can be used to specify the original shape of the object. :param shape: Optional override for the stored ``original_shape`` used to unravel the compound axes. :return: ``self`` with unraveled orbital and frequency axes (compressed momentum). @@ -513,9 +513,9 @@ def _add(self, other, subtract: bool = False) -> "FourPoint": def sub(self, other) -> "FourPoint": """ - Helper method that allows for subtracted of FourPoint objects and other FourPoint, LocalFourPoint, Interaction or - LocalInteraction objects. Additions with numpy arrays, floats, ints or complex numbers are also supported. - Depending on the number of frequency and momentum dimensions, the vertices have to be added slightly different. + Helper method that allows for subtraction of FourPoint objects and other FourPoint, LocalFourPoint, Interaction or + LocalInteraction objects. Subtractions with numpy arrays, floats, ints or complex numbers are also supported. + Depending on the number of frequency and momentum dimensions, the vertices have to be subtracted slightly different. If the objects have different niw ranges, they will be converted to the half niw range before the subtraction. Objects will always be returned in the half niw range to save memory. @@ -529,7 +529,7 @@ def sub(self, other) -> "FourPoint": def mul(self, other) -> "FourPoint": r""" Allows for the multiplication with a number, a numpy array or another FourPoint object. This is different from - the `matmul` method, which is used for matrix multiplication. + the :meth:`matmul` method, which is used for matrix multiplication. In the case the other object is a FourPoint object, we require that both objects have only one fermionic frequency dimension, such that :math:`A_{abcd}^{qv} * B_{dcef}^{qv'} = C_{abef}^{qvv'}`. This is needed to construct the full vertex, see Eq. (3.139) in my thesis. Returns the object in the half niw range. @@ -752,7 +752,7 @@ def invert_and_sum_over_last_vn(self, beta: float): return self def invert_and_sum_over_last_vn_v2(self, beta: float): - """ + r""" Helper method that explicitly handles the calculation of the sum over the auxiliary susceptibility while being highly memory-efficient. Does not invert the matrix directly but uses a linear solver to avoid the creation of large intermediate arrays. This is especially important for objects with a large number of diff --git a/dgamore/gap_function.py b/dgamore/gap_function.py index 2160093f..916c50ff 100644 --- a/dgamore/gap_function.py +++ b/dgamore/gap_function.py @@ -3,8 +3,8 @@ # # DGAmore — Multi-Orbital Ladder Dynamical Vertex Approximation (LDGA) & # Eliashberg Equation Solver for Strongly Correlated Electron Systems -""" -The superconducting gap function :math:`\\Delta`, i.e. the eigenvector of the linearized Eliashberg equation. +r""" +The superconducting gap function :math:`\Delta`, i.e. the eigenvector of the linearized Eliashberg equation. """ import numpy as np @@ -34,10 +34,10 @@ def __init__( :param mat: Gap-function array with one momentum dimension, two orbital axes and one fermionic frequency axis. :param channel: Pairing channel, i.e. singlet or triplet (see :class:`SpinChannel`). :param nk: Number of momenta per spatial direction ``(nkx, nky, nkz)``. - :param full_niv_range: Whether the fermionic frequency axis spans the full (signed) range or only + :param full_niv_range: Whether the object spans the full (signed) fermionic range or only :math:`\nu \geq 0`. :param has_compressed_q_dimension: Whether the momentum is stored as a single compressed axis ``[q, ...]`` - (True) or as three separate axes ``[qx, qy, qz, ...]`` (False). + (True) or as three separate axes ``[kx, ky, kz, ...]`` (False). """ TwoPoint.__init__(self, mat, nk, full_niv_range, has_compressed_q_dimension) IHaveChannel.__init__(self, channel, FrequencyNotation.PP) diff --git a/dgamore/greens_function.py b/dgamore/greens_function.py index c74b5c85..7e38e605 100644 --- a/dgamore/greens_function.py +++ b/dgamore/greens_function.py @@ -7,7 +7,7 @@ Single-particle Green's function. :class:`GreensFunction` builds the momentum-dependent interacting Green's function :math:`G_{ab}(k, \nu) = [(\imath\nu + \mu)\delta_{ab} - \varepsilon_{ab}(k) - \Sigma_{ab}(k, \nu)]^{-1}` from a :class:`SelfEnergy`, the band dispersion :math:`\varepsilon(k)` and the chemical potential :math:`\mu`, -and derives the filling, occupation, kinetic and (Galitskii–Migdal) potential energies. The module-level helpers +and derives the filling, occupation, kinetic and (Galitskii-Migdal) potential energies. The module-level helpers adjust :math:`\mu` to a target filling via a Newton root search. Moment-corrected asymptotic sums are used so the finite Matsubara box does not bias the energies/filling. """ @@ -137,7 +137,7 @@ class GreensFunction(TwoPoint): \varepsilon_{ab}(k) - \Sigma_{ab}(k, \nu)]^{-1}`. Built from a :class:`SelfEnergy`, the band dispersion :math:`\varepsilon(k)` and the chemical potential :math:`\mu`; on top of the two-point orbital bookkeeping inherited from :class:`LocalTwoPoint` it adds the Dyson construction (local and momentum-resolved) and the - derived quantities — filling, occupation matrices, kinetic and (Galitskii–Migdal) potential energy — all using + derived quantities — filling, occupation matrices, kinetic and (Galitskii-Migdal) potential energy — all using moment-corrected asymptotic Matsubara sums so the finite frequency box does not bias the result. """ @@ -164,9 +164,9 @@ def __init__( :param full_niv_range: Whether the object spans the full (signed) fermionic range or only :math:`\nu \geq 0`. :param calc_filling: If True (and ``sigma``/``ek`` are given), compute the local Green's function and the filling/occupation, exposed via the :attr:`n`, :attr:`occ` and :attr:`occ_k` properties. - :param has_compressed_q_dimension: Whether the momentum is stored as a single compressed axis (True) or as - ``[kx, ky, kz, ...]`` (False). - :param nk: Number of momenta per spatial direction. + :param has_compressed_q_dimension: Whether the momentum is stored as a single compressed axis ``[q, ...]`` + (True) or as three separate axes ``[kx, ky, kz, ...]`` (False). + :param nk: Number of momenta per spatial direction ``(nkx, nky, nkz)``. :param beta: Inverse temperature :math:`\beta`. :param mu: Chemical potential :math:`\mu`. """ @@ -185,16 +185,16 @@ def __init__( @property def ek(self) -> np.ndarray: - """ + r""" The band dispersion stored on this object. - :return: The band dispersion :math:`\\varepsilon(k)` as a numpy array. + :return: The band dispersion :math:`\varepsilon(k)` as a numpy array. """ return self._ek @property def n(self) -> float: - """ + r""" The total filling computed for this Green's function. :return: The total filling :math:`n`, or None if the filling has not been computed. @@ -246,13 +246,13 @@ def get_g_full(siw: SelfEnergy, mu: float, ek: np.ndarray, beta: float): @staticmethod def create_g_loc(siw: SelfEnergy, ek: np.ndarray, beta: float, mu: float, calc_filling: bool = True) -> "GreensFunction": - """ + r""" Builds a local (k-summed) Green's function from a self-energy and band dispersion. - :param siw: The :class:`SelfEnergy` :math:`\\Sigma`. - :param ek: Band dispersion :math:`\\varepsilon(k)`. - :param beta: Inverse temperature :math:`\\beta`. - :param mu: Chemical potential :math:`\\mu`. + :param siw: The :class:`SelfEnergy` :math:`\Sigma`. + :param ek: Band dispersion :math:`\varepsilon(k)`. + :param beta: Inverse temperature :math:`\beta`. + :param mu: Chemical potential :math:`\mu`. :param calc_filling: If True, compute the filling/occupation (exposed via the ``n``/``occ``/``occ_k`` properties). :return: The local :class:`GreensFunction`. @@ -321,7 +321,7 @@ def get_ekin(self) -> float: def get_epot(self, niv_asympt: int = 50000) -> float: r""" - Moment-corrected Galitskii–Migdal potential energy, + Computes the moment-corrected Galitskii-Migdal potential energy, .. math:: diff --git a/dgamore/hamiltonian.py b/dgamore/hamiltonian.py index 27133099..2d573330 100644 --- a/dgamore/hamiltonian.py +++ b/dgamore/hamiltonian.py @@ -27,8 +27,8 @@ class HoppingElement: """ Data class to store a hopping element of the Hamiltonian. The hopping element is defined by the relative lattice - vector 'r_lat', the orbitals 'orbs' and the value of the hopping 'value'. A hopping element represents a single line - in a w2k file. Added this to make the code more readable and to avoid passing around lists of values. + vector ``r_lat``, the orbitals ``orbs`` and the value of the hopping ``value``. A hopping element represents a + single line in a w2k file. Added this to make the code more readable and to avoid passing around lists of values. """ def __init__(self, r_lat: list, orbs: list, value: float = 0.0): @@ -38,7 +38,8 @@ def __init__(self, r_lat: list, orbs: list, value: float = 0.0): :param r_lat: The relative lattice vector as a list of 3 integers. :param orbs: The two (1-based) orbital indices ``[o1, o2]`` of the hopping. :param value: The hopping amplitude. - :raises ValueError: If ``r_lat`` is not 3 integers, ``orbs`` is not 2 positive integers, or ``value`` is not a number. + :raises ValueError: If ``r_lat`` is not 3 integers, ``orbs`` is not 2 positive integers, or ``value`` is not + a number. """ if not (isinstance(r_lat, list) and len(r_lat) == 3 and all(isinstance(x, int) for x in r_lat)): raise ValueError("'r_lat' must be a list with exactly 3 integer elements.") @@ -59,9 +60,10 @@ def __init__(self, r_lat: list, orbs: list, value: float = 0.0): class InteractionElement: """ - Data class to store an interaction element of the Hamiltonian. The interaction element is defined by the relative lattice - vector 'r_lat', the orbitals 'orbs' and the value of the interaction 'value'. An interaction element represents a single entry - in the interaction matrix. Added this to make the code more readable and to avoid passing around lists of values. + Data class to store an interaction element of the Hamiltonian. The interaction element is defined by the relative + lattice vector ``r_lat``, the orbitals ``orbs`` and the value of the interaction ``value``. An interaction element + represents a single entry in the interaction matrix. Added this to make the code more readable and to avoid passing + around lists of values. """ def __init__(self, r_lat: list[int], orbs: list[int], value: float): @@ -71,7 +73,8 @@ def __init__(self, r_lat: list[int], orbs: list[int], value: float): :param r_lat: The relative lattice vector as a list of 3 integers. :param orbs: The four (1-based) orbital indices ``[o1, o2, o3, o4]`` of the interaction. :param value: The interaction value. - :raises ValueError: If ``r_lat`` is not 3 integers, ``orbs`` is not 4 positive integers, or ``value`` is not a number. + :raises ValueError: If ``r_lat`` is not 3 integers, ``orbs`` is not 4 positive integers, or ``value`` is not + a number. """ if not (isinstance(r_lat, list) and len(r_lat) == 3 and all(isinstance(x, int) for x in r_lat)): raise ValueError("'r_lat' must be a list with exactly 3 integer elements.") @@ -92,8 +95,9 @@ def __init__(self, r_lat: list[int], orbs: list[int], value: float): class Hamiltonian: """ - Class to handle the Hamiltonian of the Hubbard model. Contains the hopping terms ('er') and the local ('local_interaction') - and nonlocal interaction ('nonlocal_interaction') terms. Has a few helper methods to simplify adding terms to the Hamiltonian. + Class to handle the Hamiltonian of the Hubbard model. Contains the hopping terms (``er``) and the local + (``local_interaction``) and nonlocal interaction (``nonlocal_interaction``) terms. Has a few helper methods to + simplify adding terms to the Hamiltonian. """ def __init__(self): @@ -117,7 +121,7 @@ def __init__(self): self._nonlocal_interaction = None def single_band_interaction(self, u: float) -> "Hamiltonian": - """ + r""" Sets the local interaction for a single-band model from a single Hubbard :math:`U`. :param u: The Hubbard interaction :math:`U`. @@ -126,7 +130,7 @@ def single_band_interaction(self, u: float) -> "Hamiltonian": return self.interaction_orbital_diagonal(u, 1) def interaction_orbital_diagonal(self, u: float, n_bands: int = 1) -> "Hamiltonian": - """ + r""" Sets a purely orbital-diagonal local interaction for a multi-band model: the interaction tensor is zero everywhere except the ``[0,0,0,0]`` element, which is set to ``u``. @@ -144,11 +148,11 @@ def interaction_orbital_diagonal(self, u: float, n_bands: int = 1) -> "Hamiltoni return self._add_interaction_term(interaction_elements) def kanamori_interaction_d(self, n_bands: int, udd: float, jdd: float, vdd: float = None) -> "Hamiltonian": - """ + r""" Adds the Kanamori interaction terms ONLY for d orbitals to the Hamiltonian. - The interaction terms are defined by the Hubbard 'udd' (U), - the exchange interaction 'jdd' (J) and the pair hopping 'vdd' (V or sometimes U'). - 'vdd' is an optional parameter, if left empty, it is set to V=U-2J. + The interaction terms are defined by the Hubbard ``udd`` (U), + the exchange interaction ``jdd`` (J) and the inter-orbital density-density interaction ``vdd`` (V or sometimes U'). + ``vdd`` is an optional parameter, if left empty, it is set to V=U-2J. :param n_bands: Number of d orbitals/bands. :param udd: The intra-orbital Hubbard interaction :math:`U_{dd}`. @@ -159,11 +163,11 @@ def kanamori_interaction_d(self, n_bands: int, udd: float, jdd: float, vdd: floa return self.kanamori_interaction_dp(nd_bands=n_bands, udd=udd, jdd=jdd, vdd=vdd) def kanamori_interaction_p(self, n_bands: int, upp: float, jpp: float, vpp: float = None) -> "Hamiltonian": - """ + r""" Adds the Kanamori interaction terms ONLY for p orbitals to the Hamiltonian. - The interaction terms are defined by the Hubbard 'upp' (U), - the exchange interaction 'jpp' (J) and the pair hopping 'vpp' (V or sometimes U'). - 'vpp' is an optional parameter, if left empty, it is set to V=U-2J. + The interaction terms are defined by the Hubbard ``upp`` (U), + the exchange interaction ``jpp`` (J) and the inter-orbital density-density interaction ``vpp`` (V or sometimes U'). + ``vpp`` is an optional parameter, if left empty, it is set to V=U-2J. :param n_bands: Number of p orbitals/bands. :param upp: The intra-orbital Hubbard interaction :math:`U_{pp}`. @@ -186,10 +190,10 @@ def kanamori_interaction_dp( vdd: float = None, vpp: float = None, ) -> "Hamiltonian": - """ + r""" Adds the full Kanamori interaction terms for d and p orbitals to the Hamiltonian. The interaction terms are defined by the local interaction Hubbard U, - the exchange interaction J and the pair hopping V or sometimes U'. + the exchange interaction J and the inter-orbital density-density interaction V or sometimes U'. vdd (vpp) (vdp) are optional parameters, if left empty, they are set to V=U-2J. :param nd_bands: Number of d orbitals (placed first in the orbital ordering). @@ -258,7 +262,7 @@ def get_params(o1: int, o2: int) -> tuple[float, float, float]: return self._add_interaction_term(interaction_elements) def kinetic_one_band_2d_t_tp_tpp(self, t: float, tp: float, tpp: float) -> "Hamiltonian": - """ + r""" Adds the kinetic terms for a one-band model in 2D with nearest (t), next-nearest (tp) and next-next-nearest (tpp) neighbor hopping. @@ -287,7 +291,7 @@ def kinetic_one_band_2d_t_tp_tpp(self, t: float, tp: float, tpp: float) -> "Hami def read_hr_w2k(self, filename: str = "./wannier_hr.dat") -> "Hamiltonian": """ - Reads the 'wannier_hr.dat' file from a wien2k hr file and sets the real-space kinetic Hamiltonian. + Reads the ``wannier_hr.dat`` file from a wien2k hr file and sets the real-space kinetic Hamiltonian. This is then typically Fourier-transformed to momentum space to obtain the k-dependent band dispersion. :param filename: Path to the ``wannier_hr.dat`` file. diff --git a/dgamore/interaction.py b/dgamore/interaction.py index aa91dd7d..acc695a7 100644 --- a/dgamore/interaction.py +++ b/dgamore/interaction.py @@ -3,7 +3,7 @@ # # DGAmore — Multi-Orbital Ladder Dynamical Vertex Approximation (LDGA) & # Eliashberg Equation Solver for Strongly Correlated Electron Systems -""" +r""" Interaction tensors. :class:`LocalInteraction` wraps the momentum-independent (Hubbard/Kanamori) interaction :math:`U_{abcd}`; :class:`Interaction` adds a momentum dimension for the non-local interaction :math:`V_{abcd}^q`. Both provide the channel projections (density/magnetic/singlet/triplet) and the algebra used in the ladder @@ -46,7 +46,7 @@ def permute_orbitals(self, permutation: str = "abcd->abcd") -> "LocalInteraction """ Permutes the four orbital axes according to an einsum-style permutation string. - :param permutation: einsum permutation of the four orbital labels, e.g. ``"abcd->adcb"``. + :param permutation: Einsum permutation of the four orbital labels, e.g. ``"abcd->adcb"``. :return: A new :class:`LocalInteraction` with permuted orbitals (a deep copy for the identity permutation). :raises ValueError: If the permutation string is not a valid four-orbital permutation. """ @@ -91,7 +91,7 @@ def as_channel(self, channel: SpinChannel) -> "LocalInteraction": def add(self, other) -> "LocalInteraction": """ - Adds another interaction or a raw numpy array elementwise; see :meth:`_add`. + Adds another interaction or a raw numpy array element-wise; see :meth:`_add`. :param other: A :class:`LocalInteraction` or a numpy array broadcastable to ``mat``. :return: A new :class:`LocalInteraction` holding the sum (inheriting the non-``NONE`` channel of the operands). @@ -100,7 +100,7 @@ def add(self, other) -> "LocalInteraction": def _add(self, other, subtract: bool = False) -> "LocalInteraction": """ - Adds (or, if ``subtract`` is True, subtracts) another interaction or a raw numpy array elementwise. + Adds (or, if ``subtract`` is True, subtracts) another interaction or a raw numpy array element-wise. :param other: A :class:`LocalInteraction` or a numpy array broadcastable to ``mat``. :param subtract: If True, subtract ``other`` instead of adding it (used by :meth:`sub` to avoid a negated copy). @@ -121,7 +121,7 @@ def _add(self, other, subtract: bool = False) -> "LocalInteraction": def sub(self, other) -> "LocalInteraction": """ - Subtracts another interaction or a raw numpy array elementwise; see :meth:`_add`. + Subtracts another interaction or a raw numpy array element-wise; see :meth:`_add`. :param other: A :class:`LocalInteraction` or a numpy array broadcastable to ``mat``. :return: A new :class:`LocalInteraction` holding the difference ``self - other``. @@ -219,7 +219,7 @@ def permute_orbitals(self, permutation: str = "abcd->abcd") -> "Interaction": """ Permutes the four orbital axes (leaving the momentum axis untouched). - :param permutation: einsum permutation of the four orbital labels, e.g. ``"abcd->adcb"``. + :param permutation: Einsum permutation of the four orbital labels, e.g. ``"abcd->adcb"``. :return: A new :class:`Interaction` with permuted orbitals (a deep copy for the identity permutation). :raises ValueError: If the permutation string is not a valid four-orbital permutation. """ diff --git a/dgamore/local_four_point.py b/dgamore/local_four_point.py index 55bada51..7e774031 100644 --- a/dgamore/local_four_point.py +++ b/dgamore/local_four_point.py @@ -234,8 +234,7 @@ def to_compound_indices(self) -> "LocalFourPoint": Converts the indices of the LocalFourPoint object :math:`F^{wvv'}_{lmm'l'}` to compound indices :math:`F^{w}_{c_1, c_2}` by transposing the object to [w, o1, o2, v, o4, o3, v'] (if the object has any fermionic frequency dimension, otherwise the compound indices are built from orbital dimensions only) and grouping {o1, o2, v} and {o4, o3, v'} - to the new compound index. Always returns the object with a compressed momentum dimension and in the same niw - range as the original object. + to the new compound index. Always returns the object in the same niw range as the original object. :return: ``self`` with shape ``[w, c1, c2]`` (compound indices). :raises NotImplementedError: If the frequency notation is neither ph nor pp. @@ -294,11 +293,11 @@ def _to_compound_indices_pp(self) -> "LocalFourPoint": def to_full_indices(self, shape: tuple = None) -> "LocalFourPoint": """ - Converts an object stored with compound indices to an object that has unraveled momentum, - orbital and frequency axes. Always returns the object with a compressed momentum dimension. This is the inverse - transformation as `to_compound_indices`. Will make use of the `original_shape` the object was created or last - modified with. If the `original_shape` is not set or is hard to obtain, the `shape` argument can be used to - specify the original shape of the object. + Converts an object stored with compound indices to an object that has unraveled orbital + and frequency axes. This is the inverse + transformation of :meth:`to_compound_indices`. Will make use of the ``original_shape`` the object was + created or last modified with. If the ``original_shape`` is not set or is hard to obtain, the ``shape`` + argument can be used to specify the original shape of the object. :param shape: Optional override for the stored ``original_shape`` used to unravel the compound axes. :return: ``self`` with unraveled orbital and frequency axes. @@ -634,7 +633,7 @@ def _add(self, other, subtract: bool = False): def sub(self, other): """ - Helper method that allows for Subtraction of LocalFourPoint objects and other LocalFourPoint or LocalInteraction + Helper method that allows for subtraction of LocalFourPoint objects and other LocalFourPoint or LocalInteraction objects. Subtractions with numpy arrays, floats, ints or complex numbers are also supported. Depending on the number of frequency and momentum dimensions, the vertices have to be subtracted slightly different. If the objects have different niw ranges, they will be converted to the half niw range before the subtraction. diff --git a/dgamore/local_n_point.py b/dgamore/local_n_point.py index 7c7b6459..016b8be6 100644 --- a/dgamore/local_n_point.py +++ b/dgamore/local_n_point.py @@ -304,8 +304,7 @@ def take_vn_diagonal(self): def to_full_niw_range(self): """ Converts the object to the full bosonic frequency range and returns the original object. For details, we refer - to Eq. (2.39) and the associated text in Georg Rohringer's PhD thesis. This corresponds to time-reversal - symmetry. + to Eq. (2.39) and the associated text in Georg Rohringer's PhD thesis. This corresponds to complex-conjugation symmetry. :return: ``self`` over the full (signed) bosonic range (a no-op if there is no bosonic axis or it is already full). """ diff --git a/dgamore/local_sde.py b/dgamore/local_sde.py index fb3a19eb..e1c16089 100644 --- a/dgamore/local_sde.py +++ b/dgamore/local_sde.py @@ -4,11 +4,11 @@ # DGAmore — Multi-Orbital Ladder Dynamical Vertex Approximation (LDGA) & # Eliashberg Equation Solver for Strongly Correlated Electron Systems r""" -Local Schwinger–Dyson step. Given the two-particle DMFT Green's functions and the bare interaction, the functions +Local Schwinger-Dyson step. Given the two-particle DMFT Green's functions and the bare interaction, the functions here build the local vertex hierarchy per spin channel — the generalized susceptibility :math:`\chi_{r}`, the irreducible vertex :math:`\Gamma_{r}` (with the Kitatani shell asymptotics), the auxiliary susceptibility :math:`\chi^{*}_{r}`, the three-leg vertex :math:`\gamma_{r}` (``vrg``), the full vertex :math:`F_{r}`, and the -physical susceptibility — and recompute the local self-energy via the Schwinger–Dyson equation as a sanity check +physical susceptibility — and recompute the local self-energy via the Schwinger-Dyson equation as a sanity check against the DMFT input. Equation numbers refer to the author's master's thesis (Chapter 3). A second set of functions implements the alternative ab-initio DGA formulation. """ @@ -65,7 +65,7 @@ def create_gamma_r_with_shell_correction( ) -> LocalFourPoint: r""" Calculates the irreducible vertex with the shell correction as described by Motoharu Kitatani - et al. 2022 J. Phys. Mater. 5 034005; DOI 10.1088/2515-7639/ac7e6d. More specifically equations A.4 and A.8. + et al. 2022 J. Phys. Mater. 5 034005; DOI 10.1088/2515-7639/ac7e6d. More specifically, see equations A.4 and A.8. The irreducible vertex has an additional factor of :math:`1/\beta^2` compared to DGApy. This is also described in my master's thesis, Sec. 3.7.2. @@ -96,15 +96,15 @@ def create_auxiliary_chi(gamma_r: LocalFourPoint, gchi0_inv: LocalFourPoint, u_l def create_generalized_chi_with_shell_correction( gchi_aux_sum: LocalFourPoint, gchi0: LocalFourPoint, u_loc: LocalInteraction ) -> LocalFourPoint: - """ + r""" Calculates the generalized susceptibility with the shell correction as described by Motoharu Kitatani et al. 2022 J. Phys. Mater. 5 034005; DOI 10.1088/2515-7639/ac7e6d. Eq. A.15. This is also described in my master's thesis, Sec. 3.7.2. - :param gchi_aux_sum: The frequency-summed auxiliary susceptibility :math:`\\sum_{\\nu\\nu'} \\chi^{*}_{r}`. - :param gchi0: The bare bubble :math:`\\chi_0` over the full frequency box. + :param gchi_aux_sum: The frequency-summed auxiliary susceptibility :math:`\sum_{\nu\nu'} \chi^{*}_{r}`. + :param gchi0: The bare bubble :math:`\chi_0` over the full frequency box. :param u_loc: The bare local interaction :math:`U`. - :return: The shell-corrected physical susceptibility :math:`\\chi_{r}^{\\omega}` as a :class:`LocalFourPoint`. + :return: The shell-corrected physical susceptibility :math:`\chi_{r}^{\omega}` as a :class:`LocalFourPoint`. """ gchi0_full_sum = 1.0 / config.sys.beta * gchi0.sum_over_all_vn(config.sys.beta) gchi0_core_sum = 1.0 / config.sys.beta * gchi0.cut_niv(config.box.niv_core).sum_over_all_vn(config.sys.beta) @@ -114,7 +114,7 @@ def create_generalized_chi_with_shell_correction( def create_full_vertex_from_gamma(gamma_r, gchi0, u_loc): r""" Returns the local full vertex in the ``niv_full`` region from the irreducible vertex, - :math:`F = \Gamma [1 + \chi_0 \Gamma]^{-1}` (with :math:`\Gamma` padded with :math:`U` beyond the core box). + :math:`F = \Gamma [1 + \frac{1}{\beta^2} \chi_0 \Gamma]^{-1}` (with :math:`\Gamma` padded with :math:`U` beyond the core box). :param gamma_r: The irreducible vertex :math:`\Gamma_{r}` (core box). :param gchi0: The bare bubble :math:`\chi_0` (with its fermionic axis taken on the diagonal). @@ -237,20 +237,20 @@ def get_loc_self_energy_vrg( g_dmft: GreensFunction, u_loc: LocalInteraction, ) -> SelfEnergy: - """ + r""" Performs the local self-energy calculation using the Schwinger-Dyson equation, i.e. the local variant of Eq. (3.64) in my master's thesis. This is done to verify the implementation of the Schwinger-Dyson equation with the three-leg vertex and the local susceptibility against the DMFT self-energy. Note that there will never be a perfect match due to the sampling method of w2dynamics and the stochastic nature of the CTQMC solver. Nevertheless, the results should be very close. For more details, see also Paul Worm's PhD thesis, Eq. (3.70) and Anna Galler's PhD Thesis, P. 76 ff. - :param vrg_dens: The density three-leg vertex :math:`\\gamma_{\\mathrm{dens}}`. - :param vrg_magn: The magnetic three-leg vertex :math:`\\gamma_{\\mathrm{magn}}`. - :param gchi_dens_sum: The frequency-summed density susceptibility :math:`\\chi_{\\mathrm{dens}}^{\\omega}`. - :param gchi_magn_sum: The frequency-summed magnetic susceptibility :math:`\\chi_{\\mathrm{magn}}^{\\omega}`. + :param vrg_dens: The density three-leg vertex :math:`\gamma_{\mathrm{dens}}`. + :param vrg_magn: The magnetic three-leg vertex :math:`\gamma_{\mathrm{magn}}`. + :param gchi_dens_sum: The frequency-summed density susceptibility :math:`\chi_{\mathrm{dens}}^{\omega}`. + :param gchi_magn_sum: The frequency-summed magnetic susceptibility :math:`\chi_{\mathrm{magn}}^{\omega}`. :param g_dmft: The local (DMFT) :class:`GreensFunction`. :param u_loc: The bare local interaction :math:`U`. - :return: The local :class:`SelfEnergy` (including the Hartree–Fock term). + :return: The local :class:`SelfEnergy` (including the Hartree-Fock term). """ # 1=i, 2=j, 3=k, 4=l, 7=o, 8=p g_wv = g_dmft.get_g_wv(MFHelper.wn(config.box.niw_core), config.box.niv_core) @@ -265,7 +265,7 @@ def get_loc_self_energy_vrg( def perform_local_schwinger_dyson( g_dmft: GreensFunction, g2_dens: LocalFourPoint, g2_magn: LocalFourPoint, u_loc: LocalInteraction ): - """ + r""" Performs the local Schwinger-Dyson equation calculation for the local self-energy for sanity checks against the DMFT self-energy. Includes the calculation of the local three-leg and full vertices, (auxiliary/bare/physical) susceptibilities and the irreducible vertices for both the density and magnetic channel. Employs explicit @@ -349,7 +349,7 @@ def perform_local_schwinger_dyson_abinitio_dga( g2_magn: LocalFourPoint, u_loc: LocalInteraction, ): - """ + r""" DEVELOPMENT / TESTING ONLY -- this is the ab-initio DGA cross-check, NOT the production routine (:func:`perform_local_schwinger_dyson`). Performs the local Schwinger-Dyson equation for the local (DMFT) self-energy as an internal sanity check, building the local self-energy from the full vertices. diff --git a/dgamore/matsubara_frequencies.py b/dgamore/matsubara_frequencies.py index 830fd393..3f703948 100644 --- a/dgamore/matsubara_frequencies.py +++ b/dgamore/matsubara_frequencies.py @@ -107,7 +107,7 @@ def get_frequencies_for_ph_to_pp_w0_channel_conversion( Returns the index arrays that map a particle-hole quantity onto the :math:`\omega = 0` particle-particle notation, i.e. the :math:`(\omega', \nu_1', \nu_2')` indices such that :math:`F_{pp}[\omega, \nu_1, \nu_2] = F_{ph}[\omega', \nu_1', \nu_2']` with the frequency shift - :math:`(\omega, \nu_1, \nu_2) \to (\omega + \nu_1 + \nu_2, \nu_1, \nu_2)`. The returned arrays are already + :math:`(\omega = 0, \nu_1, \nu_2) \to (\nu_1 + \nu_2, \nu_1, \nu_2)`. The returned arrays are already offset so they can be used to index directly into the full (positive-and-negative) ph frequency axes. :param niw: Half-width of the bosonic frequency box of the source ph quantity. diff --git a/dgamore/memory_estimator.py b/dgamore/memory_estimator.py index a80108d0..c34d48fb 100644 --- a/dgamore/memory_estimator.py +++ b/dgamore/memory_estimator.py @@ -13,7 +13,7 @@ All heavy quantities are backed by a single :data:`~dgamore.n_point_base.DTYPE` array, and q-points are distributed across MPI ranks, so per-rank arrays scale with the per-rank q-count rather than the total. Only the dominant large -arrays of each branch are modelled; a single global ``OVERHEAD_FACTOR`` accounts for the un-modelled transients. +arrays of each branch are modeled; a single global ``OVERHEAD_FACTOR`` accounts for the un-modeled transients. """ from dataclasses import dataclass @@ -127,7 +127,7 @@ def estimate_peaks( construct_fq_cheap: bool = False, overhead: float = OVERHEAD_FACTOR, ) -> tuple[float, dict[str, BranchPeak]]: - """ + r""" Estimates the per-rank transient peak host-memory (in bytes) of the fast and lean code path of each memory-sensitive branch, split by whether each transient is distributed across the ranks of a node or built on a single rank, together with the per-rank persistent baseline. @@ -156,7 +156,7 @@ def estimate_peaks( True the per-rank ``fq`` accumulator spans the full ``[wn, vc, vc]`` block instead of the small pp box. :param construct_fq_cheap: Whether the ``fq`` per-q blocks are built on the smaller pp frequency box (``config.eliashberg.construct_fq_cheap``), shrinking every per-q two-fermion block from ``vc`` to ``vpp``. - :param overhead: Global multiplicative factor accounting for un-modelled transient arrays. + :param overhead: Global multiplicative factor accounting for un-modeled transient arrays. :return: A tuple ``(baseline_bytes, peaks)`` of the per-rank baseline and a dict mapping each branch key to its :class:`BranchPeak`. """ diff --git a/dgamore/mpi_utils.py b/dgamore/mpi_utils.py index c6139054..58d4dc3e 100644 --- a/dgamore/mpi_utils.py +++ b/dgamore/mpi_utils.py @@ -261,7 +261,7 @@ class MpiDistributor: """ Distributes tasks among all available cores. Uses the first (q) dimension to slice the vertex data into chunks and sends it to all active MPI processes. Saves intermediate computational results in rank files. Each rank - has their own instance of an MPI distributor and hdf5-file to avoid write conflicts. + has its own instance of an MPI distributor and hdf5-file to avoid write conflicts. """ def __init__(self, ntasks: int = 1, comm: MPI.Comm = None, name: str = "", output_path: str = None): @@ -693,7 +693,7 @@ def allreduce(self, rank_result=None) -> np.ndarray: ``Allreduce`` is collective, so the chunk schedule must be identical on every rank. That holds here because the reduced arrays are always equally shaped across ranks (the callers reduce full, replicated quantities such as the full-k-space self-energy / Fock term — each rank holds a partial sum of the *same* array), so every rank - derives the same chunk boundaries. The single-chunk case is byte-for-byte the previous behaviour. + derives the same chunk boundaries. The single-chunk case is byte-for-byte the previous behavior. :param rank_result: This rank's contribution; reduced in place. Must have the same shape on every rank. :return: The summed array (same buffer), identical on all ranks. @@ -867,13 +867,13 @@ def exchange_and_map_irrbz_fullbz( obj: FourPoint, mpi_dist_irrk: MpiDistributor, mpi_dist_fullbz: MpiDistributor ) -> FourPoint: """ - Maps an obj from the irreducible BZ distribution to the full BZ distribution without + Maps an object from the irreducible BZ distribution to the full BZ distribution without ever assembling the full object on any single rank. - Each rank holds a slice of the obj over the irreducible BZ (shape [q_irr_rank, ...]). + Each rank holds a slice of the object over the irreducible BZ (shape [q_irr_rank, ...]). This routine redistributes the data peer-to-peer so that each rank ends up with a slice over the full BZ (shape [q_full_rank, ...]), with symmetry-equivalent points correctly - replicated according to the irrk_inv mapping. + replicated according to the ``irrk_inv`` mapping. If ``config.lattice.q_grid`` is in auto-discovered symmetry mode (its ``specify_auto_symmetries`` has been called), the per-k orbital transformation @@ -887,7 +887,7 @@ def exchange_and_map_irrbz_fullbz( obj = obj.map_to_full_bz(q_grid) obj.mat = mpi_dist_fullbz.scatter(obj.mat) - which would require rank 0 to hold the entire full-BZ obj in memory. + which would require rank 0 to hold the entire full-BZ object in memory. :param obj: The :class:`FourPoint` distributed over the irreducible BZ. :param mpi_dist_irrk: MPI distributor over the irreducible BZ (source layout). @@ -1043,7 +1043,7 @@ def gather_full_ibz_for_vslice( gamma_r: FourPoint, mpi_dist_irrq: MpiDistributor, mpi_dist_v: MpiDistributor, q_grid: KGrid ) -> FourPoint: """ - Re-layouts a q-distributed pairing vertex into a fermionic-frequency-distributed one for the Eliashberg solver: + Re-lays out a q-distributed pairing vertex into a fermionic-frequency-distributed one for the Eliashberg solver: each rank ends up with the full BZ but only its node-aware slice of the (second) fermionic frequency. The momentum is unfolded to the full BZ locally. Ranks with an empty frequency slice receive ``None``. @@ -1272,12 +1272,12 @@ def _redistribute_p2p(mat, nq, comm, source_layout, target_layout): def execute_distributed_fft(obj: FourPoint, comm: MPI.Comm) -> FourPoint: """ Main routine: Call this for objects that are local to a rank but in the respective full BZ slice. E.g., after - a call of exchange_and_map_irrbz_fullbz. + a call to :func:`exchange_and_map_irrbz_fullbz`. This routine performs a distributed 3D FFT by redistributing the data into pencil decompositions for each dimension, performing local FFTs, and then redistributing back to the original layout. - The final result is that obj.mat is transformed in-place to the Fourier space representation + The final result is that ``obj.mat`` is transformed in place to the Fourier space representation corresponding to the full BZ. - Attention: modifies the object in-place! + Attention: modifies the object in place! :param obj: The :class:`FourPoint` distributed over the full BZ (``flat`` layout), transformed in place. :param comm: The MPI communicator. diff --git a/dgamore/n_point_base.py b/dgamore/n_point_base.py index 69b1c90d..5dbad618 100644 --- a/dgamore/n_point_base.py +++ b/dgamore/n_point_base.py @@ -408,7 +408,7 @@ def __init__( @property def channel(self) -> SpinChannel: """ - Returns the spin channel of the object. For a set of available channels, see the enum `SpinChannel`. + Returns the spin channel of the object. For a set of available channels, see the enum :class:`SpinChannel`. :return: The current spin channel. """ @@ -417,7 +417,7 @@ def channel(self) -> SpinChannel: @channel.setter def channel(self, value: SpinChannel) -> None: """ - Sets the spin channel of the object. For a set of available channels, see the enum `SpinChannel`. + Sets the spin channel of the object. For a set of available channels, see the enum :class:`SpinChannel`. :param value: The spin channel to set. :raises ValueError: If ``value`` is not a :class:`SpinChannel`. @@ -428,7 +428,8 @@ def channel(self, value: SpinChannel) -> None: def set_channel(self, channel: SpinChannel): """ - Sets the spin channel of the object (chainable). For a set of available channels, see the enum `SpinChannel`. + Sets the spin channel of the object (chainable). For a set of available channels, see the enum + :class:`SpinChannel`. :param channel: The spin channel to set. :return: ``self`` (for chaining). @@ -440,7 +441,7 @@ def set_channel(self, channel: SpinChannel): def frequency_notation(self) -> FrequencyNotation: """ Returns the frequency notation (not the channel reducibility) of the object. - For a set of available frequency notations, see the enum `FrequencyNotation`. + For a set of available frequency notations, see the enum :class:`FrequencyNotation`. :return: The current frequency notation. """ @@ -450,7 +451,7 @@ def frequency_notation(self) -> FrequencyNotation: def frequency_notation(self, value: FrequencyNotation) -> None: """ Sets the frequency notation of the object. For a set of available frequency notations, - see the enum `FrequencyNotation`. + see the enum :class:`FrequencyNotation`. :param value: The frequency notation to set. :raises ValueError: If ``value`` is not a :class:`FrequencyNotation`. @@ -462,7 +463,7 @@ def frequency_notation(self, value: FrequencyNotation) -> None: def set_frequency_notation(self, value: FrequencyNotation): """ Sets the frequency notation of the object (chainable). For a set of available frequency notations, - see the enum `FrequencyNotation`. + see the enum :class:`FrequencyNotation`. :param value: The frequency notation to set. :return: ``self`` (for chaining). @@ -635,7 +636,7 @@ def reduce_q(self, q_list: np.ndarray): def find_q(self, q: tuple[int, int, int] = (0, 0, 0)): r""" - Find the matrix element for a single momentum :math:`\vec{q}` and returns a compressed copy. + Finds the matrix element for a single momentum :math:`\vec{q}` and returns a compressed copy. :param q: The momentum grid index ``(qx, qy, qz)`` to select. :return: A compressed copy containing only the requested momentum (``nq = (1, 1, 1)``). diff --git a/dgamore/nonlocal_sde.py b/dgamore/nonlocal_sde.py index 670d9cd3..b98b1bc5 100644 --- a/dgamore/nonlocal_sde.py +++ b/dgamore/nonlocal_sde.py @@ -12,7 +12,7 @@ the momentum-dependent self-energy :math:`\Sigma(k, \nu)`. Several CPU/GPU/FFT variants of the heavy contractions are provided, distributed over MPI ranks. The whole thing is wrapped in a self-consistency loop with chemical- potential adjustment and self-energy mixing (linear / Pulay / Anderson). Equation numbers refer to the author's -master's thesis (Chapter 4). +master's thesis (Chapters 3 & 4). """ import glob @@ -45,14 +45,16 @@ def get_hartree_fock( r""" Returns the Hartree-Fock term separately for the local and non-local interaction. Since we are always SU(2)-symmetric, the sum over the spins of the first term in Eq. (4.55) in Anna Galler's thesis results in a simple factor of 2. This - can be seen in my master's thesis, Eq. (3.56). The Hartree-Fock term is given by + can be seen in my master's thesis, Eq. (3.55). The Hartree-Fock term is given by + .. math:: \Sigma_{HF}^k = 2(U_{acbd} + V^{q=0}_{acbd}) n_{dc} - 1/N_q \sum_q (U_{adcb} + V^{q}_{adcb}) n^{k-q}_{dc} - where the Hartree-term reads :math:`\Sigma_{H} = 2(U_{acbd} + V^{q=0}_{acbd}) n_{dc}` and the Fock-term reads + + where the Hartree term reads :math:`\Sigma_{H} = 2(U_{acbd} + V^{q=0}_{acbd}) n_{dc}` and the Fock term reads :math:`\Sigma_{F}^k = - 1/N_q \sum_q (U_{adcb} + V^{q}_{adcb}) n^{k-q}_{dc}`. The Hartree contraction uses the middle-index-swapped ``U_{acbd}`` so it picks up the inter-orbital density :math:`U'` (stored at :math:`U_{abab}`); see :func:`dgamore.local_sde.get_local_hartree_fock`. - Processes the Fock-Term for each individual orbital to save memory, as for high momentum grids, - the occ_qk property can become large. + Processes the Fock term for each individual orbital to save memory, as for high momentum grids, + the ``occ_qk`` property can become large. :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}` (see :class:`Interaction`). @@ -228,17 +230,17 @@ def create_generalized_chi_q_with_shell_correction( u_loc: LocalInteraction, v_nonloc: Interaction, ) -> FourPoint: - """ + r""" Calculates the generalized susceptibility with the shell correction as described by Motoharu Kitatani et al. 2022 J. Phys. Mater. 5 034005; DOI 10.1088/2515-7639/ac7e6d. Eq. A.15. See also Sec. 3.7.2 in my master's thesis for details. - :param gchi_aux_q_sum: The frequency-summed auxiliary susceptibility :math:`\\sum_{\\nu\\nu'}\\chi^{*;q}_{r}`. + :param gchi_aux_q_sum: The frequency-summed auxiliary susceptibility :math:`\sum_{\nu\nu'}\chi^{*;q}_{r}`. :param gchi0_q_full_sum: The frequency-summed bare bubble over the full box. :param gchi0_q_core_sum: The frequency-summed bare bubble over the core box. :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}`. - :return: The shell-corrected physical susceptibility :math:`\\chi^{q}_{r}` as a :class:`FourPoint`. + :return: The shell-corrected physical susceptibility :math:`\chi^{q}_{r}` as a :class:`FourPoint`. """ return ( (gchi_aux_q_sum + gchi0_q_full_sum - gchi0_q_core_sum).invert() @@ -247,12 +249,12 @@ def create_generalized_chi_q_with_shell_correction( def calculate_sigma_dc_kernel(f_dc_loc: LocalFourPoint, gchi0_q: FourPoint, u_loc: LocalInteraction) -> FourPoint: - """ + r""" Returns the double-counting kernel for the self-energy calculation, contracting the local full vertex with the momentum-dependent bubble per q-point. For details, see Eq. (4.28) in my master's thesis. :param f_dc_loc: The local full vertex :math:`F` used for the double-counting correction. - :param gchi0_q: The momentum-dependent bare bubble :math:`\\chi_0^q`. + :param gchi0_q: The momentum-dependent bare bubble :math:`\chi_0^q`. :param u_loc: The bare local interaction :math:`U`. :return: The double-counting kernel as a :class:`FourPoint`, cut to the core fermionic box. """ @@ -291,9 +293,9 @@ def calculate_kernel_r_q( return u_r @ kernel -def perform_ornstein_zernicke_fit(chi_phys_q_r: FourPoint) -> None: +def perform_ornstein_zernike_fit(chi_phys_q_r: FourPoint) -> None: r""" - Fits the static (:math:`\omega = 0`) physical susceptibility to an Ornstein–Zernike form + Fits the static (:math:`\omega = 0`) physical susceptibility to an Ornstein-Zernike form :math:`\chi(q) = A / (\xi^{-2} + (q - q_0)^2)` around the antiferromagnetic wave vector :math:`q_0 = (\pi, \pi, 0)`, per orbital combination, and writes the amplitude :math:`A` and correlation length :math:`\xi` to ``oz_coeff.txt``. Non-converging fits are flagged with ``[-1, -1]``. @@ -303,12 +305,12 @@ def perform_ornstein_zernicke_fit(chi_phys_q_r: FourPoint) -> None: """ def oz_spin_w0(q_grid: KGrid, a: float, xi: float): - """ - Evaluates the Ornstein–Zernike model on the full BZ grid, flattened to match the fit data. + r""" + Evaluates the Ornstein-Zernike model on the full BZ grid, flattened to match the fit data. :param q_grid: The :class:`KGrid` providing the momentum coordinates. :param a: The amplitude :math:`A`. - :param xi: The correlation length :math:`\\xi`. + :param xi: The correlation length :math:`\xi`. :return: The flattened model susceptibility over the BZ grid. """ qx = qy = np.pi @@ -323,7 +325,7 @@ def oz_spin_w0(q_grid: KGrid, a: float, xi: float): def fit_oz_spin(q_grid: KGrid, mat: np.ndarray): """ - Least-squares fits the Ornstein–Zernike model to one orbital slice of the susceptibility. + Least-squares fits the Ornstein-Zernike model to one orbital slice of the susceptibility. :param q_grid: The :class:`KGrid` providing the momentum coordinates. :param mat: The flattened susceptibility slice to fit. @@ -465,9 +467,9 @@ def calculate_sigma_kernel_r_q( chi_phys_q_r = perform_lambda_correction(chi_phys_q_r) chi_phys_q_r.save(name=f"chi_phys_q_{chi_phys_q_r.channel.value}", output_dir=config.output.output_path) - # perform Ornstein-Zernicke fit + # perform Ornstein-Zernike fit if chi_phys_q_r.channel == SpinChannel.MAGN: - perform_ornstein_zernicke_fit(chi_phys_q_r) + perform_ornstein_zernike_fit(chi_phys_q_r) chi_phys_q_r.mat = mpi_dist_irrq.scatter(chi_phys_q_r.mat) logger.info(f"Saved physical susceptibility ({chi_phys_q_r.channel.value}) to file.") @@ -688,7 +690,7 @@ def calculate_sigma_from_kernel_gpu( def calculate_sigma_from_kernel_auto( mpi_distributor: MpiDistributor, kernel: FourPoint, giwk: GreensFunction, my_full_q_list: np.ndarray ) -> SelfEnergy: - """ + r""" Dispatches the q-loop self-energy contraction to the GPU (:func:`calculate_sigma_from_kernel_gpu`) when CuPy and a usable CUDA device are available (one GPU per MPI rank, round-robin), otherwise falls back to the CPU implementation (:func:`calculate_sigma_from_kernel_cpu`). @@ -728,7 +730,7 @@ def calculate_sigma_from_kernel_fft_cpu( mpi_dist: MpiDistributor, kernel: FourPoint, giwk: GreensFunction, niw_index_w_pairs: list[tuple[int, int]] ) -> SelfEnergy: r""" - Optimized self-energy calculation using distributed FFTs (CPU). Replaces the q-loop with a real-space pointwise + Computes the self-energy using distributed FFTs (CPU). Replaces the q-loop with a real-space pointwise multiplication: both the Green's function and the kernel are FFT'd to real space (the kernel to :math:`-R` via the conjugate trick), contracted pointwise per rank-local R-slice, and accumulated. Returns :math:`\Sigma` in R-space, positive-:math:`\nu` half only; the caller must ifft over :math:`(k_x, k_y, k_z)` and then call @@ -799,7 +801,7 @@ def calculate_sigma_from_kernel_fft_gpu( mpi_dist: MpiDistributor, kernel: FourPoint, giwk: GreensFunction, niw_index_w_pairs: list[tuple[int, int]] ) -> SelfEnergy: r""" - Optimized self-energy calculation using distributed FFTs, running on the GPU (CuPy). Same algorithm as + Computes the self-energy using distributed FFTs, running on the GPU (CuPy). Same algorithm as :func:`calculate_sigma_from_kernel_fft_cpu` (including the single-niw-half / ``niw_index_w_pairs`` contraction). Returns :math:`\Sigma` in R-space, positive-:math:`\nu` half only; the caller must ifft over :math:`(k_x, k_y, k_z)` and then call :meth:`SelfEnergy.to_full_niv_range` before use. @@ -892,7 +894,7 @@ def calculate_sigma_from_kernel_fft( niw_index_w_pairs: list[tuple[int, int]], use_gpu: bool, ) -> SelfEnergy: - """ + r""" Dispatches one bosonic-frequency FFT pass to the GPU (:func:`calculate_sigma_from_kernel_fft_gpu`) or CPU (:func:`calculate_sigma_from_kernel_fft_cpu`) implementation according to ``use_gpu`` (decided once by :func:`select_sigma_fft_device`, so no per-pass GPU-detection logging). @@ -929,9 +931,9 @@ def _map_kernel_to_full_bz( def get_starting_sigma(default_sigma: SelfEnergy) -> tuple[SelfEnergy, int]: """ - If one continues from a previous self-consistency calculation, we try to retrieve the last calculated self-energy as - a starting point for the next calculation. Whether the normal or interpolated sigma is chosen depends on the - setting. If no ``sigma_dga_*_N.npy`` file is found, we use the DMFT self-energy as a starting point. + Tries to retrieve the last calculated self-energy from a previous self-consistency calculation as a starting point + for the next calculation. Whether the normal or interpolated sigma is chosen depends on the setting. If no + ``sigma_dga_*_N.npy`` file is found, we use the DMFT self-energy as a starting point. :param default_sigma: The fallback (DMFT) :class:`SelfEnergy` used when no previous result is found. :return: A tuple of the starting :class:`SelfEnergy` (cut to the core box and interpolated onto the k-grid) and @@ -1044,8 +1046,8 @@ def _get_top_n_files(path: str, pattern: str, regex: re.Pattern) -> list[tuple[i def calculate_self_energy_q( comm: MPI.Comm, u_loc: LocalInteraction, v_nonloc: Interaction, sigma_dmft: SelfEnergy, sigma_local: SelfEnergy ) -> SelfEnergy: - """ - Main routine for the non-local DGA self-energy calculation. Calculates the Hartree- and Fock-terms, the bubble, + r""" + Runs the non-local DGA self-energy calculation. Calculates the Hartree- and Fock terms, the bubble, the double-counting correction and the kernel in the density and magnetic channel. Finally, calculates the non-local self-energy from the kernel and the Green's function. Also takes care of the self-consistency loop and the chemical potential adjustment as well as the self-energy mixing, etc. @@ -1054,7 +1056,7 @@ def calculate_self_energy_q( :param u_loc: The bare local interaction :math:`U`. :param v_nonloc: The non-local interaction :math:`V^{q}`. :param sigma_dmft: The DMFT self-energy (used as the starting point and for the shell/tail correction). - :param sigma_local: The locally recomputed self-energy (used for the double-counting :math:`\\Delta\\Sigma`). + :param sigma_local: The locally recomputed self-energy (used for the double-counting :math:`\Delta\Sigma`). :return: The converged (or last-iteration) momentum-dependent DGA :class:`SelfEnergy`. """ logger = config.logger diff --git a/dgamore/plotting.py b/dgamore/plotting.py index 54a9d3dc..5fd61325 100644 --- a/dgamore/plotting.py +++ b/dgamore/plotting.py @@ -285,7 +285,7 @@ def plot_two_point_kx_ky( save: bool = True, show: bool = False, ): - """ + r""" Plots the real and imaginary parts of a two-point function in the :math:`(k_x, k_y)` plane (at :math:`k_z = 0` and the first positive Matsubara frequency) for fixed orbitals, with the antiferromagnetic zone boundary and optional scatter points overlaid. @@ -293,7 +293,7 @@ def plot_two_point_kx_ky( :param obj: The two-point object to plot (a :class:`LocalNPoint` / :class:`IAmNonLocal`). :param kx: The kx grid values for the plot axes. :param ky: The ky grid values for the plot axes. - :param pi_shift: Whether to shift the momentum grid by :math:`\\pi` before plotting. + :param pi_shift: Whether to shift the momentum grid by :math:`\pi` before plotting. :param title: Title suffix for the subplots. :param name: Output filename tag. :param orbs: The two orbital indices to select. @@ -379,14 +379,14 @@ def plot_two_point_kx_ky_real_and_imag( save: bool = True, show: bool = False, ): - """ + r""" Plots a two-point function in the :math:`(k_x, k_y)` plane for fixed orbitals, writing the real and imaginary parts to two separate files. :param obj: The two-point object to plot (a :class:`LocalNPoint` / :class:`IAmNonLocal`). :param kx: The kx grid values for the plot axes. :param ky: The ky grid values for the plot axes. - :param pi_shift: Whether to shift the momentum grid by :math:`\\pi` before plotting. + :param pi_shift: Whether to shift the momentum grid by :math:`\pi` before plotting. :param title: Title (rendered inside the math mode of the subplot titles). :param name: Output filename tag (``_real``/``_imag`` is appended). :param orbs: The two orbital indices to select. @@ -458,7 +458,7 @@ def plot_two_point_kx_ky_with_fs_points( do_save: bool = True, show: bool = False, ): - """ + r""" Plots a two-point function in the :math:`(k_x, k_y)` plane for fixed orbitals, with the Fermi-surface points (zero crossings of the quantity in the reduced BZ quadrant) scattered on top (see :func:`plot_two_point_kx_ky`). @@ -466,7 +466,7 @@ def plot_two_point_kx_ky_with_fs_points( :param k_grid: The :class:`KGrid` providing the k-axis values for the Fermi-surface points. :param kx: The kx grid values for the plot axes. :param ky: The ky grid values for the plot axes. - :param pi_shift: Whether to shift the momentum grid by :math:`\\pi` before plotting. + :param pi_shift: Whether to shift the momentum grid by :math:`\pi` before plotting. :param title: Title suffix for the subplots. :param name: Output filename tag. :param orbs: The two orbital indices to select. diff --git a/dgamore/self_energy.py b/dgamore/self_energy.py index edb85694..58dbd801 100644 --- a/dgamore/self_energy.py +++ b/dgamore/self_energy.py @@ -46,10 +46,10 @@ def __init__( :param mat: Underlying self-energy array (two orbital axes and one fermionic frequency axis, optionally preceded by momentum axes). - :param nk: Number of momenta per spatial direction. + :param nk: Number of momenta per spatial direction ``(nkx, nky, nkz)``. :param full_niv_range: Whether the object spans the full (signed) fermionic range or only :math:`\nu \geq 0`. - :param has_compressed_q_dimension: Whether the momentum is stored as a single compressed axis (True) or as - ``[kx, ky, kz, ...]`` (False). + :param has_compressed_q_dimension: Whether the momentum is stored as a single compressed axis ``[q, ...]`` + (True) or as three separate axes ``[kx, ky, kz, ...]`` (False). :param estimate_niv_core: If True, estimate the core frequency box from the deviation to the asymptotic tail; otherwise the core extends over the full stored box. :param calc_smom: If True, fit the high-frequency moments :math:`(\Sigma_\infty, \Sigma_1)` on construction. @@ -295,7 +295,7 @@ def fit_polynomial(self, n_fit: int = 4, degree: int = 3, niv_core: int = 0) -> def interpolate(self, beta_target: float, niv_target: int, niv_linear: int = 4) -> "SelfEnergy": r""" - Re-grid the self-energy from its own inverse temperature :math:`\beta` (``self._beta``) to ``beta_target``. + Re-grids the self-energy from its own inverse temperature :math:`\beta` (``self._beta``) to ``beta_target``. Only the last (frequency) axis is interpolated. The innermost niv_linear source frequencies are interpolated linearly diff --git a/tests/test_brillouin_zone.py b/tests/test_brillouin_zone.py index 885eca87..089f4246 100644 --- a/tests/test_brillouin_zone.py +++ b/tests/test_brillouin_zone.py @@ -37,14 +37,14 @@ def test_applies_inversion_symmetry_along_z_axis(): def test_raises_error_for_invalid_axis(): """Inversion symmetry raises for an invalid axis.""" mat = np.random.rand(4, 4, 4) - with pytest.raises(AssertionError, match="axis = 3 but must be in \[0,1,2\]"): + with pytest.raises(AssertionError, match=r"axis = 3 but must be in \[0,1,2\]"): bz.inv_sym(mat, axis=3) def test_raises_error_for_insufficient_dimensions_on_inv_sym(): """Inversion symmetry raises for insufficient dimensions.""" mat = np.random.rand(4, 4) - with pytest.raises(AssertionError, match="dim\(mat\) = 2 but must be at least 3 dimensional"): + with pytest.raises(AssertionError, match=r"dim\(mat\) = 2 but must be at least 3 dimensional"): bz.inv_sym(mat, axis=0) @@ -108,7 +108,7 @@ def test_applies_simultaneous_inversion_in_x_and_y_directions(): def test_raises_error_for_insufficient_dimensions_on_x_y_inv(): """Simultaneous x-y inversion raises for insufficient dimensions.""" mat = np.random.rand(4, 4) - with pytest.raises(AssertionError, match="dim\(mat\) = 2 but must be at least 3 dimensional"): + with pytest.raises(AssertionError, match=r"dim\(mat\) = 2 but must be at least 3 dimensional"): bz.x_y_inv(mat) @@ -199,7 +199,7 @@ def test_does_nothing_when_no_symmetries_provided(): def test_raises_error_for_insufficient_dimensions_on_apply_symmetries(): """apply_symmetries raises for insufficient dimensions.""" mat = np.random.rand(4, 4) - with pytest.raises(AssertionError, match="dim\(mat\) = 2 but must at least 3 dimensional"): + with pytest.raises(AssertionError, match=r"dim\(mat\) = 2 but must at least 3 dimensional"): bz.apply_symmetries(mat, [bz.KnownSymmetries.X_INV]) @@ -503,6 +503,21 @@ def test_build_k_path_single_segment_gamma_to_x(): assert nkp == [2] +def test_get_kpath_val_reads_each_axis_for_its_own_column(): + """get_kpath_val maps the x/y/z path columns through kx/ky/kz respectively (regression: kx was used for all three).""" + kp = KPath(nk=(4, 4, 4), path="gamma-x") + kp.kx = np.array([10.0, 11.0, 12.0]) + kp.ky = np.array([20.0, 21.0, 22.0]) + kp.kz = np.array([30.0, 31.0, 32.0]) + kp.kpts = np.array([[0, 1, 2], [2, 0, 1]]) + + kx_vals, ky_vals, kz_vals = kp.get_kpath_val() + + assert np.array_equal(kx_vals, np.array([10.0, 12.0])) + assert np.array_equal(ky_vals, np.array([21.0, 20.0])) + assert np.array_equal(kz_vals, np.array([32.0, 31.0])) + + def test_get_bands_returns_sorted_real_eigenvalues(): """Patch KPath.map_to_kpath to return an object that yields 2x2 matrices. Ensure get_bands returns sorted real eigenvalues for each k-point.""" diff --git a/tests/test_nonlocal_sde.py b/tests/test_nonlocal_sde.py index ebb6b678..8eeaecdb 100644 --- a/tests/test_nonlocal_sde.py +++ b/tests/test_nonlocal_sde.py @@ -16,7 +16,7 @@ from dgamore.interaction import Interaction from dgamore.local_sde import get_local_hartree_fock from dgamore.n_point_base import SpinChannel -from dgamore.nonlocal_sde import _init_mu_history, get_hartree_fock, perform_ornstein_zernicke_fit +from dgamore.nonlocal_sde import _init_mu_history, get_hartree_fock, perform_ornstein_zernike_fit LOCAL_SDE_DATA = f"{os.path.dirname(os.path.abspath(__file__))}/test_data/local_sde" @@ -109,14 +109,14 @@ def mat(self) -> np.ndarray: return self._mat -def test_ornstein_zernicke_fit_aggregates_nonconverged_warnings(monkeypatch): +def test_ornstein_zernike_fit_aggregates_nonconverged_warnings(monkeypatch): """All non-converging OZ fits collapse into a single aggregated warning instead of one log per orbital.""" config.sys.n_bands = 2 logger = mock.Mock() monkeypatch.setattr(config, "logger", logger, raising=False) monkeypatch.setattr(nonlocal_sde.opt, "curve_fit", mock.Mock(side_effect=RuntimeError("forced non-convergence"))) - perform_ornstein_zernicke_fit(_ConstantChi(np.ones((2, 2, 1, 2, 2, 2, 2), dtype=np.complex64))) + perform_ornstein_zernike_fit(_ConstantChi(np.ones((2, 2, 1, 2, 2, 2, 2), dtype=np.complex64))) logger.warning.assert_called_once() msg = logger.warning.call_args.args[0] @@ -124,13 +124,13 @@ def test_ornstein_zernicke_fit_aggregates_nonconverged_warnings(monkeypatch): assert "(1, 1, 1, 1)" in msg and "(2, 2, 2, 2)" in msg # 1-based orbital labels, not 0-based -def test_ornstein_zernicke_fit_logs_no_warning_when_all_converge(monkeypatch): +def test_ornstein_zernike_fit_logs_no_warning_when_all_converge(monkeypatch): """A fully converging set of OZ fits emits no warning at all (the aggregation guard stays silent).""" config.sys.n_bands = 2 logger = mock.Mock() monkeypatch.setattr(config, "logger", logger, raising=False) monkeypatch.setattr(nonlocal_sde.opt, "curve_fit", mock.Mock(return_value=(np.array([1.0, 2.0]), None))) - perform_ornstein_zernicke_fit(_ConstantChi(np.ones((2, 2, 1, 2, 2, 2, 2), dtype=np.complex64))) + perform_ornstein_zernike_fit(_ConstantChi(np.ones((2, 2, 1, 2, 2, 2, 2), dtype=np.complex64))) logger.warning.assert_not_called()