Mallard 0.8.0
Unstructured, GPU accelerated, high-order finite volume CFD solver
Mallard website
Loading...
Searching...
No Matches
rosenbrock.h
Go to the documentation of this file.
1
13#ifndef CHEMISTRY_ROSENBROCK_H
14#define CHEMISTRY_ROSENBROCK_H
15
16#include <Kokkos_Core.hpp>
17
18#include <cstdint>
19
20#include "lanes.h"
21
22namespace chemistry {
23
32template <typename Lanes>
33KOKKOS_INLINE_FUNCTION bool lu_factor(const Lanes & lanes, const uint32_t n, double * A, uint32_t * pivot) {
34 constexpr bool CM = Lanes::column_major;
35 for (uint32_t c = 0; c < n; c++) {
36 uint32_t p;
37 const double largest =
38 lanes.argmax_abs(c, n, [&](const uint32_t r) { return A[dense_index<CM>(n, r, c)]; }, p);
39 if (!(largest > 0.0)) return false;
40 lanes.single([&]() { pivot[c] = p; });
41 if (p != c) {
42 lanes.for_each(n, [&](const uint32_t j) {
43 const double t = A[dense_index<CM>(n, c, j)];
44 A[dense_index<CM>(n, c, j)] = A[dense_index<CM>(n, p, j)];
45 A[dense_index<CM>(n, p, j)] = t;
46 });
47 lanes.sync();
48 }
49 const double inv = 1.0 / A[dense_index<CM>(n, c, c)];
50 lanes.for_each(n - c - 1, [&](const uint32_t m) {
51 const uint32_t r = c + 1 + m;
52 const double l = A[dense_index<CM>(n, r, c)] * inv;
53 A[dense_index<CM>(n, r, c)] = l;
54 if (l == 0.0) return;
55 for (uint32_t j = c + 1; j < n; j++) A[dense_index<CM>(n, r, j)] -= l * A[dense_index<CM>(n, c, j)];
56 });
57 lanes.sync();
58 }
59 return true;
60}
61
63bool lu_factor(const uint32_t n, double * A, uint32_t * pivot) { return lu_factor(SerialLanes(), n, A, pivot); }
64
69template <typename Lanes>
70KOKKOS_INLINE_FUNCTION void lu_solve(const Lanes & lanes, const uint32_t n, const double * LU, const uint32_t * pivot,
71 double * b) {
72 constexpr bool CM = Lanes::column_major;
73 // The row swaps of lu_factor, in order, then L y = b and U x = y
74 lanes.single([&]() {
75 for (uint32_t i = 0; i < n; i++) {
76 const uint32_t p = pivot[i];
77 if (p != i) {
78 const double t = b[i];
79 b[i] = b[p];
80 b[p] = t;
81 }
82 }
83 });
84 lanes.sync();
85 for (uint32_t j = 0; j + 1 < n; j++) {
86 const double b_j = b[j];
87 lanes.for_each(n - j - 1, [&](const uint32_t m) { b[j + 1 + m] -= LU[dense_index<CM>(n, j + 1 + m, j)] * b_j; });
88 lanes.sync();
89 }
90 for (uint32_t j = n; j-- > 0;) {
91 const double b_j = b[j] / LU[dense_index<CM>(n, j, j)];
92 lanes.sync();
93 lanes.for_each(j + 1, [&](const uint32_t i) { b[i] = i == j ? b_j : b[i] - LU[dense_index<CM>(n, i, j)] * b_j; });
94 lanes.sync();
95 }
96}
97
99void lu_solve(const uint32_t n, const double * LU, const uint32_t * pivot, double * b) {
100 lu_solve(SerialLanes(), n, LU, pivot, b);
101}
102
104 double rtol = 1e-6;
105 double h_initial = 1e-7; // first sub-step when no previous one is known
106 uint32_t max_steps = 100000; // accepted and rejected sub-steps per call
107};
108
110 SUCCESS = 0,
111 TOO_MANY_STEPS = 1,
113};
114
120
123 KOKKOS_INLINE_FUNCTION void operator()(double, const double *, const double *) const {}
124};
125
132struct Rodas {
133 static constexpr double gamma = 0.25;
134 static constexpr double a21 = 1.544;
135 static constexpr double a31 = 0.9466785280815826, a32 = 0.2557011698983284;
136 static constexpr double a41 = 3.314825187068521, a42 = 2.896124015972201, a43 = 0.9986419139977817;
137 static constexpr double a51 = 1.221224509226641, a52 = 6.019134481288629, a53 = 12.53708332932087,
138 a54 = -0.6878860361058950;
139 static constexpr double c21 = -5.6688;
140 static constexpr double c31 = -2.430093356833875, c32 = -0.2063599157091915;
141 static constexpr double c41 = -0.1073529058151375, c42 = -9.594562251023355, c43 = -20.47028614809616;
142 static constexpr double c51 = 7.496443313967647, c52 = -10.24680431464352, c53 = -33.99990352819905,
143 c54 = 11.70890893206160;
144 static constexpr double c61 = 8.083246795921522, c62 = -7.981132988064893, c63 = -31.52159432874371,
145 c64 = 16.31930543123136, c65 = -6.058818238834054;
146};
147
153struct DenseLU {
155 double * LU;
157
158 template <typename Lanes>
159 KOKKOS_INLINE_FUNCTION bool factor(const Lanes & lanes, const double * J, const double diagonal) const {
160 constexpr bool CM = Lanes::column_major;
161 lanes.for_each(n * n, [&](const uint32_t a) { LU[a] = -J[a]; });
162 lanes.sync();
163 lanes.for_each(n, [&](const uint32_t i) { LU[dense_index<CM>(n, i, i)] += diagonal; });
164 lanes.sync();
165 return lu_factor(lanes, n, LU, pivot);
166 }
167
168 template <typename Lanes>
169 KOKKOS_INLINE_FUNCTION void solve(const Lanes & lanes, double * b) const {
170 lu_solve(lanes, n, LU, pivot, b);
171 }
172};
173
176constexpr uint32_t rosenbrock_vectors_size(const uint32_t n) { return 9 * n; }
177
184template <typename Lanes, typename System, typename Solver>
185KOKKOS_INLINE_FUNCTION void rodas_step(const Lanes & lanes, const System & system, const Solver & solver,
186 const uint32_t n, const double h, const double * y0, const double * f0,
187 double * const k[6], double * y, double * f_tmp) {
188 using R = Rodas;
189 const double inv_h = 1.0 / h;
190 lanes.for_each(n, [&](const uint32_t i) { k[0][i] = f0[i]; });
191 lanes.sync();
192 solver.solve(lanes, k[0]);
193
194 lanes.for_each(n, [&](const uint32_t i) { y[i] = y0[i] + R::a21 * k[0][i]; });
195 lanes.sync();
196 system.rhs(lanes, y, f_tmp);
197 lanes.for_each(n, [&](const uint32_t i) { k[1][i] = f_tmp[i] + R::c21 * k[0][i] * inv_h; });
198 lanes.sync();
199 solver.solve(lanes, k[1]);
200
201 lanes.for_each(n, [&](const uint32_t i) { y[i] = y0[i] + R::a31 * k[0][i] + R::a32 * k[1][i]; });
202 lanes.sync();
203 system.rhs(lanes, y, f_tmp);
204 lanes.for_each(n, [&](const uint32_t i) { k[2][i] = f_tmp[i] + (R::c31 * k[0][i] + R::c32 * k[1][i]) * inv_h; });
205 lanes.sync();
206 solver.solve(lanes, k[2]);
207
208 lanes.for_each(n, [&](const uint32_t i) {
209 y[i] = y0[i] + R::a41 * k[0][i] + R::a42 * k[1][i] + R::a43 * k[2][i];
210 });
211 lanes.sync();
212 system.rhs(lanes, y, f_tmp);
213 lanes.for_each(n, [&](const uint32_t i) {
214 k[3][i] = f_tmp[i] + (R::c41 * k[0][i] + R::c42 * k[1][i] + R::c43 * k[2][i]) * inv_h;
215 });
216 lanes.sync();
217 solver.solve(lanes, k[3]);
218
219 lanes.for_each(n, [&](const uint32_t i) {
220 y[i] = y0[i] + R::a51 * k[0][i] + R::a52 * k[1][i] + R::a53 * k[2][i] + R::a54 * k[3][i];
221 });
222 lanes.sync();
223 system.rhs(lanes, y, f_tmp);
224 lanes.for_each(n, [&](const uint32_t i) {
225 k[4][i] = f_tmp[i] + (R::c51 * k[0][i] + R::c52 * k[1][i] + R::c53 * k[2][i] + R::c54 * k[3][i]) * inv_h;
226 });
227 lanes.sync();
228 solver.solve(lanes, k[4]);
229
230 lanes.for_each(n, [&](const uint32_t i) { y[i] += k[4][i]; });
231 lanes.sync();
232 system.rhs(lanes, y, f_tmp);
233 lanes.for_each(n, [&](const uint32_t i) {
234 k[5][i] = f_tmp[i] + (R::c61 * k[0][i] + R::c62 * k[1][i] + R::c63 * k[2][i] + R::c64 * k[3][i] +
235 R::c65 * k[4][i]) * inv_h;
236 });
237 lanes.sync();
238 solver.solve(lanes, k[5]);
239 lanes.for_each(n, [&](const uint32_t i) { y[i] += k[5][i]; });
240 lanes.sync();
241}
242
261template <typename Lanes, typename System, typename Solver, typename Observer = NoObserver>
263 const double t_start, const double t_end, double * y, double & h,
264 const RosenbrockOptions & options, double * J,
265 double * vectors, Observer && observer = Observer()) {
266 const uint32_t n = system.size();
267 double * f0 = vectors;
268 double * y_new = f0 + n;
269 double * f_tmp = y_new + n;
270 double * k[6];
271 for (uint32_t s = 0; s < 6; s++) k[s] = f_tmp + (s + 1) * n;
272
274 double t = t_start;
275 if (!(t_end > t_start)) return result;
276 if (!(h > 0.0)) h = options.h_initial;
277 h = Kokkos::fmin(h, t_end - t_start);
278 system.rhs_jacobian(lanes, y, f0, J);
279 observer(t, y, f0);
280 bool rejected_last = false;
281 while (true) {
282 if (result.steps + result.rejected >= options.max_steps) {
284 return result;
285 }
286 const bool last = t + 1.01 * h >= t_end;
287 const double h_step = last ? t_end - t : h;
288 if (!(h_step > 1e-14 * Kokkos::fmax(Kokkos::fabs(t), t_end - t_start))) {
290 return result;
291 }
292 double err = 0.0;
293 bool ok = solver.factor(lanes, J, 1.0 / (Rodas::gamma * h_step));
294 if (ok) {
295 rodas_step(lanes, system, solver, n, h_step, y, f0, k, y_new, f_tmp);
296 err = lanes.sum(n, [&](const uint32_t i) {
297 const double scale = system.atol(i) + options.rtol * Kokkos::fmax(Kokkos::fabs(y[i]),
298 Kokkos::fabs(y_new[i]));
299 const double e = k[5][i] / scale;
300 return e * e;
301 });
302 err = Kokkos::sqrt(err / n);
303 ok = Kokkos::isfinite(err) && system.admissible(lanes, y_new);
304 }
305 if (!ok || err > 1.0) {
306 result.rejected++;
307 rejected_last = true;
308 h = h_step * (ok ? Kokkos::fmax(0.2, 0.9 * Kokkos::pow(err, -0.25)) : 0.25);
309 continue;
310 }
311 result.steps++;
312 t = last ? t_end : t + h_step;
313 lanes.for_each(n, [&](const uint32_t i) { y[i] = y_new[i]; });
314 lanes.sync();
315 double h_new = h_step * Kokkos::fmin(6.0, Kokkos::fmax(0.2, 0.9 * Kokkos::pow(err, -0.25)));
316 if (rejected_last) h_new = Kokkos::fmin(h_new, h_step);
317 rejected_last = false;
318 if (last) {
319 // A step shortened to reach t_end does not shrink the proposal
320 if (h_step >= h) h = h_new;
321 return result;
322 }
323 h = h_new;
324 system.rhs_jacobian(lanes, y, f0, J);
325 observer(t, y, f0);
326 }
327}
328
329} // namespace chemistry
330
331#endif // CHEMISTRY_ROSENBROCK_H
Definition solver.h:85
KOKKOS_INLINE_FUNCTION rtype dot(const rtype *a, const rtype *b)
Compute the dot product of two arrays.
Definition common_math.h:32
Execution of one cell's chemistry by one thread or by the vector lanes of a team: loops over species,...
Definition kinetics.h:25
KOKKOS_INLINE_FUNCTION void lu_solve(const Lanes &lanes, const uint32_t n, const double *LU, const uint32_t *pivot, double *b)
Solve A x = b in place with the factors of lu_factor, by columns: each column's updates go one row pe...
Definition rosenbrock.h:70
KOKKOS_INLINE_FUNCTION bool lu_factor(const Lanes &lanes, const uint32_t n, double *A, uint32_t *pivot)
Dense LU factorization with partial pivoting of the n x n matrix A (by rows, or by columns for lanes ...
Definition rosenbrock.h:33
KOKKOS_INLINE_FUNCTION void rodas_step(const Lanes &lanes, const System &system, const Solver &solver, const uint32_t n, const double h, const double *y0, const double *f0, double *const k[6], double *y, double *f_tmp)
One RODAS step of size h from y0 with f0 = f(y0), given the factored I / (gamma h) - J.
Definition rosenbrock.h:185
RosenbrockStatus
Definition rosenbrock.h:109
KOKKOS_INLINE_FUNCTION RosenbrockResult integrate(const Lanes &lanes, const System &system, const Solver &solver, const double t_start, const double t_end, double *y, double &h, const RosenbrockOptions &options, double *J, double *vectors, Observer &&observer=Observer())
Integrate dy/dt = f(y) from t_start to t_end with adaptive RODAS steps and error control sqrt(mean((e...
Definition rosenbrock.h:262
KOKKOS_INLINE_FUNCTION constexpr uint32_t rosenbrock_vectors_size(const uint32_t n)
Doubles of the vectors integrate() needs for a system of size n (besides the dense J).
Definition rosenbrock.h:176
Dense linear solver of integrate(): A = diagonal I - J factored by lu_factor in n * n doubles (LU,...
Definition rosenbrock.h:153
uint32_t * pivot
Definition rosenbrock.h:156
KOKKOS_INLINE_FUNCTION void solve(const Lanes &lanes, double *b) const
Definition rosenbrock.h:169
KOKKOS_INLINE_FUNCTION bool factor(const Lanes &lanes, const double *J, const double diagonal) const
Definition rosenbrock.h:159
uint32_t n
Definition rosenbrock.h:154
double * LU
Definition rosenbrock.h:155
An observer that ignores the trajectory.
Definition rosenbrock.h:122
KOKKOS_INLINE_FUNCTION void operator()(double, const double *, const double *) const
Definition rosenbrock.h:123
Coefficients of RODAS (Hairer & Wanner, Solving ODEs II, IV.7; rodas.f), a stiffly accurate,...
Definition rosenbrock.h:132
static constexpr double c21
Definition rosenbrock.h:139
static constexpr double gamma
Definition rosenbrock.h:133
static constexpr double c31
Definition rosenbrock.h:140
static constexpr double a21
Definition rosenbrock.h:134
static constexpr double a32
Definition rosenbrock.h:135
static constexpr double c63
Definition rosenbrock.h:144
static constexpr double a51
Definition rosenbrock.h:137
static constexpr double c65
Definition rosenbrock.h:145
static constexpr double a31
Definition rosenbrock.h:135
static constexpr double c61
Definition rosenbrock.h:144
static constexpr double c62
Definition rosenbrock.h:144
static constexpr double a43
Definition rosenbrock.h:136
static constexpr double c32
Definition rosenbrock.h:140
static constexpr double a53
Definition rosenbrock.h:137
static constexpr double a41
Definition rosenbrock.h:136
static constexpr double a42
Definition rosenbrock.h:136
static constexpr double c41
Definition rosenbrock.h:141
static constexpr double c54
Definition rosenbrock.h:143
static constexpr double c64
Definition rosenbrock.h:145
static constexpr double c42
Definition rosenbrock.h:141
static constexpr double a52
Definition rosenbrock.h:137
static constexpr double c53
Definition rosenbrock.h:142
static constexpr double c43
Definition rosenbrock.h:141
static constexpr double c52
Definition rosenbrock.h:142
static constexpr double a54
Definition rosenbrock.h:138
static constexpr double c51
Definition rosenbrock.h:142
Definition rosenbrock.h:103
double rtol
Definition rosenbrock.h:104
uint32_t max_steps
Definition rosenbrock.h:106
double h_initial
Definition rosenbrock.h:105
Definition rosenbrock.h:115
RosenbrockStatus status
Definition rosenbrock.h:116
uint32_t steps
Definition rosenbrock.h:117
uint32_t rejected
Definition rosenbrock.h:118
One thread does all the work of a cell.
Definition lanes.h:38
CellSetup< ExecSpace > c
Definition teno_setup.cpp:1810
uint8_t r
Definition teno_setup.cpp:687
SlotArray< double, Space > A
Definition teno_setup.cpp:478
Lane< rtype > scale
Definition teno_setup.cpp:531