ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
Loading...
Searching...
No Matches
NumCalc_quadIntegrate.hpp
1#pragma once
2#include "Maths/Grid.hpp"
3#include "Maths/NumCalc_coeficients.hpp"
4#include "qip/Vector.hpp"
5#include <array>
6#include <cmath>
7#include <functional>
8#include <iostream>
9#include <vector>
10
12namespace NumCalc {
13
14// Quadrature integration order [1,13], only odd
15constexpr std::size_t Nquad = 13;
16static_assert(
17 Nquad >= 1 && Nquad <= 13 && Nquad % 2 != 0,
18 "\nFAIL10 in NumCalc: Nquad must be in [1,13], and must be odd\n");
19
20// instantiate coefs for correct Nquad order:
21constexpr QintCoefs<Nquad> quintcoef;
22constexpr auto cq = quintcoef.cq;
23constexpr auto dq_inv = quintcoef.dq_inv;
24
25//==============================================================================
26template <typename C, typename... Args>
27inline double integrate(const double dt, std::size_t beg, std::size_t end,
28 const C &f1, const Args &...rest)
29// // Note: includes no safety checks!
30// // Integrates from (point) beg to end-1 (i.e., not including end)
31// // Require:
32// // * (beg-end) > 2*Nquad
33// // * end - Nquad > Nquad
34// // * beg + 2*Nquad
35// // NB: end-point corrections only applied if beg < Nquad, end > max - nquad
36// // Not sure if this is best choice - but it ensures that:
37// // int_{a->b} + int_{b->c} = int_{a->c}
38{
39
40 const auto max_grid = f1.size();
41 if (end == 0)
42 end = max_grid;
43 const auto end_mid = std::min(max_grid - Nquad, end);
44 const auto start_mid = std::max(Nquad, beg);
45
46 double Rint_ends = qip::inner_product_sub(beg, Nquad, cq, f1, rest...);
47
48 const double Rint_mid =
49 qip::inner_product_sub(start_mid, end_mid, f1, rest...);
50
51 for (auto i = end_mid; i < end; ++i) {
52 Rint_ends += cq[end_mid + Nquad - i - 1] * qip::multiply_at(i, f1, rest...);
53 }
54 return (Rint_mid + dq_inv * Rint_ends) * dt;
55}
56
57//==============================================================================
58template <typename T>
59inline std::vector<T> derivative(const std::vector<T> &f,
60 const std::vector<T> &drdt, const T dt,
61 const int order = 1)
62// df/dr = df/dt * dt/dr = (df/dt) / (dr/dt)
63// = (df/di) * (di/dt) / (dr/dt)
64// = (df/di) / (dt * dr/dt)
65// coeficients from: http://en.wikipedia.org/wiki/Finite_difference_coefficient
66{
67
68 std::size_t num_points = f.size();
69 std::vector<T> df(num_points);
70 if (num_points < 4)
71 return df;
72
73 df[0] = (f[1] - f[0]) / (dt * drdt[0]);
74 df[num_points - 1] =
75 (f[num_points - 1] - f[num_points - 2]) / (dt * drdt[num_points - 1]);
76
77 df[1] = (f[2] - f[0]) / (2 * dt * drdt[1]);
78 df[num_points - 2] =
79 (f[num_points - 1] - f[num_points - 3]) / (2 * dt * drdt[num_points - 2]);
80
81 df[2] = (f[0] - 8 * f[1] + 8 * f[3] - f[4]) / (12 * dt * drdt[2]);
82 df[num_points - 3] = (f[num_points - 5] - 8 * f[num_points - 4] +
83 8 * f[num_points - 2] - f[num_points - 1]) /
84 (12 * dt * drdt[num_points - 3]);
85
86 df[3] = (-1 * f[0] + 9 * f[1] - 45 * f[2] + 45 * f[4] - 9 * f[5] + 1 * f[6]) /
87 (60 * dt * drdt[3]);
88 df[num_points - 4] =
89 (-1 * f[num_points - 7] + 9 * f[num_points - 6] - 45 * f[num_points - 5] +
90 45 * f[num_points - 3] - 9 * f[num_points - 2] + 1 * f[num_points - 1]) /
91 (60 * dt * drdt[num_points - 4]);
92
93 for (std::size_t i = 4; i < (num_points - 4); i++) {
94 df[i] = ((1.0 / 8) * f[i - 4] - (4.0 / 3) * f[i - 3] + 7 * f[i - 2] -
95 28 * f[i - 1] - (1.0 / 8) * f[i + 4] + (4.0 / 3) * f[i + 3] -
96 7 * f[i + 2] + 28 * f[i + 1]) /
97 (35 * dt * drdt[i]);
98 }
99
100 if (order > 1)
101 df = derivative(df, drdt, dt, order - 1);
102
103 return df;
104}
105
106//==============================================================================
107enum Direction { zero_to_r, r_to_inf };
108template <Direction direction, typename Real>
109inline void
110additivePIntegral(std::vector<Real> &answer, const std::vector<Real> &f,
111 const std::vector<Real> &g, const std::vector<Real> &h,
112 const Grid &gr, std::size_t pinf = 0)
113// answer(r) += f(r) * Int[g(r')*h(r') , {r',0,r}]
114// Note '+=' - this is additive!
115// Note: vector answer must ALREADY exist, and be correctly initialised!
116{
117 const auto size = g.size();
118 if (pinf == 0 || pinf >= size)
119 pinf = size;
120 const auto max = static_cast<int>(pinf - 1); // must be signed
121
122 constexpr const bool forward = (direction == zero_to_r);
123 constexpr const int inc = forward ? +1 : -1;
124 const auto init = forward ? 0ul : std::size_t(max);
125 const auto fin = forward ? std::size_t(max) : 0ul;
126
127 // Quadrature weights; doesn't seem to help
128 // auto Wquad = [&](std::size_t i) {
129 // return i < Nquad ? cq[i] * dq_inv
130 // : i >= size - Nquad ? cq[size - i - 1] * dq_inv : 1.0;
131 // };
132
133 Real x = int(init) < max ? 0.5 * g[init] * h[init] * gr.drdu()[init] : 0.0;
134 answer[init] += f[init] * x * gr.du();
135 for (auto i = int(init) + inc; i != int(fin) + inc; i += inc) {
136 const auto im = std::size_t(i - inc);
137 const auto i2 = std::size_t(i);
138 x += 0.5 * (g[im] * h[im] * gr.drdu()[im] +
139 g[i2] * h[i2] * gr.drdu()[i2] );
140 answer[i2] += f[i2] * x * gr.du();
141 }
142 if (int(fin) < max)
143 answer[fin] += 0.5 * f[fin] * g[fin] * h[fin] * gr.drdu()[fin] *
144 gr.du(); // * Wquad(fin);
145}
146//------------------------
147template <Direction direction, typename Real>
148inline void additivePIntegral(std::vector<Real> &answer,
149 const std::vector<Real> &f,
150 const std::vector<Real> &g, const Grid &gr,
151 std::size_t pinf = 0)
152// answer(r) += f(r) * Int[g(r') , {r',0,r}]
153// Note '+=' - this is additive!
154// Note: vector answer must ALREADY exist, and be correctly initialised!
155{
156 const auto size = g.size();
157 if (pinf == 0 || pinf >= size)
158 pinf = size;
159 const auto max = static_cast<int>(pinf - 1); // must be signed
160
161 constexpr const bool forward = (direction == zero_to_r);
162 constexpr const int inc = forward ? +1 : -1;
163 const auto init = forward ? 0ul : std::size_t(max);
164 const auto fin = forward ? std::size_t(max) : 0ul;
165
166 Real x = int(init) < max ? 0.5 * g[init] * gr.drdu()[init] : 0.0;
167 answer[init] += f[init] * x * gr.du();
168 for (auto i = int(init) + inc; i != int(fin) + inc; i += inc) {
169 const auto im = std::size_t(i - inc);
170 const auto i2 = std::size_t(i);
171 x += 0.5 * (g[im] * gr.drdu()[im] + g[i2] * gr.drdu()[i2]);
172 answer[i2] += f[i2] * x * gr.du();
173 }
174 if (int(fin) < max)
175 answer[fin] +=
176 0.5 * f[fin] * g[fin] * gr.drdu()[fin] * gr.du(); // * Wquad(fin);
177}
178
179//------------------------------------------------------------------------------
180template <Direction direction, typename Real>
181std::vector<Real> partialIntegral(const std::vector<Real> &f,
182 const std::vector<Real> &g,
183 const std::vector<Real> &h, const Grid &gr,
184 std::size_t pinf = 0) {
185 std::vector<Real> answer(f.size(), 0.0);
186 additivePIntegral(answer, f, g, h, gr, pinf);
187 return answer;
188}
189
190//==============================================================================
191//==============================================================================
192
193enum t_grid { linear, logarithmic };
194
195inline std::function<double(long unsigned)> linx(double a, double dt) {
196 return [=](long unsigned i) { return a + double(i) * dt; };
197}
198
199inline std::function<double(long unsigned)> one() {
200 return [=](long unsigned) { return 1.0; };
201}
202
203inline std::function<double(long unsigned)> logx(double a, double dt) {
204 return [=](long unsigned i) { return a * std::exp(double(i) * dt); };
205}
206
207//==============================================================================
208inline double num_integrate(const std::function<double(double)> &f, double a,
209 double b, long unsigned n_pts,
210 t_grid type = linear) {
211 //
212 if (a >= b || n_pts <= 1)
213 return 0.0;
214 const auto dt = (type == linear) ? (b - a) / double(n_pts - 1) :
215 std::log(b / a) / double(n_pts - 1);
216
217 std::function<double(long unsigned)> x =
218 (type == linear) ? linx(a, dt) : logx(a, dt);
219 std::function<double(long unsigned)> dxdt =
220 (type == linear) ? one() : logx(a, dt);
221
222 double Rint_s = 0.0;
223 for (long unsigned i = 0; i < Nquad; i++) {
224 Rint_s += cq[i] * f(x(i)) * dxdt(i);
225 }
226
227 double Rint_m = 0.0;
228 for (auto i = Nquad; i < n_pts - Nquad; i++) {
229 Rint_m += f(x(i)) * dxdt(i);
230 }
231
232 double Rint_e = 0;
233 for (auto i = n_pts - Nquad; i < n_pts; i++) {
234 Rint_e += cq[n_pts - i - 1] * f(x(i)) * dxdt(i);
235 }
236
237 return (Rint_m + dq_inv * (Rint_s + Rint_e)) * dt;
238}
239
240} // namespace NumCalc
Holds grid, including type + Jacobian (dr/du)
Definition Grid.hpp:31
auto du() const
Linear step size dr = (dr/dr)*du.
Definition Grid.hpp:68
const std::vector< double > & drdu() const
Jacobian (dr/du)[i].
Definition Grid.hpp:80
double f(RaB r, PrincipalQN n, DiracQN k, Zeff z, AlphaFS a)
Upper radial component.
Definition DiracHydrogen.cpp:71
Numerical integration and differentiation. Bit of a mess right now..
Definition NumCalc_coeficients.hpp:4
void additivePIntegral(std::vector< Real > &answer, const std::vector< Real > &f, const std::vector< Real > &g, const std::vector< Real > &h, const Grid &gr, std::size_t pinf=0)
Definition NumCalc_quadIntegrate.hpp:110
T max(T first, Args... rest)
Returns maximum of any number of parameters (variadic function)
Definition Maths.hpp:22
constexpr auto multiply_at(std::size_t i, const T &first, const Args &...rest)
first[i]*...rest[i] – used to allow inner_product
Definition Vector.hpp:331