High-precision calculations for one- and two-valence atomic systems
SpinorMatrix.hpp
1#pragma once
2#include "LinAlg/Matrix.hpp"
3#include "Maths/Grid.hpp"
4#include "Maths/Interpolator.hpp"
5#include "RadialMatrix.hpp"
6#include "Wavefunction/DiracSpinor.hpp"
7#include <cassert>
8#include <iostream>
9#include <type_traits>
10
11namespace MBPT {
12
13/*! Defines SpinorMatrix, Radial Dirac Spinor matrix. Designed to store
14 Greens-function like operators: |Fa><Fb| (where Fa, Fb are radial Dirac
15 spinors), as a radial matrix. The matrix is stored on a sub-grid (between r0
16 and rmax), with a specified stride.
17
18@details
19
20SpinorMatrix is a 2*2 matrix in spinor space {ff, fg, gf, gg} - the g blocks are
21small and are optional. Each block is an N*N radial matrix, where N is a subset
22of the number of points along the full radial grid. May store doubles or complex
23doubles.
24
25 SpinorMatrix = {ff fg}
26 {gf gg}
27 SpinorMatrix * F = {ff fg} * (f)
28 {gf gg} (g)
29 = (ff(r,r')*f(r') + fg(r,r')*g(r'))
30 (gf(r,r')*f(r') + gg(r,r')*g(r'))
31
32Note: Careful to distinguish SpinorMatrix multiplication/integration:
33 G1 * G2 = Int G1(ra,rb)*G2(rb,rc)
34 = Sum_j G1(i,j)*G2(j,k)
35
36G1.drj() * G2 = Int G1(ra,rb)*G2(rb,rc)*dr_b
37 = Sum_j G1(i,j)*G2(j,k)*drdu_j*du
38 = G1 * G2.dri()
39
40While almost always symmetric, this doesn't assume that.
41*/
42template <typename T>
44
45 std::size_t m_i0, m_stride;
46 std::size_t m_size;
47 std::size_t m_g_size;
48 LinAlg::Matrix<T> m_ff, m_fg, m_gf, m_gg;
49 bool m_incl_g;
50 std::shared_ptr<const Grid> m_rgrid; // "full" grid
51 std::vector<double> sub_r{}; // sub grid
52
53public:
54 //============================================================================
55
56 SpinorMatrix(std::size_t i0, std::size_t stride, std::size_t size,
57 bool incl_g, std::shared_ptr<const Grid> rgrid)
58 : m_i0(i0),
59 m_stride(stride),
60 m_size(size),
61 m_g_size(incl_g ? size : 0),
62 m_ff(m_size),
63 m_fg(m_g_size),
64 m_gf(m_g_size),
65 m_gg(m_g_size),
66 m_incl_g(incl_g),
67 m_rgrid(rgrid) {
68 //------------------
69 // create vector of r on sub-grid, used to interpolate values onto full
70 const auto &r = m_rgrid->r();
71 sub_r.reserve(m_size);
72 assert(m_i0 + m_stride * m_size <= r.size());
73 for (std::size_t i = 0; i < m_size; ++i) {
74 sub_r.push_back(r[index_to_fullgrid(i)]);
75 }
76 assert(m_i0 + m_stride * m_size <= r.size());
77 assert(sub_r[1] == r[index_to_fullgrid(1)]);
78 assert(sub_r[m_size - 1] == r[index_to_fullgrid(m_size - 1)]);
79 //------------------
80 }
81
82 //============================================================================
83 //! direct access to matrix elements
84 T &ff(std::size_t i, std::size_t j) { return m_ff(i, j); }
85 T &fg(std::size_t i, std::size_t j) { return m_fg(i, j); }
86 T &gf(std::size_t i, std::size_t j) { return m_gf(i, j); }
87 T &gg(std::size_t i, std::size_t j) { return m_gg(i, j); }
88 const T ff(std::size_t i, std::size_t j) const { return m_ff(i, j); }
89 const T fg(std::size_t i, std::size_t j) const { return m_fg(i, j); }
90 const T gf(std::size_t i, std::size_t j) const { return m_gf(i, j); }
91 const T gg(std::size_t i, std::size_t j) const { return m_gg(i, j); }
92
93 //! direct access to matrix's
94 const LinAlg::Matrix<T> &ff() const { return m_ff; }
95 const LinAlg::Matrix<T> &fg() const { return m_fg; }
96 const LinAlg::Matrix<T> &gf() const { return m_gf; }
97 const LinAlg::Matrix<T> &gg() const { return m_gg; }
98 LinAlg::Matrix<T> &ff() { return m_ff; }
99 LinAlg::Matrix<T> &fg() { return m_fg; }
100 LinAlg::Matrix<T> &gf() { return m_gf; }
101 LinAlg::Matrix<T> &gg() { return m_gg; }
102
103 LinAlg::Matrix<T> &sp(std::size_t mu, std::size_t nu) {
104 assert(mu < 2 && nu < 2);
105 if (mu == 0 && nu == 0)
106 return m_ff;
107 if (mu == 0 && nu == 1)
108 return m_fg;
109 if (mu == 1 && nu == 0)
110 return m_gf;
111 if (mu == 1 && nu == 1)
112 return m_gg;
113 assert(false);
114 }
115
116 const LinAlg::Matrix<T> &sp(std::size_t mu, std::size_t nu) const {
117 assert(mu < 2 && nu < 2);
118 if (mu == 0 && nu == 0)
119 return m_ff;
120 if (mu == 0 && nu == 1)
121 return m_fg;
122 if (mu == 1 && nu == 0)
123 return m_gf;
124 if (mu == 1 && nu == 1)
125 return m_gg;
126 assert(false);
127 }
128
129 std::size_t size() const { return m_size; }
130 std::size_t g_size() const { return m_g_size; }
131 bool includes_g() const { return m_g_size == m_size; };
132 std::size_t i0() const { return m_i0; }
133 std::size_t stride() const { return m_stride; }
134
135 //============================================================================
136 //! Sets all matrix elements to zero
137 void zero() {
138 m_ff.zero();
139 m_fg.zero();
140 m_gf.zero();
141 m_gg.zero();
142 }
143
144 //============================================================================
145 //! Kills g parts of spinor matrix, in place!
147 m_g_size = 0;
148 m_incl_g = false;
149 m_fg.resize(0, 0);
150 m_gf.resize(0, 0);
151 m_gg.resize(0, 0);
152 return *this;
153 }
154
155 //! Creates g parts of spinor matrix - will have value 0
157 m_g_size = m_size;
158 m_incl_g = true;
159 m_fg.resize(m_size, m_size);
160 m_gf.resize(m_size, m_size);
161 m_gg.resize(m_size, m_size);
162 return *this;
163 }
164
165 //============================================================================
166 //! Matrix adition +,-. A matrix without g parts is treated as having
167 //! zero g parts: adding one to a matrix with g parts leaves its g parts
168 //! unchanged; adding a matrix with g parts to one without creates them
170 m_ff += rhs.m_ff;
171 if (rhs.m_incl_g) {
172 if (!m_incl_g) {
173 create_g();
174 }
175 m_fg += rhs.m_fg;
176 m_gf += rhs.m_gf;
177 m_gg += rhs.m_gg;
178 }
179 return *this;
180 }
181 //! Matrix adition +,- (see operator+= for matrices without g parts)
183 m_ff -= rhs.m_ff;
184 if (rhs.m_incl_g) {
185 if (!m_incl_g) {
186 create_g();
187 }
188 m_fg -= rhs.m_fg;
189 m_gf -= rhs.m_gf;
190 m_gg -= rhs.m_gg;
191 }
192 return *this;
193 }
194 //! Scalar multiplication
196 m_ff *= x;
197 m_fg *= x;
198 m_gf *= x;
199 m_gg *= x;
200 return *this;
201 }
202
203 //! Matrix adition +,-
204 [[nodiscard]] friend SpinorMatrix<T> operator+(SpinorMatrix<T> lhs,
205 const SpinorMatrix<T> &rhs) {
206 return (lhs += rhs);
207 }
208 //! Matrix adition +,-
209 [[nodiscard]] friend SpinorMatrix<T> operator-(SpinorMatrix<T> lhs,
210 const SpinorMatrix<T> &rhs) {
211 return (lhs -= rhs);
212 }
213 //! Scalar multiplication
214 [[nodiscard]] friend SpinorMatrix<T> operator*(const T x,
215 SpinorMatrix<T> rhs) {
216 return (rhs *= x);
217 }
218
219 //! Adition of identity: Matrix<T> += T : T assumed to be *Identity!
221 m_ff += aI;
222 m_gg += aI;
223 return *this;
224 }
225 //! Adition of identity: Matrix<T> -= T : T assumed to be *Identity!
227 m_ff -= aI;
228 m_gg -= aI;
229 return *this;
230 }
231
232 //! Adition of identity: Matrix<T> + T : T assumed to be *Identity!
233 [[nodiscard]] friend SpinorMatrix<T> operator+(SpinorMatrix<T> M, T aI) {
234 return (M += aI);
235 }
236 //! Adition of identity: Matrix<T> - T : T assumed to be *Identity!
237 [[nodiscard]] friend SpinorMatrix<T> operator-(SpinorMatrix<T> M, T aI) {
238 return (M -= aI);
239 }
240
241 //============================================================================
242
243 //! Matrix multplication: \f$ C=A\times B \equiv C_{ij} = \sum_k A_{ik}\,B_{kj}. \f$
244 //! Note: integration measure not automatically included: call .drj() first to include it!
245 [[nodiscard]] friend SpinorMatrix<T> operator*(const SpinorMatrix<T> &a,
246 const SpinorMatrix<T> &b) {
247
248 SpinorMatrix<T> out(a.m_i0, a.m_stride, a.m_size, a.m_incl_g, a.m_rgrid);
249
250 // FF = FF*FF + FG*GF
251 // FG = FF*FG + FG*GG
252 // GF = GF*FF + GG*GF
253 // GG = GF*FG + GG*GG
254 out.ff() = a.ff() * b.ff();
255 if (a.m_incl_g && b.m_incl_g) {
256 out.ff() += a.fg() * b.gf();
257 out.fg() = a.ff() * b.fg() + a.fg() * b.gg();
258 out.gf() = a.gf() * b.ff() + a.gg() * b.gf();
259 out.gg() = a.gf() * b.fg() + a.gg() * b.gg();
260 }
261 return out;
262 }
263
264 //============================================================================
265 //! Multiply elements (in place): Gij -> Gij*Bij
267 m_ff.mult_elements_by(rhs.ff());
268 if (this->m_incl_g) {
269 // && rhs.m_incl_g
270 // I WANT an error if matrices not identical!?
271 m_fg.mult_elements_by(rhs.fg());
272 m_gf.mult_elements_by(rhs.gf());
273 m_gg.mult_elements_by(rhs.gg());
274 }
275 return *this;
276 }
277 //! Multiply elements (new matrix): Gij = Aij*Bij
278 [[deprecated]] [[nodiscard]] friend SpinorMatrix<T>
280 lhs.mult_elements_by(rhs);
281 return lhs;
282 }
283
284 //============================================================================
285 //! Multiply elements (in place): Gij -> Gij*Bij
287 m_ff.mult_elements_by(rhs.Rmatrix());
288 if (this->m_incl_g) {
289 m_fg.mult_elements_by(rhs.Rmatrix());
290 m_gf.mult_elements_by(rhs.Rmatrix());
291 m_gg.mult_elements_by(rhs.Rmatrix());
292 }
293 return *this;
294 }
295
296 //! Multiply elements (new matrix): Gij = Aij*Bij
297 [[nodiscard]] friend SpinorMatrix<T>
299 lhs.mult_elements_by(rhs);
300 return lhs;
301 }
302
303 //! Multiply elements (new matrix): Gij = Aij*Bij
304 [[nodiscard]] friend SpinorMatrix<T> mult_elements(const RadialMatrix<T> &rhs,
305 SpinorMatrix<T> lhs) {
306 lhs.mult_elements_by(rhs);
307 return lhs;
308 }
309
310 //============================================================================
311
312 //! Returns conjugate of matrix
313 [[nodiscard]] SpinorMatrix<T> conj() const {
314 auto out = *this;
315 out.ff().conj_in_place();
316 out.fg().conj_in_place();
317 out.gf().conj_in_place();
318 out.gg().conj_in_place();
319 return out;
320 }
321 //! Returns real part of complex matrix (changes type; returns a real
322 //! matrix)
323 [[nodiscard]] SpinorMatrix<double> real() const {
324 SpinorMatrix<double> out(m_i0, m_stride, m_size, m_incl_g, m_rgrid);
325 out.ff() = m_ff.real();
326 out.fg() = m_fg.real();
327 out.gf() = m_gf.real();
328 out.gg() = m_gg.real();
329 return out;
330 }
331 //! Returns imag part of complex matrix (changes type; returns a real matrix)
332 [[nodiscard]] SpinorMatrix<double> imag() const {
333 SpinorMatrix<double> out(m_i0, m_stride, m_size, m_incl_g, m_rgrid);
334 out.ff() = m_ff.imag();
335 out.fg() = m_fg.imag();
336 out.gf() = m_gf.imag();
337 out.gg() = m_gg.imag();
338 return out;
339 }
340 //! Converts a real to complex matrix (changes type; returns a complex
341 //! matrix)
343 SpinorMatrix<std::complex<double>> out(m_i0, m_stride, m_size, m_incl_g,
344 m_rgrid);
345 out.ff() = m_ff.complex();
346 out.fg() = m_fg.complex();
347 out.gf() = m_gf.complex();
348 out.gg() = m_gg.complex();
349 return out;
350 }
351
352 //============================================================================
353 //! Inversion (in place)
355 m_ff.invert_in_place();
356 if (m_incl_g) {
357 const auto &ai = m_ff; // already inverted
358 const auto &b = m_fg;
359 const auto &c = m_gf;
360 const auto &d = m_gg;
361 const auto cai = c * ai;
362 const auto dmcaib = (d - cai * b).invert_in_place();
363 const auto aib_dmcaib = ai * b * dmcaib;
364 m_ff += aib_dmcaib * cai;
365 m_fg = -1.0 * aib_dmcaib;
366 m_gf = -1.0 * dmcaib * cai;
367 m_gg = dmcaib;
368 }
369 return *this;
370 }
371 //! Returns inverse of matrix; original matrix unchanged
372 [[nodiscard]] SpinorMatrix<T> inverse() const {
373 auto out = *this; //
374 return out.invert_in_place();
375 }
376
377 //============================================================================
378 //! Multiplies by drj: Q_ij -> Q_ij*dr_j, in place
380 const auto dus = m_rgrid->du() * double(m_stride);
381 for (auto i = 0ul; i < m_size; ++i) {
382 for (auto j = 0ul; j < m_size; ++j) {
383 const auto sj = index_to_fullgrid(j);
384 const auto dr = m_rgrid->drdu(sj) * dus;
385 m_ff[i][j] *= dr;
386 }
387 }
388 if (m_incl_g) {
389 for (auto i = 0ul; i < m_size; ++i) {
390 for (auto j = 0ul; j < m_size; ++j) {
391 const auto sj = index_to_fullgrid(j);
392 const auto dr = m_rgrid->drdu(sj) * dus;
393 m_fg[i][j] *= dr;
394 m_gf[i][j] *= dr;
395 m_gg[i][j] *= dr;
396 }
397 }
398 }
399 return *this;
400 }
401 //! Multiplies by dri: Q_ij -> Q_ij*dr_i, in place
403 const auto dus = m_rgrid->du() * double(m_stride);
404 for (auto i = 0ul; i < m_size; ++i) {
405 const auto si = index_to_fullgrid(i);
406 const auto dr = m_rgrid->drdu(si) * dus;
407 for (auto j = 0ul; j < m_size; ++j) {
408 m_ff[i][j] *= dr;
409 }
410 }
411 if (m_incl_g) {
412 for (auto i = 0ul; i < m_size; ++i) {
413 const auto si = index_to_fullgrid(i);
414 const auto dr = m_rgrid->drdu(si) * dus;
415 for (auto j = 0ul; j < m_size; ++j) {
416 m_fg[i][j] *= dr;
417 m_gf[i][j] *= dr;
418 m_gg[i][j] *= dr;
419 }
420 }
421 }
422 return *this;
423 }
424 //! Multiplies by drj: Q_ij -> Q_ij*dr_j. Returns new matrix (orig unchanged)
426 auto out = *this;
427 return out.drj_in_place();
428 }
429 //! Multiplies by dri: Q_ij -> Q_ij*dr_i. Returns new matrix (orig unchanged)
431 auto out = *this;
432 return out.dri_in_place();
433 }
434
435 //! returns dr at position along sub grid
436 double dr(std::size_t sub_index) const {
437 const auto full_index = index_to_fullgrid(sub_index);
438 return m_rgrid->drdu(full_index) * m_rgrid->du() * double(m_stride);
439 }
440
441 //============================================================================
442 //! Converts an index on the sub-grid to the full grid.
443 std::size_t index_to_fullgrid(std::size_t i) const {
444 return m_i0 + i * m_stride;
445 }
446
447 //============================================================================
448 //! Adds k*|ket><bra| to matrix (used for building Green's functions)
449 void add(const DiracSpinor &ket, const DiracSpinor &bra, T k = T(1.0)) {
450 // Adds (k)*|ket><bra| to G matrix
451 // G_ij = f * Q_i * W_j
452 // Q = Q(1) = ket, W = W(2) = bra
453 // Takes sub-grid into account; ket,bra are on full grid, G on sub-grid
454 for (auto i = 0ul; i < m_size; ++i) {
455 const auto si = index_to_fullgrid(i);
456 for (auto j = 0ul; j < m_size; ++j) {
457 const auto sj = index_to_fullgrid(j);
458 m_ff[i][j] += k * ket.f(si) * bra.f(sj);
459 }
460 }
461
462 if (m_incl_g) {
463 for (auto i = 0ul; i < m_size; ++i) {
464 const auto si = index_to_fullgrid(i);
465 for (auto j = 0ul; j < m_size; ++j) {
466 const auto sj = index_to_fullgrid(j);
467 // XXX Double check fg/gf right way!
468 m_fg[i][j] += k * ket.f(si) * bra.g(sj);
469 m_gf[i][j] += k * ket.g(si) * bra.f(sj); // symmetric, transpose?
470 m_gg[i][j] += k * ket.g(si) * bra.g(sj);
471 }
472 }
473 }
474 }
475
476 //============================================================================
477 //! Action of SpinorMatrix operator on DiracSpinor. Assumes matrix already includes integration measure
479
480 const auto &r = Fn.grid().r();
481
482 std::vector<double> f(m_size), g;
483 for (auto i = 0ul; i < m_size; ++i) {
484 for (auto j = 0ul; j < m_size; ++j) {
485 const auto j_f = index_to_fullgrid(j);
486 f[i] += m_ff(i, j) * Fn.f(j_f);
487 }
488 }
489 if (m_incl_g) {
490 g.resize(m_size);
491 for (auto i = 0ul; i < m_size; ++i) {
492 for (auto j = 0ul; j < m_size; ++j) {
493 const auto j_f = index_to_fullgrid(j);
494 f[i] += m_fg(i, j) * Fn.g(j_f);
495 g[i] += (m_gf(i, j) * Fn.f(j_f) + m_gg(i, j) * Fn.g(j_f));
496 }
497 }
498 }
499
500 DiracSpinor out = Fn * 0.0;
501 // Interpolate from sub-grid to full grid
502 out.f() = Interpolator::interpolate(sub_r, f, r);
503 if (m_incl_g) {
504 out.g() = Interpolator::interpolate(sub_r, g, r);
505 }
506
507 // Beyond the sub-grid (r > rmax), where the matrix is not calculated,
508 // treat it as a local potential with the asymptotic polarisation form
509 // V(r) = alpha_eff / r^4 (alpha_eff ~ -alpha/2 for the polarisability
510 // alpha). alpha_eff is the average of V(r_i) r_i^4 over the last few
511 // sub-grid points, with V(r_i) = (G*F)(r_i)/F(r_i) from the large
512 // component. Otherwise, (G*F)(r > rmax) = 0.
513 // Switch is hard-coded: for testing only
514 constexpr bool extrapolate_tail = true;
515 if (extrapolate_tail) {
516 constexpr std::size_t n_fit = 10;
517 double alpha_eff = 0.0;
518 std::size_t n_used = 0;
519 for (auto i = m_size - std::min(n_fit, m_size); i < m_size; ++i) {
520 const auto i_f = index_to_fullgrid(i);
521 if (Fn.f(i_f) == 0.0)
522 continue;
523 alpha_eff += f[i] / Fn.f(i_f) * std::pow(r[i_f], 4);
524 ++n_used;
525 }
526 if (n_used > 0) {
527 alpha_eff /= double(n_used);
528 const auto i_rmax = index_to_fullgrid(m_size - 1);
529 for (auto i = i_rmax + 1; i < Fn.max_pt(); ++i) {
530 const auto V = alpha_eff / std::pow(r[i], 4);
531 out.f(i) = V * Fn.f(i);
532 if (m_incl_g) {
533 out.g(i) = V * Fn.g(i);
534 }
535 }
536 }
537 }
538 return out;
539 }
540
541 //============================================================================
542 // For testing only:
543 friend std::ostream &operator<<(std::ostream &os, const SpinorMatrix<T> &a) {
544 os << "FF:\n";
545 os << a.m_ff;
546 if (a.m_incl_g) {
547 os << "FG:\n";
548 os << a.m_fg;
549 os << "GF:\n";
550 os << a.m_gf;
551 os << "GG:\n";
552 os << a.m_gg;
553 }
554 return os;
555 }
556};
557
558//! Checks if two matrix's are equal (to within parts in 10^12)
559template <typename T>
560bool equal(const SpinorMatrix<T> &lhs, const SpinorMatrix<T> &rhs) {
561 return equal(lhs.ff(), rhs.ff()) && equal(lhs.fg(), rhs.fg()) &&
562 equal(lhs.gf(), rhs.gf()) && equal(lhs.gg(), rhs.gg());
563}
564
565//! returns maximum element (by abs)
566template <typename T>
567double max_element(const SpinorMatrix<T> &a) {
568 double xff = 0.0, xfg = 0.0, xgf = 0.0, xgg = 0.0;
569 for (auto i = 0ul; i < a.size(); ++i) {
570 for (auto j = 0ul; j < a.size(); ++j) {
571 if (std::abs(a.ff(i, j)) > xff)
572 xff = std::abs(a.ff(i, j));
573 if (a.g_size() != 0) {
574 if (std::abs(a.fg(i, j)) > xfg)
575 xfg = std::abs(a.fg(i, j));
576 if (std::abs(a.gf(i, j)) > xgf)
577 xgf = std::abs(a.gf(i, j));
578 if (std::abs(a.gg(i, j)) > xgg)
579 xgg = std::abs(a.gg(i, j));
580 }
581 }
582 }
583 return std::max({xff, xfg, xgf, xgg});
584}
585
586//! returns maximum difference (abs) between two matrixs
587template <typename T>
588double max_delta(const SpinorMatrix<T> &a, const SpinorMatrix<T> &b) {
589 double xff = 0.0, xfg = 0.0, xgf = 0.0, xgg = 0.0;
590 for (auto i = 0ul; i < a.size(); ++i) {
591 for (auto j = 0ul; j < a.size(); ++j) {
592 if (std::abs(a.ff(i, j) - b.ff(i, j)) > xff)
593 xff = std::abs(a.ff(i, j) - b.ff(i, j));
594 if (a.g_size() != 0) {
595 if (std::abs(a.fg(i, j) - b.fg(i, j)) > xfg)
596 xfg = std::abs(a.fg(i, j) - b.fg(i, j));
597 if (std::abs(a.gf(i, j) - b.gf(i, j)) > xgf)
598 xgf = std::abs(a.gf(i, j) - b.gf(i, j));
599 if (std::abs(a.gg(i, j) - b.gg(i, j)) > xgg)
600 xgg = std::abs(a.gg(i, j) - b.gg(i, j));
601 }
602 }
603 }
604 return std::max({xff, xfg, xgf, xgg});
605}
606
607//! returns maximum relative diference [aij-bij/(aij+bij)] (abs) between two
608//! matrices
609template <typename T>
610double max_epsilon(const SpinorMatrix<T> &a, const SpinorMatrix<T> &b) {
611 double xff = 0.0, xfg = 0.0, xgf = 0.0, xgg = 0.0;
612 for (auto i = 0ul; i < a.size(); ++i) {
613 for (auto j = 0ul; j < a.size(); ++j) {
614 const auto eps_ff =
615 std::abs((a.ff(i, j) - b.ff(i, j)) / (a.ff(i, j) + b.ff(i, j)));
616 if (eps_ff > xff)
617 xff = eps_ff;
618 if (a.g_size() != 0) {
619 const auto eps_fg =
620 std::abs((a.fg(i, j) - b.fg(i, j)) / (a.fg(i, j) + b.fg(i, j)));
621 const auto eps_gf =
622 std::abs((a.gf(i, j) - b.gf(i, j)) / (a.gf(i, j) + b.gf(i, j)));
623 const auto eps_gg =
624 std::abs((a.gg(i, j) - b.gg(i, j)) / (a.gg(i, j) + b.gg(i, j)));
625 if (eps_ff > xfg)
626 xfg = eps_fg;
627 if (eps_gf > xgf)
628 xgf = eps_gf;
629 if (eps_gg > xgg)
630 xgg = eps_gg;
631 }
632 }
633 }
634 return std::max({xff, xfg, xgf, xgg});
635}
636
637//==============================================================================
638using GMatrix = SpinorMatrix<double>;
639using ComplexGMatrix = SpinorMatrix<std::complex<double>>;
640using ComplexDouble = std::complex<double>;
641
642} // namespace MBPT
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:44
auto max_pt() const
Effective size(); index after last non-zero point (index for f[i])
Definition DiracSpinor.hpp:157
const std::vector< double > & f() const
Upper (large) radial component function, f.
Definition DiracSpinor.hpp:136
const Grid & grid() const
Resturns a const reference to the radial grid.
Definition DiracSpinor.hpp:126
const std::vector< double > & g() const
Lower (small) radial component function, g.
Definition DiracSpinor.hpp:143
const std::vector< double > & r() const
Full grid vector r.
Definition Grid.hpp:131
Row-major dense matrix with arithmetic and linear algebra support.
Definition Matrix.hpp:208
Matrix< T > & invert_in_place()
Inverts the matrix in place.
Definition Matrix.ipp:54
auto complex() const
Converts a real to complex matrix (changes type; returns a complex matrix)
Definition Matrix.ipp:188
auto imag() const
Returns imag part of complex matrix (changes type; returns a real matrix)
Definition Matrix.ipp:177
Matrix< T > & zero()
Sets all elements to zero, in place.
Definition Matrix.ipp:137
Matrix< T > & mult_elements_by(const Matrix< T > &a)
Elementwise multiply in place: M_ij *= a_ij.
Definition Matrix.ipp:268
auto real() const
Returns real part of complex matrix (changes type; returns a real matrix)
Definition Matrix.ipp:166
void resize(std::size_t rows, std::size_t cols)
Resizes matrix to new dimension; all values reset to default.
Definition Matrix.hpp:265
Definition RadialMatrix.hpp:27
const LinAlg::Matrix< T > & Rmatrix() const
direct access to radial matrix
Definition RadialMatrix.hpp:69
Definition SpinorMatrix.hpp:43
void add(const DiracSpinor &ket, const DiracSpinor &bra, T k=T(1.0))
Adds k*|ket><bra| to matrix (used for building Green's functions)
Definition SpinorMatrix.hpp:449
SpinorMatrix< T > & operator-=(T aI)
Adition of identity: Matrix<T> -= T : T assumed to be *Identity!
Definition SpinorMatrix.hpp:226
friend SpinorMatrix< T > mult_elements(SpinorMatrix< T > lhs, const SpinorMatrix< T > &rhs)
Multiply elements (new matrix): Gij = Aij*Bij.
Definition SpinorMatrix.hpp:279
SpinorMatrix< std::complex< double > > complex() const
Converts a real to complex matrix (changes type; returns a complex matrix)
Definition SpinorMatrix.hpp:342
SpinorMatrix< T > & create_g()
Creates g parts of spinor matrix - will have value 0.
Definition SpinorMatrix.hpp:156
T & ff(std::size_t i, std::size_t j)
direct access to matrix elements
Definition SpinorMatrix.hpp:84
friend SpinorMatrix< T > operator+(SpinorMatrix< T > M, T aI)
Adition of identity: Matrix<T> + T : T assumed to be *Identity!
Definition SpinorMatrix.hpp:233
SpinorMatrix< T > drj() const
Multiplies by drj: Q_ij -> Q_ij*dr_j. Returns new matrix (orig unchanged)
Definition SpinorMatrix.hpp:425
SpinorMatrix< T > & drj_in_place()
Multiplies by drj: Q_ij -> Q_ij*dr_j, in place.
Definition SpinorMatrix.hpp:379
SpinorMatrix< T > & operator*=(const T x)
Scalar multiplication.
Definition SpinorMatrix.hpp:195
SpinorMatrix< T > & dri_in_place()
Multiplies by dri: Q_ij -> Q_ij*dr_i, in place.
Definition SpinorMatrix.hpp:402
friend SpinorMatrix< T > mult_elements(SpinorMatrix< T > lhs, const RadialMatrix< T > &rhs)
Multiply elements (new matrix): Gij = Aij*Bij.
Definition SpinorMatrix.hpp:298
const LinAlg::Matrix< T > & ff() const
direct access to matrix's
Definition SpinorMatrix.hpp:94
friend SpinorMatrix< T > operator*(const T x, SpinorMatrix< T > rhs)
Scalar multiplication.
Definition SpinorMatrix.hpp:214
SpinorMatrix< T > & operator-=(const SpinorMatrix< T > &rhs)
Matrix adition +,- (see operator+= for matrices without g parts)
Definition SpinorMatrix.hpp:182
SpinorMatrix< T > & operator+=(T aI)
Adition of identity: Matrix<T> += T : T assumed to be *Identity!
Definition SpinorMatrix.hpp:220
SpinorMatrix< double > imag() const
Returns imag part of complex matrix (changes type; returns a real matrix)
Definition SpinorMatrix.hpp:332
void zero()
Sets all matrix elements to zero.
Definition SpinorMatrix.hpp:137
SpinorMatrix< T > dri() const
Multiplies by dri: Q_ij -> Q_ij*dr_i. Returns new matrix (orig unchanged)
Definition SpinorMatrix.hpp:430
SpinorMatrix< T > & mult_elements_by(const SpinorMatrix< T > &rhs)
Multiply elements (in place): Gij -> Gij*Bij.
Definition SpinorMatrix.hpp:266
DiracSpinor operator*(const DiracSpinor &Fn) const
Action of SpinorMatrix operator on DiracSpinor. Assumes matrix already includes integration measure.
Definition SpinorMatrix.hpp:478
SpinorMatrix< T > & drop_g()
Kills g parts of spinor matrix, in place!
Definition SpinorMatrix.hpp:146
SpinorMatrix< T > & operator+=(const SpinorMatrix< T > &rhs)
Matrix adition +,-. A matrix without g parts is treated as having zero g parts: adding one to a matri...
Definition SpinorMatrix.hpp:169
SpinorMatrix< T > & invert_in_place()
Inversion (in place)
Definition SpinorMatrix.hpp:354
friend SpinorMatrix< T > mult_elements(const RadialMatrix< T > &rhs, SpinorMatrix< T > lhs)
Multiply elements (new matrix): Gij = Aij*Bij.
Definition SpinorMatrix.hpp:304
std::size_t index_to_fullgrid(std::size_t i) const
Converts an index on the sub-grid to the full grid.
Definition SpinorMatrix.hpp:443
friend SpinorMatrix< T > operator-(SpinorMatrix< T > M, T aI)
Adition of identity: Matrix<T> - T : T assumed to be *Identity!
Definition SpinorMatrix.hpp:237
double dr(std::size_t sub_index) const
returns dr at position along sub grid
Definition SpinorMatrix.hpp:436
friend SpinorMatrix< T > operator*(const SpinorMatrix< T > &a, const SpinorMatrix< T > &b)
Matrix multplication: Note: integration measure not automatically included: call ....
Definition SpinorMatrix.hpp:245
SpinorMatrix< double > real() const
Returns real part of complex matrix (changes type; returns a real matrix)
Definition SpinorMatrix.hpp:323
friend SpinorMatrix< T > operator+(SpinorMatrix< T > lhs, const SpinorMatrix< T > &rhs)
Matrix adition +,-.
Definition SpinorMatrix.hpp:204
SpinorMatrix< T > inverse() const
Returns inverse of matrix; original matrix unchanged.
Definition SpinorMatrix.hpp:372
SpinorMatrix< T > & mult_elements_by(const RadialMatrix< T > &rhs)
Multiply elements (in place): Gij -> Gij*Bij.
Definition SpinorMatrix.hpp:286
SpinorMatrix< T > conj() const
Returns conjugate of matrix.
Definition SpinorMatrix.hpp:313
friend SpinorMatrix< T > operator-(SpinorMatrix< T > lhs, const SpinorMatrix< T > &rhs)
Matrix adition +,-.
Definition SpinorMatrix.hpp:209
std::vector< double > interpolate(const std::vector< double > &x_in, const std::vector< double > &y_in, const std::vector< double > &x_out, Method method=Method::cspline)
Convenience wrapper: interpolates y_in(x_in) and evaluates at x_out.
Definition Interpolator.hpp:154
Many-body perturbation theory.
Definition MatrixElements.hpp:12
double max_element(const RadialMatrix< T > &a)
returns maximum element (by abs)
Definition RadialMatrix.hpp:287
bool equal(const RadialMatrix< T > &lhs, const RadialMatrix< T > &rhs)
Checks if two matrix's are equal (to within parts in 10^12)
Definition RadialMatrix.hpp:281
double max_delta(const RadialMatrix< T > &a, const RadialMatrix< T > &b)
returns maximum difference (abs) between two matrixs
Definition RadialMatrix.hpp:301
double max_epsilon(const RadialMatrix< T > &a, const RadialMatrix< T > &b)
returns maximum relative diference [aij-bij/(aij+bij)] (abs) between two matrices
Definition RadialMatrix.hpp:316