TRIQS/triqs_modest 3.3.0
Modular Electronic Structure Toolkit
Loading...
Searching...
No Matches
ibz_symmetry_ops.hpp
Go to the documentation of this file.
1// Copyright (c) 2025--present, The Simons Foundation
2// This file is part of TRIQS/modest and is licensed under the terms of GPLv3 or later.
3// SPDX-License-Identifier: GPL-3.0-or-later
4// See LICENSE in the root of this distribution for details.
5
6#pragma once
7#include "utils/defs.hpp"
8#include "utils/gf_supp.hpp"
9#include <nda/nda.hpp>
10#include <nda/mpi.hpp>
11#include <mpi/mpi.hpp>
12#include <triqs/gfs.hpp>
14
15namespace triqs::modest {
16
17 // IBZ symmetry operations to obtain observables (equivalent to summing on FBZ).
18
19 // NB: if SOC and time inversion present <T*O> = <K^-1 O K> = <transpose(O)>.
20 // FIXME : OP : document the size of matrices, meaning of permutations.
21 // FIXME OP : rename into ibz_symmetrizer
22 // FIMXE HL : can we generalize to work on any type T that supports matrix multiplication?
23
48
49 //-----------------------------------------------------------------------------------
51 struct op {
52 std::vector<nda::matrix<dcomplex>> mats; // mats[i_alpha]
53 std::vector<long> permutation; // permutation [i_alpha]
54 long time_inv; // FIXME : we should supress/comment this ?
55
57 bool operator==(op const &) const = default;
58
60 friend void mpi_broadcast(op &x, mpi::communicator c = {}, int root = 0) {
61 mpi::broadcast(x.mats, c, root);
62 mpi::broadcast(x.permutation, c, root);
63 mpi::broadcast(x.time_inv, c, root);
64 }
65 };
67 std::vector<op> ops; // ops[i_sym]
68
70 bool operator==(ibz_symmetry_ops const &) const = default;
71
73 friend void mpi_broadcast(ibz_symmetry_ops &x, mpi::communicator c = {}, int root = 0) { mpi::broadcast(x.ops, c, root); }
74
75 // printing
76 friend std::ostream &operator<<(std::ostream &out, ibz_symmetry_ops const &ibz);
77
78 //-----------------------------------------------------------------------------------
79 template <typename T> nda::array<T, 2> symmetrize(nda::array<T, 2> const &X) const {
80 auto [n_alpha, n_sigma] = X.shape();
81 nda::array<T, 2> result(n_alpha, n_sigma);
82 for (auto [a, s] : result.indices()) { result(a, s) = nda::zeros<dcomplex>(X(a, s).shape()); }
83 auto n_symm = double(this->ops.size());
84 for (auto const &sym_op : this->ops) {
85 for (auto &&[ialpha, jalpha, mat] : zip(range(n_alpha), sym_op.permutation, sym_op.mats)) {
86 for (auto sigma : range(n_sigma)) {
87 result(jalpha, sigma) += mat * (sym_op.time_inv ? transpose(X(ialpha, sigma)) : X(ialpha, sigma)) * dagger(mat) / n_symm;
88 } // end loop on sigma
89 } // end loop on alpha
90 } // end loop on ops
91 return result;
92 }
93
94 // -------------------------------------------------------------------------------------------
95
96 // FIXME : Pas Gin in the atomic decomposition directly ??
97 // as a block2_gf_view ??
98 // Or array<gf_view, 2> ??
99 template <typename Mesh>
100 block2_gf<Mesh, matrix_valued> symmetrize(block2_gf<Mesh, matrix_valued> const &Gin, auto const &atomic_decomposition) const {
101 // FIXME : copy it , take atom_ivew of it, operate and return it.
102 // FIXME : are we sure all Gin have the same mesh ? We use this internally and we have a check at E.embed that the meshes are the same. We could add this here.
103 auto Gout = make_block2_gf(Gin(0, 0).mesh(), get_struct(Gin));
104 auto n_sigma = Gout.size2();
105 auto n_symm = double(this->ops.size());
106
107 auto range_list =
108 enumerated_sub_slices(atomic_decomposition) | stdv::transform([](auto &&x) { return std::get<1>(x); }) | tl::to<std::vector>();
109
110 for (auto [alpha, R_alpha] : enumerated_sub_slices(atomic_decomposition)) { // loop on alpha
111 for (auto sigma : range(n_sigma)) { // loop on sigma
112 for (auto const &op : this->ops) { // loop on ops
113 auto const &mat = op.mats[alpha];
114 auto R_jalpha = range_list[op.permutation[alpha]];
115 for (auto om : Gin(0, sigma).mesh()) { // loop on mesh
116 auto A = nda::matrix<dcomplex>{Gin(0, sigma)[om](R_alpha, R_alpha)};
117 Gout(0, sigma)[om](R_jalpha, R_jalpha) += mat * (op.time_inv ? transpose(A) : A) * dagger(mat) / n_symm;
118 } // end loop on mesh
119 } // end loop on ops
120 } // end loop on sigma
121 } // end loop on alpha
122 return Gout;
123 }
124 };
125
133 inline ibz_symmetry_ops rotate_local_basis(nda::array<nda::matrix<dcomplex>, 2> const &U, ibz_symmetry_ops const &x) {
134 auto result = x;
135 for (auto &sym_op : result.ops)
136 for (auto &&[a, b] : zip(range(U.extent(0)), sym_op.permutation)) sym_op.mats[a] = dagger(U(b, 0)) * sym_op.mats[a] * U(a, 0);
137 return result;
138 }
139
140} // namespace triqs::modest
gf_struct2_t get_struct(block2_gf< Mesh, matrix_valued > const &g)
Definition gf_supp.hpp:52
block2_gf< Mesh, matrix_valued > make_block2_gf(Mesh const &mesh, gf_struct2_t const &gf_s)
Definition gf_supp.hpp:41
one_body_elements_on_grid rotate_local_basis(nda::array< nda::matrix< dcomplex >, 2 > const &U, one_body_elements_on_grid const &x)
Rotates the local basis of the downfolding projector.
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)
Irreducible Brillouin Zone (IBZ) symmetry operations to symmetrize observables over the entire Brillo...
friend void mpi_broadcast(ibz_symmetry_ops &x, mpi::communicator c={}, int root=0)
MPI broadcast.
friend std::ostream & operator<<(std::ostream &out, ibz_symmetry_ops const &ibz)
Definition printing.cpp:63
bool operator==(ibz_symmetry_ops const &) const =default
Equality comparison operator.
block2_gf< Mesh, matrix_valued > symmetrize(block2_gf< Mesh, matrix_valued > const &Gin, auto const &atomic_decomposition) const
nda::array< T, 2 > symmetrize(nda::array< T, 2 > const &X) const