# Copyright (c) 2013 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
# Copyright (c) 2013 Centre national de la recherche scientifique (CNRS)
# Copyright (c) 2019-2023 Simons Foundation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You may obtain a copy of the License at
# https:#www.gnu.org/licenses/gpl-3.0.txt
#
# Authors: Michel Ferrero, Alexander Hampel, Olivier Parcollet, Hugo U.R. Strand, Nils Wentzell
"""Tight-binding Hamiltonians on Bravais lattices.
Provides the higher-level Python wrapper :class:`TBLattice` that bundles a
:class:`BravaisLattice`, :class:`BrillouinZone` and :class:`TightBinding` from
:mod:`triqs.lattice.lattice_tools` together.
Also exposes the density-of-states helpers :func:`dos` (over a regular k-grid)
and :func:`dos_patch` (over a triangular Brillouin-zone patch), which wrap the
underlying C++ routines and return :class:`triqs.dos.DOS` objects.
"""
from h5.formats import register_class
__all__ = ['BravaisLattice', 'BrillouinZone', 'TightBinding', 'dos', 'TBLattice']
from ..gfs import Gf, MeshBrZone, MeshCycLat
from .lattice_tools import BravaisLattice
from .lattice_tools import BrillouinZone
from .lattice_tools import TightBinding
from .lattice_tools import dos_patch as dos_patch_c
from .lattice_tools import dos as dos_c
from triqs.dos import DOS
import numpy
import warnings
def dos(tight_binding, n_kpts, n_eps, name):
"""Compute the density of states of a tight-binding Hamiltonian on a regular k-grid.
Wraps the C++ :func:`triqs.lattice.lattice_tools.dos` and splits the result
into one :class:`triqs.dos.DOS` per band.
Parameters
----------
tight_binding : TightBinding
The tight-binding Hamiltonian.
n_kpts : int
Number of k-points along each dimension of the Brillouin zone.
n_eps : int
Number of energy bins.
name : str
Name of the resulting DOS objects.
Returns
-------
list of triqs.dos.DOS
One density of states per band.
"""
eps, arr = dos_c(tight_binding, n_kpts, n_eps)
return [DOS(eps, arr[:, i], name) for i in range(arr.shape[1])]
def dos_patch(tight_binding, triangles, n_eps, n_div, name):
"""Compute the density of states of a tight-binding Hamiltonian on a triangular Brillouin-zone patch.
Only supported for 2-dimensional lattices.
Parameters
----------
tight_binding : TightBinding
The tight-binding Hamiltonian.
triangles : numpy.ndarray
2-D array of shape ``(n_triangles * 3, 2)`` containing the vertices of
the triangular patches in the Brillouin zone, three rows per triangle.
n_eps : int
Number of energy bins.
n_div : int
Number of sub-divisions of each triangle used for the sampling.
name : str
Name of the resulting DOS object.
Returns
-------
triqs.dos.DOS
The density of states summed over orbitals on the given patch.
"""
eps, arr = dos_patch_c(tight_binding, triangles, n_eps, n_div)
return DOS(eps, arr, name)
[docs]
class TBLattice(object):
"""A tight-binding Hamiltonian on top of a Bravais lattice.
Bundles a :class:`BravaisLattice`, a :class:`BrillouinZone` and a
:class:`TightBinding` instance and exposes part of their interfaces directly.
Parameters
----------
units : list of tuples of floats
Basis vectors of the real-space lattice.
hoppings : dict, optional
Dictionary mapping tuples of integers (real-space displacements in
multiples of the lattice basis vectors) to numpy ndarray hopping
matrices over the orbital indices.
orbital_positions : list of three-tuples of floats, optional
Internal orbital positions in the unit cell.
orbital_names : list of str, optional
Names for each orbital.
Attributes
----------
bl : BravaisLattice
The associated Bravais lattice.
bz : BrillouinZone
The associated Brillouin zone.
tb : TightBinding
The tight-binding Hamiltonian.
hoppings : dict
Real-space hoppings as a ``{displacement: matrix}`` dict.
ndim : int
Number of spatial dimensions of the lattice.
units : numpy.ndarray
``(ndim, ndim)`` array whose rows are the lattice basis vectors.
n_orbitals : int
Number of orbitals in the unit cell.
orbital_positions : list
Positions of the orbitals inside the unit cell.
orbital_names : list of str
Names of the orbitals in the unit cell.
"""
def __init__(self, units,
hoppings=dict(),
orbital_positions=[(0, 0, 0)],
orbital_names=None,
hopping=None):
if hopping is not None:
warnings.warn(
"Keyword hopping in TBLattice.__init__ deprecated; use hoppings instead.", FutureWarning)
hoppings = hopping
if orbital_names is None:
orbital_names = len(orbital_positions) * [""]
self.bl = BravaisLattice(units, orbital_positions, orbital_names)
self.bz = BrillouinZone(self.bl)
self.tb = TightBinding(self.bl, hoppings)
@property
def hoppings(self):
"""Real-space hoppings as a ``{displacement: matrix}`` dict.
Each key is a tuple of integers giving a real-space displacement in
multiples of the lattice basis vectors; the corresponding value is the
hopping matrix between orbitals at that displacement.
Returns
-------
dict
Mapping from displacement tuples to ``numpy.ndarray`` hopping
matrices of shape ``(n_orbitals, n_orbitals)``.
"""
return {tuple(displ): hop for displ, hop in zip(self.tb.displ_vec, self.tb.overlap_mat_vec)}
[docs]
def get_kmesh(self, n_k):
"""Return a mesh on the Brillouin zone with a given discretization.
Parameters
----------
n_k : int or three-tuple of int
The linear dimension(s).
Returns
-------
MeshBrZone
The mesh on the Brillouin zone.
"""
return MeshBrZone(self.bz, n_k)
[docs]
def get_rmesh(self, n_r):
"""Return a mesh on the Bravais lattice with a given periodicity.
Parameters
----------
n_r : int or three-tuple of int
The periodicity in each dimension.
Returns
-------
MeshCycLat
The cyclic lattice mesh.
"""
return MeshCycLat(self.bl, n_r)
# ---- Expose BravaisLattice API ----
@property
def ndim(self):
"""Number of spatial dimensions of the lattice.
Returns
-------
int
Number of dimensions (1, 2 or 3).
"""
return self.bl.ndim
@property
def units(self):
"""Lattice basis vectors as a ``(ndim, ndim)`` array in the standard basis.
Returns
-------
numpy.ndarray
Two-dimensional array whose rows are the basis vectors
:math:`\\{ \\mathbf{a}_1, \\dots, \\mathbf{a}_d \\}` of the
Bravais lattice.
"""
return self.bl.units[:self.ndim, :self.ndim]
@property
def n_orbitals(self):
"""Number of orbitals in the unit cell.
Returns
-------
int
Number of atomic orbitals in the unit cell.
"""
return self.bl.n_orbitals
@property
def orbital_positions(self):
"""Positions of the orbitals inside the unit cell.
Returns
-------
list
Orbital positions :math:`\\{ \\mathbf{r}_1, \\dots, \\mathbf{r}_m \\}`
in the standard basis.
"""
return list(self.bl.orbital_positions)
@property
def orbital_names(self):
"""Names of the orbitals in the unit cell.
Returns
-------
list of str
One name per orbital, in the same order as :attr:`orbital_positions`.
"""
return list(self.bl.orbital_names)
# ---- Expose TightBinding API ----
[docs]
def lattice_to_real_coordinates(self, x):
return self.tb.lattice_to_real_coordinates(x)
lattice_to_real_coordinates.__doc__ = TightBinding.lattice_to_real_coordinates.__doc__
[docs]
def fourier(self, arg):
return self.tb.fourier(arg)
fourier.__doc__ = TightBinding.fourier.__doc__
[docs]
def dispersion(self, arg):
return self.tb.dispersion(arg)
dispersion.__doc__ = TightBinding.dispersion.__doc__
# ---- H5 Serialization ----
def __reduce_to_dict__(self):
return {"BravaisLattice": self.bl,
"BrillouinZone": self.bz,
"TightBinding": self.tb}
@classmethod
def __factory_from_dict__(cls, name, d):
bl = d["BravaisLattice"]
tb = d["TightBinding"]
hoppings = {tuple(displ): hop for displ, hop in zip(
tb.displ_vec, tb.overlap_mat_vec)}
return cls(bl.units[:bl.ndim, :bl.ndim],
hoppings,
list(bl.orbital_positions),
list(bl.orbital_names))
# ---- Comparison ----
def __eq__(self, other):
if not isinstance(other, TBLattice):
return False
return self.tb == other.tb and self.bz == other.bz and self.bl == other.bl
# ---- Print ----
def __str__(self):
return str(self.tb)
register_class(TBLattice)