Source code for strawberrypy.postprocessing.tracemarker

import numpy as np

from ..config import mpimaster
from ..classes import Model
from .contractions import lattice_contraction, pbc_lattice_contraction
from .averages import average_over_radius


[docs] @mpimaster def trace_marker( model: Model, marker: np.ndarray, invariant: str = "chern", bare_marker: bool = False, macroscopic_average: bool = False, cutoff: float = 0.8, boundary_conditions: str = "pbc", ) -> float: r""" Trace a topological marker over the whole supercell to get the single-point invariant. This function is intended for periodic boundary conditions (PBC) only since within open boundary conditions the trace over the whole sample vanishes by construction. Parameters ---------- model : Model The model for which to compute the topological invariant. marker : np.ndarray The PBC local topological marker to be traced. invariant : str The type of topological marker computed. Allowed values are :python:`'chern'` when passing the PBC local Chern marker, and :python:`'z2'` when passing the PBC local spin-Chern marker or the local :math:`\mathbb{Z}_{2}` marker using time reversal symmetry. bare_marker : bool If the local marker passed is the bare marker. Default is :python:`False`. macroscopic_average : bool If :python:`True`, performs a real space average of the local marker over a radius equal to :python:`cutoff`, and then trace over the whole sample. :python:`marker` is expected to be the bare marker in this case and :python:`bare_marker` should be set to :python:`True`. Default is :python:`False`. cutoff : float Cutoff set for the calculation of the macroscopic average in real space. boundary_conditions : str If :python:`macroscopic_average == True`, the boundary conditions to be used when computing the macroscopic average in real space. Default is :python:`pbc`. Returns ------- sp_inv : float Topological invariant computed as the trace over the whole supercell of the local topological marker. """ # Only the master rank in parallel can call functions distributing the computation master_rank = model.backend.is_master_rank # Check input variables if invariant not in ("chern", "z2"): raise RuntimeError( "Invariant type not allowed. Allowed values are 'chern' and 'z2'." ) if macroscopic_average and not bare_marker: raise RuntimeError( "Macroscopic average can be performed only if the bare marker is passed." ) if bare_marker and macroscopic_average: # If macroscopic_average, prepare the contraction window for the average in real space if boundary_conditions == "pbc": contraction = pbc_lattice_contraction(model, cutoff) elif boundary_conditions == "obc": contraction = lattice_contraction(model, cutoff) else: raise RuntimeError( "Boundary condition for the macroscopic average not allowed." ) if invariant == "chern": marker = average_over_radius( model, marker, cutoff, contraction=contraction ) else: marker[0] = average_over_radius( model, marker[0], cutoff, contraction=contraction ) marker[1] = average_over_radius( model, marker[1], cutoff, contraction=contraction ) if master_rank: # Trace over the whole sample and set the correct normalization factor if invariant == "chern": if bare_marker and not macroscopic_average: sp_inv = np.sum(marker) / (model.Lx * model.Ly) else: sp_inv = np.sum(marker) / (model.Lx * model.Ly * model.states_uc) else: if bare_marker and not macroscopic_average: sp_c1 = np.sum(marker[0]) / (model.Lx * model.Ly) sp_c2 = np.sum(marker[1]) / (model.Lx * model.Ly) else: sp_c1 = np.sum(marker[0]) / (model.Lx * model.Ly * model.states_uc) sp_c2 = np.sum(marker[1]) / (model.Lx * model.Ly * model.states_uc) # sp_inv = np.abs(np.fmod(0.5 * (sp_c1 - sp_c2), 2)) sp_inv = np.mod(0.5 * (sp_c1 - sp_c2), 2) sp_inv = 1 - np.abs(1 - sp_inv) sp_inv = model.backend.comm.bcast(sp_inv if master_rank else None, root=0) return sp_inv