TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
superlattice.cpp
1#include "./superlattice.hpp"
3
4#include <itertools/itertools.hpp>
5#include <nda/nda.hpp>
6
7#include <array>
8#include <cmath>
9#include <iostream>
10#include <map>
11#include <optional>
12#include <stdexcept>
13#include <utility>
14#include <vector>
15
16namespace triqs::experimental::lattice {
17
18 constexpr auto all_ = nda::range::all;
19
20 superlattice::superlattice(nda::array<long, 2> sl_units, nda::array<long, 2> cluster_pts) : units(sl_units), cluster_points(cluster_pts) {
21 std::cout << n_cluster_sites() << " cluster points in superlattice.\n";
22 if (n_cluster_sites() == 0) throw std::runtime_error{"Superlattice must have at least one cluster point."};
23 TRIQS_ASSERT((units.shape() == std::array{dim(), dim()}));
24 TRIQS_ASSERT(cluster_pts.extent(1) == dim());
25 transfo_SL_L = nda::matrix<double>{transpose(units)};
26 // Ensure non-empty cluster points
27 if (abs(nda::linalg::det(transfo_SL_L)) != static_cast<double>(n_cluster_sites()))
28 throw std::runtime_error{"Mismatch between det(superlattice vectors) and number of cluster points!"};
29 transfo_SL_L = nda::linalg::inv(transfo_SL_L);
30 }
31
32 // ------------------------------------------------
33
34 std::optional<nda::vector<long>> superlattice::L_to_SL(nda::vector<long> const &r_l, double epsilon) const {
35 TRIQS_ASSERT(r_l.size() == dim());
36 auto R1 = nda::vector<double>(r_l);
37 auto R = transfo_SL_L * r_l;
38 nda::vector<long> R_rounded = nda::map([](double x) { return std::round(x); })(R); // round each element to nearest integer
39 if (max_element(abs(R - R_rounded)) < epsilon) {
40 return R_rounded; // Return the rounded vector if it is close enough to an integer vector
41 } else
42 return {};
43 }
44
45 // --------------------------------------------------------------
46 // REFACTOR: Move to nda::stdutil
47 namespace detail {
48 template <int D, typename V> std::array<long, D> make_std_array_from_vector(V const &vec) {
49 if (vec.size() != D) throw std::runtime_error("make_std_array_from_vector. Vector size does not match the array size.");
50 std::array<long, D> arr{};
51 for (int i = 0; i < D; ++i) arr[i] = vec[i];
52 return arr;
53 }
54 } // namespace detail
55
56 // ----------------------------------------------------
57
59 using itertools::enumerate;
60 if (sl.dim() != kdim) throw std::runtime_error("Superlattice dimension does not match the Fourier polynomial dimension.");
61
62 auto n_orb_L = fp.get_coeff_arr().shape(1); // number of orbitals in the lattice
63 auto n_orb_SL = n_orb_L * sl.n_cluster_sites(); // number of orbitals in the superlattice
64 auto orb_range = [&](long a) { return nda::range(a * n_orb_L, (a + 1) * n_orb_L); };
65
66 // create containers for the new R vectors and coefficients
67 std::vector<std::array<long, kdim>> SL_R_list;
68 std::map<std::array<long, kdim>, long> SL_R_idx;
69 std::vector<nda::array<dcomplex, 2>> SL_coeff_list;
70
71 auto const &cpts = sl.get_cluster_pts();
72 for (auto i : nda::range(sl.n_cluster_sites()))
73 for (auto j : nda::range(sl.n_cluster_sites())) {
74 auto ai = cpts(i, all_);
75 auto aj = cpts(j, all_);
76 for (auto &&[r_idx, r] : enumerate(fp.get_R_list())) {
77 auto r1 = nda::vector<long>(kdim);
78 for (int u = 0; u < kdim; ++u) r1[u] = r[u] + ai[u] - aj[u]; // r1 = r + ai - aj
79 auto R_rounded = sl.L_to_SL(r1); // transform r + ai - aj to superlattice coordinates and round it
80 if (R_rounded) { // if the rounding was successful
81 auto R_rounded_2 = detail::make_std_array_from_vector<kdim>(R_rounded.value()); // convert to std::array<long, kdim>
82 auto [it, is_new] = SL_R_idx.emplace(R_rounded_2, SL_R_list.size()); // store the R_sl if not already seen
83 if (is_new) {
84 SL_R_list.push_back(R_rounded_2);
85 SL_coeff_list.emplace_back(nda::zeros<dcomplex>(n_orb_SL, n_orb_SL));
86 }
87 SL_coeff_list[it->second](orb_range(i), orb_range(j)) += fp[r_idx];
88 }
89 }
90 }
91 return {std::move(SL_R_list), std::move(SL_coeff_list)};
92 }
93
94 // --------------------------------------------------
95
96 template fourier_polynomial<2, 3> fold(superlattice const &sl, fourier_polynomial<2, 3> const &fp);
97 template fourier_polynomial<2, 2> fold(superlattice const &sl, fourier_polynomial<2, 2> const &fp);
98 template fourier_polynomial<2, 1> fold(superlattice const &sl, fourier_polynomial<2, 1> const &fp);
99
100} // namespace triqs::experimental::lattice
Owning container for a Fourier-series representation of a lattice function.
auto const & get_R_list() const
Get the list of real-space lattice vectors.
auto get_coeff_arr()
Get the packed coefficient array.
Representation of a superlattice built on top of an underlying Bravais lattice.
auto const & get_cluster_pts() const
Get the cluster points of the superlattice.
std::optional< nda::vector< long > > L_to_SL(nda::vector< long > const &r_l, double epsilon=1.e-12) const
Transform a point from lattice coordinates to superlattice coordinates.
long dim() const
Get the dimension of the superlattice.
long n_cluster_sites() const
Get the number of cluster sites in one superlattice unit cell.
superlattice(nda::array< long, 2 > sl_units, nda::array< long, 2 > cluster_pts)
Construct a superlattice from its unit vectors and cluster points.
TRIQS exception hierarchy and related macros.
fourier_polynomial< 2, kdim > fold(superlattice const &sl, fourier_polynomial< 2, kdim > const &fp)
Fold a Fourier polynomial defined on a lattice onto a superlattice.
gf< M, matrix_valued > transpose(gf_view< M, matrix_valued > g)
Transpose the target matrix of a matrix-valued Green's function, returning a new Green's function.
#define TRIQS_ASSERT(X)
Throw a triqs::runtime_error if the boolean expression X evaluates to false.