18 nda::matrix<dcomplex>
svd(
const nda::matrix<dcomplex> &A) {
19 auto Acopy = nda::matrix<dcomplex, nda::F_layout>{transpose(A)};
20 long m = Acopy.extent(0);
22 auto U = nda::matrix<dcomplex, nda::F_layout>(m, m);
23 auto VT = nda::matrix<dcomplex, nda::F_layout>(m, m);
24 [[maybe_unused]]
auto status = nda::lapack::gesvd(Acopy, nda::vector<double>(m), U, VT);
25 return nda::matrix<dcomplex>{transpose(U * VT)};
30 nda::array<std::vector<long>, 2> inject_to_new_space(nda::array<std::vector<long>, 2>
const &T, std::vector<atomic_orbs>
const &old_space,
31 std::vector<atomic_orbs>
const &new_space) {
32 auto n_atoms = new_space.size();
33 auto n_sigma = T.extent(1);
34 auto Tembed = nda::array<std::vector<long>, 2>(n_atoms, n_sigma);
36 auto old_indices = old_space | stdv::transform([](
auto &x) {
return x.dft_idx; }) | tl::to<std::vector>();
37 auto new_indices = new_space | stdv::transform([](
auto &x) {
return x.dft_idx; }) | tl::to<std::vector>();
39 for (
auto const &[n, nidx] : enumerate(new_indices)) {
40 if (
auto it = std::find(begin(old_indices), end(old_indices), nidx); it != end(old_indices)) {
41 auto uidx = std::distance(begin(old_indices), it);
44 Tembed(n,
r_all) = std::vector<long>{long(new_space[n].dim)};
54 std::pair<nda::array<std::vector<long>, 2>, nda::array<nda::matrix<dcomplex>, 2>>
55 discover_symmetries(nda::array<nda::matrix<dcomplex>, 2>
const &Hloc0, std::vector<atomic_orbs>
const &atomic_shells,
double block_threshold,
56 bool diagonalize_hloc) {
58 auto [n_atoms, n_sigma] = Hloc0.shape();
59 auto decomposition = nda::array<std::vector<long>, 2>(n_atoms, n_sigma);
60 auto U_rotation = nda::array<nda::matrix<dcomplex>, 2>(n_atoms, n_sigma);
62 for (
auto const &[atom, shell] : enumerate(atomic_shells)) {
63 for (
auto sigma : nda::range(n_sigma)) {
64 auto D = find_blocks(nda::matrix<double>{abs(Hloc0(atom, sigma))}, block_threshold);
65 U_rotation(atom, sigma) = nda::make_matrix_from_permutation<dcomplex>(
nda::flatten(D));
66 decomposition(atom, sigma) = D | stdv::transform([](
auto &x) {
return long(x.size()); }) | tl::to<std::vector>();
69 if (diagonalize_hloc) {
70 auto U_diag = nda::matrix<dcomplex>(shell.dim, shell.dim);
72 auto hperm = dagger(U_rotation(atom, sigma)) * Hloc0(atom, sigma) * U_rotation(atom, sigma);
73 U_diag(r_idx, r_idx) = std::get<1>(nda::linalg::eigenelements(hperm(r_idx, r_idx)));
75 U_rotation(atom, sigma) *= U_diag;
79 return {decomposition, U_rotation};
95 auto SO = long(root[
"dft_input"][
"SO"]);
97 auto read_mats = [SO](
auto group,
auto name1,
auto name2) {
98 auto mats = to_vector<cmat_t>(sort_keys_as_int(group[name1]));
99 auto mats_tinv = to_vector<long>(sort_keys_as_int(group[name2]));
100 auto mats_tinv_and_SO = mats_tinv | stdv::transform([SO](
long const &x) {
return (x == 1 && SO == 1) ? 1 : 0; }) | tl::to<std::vector<long>>();
105 | stdv::transform([mats_tinv_and_SO, i = 0](
cmat_t const &x)
mutable {
return (mats_tinv_and_SO[i++] == 1) ? -conj(
svd(x)) :
svd(x); })
106 | tl::to<std::vector<cmat_t>>();
108 return (mode ==
ReadMode::Correlated) ? read_mats(root[
"dft_input"],
"rot_mat",
"rot_mat_time_inv") :
110 throw std::runtime_error(
"This should not happen!");
116 std::vector<long>
const &atom_decomp) {
117 auto load_Pks = [](
auto f,
auto m) {
120 return (m ==
ReadMode::Correlated) ? as<nda::array<dcomplex, 5>>(root[
"dft_input"][
"proj_mat"]) :
121 as<nda::array<dcomplex, 5>>(root[
"dft_bands_input"][
"proj_mat"]);
123 auto tmp = as<nda::array<dcomplex, 6>>(root[
"dft_parproj_input"][
"proj_mat_all"]);
127 throw std::runtime_error{
"This should not happen!"};
131 auto P_k_tmp = load_Pks(filename, mode);
132 auto n_atoms = P_k_tmp.extent(2);
133 auto P_k_list = range(n_atoms) | stdv::transform([&](
auto atom) {
return P_k_tmp(
r_all,
r_all, atom,
r_all,
r_all); }) | tl::to<std::vector>();
136 auto [n_k, n_sigma, n_m, n_nu] = P_k_list[0].shape();
137 for (
auto isig : range(n_sigma)) {
138 for (
auto ik : range(n_k)) {
139 for (
auto const &[R, P] : zip(rot_mats, P_k_list)) {
140 P(ik, isig, nda::range(0, R.extent(0)),
r_all) = dagger(R) * nda::matrix<dcomplex>{P(ik, isig, nda::range(0, R.extent(0)),
r_all)};
146 long M = stdr::fold_left(atom_decomp, 0, std::plus<>());
147 auto P_k = nda::zeros<dcomplex>(n_k, n_sigma, M, n_nu);
159 auto g_dft = root[
"dft_input"];
160 return {as<nda::array<dcomplex, 4>>(g_dft[
"hopping"]), as<nda::matrix<long>>(g_dft[
"n_orbitals"]),
161 as<nda::array<double, 1>>(g_dft[
"bz_weights"])};
163 auto g_dft = root[
"dft_bands_input"];
164 return {as<nda::array<dcomplex, 4>>(g_dft[
"hopping"]), as<nda::matrix<long>>(g_dft[
"n_orbitals"]), {}};
166 throw std::runtime_error{
"This should not happen!"};
174 auto g_dft =
h5::proxy{filename,
'r'}[
"dft_input"];
181 auto g_dft =
h5::proxy{filename,
'r'}[
"dft_input"];
182 return ((mode ==
ReadMode::Correlated) ? sort_keys_as_int(g_dft[
"corr_shells"]) : sort_keys_as_int(g_dft[
"shells"]))
183 | stdv::transform([](
auto const &g) {
185 return atomic_orbs{.
dim = long(g[
"dim"]), .l = long(g[
"l"]), .cls_idx = long(g[
"sort"]), .dft_idx = long(g[
"atom"])};
187 | tl::to<std::vector>();
195 auto Ylms = nda::array<nda::matrix<dcomplex>, 1>(atomic_shells.size());
209 auto g_symm = (mode ==
ReadMode::Correlated) ? root[
"dft_symmcorr_input"] : root[
"dft_symmpar_input"];
213 auto symm_ops_mats = sort_keys_as_int(g_symm[
"mat"]) | stdv::transform([](
auto const &g) {
return to_vector<cmat_t>(sort_keys_as_int(g)); })
214 | tl::to<std::vector>();
219 auto perm_table_all =
220 sort_keys_as_int(g_symm[
"perm"]) | stdv::transform([](
auto const &g) {
return to_vector<long>(sort_keys_as_int(g)); }) | tl::to<std::vector>();
223 auto corr_atom_to_alpha = std::unordered_map<long, long>{};
224 for (
auto iatom : range(atomic_shells.size())) corr_atom_to_alpha[atomic_shells[iatom].dft_idx] = iatom;
229 auto perm_table_correlated = perm_table_all | stdv::transform([&](
auto const &sym) {
231 | stdv::transform([&](
auto corr_atom) {
return corr_atom_to_alpha[sym[corr_atom.dft_idx - 1]]; })
232 | tl::to<std::vector>();
234 | tl::to<std::vector>();
237 for (
auto const &[iq, perm] : enumerate(perm_table_correlated)) {
238 for (
auto const &[a, b] : enumerate(perm)) { symm_ops_mats[iq][a] = dagger(rot_mats[b]) * symm_ops_mats[iq][a] * rot_mats[a]; }
242 auto time_inv_op = to_vector<long>(sort_keys_as_int(g_symm[
"time_inv"]));
244 symm_ops.ops = range(perm_table_correlated.size()) | stdv::transform([symm_ops_mats, perm_table_correlated, time_inv_op](
auto const &isym) {
245 return ibz_symmetry_ops::op{symm_ops_mats[isym], perm_table_correlated[isym], time_inv_op[isym]};
247 | tl::to<std::vector>();
255 bool diagonalize_hloc) {
257 auto g_dft =
h5::proxy{filename,
'r'}[
"dft_input"];
259 auto total_density = as<double>(g_dft[
"density_required"]);
262 auto charge_below = (as<std::string>(g_dft[
"dft_code"]) !=
"w90" && as<std::string>(g_dft[
"dft_code"]) !=
"hk") ?
263 as<double>(g_dft[
"charge_below"]) :
264 as<long>(g_dft[
"charge_below"]);
265 total_density -= charge_below;
280 auto atom_decomp = atomic_shells | stdv::transform([](
auto &x) {
return x.dim; }) | tl::to<std::vector<long>>();
285 auto symm_ops = (long(g_dft[
"symm_op"]) == 0) ? std::optional<ibz_symmetry_ops>{} :
288 auto n_k = H_k.extent(0);
289 auto H_k_is_diagonal =
true;
290 for (
auto ik : range(n_k)) {
292 H_k_is_diagonal =
false;
299 .
spin_kind = spin_kind, .H_k = std::move(H_k), .n_bands_per_k = n_bands_per_k, .k_weights = k_weights, .matrix_valued = !H_k_is_diagonal};
303 auto C_space_no_symm =
local_space{spin_kind, atomic_shells, {}, {}, {}};
310 auto [decomposition, U_rotations] =
discover_symmetries(Hloc0, atomic_shells, threshold, diagonalize_hloc);
325 obe.C_space =
local_space{spin_kind, atomic_shells, decomposition, U_rotations,
334 return {total_density, std::move(obe_final)};
342 if (!root.has_group(
"dft_parproj_input")) {
343 throw std::runtime_error{fmt::format(
"The hdf5 file {} does not contain the group dft_parproj_input", filename)};
359 auto atom_decomp = W_space.atomic_decomposition() | tl::to<std::vector<long>>();
365 std::optional<ibz_symmetry_ops>{};
375 if (!root.has_group(
"dft_bands_input")) {
376 throw std::runtime_error{fmt::format(
"The hdf5 file {} does not contain the group dft_bands_input", filename)};
391 .
spin_kind = obe.
C_space.
spin_kind(), .H_k = std::move(H_k), .n_bands_per_k = n_bands_per_k, .k_weights = {}, .matrix_valued =
false};
Describe the atomic orbitals within downfolded space.
spin_kind_e spin_kind() const
Spin kind of index.
nda::array< nda::matrix< dcomplex >, 2 > const & rotation_from_dft_to_local_basis() const
2-dim array of all local rotation matices that rotate the data.
nda::array< std::vector< long >, 2 > const & atoms_block_decomposition() const
2-dim array of all blocks spanning space -> atoms_block_decomposition.
auto atomic_decomposition() const
Transformed view containing the dimension of each atomic shell.
std::vector< atomic_orbs > const & atomic_shells() const
List of all atomic shells spanning the space.
nda::array< nda::matrix< dcomplex >, 2 > impurity_levels(one_body_elements_on_grid const &obe)
Compute the local impurity levels from the single-particle dispersion.
one_body_elements_on_grid one_body_elements_on_high_symmetry_path(std::string const &filename, one_body_elements_on_grid const &obe)
Create a one-body elements along specific k-path.
std::pair< double, one_body_elements_on_grid > one_body_elements_from_dft_converter(std::string const &filename, double threshold, bool diagonalize_hloc)
Create a one-body elements with orthonormalized projectors.
one_body_elements_on_grid one_body_elements_with_theta_projectors(std::string const &filename, one_body_elements_on_grid const &obe)
Create a one-body elements with the projectors.
std::vector< T > flatten(const std::vector< std::vector< T > > &nested)
bool is_diagonal(nda::matrix< T > const &M)
nda::array< dcomplex, 4 > load_rotate_and_format_projectors(std::string const &filename, ReadMode mode, std::vector< cmat_t > const &rot_mats, std::vector< long > const &atom_decomp)
std::tuple< nda::array< dcomplex, 4 >, nda::matrix< long >, nda::array< double, 1 > > read_bands_and_weights(std::string filename, ReadMode mode)
nda::array< nda::matrix< dcomplex >, 1 > read_spherical_to_dft_basis(std::string dft, std::vector< atomic_orbs > const &atomic_shells)
ibz_symmetry_ops read_ibz_symmetry_ops(auto const &filename, ReadMode mode)
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.
spin_kind_e
Kind of σ index.
nda::matrix< dcomplex > svd(const nda::matrix< dcomplex > &A)
std::pair< nda::array< std::vector< long >, 2 >, nda::array< nda::matrix< dcomplex >, 2 > > discover_symmetries(nda::array< nda::matrix< dcomplex >, 2 > const &Hloc0, std::vector< atomic_orbs > const &atomic_shells, double block_threshold, bool diagonalize_hloc)
Find symmetries of the component of a Hamiltonian to determine a GF block structure.
std::vector< cmat_t > read_rotation_matrices(std::string const &filename, ReadMode mode)
spin_kind_e read_spin_kind(auto const &filename)
std::vector< atomic_orbs > read_atomic_shells(auto const &filename, ReadMode mode)
static constexpr auto r_all
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)
nda::matrix< dcomplex > cmat_t
long dim
Dimension of the orbital space.
The one-body dispersion as a function of momentum.
nda::array< long, 2 > n_bands_per_k
Number of bands for each k-point and .
spin_kind_e spin_kind
Spin kind of the one-body data.
The projector that downfolds the energy bands onto a set of localized atomic-like orbitals.
spin_kind_e spin_kind
Spin kind of the one-body data.
Irreducible Brillouin Zone (IBZ) symmetry operations to symmetrize observables over the entire Brillo...
A one-body elements struct where all of the underlying data exists on a fixed momentum grid.
local_space C_space
Local space.
band_dispersion H
Band dispersion.
C2PY_IGNORE std::optional< ibz_symmetry_ops > ibz_symm_ops
IBZ symmetrizer after a k-sum.