TRIQS/triqs_Nevanlinna 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
Nevanlinna_factorization.cpp
1#include "Nevanlinna_factorization.hpp"
2#include <itertools/omp_chunk.hpp>
3#include <mpi/mpi.hpp>
4#include <nda/mpi/reduce.hpp>
5
6using namespace std::complex_literals;
7
8namespace triqs_Nevanlinna {
9
10 nda::vector<complex_mpt> Nevanlinna_factorization::mobius_trasformation(nda::vector_const_view<std::complex<double>> data) const {
11 nda::vector<complex_mpt> mdata(data.size());
12 std::transform(data.begin(), data.end(), mdata.begin(),
13 [](const std::complex<double> &d) { return complex_mpt(-d - 1i) / complex_mpt(-d + 1i); });
14 std::reverse(mdata.begin(), mdata.end());
15 return mdata;
16 }
17
18 void Nevanlinna_factorization::build(nda::vector_const_view<std::complex<double>> mesh, nda::vector_const_view<std::complex<double>> data) {
19 assert(mesh.size() == data.size());
20 if (std::any_of(mesh.begin(), mesh.end(), [](const std::complex<double> &v) { return v.real() != 0.0 or v.imag() < 0; })) {
21 throw Nevanlinna_negative_grid_error("Data should be defined on the positive Matsubara frequencies.");
22 }
23 size_t M = mesh.size();
24 _phis.resize(M);
25 _abcds.resize(M);
26 _mesh.resize(M);
27 // invalidate previous real frequency grid
28 _grid.resize(0);
29 _data = mobius_trasformation(data);
30 _phis[0] = _data[0];
31 for (int k = 0; k < M; k++) {
32 _abcds[k] = matrix_cplx_mpt::Identity(2, 2);
33 _mesh[M - k - 1] = mesh(k);
34 }
35 for (int j = 0; j < M - 1; j++) {
36#pragma omp parallel num_threads(NEVANLINNA_NUM_THREADS)
37 {
38 auto prod = matrix_cplx_mpt(2, 2);
39#pragma omp for
40 for (int k = j; k < M; k++) {
41 prod << (_mesh[k] - _mesh[j]) / (_mesh[k] - std::conj(_mesh[j])), _phis[j],
42 std::conj(_phis[j]) * (_mesh[k] - _mesh[j]) / (_mesh[k] - std::conj(_mesh[j])), complex_mpt{1., 0.};
43 _abcds[k] *= prod;
44 }
45 }
46 _phis[j + 1] = (-_abcds[j + 1](1, 1) * _data[j + 1] + _abcds[j + 1](0, 1)) / (_abcds[j + 1](1, 0) * _data[j + 1] - _abcds[j + 1](0, 0));
47 }
48 return;
49 }
50
51 nda::vector<double> Nevanlinna_factorization::evaluate(nda::vector_const_view<double> grid, double eta) {
52 auto complex_grid = make_regular(grid + eta * 1i);
53 nda::vector<std::complex<double>> G_w = evaluate(complex_grid, nda::vector_const_view<std::complex<double>>());
54 nda::vector<double> A_w(G_w.shape());
55 std::transform(G_w.begin(), G_w.end(), A_w.begin(), [](const std::complex<double> &v) { return -v.imag() / M_PI; });
56 return A_w;
57 }
58
59 nda::vector<std::complex<double>> Nevanlinna_factorization::evaluate(nda::vector_const_view<std::complex<double>> grid,
60 nda::vector_const_view<std::complex<double>> theta_M_1) {
61 size_t M = _phis.size();
62 if (M == 0) { throw Nevanlinna_uninitialized_error("Empty continuation data. Please run solve(...) first."); }
63 if (theta_M_1.size() != grid.size() && theta_M_1.size() != 0) {
64 throw Nevanlinna_error("theta_{M+1} should either have a value at every frequency point or be empty.");
65 }
66 // check if grid has not been changed
67 if (grid.size() == _grid.size() && std::equal(grid.begin(), grid.end(), _grid.begin(), [](const std::complex<double> &w1, const complex_mpt &w2) {
68 return std::abs(w1.real() - w2.real().convert_to<double>()) < 1e-9 && std::abs(w1.imag() - w2.imag().convert_to<double>()) < 1e-9;
69 })) {
70 return evaluate_for_theta(grid, theta_M_1);
71 }
72 _coeffs = std::vector<matrix_cplx_mpt>(grid.size());
73 _grid.resize(grid.size());
74 std::transform(grid.begin(), grid.end(), _grid.begin(), [](const std::complex<double> &w) { return complex_mpt{w.real(), w.imag()}; });
75 auto results = nda::vector<std::complex<double>>(grid.size());
76#pragma omp parallel num_threads(NEVANLINNA_NUM_THREADS)
77 {
78 auto prod = matrix_cplx_mpt(2, 2);
79
80 for (auto i : mpi::chunk(omp_chunk(range(grid.size())))) {
81 matrix_cplx_mpt result = matrix_cplx_mpt::Identity(2, 2);
82 auto z = _grid[i];
83 for (int j = 0; j < M; j++) {
84 prod << (z - _mesh[j]) / (z - std::conj(_mesh[j])), _phis[j], std::conj(_phis[j]) * ((z - _mesh[j]) / (z - std::conj(_mesh[j]))), One;
85 result *= prod;
86 }
87 _coeffs[i] = result;
88 auto param = complex_mpt{0., 0.}; //theta_{M+1}, choose to be constant function 0 here
89 auto theta = complex_mpt(result(0, 0) * param + result(0, 1)) / (result(1, 0) * param + result(1, 1));
90 auto value = complex_mpt(I * (One + theta) / (One - theta));
91 results(i) =
92 -std::complex<double>(value.real().convert_to<double>(), value.imag().convert_to<double>()); //inverse Mobius transform from theta to NG
93 }
94 }
95 results = mpi::all_reduce(results);
96 return results;
97 }
98
99 nda::vector<std::complex<double>> Nevanlinna_factorization::evaluate_for_theta(nda::vector_const_view<std::complex<double>> grid,
100 nda::vector_const_view<std::complex<double>> theta_M_1) const {
101 size_t M = _phis.size();
102 if (M == 0) { throw Nevanlinna_uninitialized_error("Empty continuation data. Please run solve(...) first."); }
103 if (theta_M_1.size() != grid.size() && theta_M_1.size() != 0) {
104 throw Nevanlinna_error("theta_{M+1} should either have a value at every frequency point or be empty.");
105 }
106 nda::vector<std::complex<double>> results(grid.shape());
107#pragma omp parallel num_threads(NEVANLINNA_NUM_THREADS)
108 for (auto i : mpi::chunk(omp_chunk(range(_grid.size())))) {
109 auto result = _coeffs[i];
110 auto theta_M_plus_1 = theta_M_1.size() == 0 ? complex_mpt{0., 0.} : complex_mpt{theta_M_1(i).real(), theta_M_1(i).imag()};
111
112 auto theta = (result(0, 0) * theta_M_plus_1 + result(0, 1)) / (result(1, 0) * theta_M_plus_1 + result(1, 1));
113 auto value = I * (One + theta) / (One - theta);
114 //inverse Mobius transform from theta to NG
115 results(i) = -std::complex<double>(value.real().convert_to<double>(), value.imag().convert_to<double>());
116 }
117 results = mpi::all_reduce(results);
118 return results;
119 }
120
121} // namespace triqs_Nevanlinna
void build(nda::vector_const_view< std::complex< double > > mesh, nda::vector_const_view< std::complex< double > > data)
nda::vector< double > evaluate(nda::vector_const_view< double > grid, double eta=0.05)