12 std::transform(data.begin(), data.end(), mdata.begin(),
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.");
23 size_t M = mesh.size();
29 _data = mobius_trasformation(data);
31 for (
int k = 0; k < M; k++) {
32 _abcds[k] = matrix_cplx_mpt::Identity(2, 2);
33 _mesh[M - k - 1] = mesh(k);
35 for (
int j = 0; j < M - 1; j++) {
36#pragma omp parallel num_threads(NEVANLINNA_NUM_THREADS)
38 auto prod = matrix_cplx_mpt(2, 2);
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.};
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));
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; });
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.");
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;
70 return evaluate_for_theta(grid, theta_M_1);
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)
78 auto prod = matrix_cplx_mpt(2, 2);
80 for (
auto i : mpi::chunk(omp_chunk(range(grid.size())))) {
81 matrix_cplx_mpt result = matrix_cplx_mpt::Identity(2, 2);
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;
88 auto param = complex_mpt{0., 0.};
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));
92 -std::complex<double>(value.real().convert_to<
double>(), value.imag().convert_to<
double>());
95 results = mpi::all_reduce(results);
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()};
112 auto theta = (result(0, 0) * theta_M_plus_1 + result(0, 1)) / (result(1, 0) * theta_M_plus_1 + result(1, 1));
115 results(i) = -std::complex<double>(value.real().convert_to<
double>(), value.imag().convert_to<
double>());