TRIQS/triqs_Nevanlinna 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
Caratheodory_kernel.cpp
1#include "Caratheodory_kernel.hpp"
2#include "Nevanlinna_error.hpp"
3#include <itertools/omp_chunk.hpp>
4#include <mpi/mpi.hpp>
5#include <nda/mpi/reduce.hpp>
6
7namespace triqs_Nevanlinna {
8 void Caratheodory_kernel::init(nda::vector_const_view<std::complex<double>> mesh, nda::array_const_view<std::complex<double>, 3> data) {
9 _dim = data.shape()[1];
10 size_t nw = std::count_if(mesh.begin(), mesh.end(), [](const std::complex<double> &w) { return w.imag() > 0; });
11 _mesh.resize(nw);
12 _Ws.resize(nw);
13 _sqrt_one.resize(nw);
14 _sqrt_two.resize(nw);
15 auto id = matrix_cplx_mpt::Identity(_dim, _dim);
16 auto val = matrix_cplx_mpt(_dim, _dim);
17 for (int iw = mesh.shape()[0] - 1, w = 0; iw >= 0; --iw) {
18 if (mesh(iw).imag() < 0.0) { continue; }
19 _mesh[w] = (complex_mpt(mesh(iw)) - I) / (complex_mpt(mesh(iw)) + I);
20 _Ws[w].resize(_dim, _dim);
21 for (int i = 0; i < _dim; ++i) {
22 for (int j = 0; j < _dim; ++j) { val(i, j) = complex_mpt(data(iw, i, j)); }
23 }
24 val = (id - I * val) * (id + I * val).inverse();
25 _Ws[w] = val;
26 ++w;
27 }
28 _data = _Ws;
29 for (int i = _mesh.size() - 1; i > 0; i--) {
30 auto &zi = _mesh[i];
31 auto &Wi = _Ws[i];
32 bool is_Schur_1 = true;
33 auto sqrt_one_i = sqrt_m(id - Wi * Wi.adjoint(), is_Schur_1);
34 auto sqrt_two_i = sqrt_m(id - Wi.adjoint() * Wi, is_Schur_1);
35 auto sqrt_one_i_inv = sqrt_one_i.inverse().eval();
36 // See Eq. 8 PhysRevB.104.165111
37#pragma omp parallel for num_threads(NEVANLINNA_NUM_THREADS)
38 for (int j = i - 1; j >= 0; j--) {
39 auto &zj = _mesh[j];
40 auto &Wj = _Ws[j];
41 auto y_ij = complex_mpt{std::abs(zi), 0.} * (zi - zj) / zi / (One - std::conj(zi) * zj);
42 _Ws[j] = sqrt_one_i_inv * (Wj - Wi) * (id - Wi.adjoint() * Wj).inverse().eval() * sqrt_two_i / y_ij;
43 }
44 _sqrt_one[i] = sqrt_one_i;
45 _sqrt_two[i] = sqrt_two_i.inverse(); // original
46 //_sqrt_two[i] = sqrt_two_i;
47 }
48 bool is_Schur = true;
49 _sqrt_one[0] = sqrt_m(id - _Ws[0] * _Ws[0].adjoint(), is_Schur);
50 _sqrt_two[0] = sqrt_m(id - _Ws[0].adjoint() * _Ws[0], is_Schur).inverse();
51 }
52
53 nda::array<std::complex<double>, 3> Caratheodory_kernel::evaluate(nda::vector_const_view<std::complex<double>> grid) {
54 if (_dim == 0) { throw Nevanlinna_uninitialized_error("Empty continuation data. Please run solve(...) first."); }
55 auto id = matrix_cplx_mpt::Identity(_dim, _dim);
56 nda::array<std::complex<double>, 3> results(grid.shape()[0], _dim, _dim);
57#pragma omp parallel num_threads(NEVANLINNA_NUM_THREADS)
58 {
59 std::vector<matrix_cplx_mpt> Vs(_mesh.size()); //intermediate Vs (for calculating Psis)
60 std::vector<matrix_cplx_mpt> Fs(_mesh.size()); //intermediate Psis (Schur class functions)
61 for (auto i : mpi::chunk(omp_chunk(range(grid.size())))) {
62 auto z = (complex_mpt(grid(i)) - I) / (complex_mpt(grid(i)) + I);
63 auto &z0 = _mesh[0];
64 auto &W0 = _Ws[0];
65 Vs[0] = complex_mpt{std::abs(z0), 0.} * (z0 - z) / z0 / (One - std::conj(z0) * z) * id;
66 Fs[0] = (id + Vs[0] * W0.adjoint()).inverse() * (Vs[0] + W0);
67 for (int j = 1; j < _mesh.size(); j++) {
68 auto &zj = _mesh[j];
69 auto &Wj = _Ws[j];
70 // See Eq. 9 PhysRevB.104.165111
71 Vs[j] = complex_mpt{std::abs(zj), 0.} * (zj - z) / zj / (One - std::conj(zj) * z) * _sqrt_one[j] * Fs[j - 1] * _sqrt_two[j];
72 // See Eq. 10 PhysRevB.104.165111
73 Fs[j] = (id + Vs[j] * Wj.adjoint()).inverse() * (Vs[j] + Wj);
74 }
75 // See Eq. 11 PhysRevB.104.165111
76 auto val = matrix_cplx_mpt(-I * (id + Fs[_mesh.size() - 1]).inverse() * (id - Fs[_mesh.size() - 1]));
77 for (int n = 0; n < _dim; ++n) {
78 for (int m = 0; m < _dim; ++m) {
79 results(i, n, m) = std::complex<double>(val(n, m).real().convert_to<double>(), val(n, m).imag().convert_to<double>());
80 }
81 }
82 }
83 }
84 results = mpi::all_reduce(results);
85 return results;
86 }
87
88 nda::vector<double> Caratheodory_kernel::get_Pick_eigenvalues() const {
89 auto nw = _data.shape(0);
90 if (nw == 0) { return nda::vector<double>(); }
91 auto N = _data(0).cols();
92 auto Pick = Eigen::MatrixXcd(nw * N, nw * N);
93 auto id = matrix_cplx_mpt::Identity(N, N);
94 for (int i = 0; i < nw; i++) {
95 for (int j = 0; j < nw; j++) {
96 auto val = (id - _data(i).adjoint() * _data(j)) / (One - std::conj(_mesh(i)) * _mesh(j));
97 for (int n = 0; n < N; ++n) {
98 for (int m = 0; m < N; ++m) {
99 Pick.block(i * N, j * N, N, N)(n, m) = std::complex<double>(val(n, m).real().convert_to<double>(), val(n, m).imag().convert_to<double>());
100 }
101 }
102 }
103 }
104 auto eigenvalues = Pick.eigenvalues();
105 auto pick_eigenvalues = nda::vector<double>(nw * N);
106 std::transform(eigenvalues.data(), eigenvalues.data() + eigenvalues.size(), pick_eigenvalues.begin(), [](const std::complex<double> &r) { return r.real(); });
107 return pick_eigenvalues;
108 }
109
110} // namespace triqs_Nevanlinna
nda::array< std::complex< double >, 3 > evaluate(nda::vector_const_view< std::complex< double > > grid) override
Evaluate the full matrix-valued real-frequency Green's function on a chosen grid.
void init(nda::vector_const_view< std::complex< double > > mesh, nda::array_const_view< std::complex< double >, 3 > data) override
Build the full matrix-valued Caratheodory continuation from Matsubara-frequency input data.