17 nda::matrix<dcomplex>
svd(
const nda::matrix<dcomplex> &A) {
18 auto Acopy = nda::matrix<dcomplex, nda::F_layout>{transpose(A)};
19 long m = Acopy.extent(0);
21 auto U = nda::matrix<dcomplex, nda::F_layout>(m, m);
22 auto VT = nda::matrix<dcomplex, nda::F_layout>(m, m);
23 [[maybe_unused]]
auto status = nda::lapack::gesvd(Acopy, nda::vector<double>(m), U, VT);
24 return nda::matrix<dcomplex>{transpose(U * VT)};
29 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,
30 std::vector<atomic_orbs>
const &new_space) {
31 auto n_atoms = new_space.size();
32 auto n_sigma = T.extent(1);
33 auto Tembed = nda::array<std::vector<long>, 2>(n_atoms, n_sigma);
35 auto old_indices = old_space | stdv::transform([](
auto &x) {
return x.dft_idx; }) | tl::to<std::vector>();
36 auto new_indices = new_space | stdv::transform([](
auto &x) {
return x.dft_idx; }) | tl::to<std::vector>();
38 for (
auto const &[n, nidx] : enumerate(new_indices)) {
39 if (
auto it = std::find(begin(old_indices), end(old_indices), nidx); it != end(old_indices)) {
40 auto uidx = std::distance(begin(old_indices), it);
43 Tembed(n,
r_all) = std::vector<long>{long(new_space[n].dim)};
53 std::pair<nda::array<std::vector<long>, 2>, nda::array<nda::matrix<dcomplex>, 2>>
54 discover_symmetries(nda::array<nda::matrix<dcomplex>, 2>
const &Hloc0, std::vector<atomic_orbs>
const &atomic_shells,
double block_threshold,
55 bool diagonalize_hloc) {
57 auto [n_atoms, n_sigma] = Hloc0.shape();
58 auto decomposition = nda::array<std::vector<long>, 2>(n_atoms, n_sigma);
59 auto U_rotation = nda::array<nda::matrix<dcomplex>, 2>(n_atoms, n_sigma);
61 for (
auto const &[atom, shell] : enumerate(atomic_shells)) {
62 for (
auto sigma : nda::range(n_sigma)) {
63 auto D = find_blocks(nda::matrix<double>{abs(Hloc0(atom, sigma))}, block_threshold);
64 U_rotation(atom, sigma) = nda::make_matrix_from_permutation<dcomplex>(
nda::flatten(D));
65 decomposition(atom, sigma) = D | stdv::transform([](
auto &x) {
return long(x.size()); }) | tl::to<std::vector>();
68 if (diagonalize_hloc) {
69 auto U_diag = nda::matrix<dcomplex>(shell.dim, shell.dim);
71 auto hperm = dagger(U_rotation(atom, sigma)) * Hloc0(atom, sigma) * U_rotation(atom, sigma);
72 U_diag(r_idx, r_idx) = std::get<1>(nda::linalg::eigenelements(hperm(r_idx, r_idx)));
74 U_rotation(atom, sigma) *= U_diag;
78 return {decomposition, U_rotation};
94 auto SO = long(root[
"dft_input"][
"SO"]);
96 auto read_mats = [SO](
auto group,
auto name1,
auto name2) {
97 auto mats = to_vector<cmat_t>(sort_keys_as_int(group[name1]));
98 auto mats_tinv = to_vector<long>(sort_keys_as_int(group[name2]));
99 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>>();
104 | 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); })
105 | tl::to<std::vector<cmat_t>>();
107 return (mode ==
ReadMode::Correlated) ? read_mats(root[
"dft_input"],
"rot_mat",
"rot_mat_time_inv") :
109 throw std::runtime_error(
"This should not happen!");
115 std::vector<long>
const &atom_decomp) {
116 auto load_Pks = [](
auto f,
auto m) {
119 return (m ==
ReadMode::Correlated) ? as<nda::array<dcomplex, 5>>(root[
"dft_input"][
"proj_mat"]) :
120 as<nda::array<dcomplex, 5>>(root[
"dft_bands_input"][
"proj_mat"]);
122 auto tmp = as<nda::array<dcomplex, 6>>(root[
"dft_parproj_input"][
"proj_mat_all"]);
126 throw std::runtime_error{
"This should not happen!"};
130 auto P_k_tmp = load_Pks(filename, mode);
131 auto n_atoms = P_k_tmp.extent(2);
132 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>();
135 auto [n_k, n_sigma, n_m, n_nu] = P_k_list[0].shape();
136 for (
auto isig : range(n_sigma)) {
137 for (
auto ik : range(n_k)) {
138 for (
auto const &[R, P] : zip(rot_mats, P_k_list)) {
139 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)};
145 long M = stdr::fold_left(atom_decomp, 0, std::plus<>());
146 auto P_k = nda::zeros<dcomplex>(n_k, n_sigma, M, n_nu);
158 auto g_dft = root[
"dft_input"];
159 return {as<nda::array<dcomplex, 4>>(g_dft[
"hopping"]), as<nda::matrix<long>>(g_dft[
"n_orbitals"]),
160 as<nda::array<double, 1>>(g_dft[
"bz_weights"])};
162 auto g_dft = root[
"dft_bands_input"];
163 return {as<nda::array<dcomplex, 4>>(g_dft[
"hopping"]), as<nda::matrix<long>>(g_dft[
"n_orbitals"]), {}};
165 throw std::runtime_error{
"This should not happen!"};
173 auto g_dft =
h5::proxy{filename,
'r'}[
"dft_input"];
180 auto g_dft =
h5::proxy{filename,
'r'}[
"dft_input"];
181 return ((mode ==
ReadMode::Correlated) ? sort_keys_as_int(g_dft[
"corr_shells"]) : sort_keys_as_int(g_dft[
"shells"]))
182 | stdv::transform([](
auto const &g) {
184 return atomic_orbs{.
dim = long(g[
"dim"]), .l = long(g[
"l"]), .cls_idx = long(g[
"sort"]), .dft_idx = long(g[
"atom"])};
186 | tl::to<std::vector>();
194 auto Ylms = nda::array<nda::matrix<dcomplex>, 1>(atomic_shells.size());
208 auto g_symm = (mode ==
ReadMode::Correlated) ? root[
"dft_symmcorr_input"] : root[
"dft_symmpar_input"];
212 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)); })
213 | tl::to<std::vector>();
218 auto perm_table_all =
219 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>();
222 auto corr_atom_to_alpha = std::unordered_map<long, long>{};
223 for (
auto iatom : range(atomic_shells.size())) corr_atom_to_alpha[atomic_shells[iatom].dft_idx] = iatom;
228 auto perm_table_correlated = perm_table_all | stdv::transform([&](
auto const &sym) {
230 | stdv::transform([&](
auto corr_atom) {
return corr_atom_to_alpha[sym[corr_atom.dft_idx - 1]]; })
231 | tl::to<std::vector>();
233 | tl::to<std::vector>();
236 for (
auto const &[iq, perm] : enumerate(perm_table_correlated)) {
237 for (
auto const &[a, b] : enumerate(perm)) { symm_ops_mats[iq][a] = dagger(rot_mats[b]) * symm_ops_mats[iq][a] * rot_mats[a]; }
241 auto time_inv_op = to_vector<long>(sort_keys_as_int(g_symm[
"time_inv"]));
243 symm_ops.ops = range(perm_table_correlated.size()) | stdv::transform([symm_ops_mats, perm_table_correlated, time_inv_op](
auto const &isym) {
244 return ibz_symmetry_ops::op{symm_ops_mats[isym], perm_table_correlated[isym], time_inv_op[isym]};
246 | tl::to<std::vector>();
254 bool diagonalize_hloc) {
256 auto g_dft =
h5::proxy{filename,
'r'}[
"dft_input"];
258 auto total_density = as<double>(g_dft[
"density_required"]);
261 auto charge_below = (as<std::string>(g_dft[
"dft_code"]) !=
"w90" && as<std::string>(g_dft[
"dft_code"]) !=
"hk") ?
262 as<double>(g_dft[
"charge_below"]) :
263 as<long>(g_dft[
"charge_below"]);
264 total_density -= charge_below;
279 auto atom_decomp = atomic_shells | stdv::transform([](
auto &x) {
return x.dim; }) | tl::to<std::vector<long>>();
284 auto symm_ops = (long(g_dft[
"symm_op"]) == 0) ? std::optional<ibz_symmetry_ops>{} :
288 .
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};
292 auto C_space_no_symm =
local_space{spin_kind, atomic_shells, {}, {}, {}};
299 auto [decomposition, U_rotations] =
discover_symmetries(Hloc0, atomic_shells, threshold, diagonalize_hloc);
314 obe.C_space =
local_space{spin_kind, atomic_shells, decomposition, U_rotations,
323 return {total_density, std::move(obe_final)};
331 if (!root.has_group(
"dft_parproj_input")) {
332 throw std::runtime_error{fmt::format(
"The hdf5 file {} does not contain the group dft_parproj_input", filename)};
348 auto atom_decomp = W_space.atomic_decomposition() | tl::to<std::vector<long>>();
354 std::optional<ibz_symmetry_ops>{};
364 if (!root.has_group(
"dft_bands_input")) {
365 throw std::runtime_error{fmt::format(
"The hdf5 file {} does not contain the group dft_bands_input", filename)};
380 .
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
nda::array< nda::matrix< dcomplex >, 2 > const & rotation_from_dft_to_local_basis() const
List of all (a, sigma) local rotation matices that rotate the data.
nda::array< std::vector< long >, 2 > const & atoms_block_decomposition() const
List of all blocks spanning 𝓒 space -> atoms_block_decomposition.
auto atomic_decomposition() const
Generates [dimension of the 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.
std::pair< double, one_body_elements_on_grid > one_body_elements_from_dft_converter(std::string const &filename, double threshold, bool diagonalize_hloc)
Prepare one-body elements for a DMFT calculation.
one_body_elements_on_grid one_body_elements_on_high_symmetry_path(std::string const &filename, one_body_elements_on_grid const &obe)
Prepare one-body elements along high-symmetry k-path.
one_body_elements_on_grid one_body_elements_with_theta_projectors(std::string const &filename, one_body_elements_on_grid const &obe)
Prepare 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::matrix< dcomplex > get_spherical_to_dft_rotation(DFTCode code, long l)
DFTCode dft_code_to_enum(std::string const &code)
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)
Read projectors using ReadMode, rotate to local frame, and embed them in the M space....
std::tuple< nda::array< dcomplex, 4 >, nda::matrix< long >, nda::array< double, 1 > > read_bands_and_weights(std::string filename, ReadMode mode)
Read band dispersion and k-weights according to ReadMode. (internal)
nda::array< nda::matrix< dcomplex >, 1 > read_spherical_to_dft_basis(std::string dft, std::vector< atomic_orbs > const &atomic_shells)
Prepare the spherical Ylm to DFT orbital basis rotations. (internal)
ibz_symmetry_ops read_ibz_symmetry_ops(auto const &filename, ReadMode mode)
Construct the ibz_symmetry_ops according to ReadMode.
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)
utility to flatten a nested vector (move to utils/ ?)
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 R = 0 component of a Hamiltonian to determine a GF block structure.
std::vector< cmat_t > read_rotation_matrices(std::string const &filename, ReadMode mode)
Read rotation matrices from hdf5. (internal)
spin_kind_e read_spin_kind(auto const &filename)
Setup spin_kind enum. (internal)
std::vector< atomic_orbs > read_atomic_shells(auto const &filename, ReadMode mode)
Read atomic shells according to ReadMode. (internal)
ReadMode
Enumerate the different reading modes for the obe factory functions.
static constexpr auto r_all
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)
nda::matrix< dcomplex > cmat_t
The one-body dispersion as a function of momentum.
nda::array< long, 2 > n_bands_per_k
n_bands_per_k [k_idx, σ'] = # of nu
spin_kind_e spin_kind
Spin kind of the one-body data.
The projector that downfolds the one-body dispersion (ν) onto local orbitals (m).
A one-body elements struct where all of the underlying data exists on a fixed momentum grid.
C2PY_IGNORE std::optional< ibz_symmetry_ops > ibz_symm_ops
IBZ symmetrizer after a k-sum.