LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
ode_rosenbrock.c
浏览该文件的文档.
1
8#include <math.h>
9#include <string.h>
10
11#include "memory_bridge.h"
12#include "internal.h"
13#include "ode_internal.h"
14#include "lmmc/ode.h"
15#include "lmmc/dense.h"
16#include "lmmc/linear_algebra.h"
17
18#define ROS_STAGES 4
19#define ROS_VECTORS 13
20
21static const lmmc_real_t ros_gamma = 0.231;
22static const lmmc_real_t ros_a21 = 2.0;
23static const lmmc_real_t ros_a31 = 4.524708207373116;
24static const lmmc_real_t ros_a32 = 4.163528788597648;
25static const lmmc_real_t ros_c21 = -5.071675338776316;
26static const lmmc_real_t ros_c31 = 6.020152728650786;
27static const lmmc_real_t ros_c32 = 0.1597506846727117;
28static const lmmc_real_t ros_c41 = -1.856343618686113;
29static const lmmc_real_t ros_c42 = -8.505380858179826;
30static const lmmc_real_t ros_c43 = -2.084075136023187;
31static const lmmc_real_t ros_b[ROS_STAGES] = {
32 3.957503746640777, 4.624892388363313,
33 0.6174772638750108, 1.282612945269037
34};
35static const lmmc_real_t ros_e[ROS_STAGES] = {
36 2.302155402932996, 3.073634485392623,
37 -0.8732808018045032, -1.282612945269037
38};
39static const lmmc_real_t ros_d[ROS_STAGES] = {
40 0.231, -0.03962966775244303,
41 0.5507789395789127, -0.05535098457052764
42};
43static const lmmc_real_t ros_c2 = 0.462;
44static const lmmc_real_t ros_c3 = 0.8802083333333334;
45
46
47static lmmc_status_t ros_time_derivative(
49 lmmc_ode_dfdt_t time_derivative,
50 void* user_data,
52 const lmmc_real_t* y,
53 const lmmc_real_t* f0,
54 size_t dim,
55 lmmc_real_t* dfdt,
56 lmmc_real_t* f_pert,
57 lmmc_ode_result_t* result
58) {
59 size_t i;
61 int callback_failed = 0;
62
63 if (time_derivative != NULL) {
64 st = time_derivative(t, y, dfdt, dim, user_data);
65 if (st != LMMC_STATUS_OK) {
66 return st;
67 }
68 return lmmc_ode_values_are_finite(dfdt, dim);
69 }
70
71 {
72 lmmc_real_t delta = sqrt(2.2204460492503131e-16) * fmax(1.0, fabs(t));
73 st = lmmc_ode_rhs_eval(rhs, t + delta, y, f_pert, dim, user_data,
74 &result->num_rhs_evals, &callback_failed);
75 if (st != LMMC_STATUS_OK) {
76 return st;
77 }
78 for (i = 0; i < dim; ++i) {
79 dfdt[i] = (f_pert[i] - f0[i]) / delta;
80 }
81 }
82 return lmmc_ode_values_are_finite(dfdt, dim);
83}
84
85static lmmc_status_t ros_solve_stage(
86 const lmmc_mat_t* lu,
87 const size_t* pivots,
88 const lmmc_real_t* rhs,
89 lmmc_real_t* stage,
90 size_t dim
91) {
92 const lmmc_vec_t rhs_vec = {dim, (lmmc_real_t*)rhs, 0};
93 lmmc_vec_t stage_vec = {dim, stage, 0};
94 lmmc_status_t st = lmmc_lu_solve(lu, pivots, &rhs_vec, &stage_vec);
95 if (st != LMMC_STATUS_OK) {
96 return st;
97 }
98 return lmmc_ode_values_are_finite(stage, dim);
99}
100
117
118static lmmc_status_t ros_prepare_system(ode_rosenbrock_state_t* s) {
119 size_t i, j, swap_count = 0;
120 int callback_failed = 0;
121 lmmc_status_t st;
122 st = lmmc_ode_rhs_eval(s->rhs, s->t, s->y, s->f0, s->dim, s->user_data,
123 &s->out_result->num_rhs_evals, &callback_failed);
124 if (st != LMMC_STATUS_OK) {
127 return st;
128 }
130 s->rhs, s->local_cfg.jacobian, s->user_data, s->t, s->y, s->f0, s->dim, s->matrix_data,
132 &callback_failed});
133 if (st != LMMC_STATUS_OK) {
135 callback_failed ? LMMC_ODE_FAILURE_RHS_EVAL_FAILED
137 return st;
138 }
139 st = ros_time_derivative(s->rhs, s->local_cfg.time_derivative, s->user_data, s->t, s->y,
140 s->f0, s->dim, s->dfdt, s->f_pert, s->out_result);
141 if (st != LMMC_STATUS_OK) {
143 return st;
144 }
145
146 for (i = 0; i < s->dim; ++i) {
147 for (j = 0; j < s->dim; ++j) {
148 s->W.data[i * s->dim + j] = -s->matrix_data[i * s->dim + j];
149 }
150 s->W.data[i * s->dim + i] += 1.0 / (s->h * ros_gamma);
151 }
152 st = lmmc_lu_decompose_inplace(&s->W, s->pivots, &swap_count);
153 if (st != LMMC_STATUS_OK) {
154 return st;
155 }
156 return LMMC_STATUS_OK;
157}
158
159static lmmc_status_t ros_evaluate_stages(ode_rosenbrock_state_t* s) {
160 size_t i;
161 int callback_failed = 0;
162 lmmc_status_t st;
163 for (i = 0; i < s->dim; ++i) {
164 s->rhs_vec[i] = s->f0[i] + s->h * ros_d[0] * s->dfdt[i];
165 }
166 st = ros_solve_stage(&s->W, s->pivots, s->rhs_vec, s->k[0], s->dim);
167 if (st != LMMC_STATUS_OK) { return st; }
168
169 for (i = 0; i < s->dim; ++i) {
170 s->y_stage[i] = s->y[i] + ros_a21 * s->k[0][i];
171 }
172 st = lmmc_ode_rhs_eval(s->rhs, s->t + ros_c2 * s->h, s->y_stage, s->f_stage, s->dim, s->user_data,
173 &s->out_result->num_rhs_evals, &callback_failed);
174 if (st != LMMC_STATUS_OK) {
177 return st;
178 }
179 for (i = 0; i < s->dim; ++i) {
180 s->rhs_vec[i] = s->f_stage[i] + s->h * ros_d[1] * s->dfdt[i] + (ros_c21 / s->h) * s->k[0][i];
181 }
182 st = ros_solve_stage(&s->W, s->pivots, s->rhs_vec, s->k[1], s->dim);
183 if (st != LMMC_STATUS_OK) { return st; }
184
185 for (i = 0; i < s->dim; ++i) {
186 s->y_stage[i] = s->y[i] + ros_a31 * s->k[0][i] + ros_a32 * s->k[1][i];
187 }
188 st = lmmc_ode_rhs_eval(s->rhs, s->t + ros_c3 * s->h, s->y_stage, s->f_stage, s->dim, s->user_data,
189 &s->out_result->num_rhs_evals, &callback_failed);
190 if (st != LMMC_STATUS_OK) {
193 return st;
194 }
195 for (i = 0; i < s->dim; ++i) {
196 s->rhs_vec[i] = s->f_stage[i] + s->h * ros_d[2] * s->dfdt[i]
197 + (ros_c31 / s->h) * s->k[0][i] + (ros_c32 / s->h) * s->k[1][i];
198 }
199 st = ros_solve_stage(&s->W, s->pivots, s->rhs_vec, s->k[2], s->dim);
200 if (st != LMMC_STATUS_OK) { return st; }
201
202 for (i = 0; i < s->dim; ++i) {
203 s->rhs_vec[i] = s->f_stage[i] + s->h * ros_d[3] * s->dfdt[i]
204 + (ros_c41 / s->h) * s->k[0][i] + (ros_c42 / s->h) * s->k[1][i]
205 + (ros_c43 / s->h) * s->k[2][i];
206 }
207 st = ros_solve_stage(&s->W, s->pivots, s->rhs_vec, s->k[3], s->dim);
208 if (st != LMMC_STATUS_OK) { return st; }
209 return LMMC_STATUS_OK;
210}
211
212static lmmc_status_t ros_estimate_error(ode_rosenbrock_state_t* s, lmmc_real_t* error_norm) {
213 size_t i;
214 lmmc_status_t st;
215 for (i = 0; i < s->dim; ++i) {
216 s->y_new[i] = s->y[i] + ros_b[0] * s->k[0][i] + ros_b[1] * s->k[1][i]
217 + ros_b[2] * s->k[2][i] + ros_b[3] * s->k[3][i];
218 s->error[i] = ros_e[0] * s->k[0][i] + ros_e[1] * s->k[1][i]
219 + ros_e[2] * s->k[2][i] + ros_e[3] * s->k[3][i];
220 }
222 if (st != LMMC_STATUS_OK) { return st; }
223 st = lmmc_ode_weighted_rms(s->error, s->y, s->y_new, s->dim, s->local_cfg.abs_tol,
224 s->local_cfg.rel_tol, error_norm);
225 if (st != LMMC_STATUS_OK) { return st; }
226 return LMMC_STATUS_OK;
227}
228
229static lmmc_status_t ros_integrate(ode_rosenbrock_state_t* s, lmmc_real_t t_end) {
230 size_t attempts = 0;
231 lmmc_status_t st;
232 while (s->t < t_end && attempts < s->local_cfg.max_steps) {
233 lmmc_real_t error_norm = 0.0;
234 ++attempts;
235 if (s->h > t_end - s->t) {
236 s->h = t_end - s->t;
237 }
238 st = ros_prepare_system(s);
239 if (st != LMMC_STATUS_OK) { return st; }
240 st = ros_evaluate_stages(s);
241 if (st != LMMC_STATUS_OK) { return st; }
242 st = ros_estimate_error(s, &error_norm);
243 if (st != LMMC_STATUS_OK) { return st; }
244 if (error_norm <= 1.0) {
245 memcpy(s->y, s->y_new, s->work_bytes);
246 s->t += s->h;
247 s->out_result->num_steps += 1;
248 s->out_result->final_t = s->t;
249 lmmc_ode_do_log(&s->local_cfg, s->out_result->num_steps, s->t, s->y, s->dim);
250 } else if (s->h <= s->local_cfg.min_step) {
253 return st;
254 }
255 s->h = lmmc_ode_next_step(s->h, error_norm, &s->local_cfg);
256 }
257
258 if (s->t >= t_end) {
259 s->out_result->converged = 1;
261 st = LMMC_STATUS_OK;
262 } else {
265 }
266 return st;
267}
268
269static lmmc_status_t ros_cleanup(ode_rosenbrock_state_t* s, lmmc_status_t st) {
270 if (st != LMMC_STATUS_OK && s->out_result != NULL &&
273 }
277 return st;
278}
279
281 lmmc_ode_rhs_t rhs,
282 void* user_data,
283 size_t dim,
284 lmmc_real_t t_start,
285 lmmc_real_t t_end,
286 lmmc_real_t* y,
287 const lmmc_ode_config_t* cfg,
288 lmmc_ode_result_t* out_result
289) {
290 ode_rosenbrock_state_t state = {0};
291 ode_rosenbrock_state_t* s = &state;
292 size_t vectors_bytes = 0, matrix_count = 0, matrix_bytes = 0;
293 size_t i;
294 lmmc_status_t st;
295 s->rhs = rhs;
296 s->user_data = user_data;
297 s->dim = dim;
298 s->y = y;
299 s->out_result = out_result;
300 s->t = t_start;
301 st = validate_and_init_ode_config(s->rhs, s->dim, t_start, t_end, s->y, cfg,
302 &s->local_cfg, s->out_result, &s->work_bytes);
303 if (st != LMMC_STATUS_OK) {
304 return st;
305 }
306 if (!lmmc_safe_mul_size(s->work_bytes, ROS_VECTORS, &vectors_bytes) ||
307 !lmmc_safe_mul_size(s->dim, s->dim, &matrix_count) ||
308 !lmmc_safe_mul_size(matrix_count, sizeof(lmmc_real_t), &matrix_bytes) ||
309 !lmmc_safe_mul_size(s->dim, sizeof(size_t), &matrix_count)) {
312 }
313
314 s->work = (lmmc_real_t*)lmmc_memory_alloc(vectors_bytes);
315 s->matrix_data = (lmmc_real_t*)lmmc_memory_alloc(matrix_bytes);
316 s->pivots = (size_t*)lmmc_memory_alloc(matrix_count);
317 if (s->work == NULL || s->matrix_data == NULL || s->pivots == NULL) {
319 return ros_cleanup(s, st);
320 }
321
322 for (i = 0; i < ROS_STAGES; ++i) {
323 s->k[i] = s->work + i * s->dim;
324 }
325 s->f0 = s->work + 4 * s->dim;
326 s->f_stage = s->work + 5 * s->dim;
327 s->y_stage = s->work + 6 * s->dim;
328 s->y_pert = s->work + 7 * s->dim;
329 s->f_pert = s->work + 8 * s->dim;
330 s->rhs_vec = s->work + 9 * s->dim;
331 s->dfdt = s->work + 10 * s->dim;
332 s->y_new = s->work + 11 * s->dim;
333 s->error = s->work + 12 * s->dim;
334 s->W = (lmmc_mat_t){s->dim, s->dim, s->dim, s->matrix_data, 0};
335
336 s->h = lmmc_clamp(s->local_cfg.initial_step, s->local_cfg.min_step, s->local_cfg.max_step);
337 if (s->h > t_end - t_start) {
338 s->h = t_end - t_start;
339 }
340 lmmc_ode_do_log(&s->local_cfg, 0, s->t, s->y, s->dim);
341 st = ros_integrate(s, t_end);
342 return ros_cleanup(s, st);
343}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_real_t * data
行优先存储的稠密矩阵。
一维稠密向量。
LMMC 内部使用的公共工具(仅源文件可见).
稠密矩阵直接分解接口(LU、Cholesky、QR)。
lmmc_status_t lmmc_lu_solve(const lmmc_mat_t *lu, const size_t *pivots, const lmmc_vec_t *b, lmmc_vec_t *x)
利用 LU 分解结果求解线性系统 A*x = b。
lmmc_status_t lmmc_lu_decompose_inplace(lmmc_mat_t *a, size_t *pivots, size_t *out_swap_count)
就地 LU 分解(带部分主元选取):P*A = L*U。
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
常微分方程初值问题求解器:Euler、RK4、RK45(自适应)。
size_t num_rhs_evals
定义 ode.h:49
lmmc_status_t(*) lmmc_ode_rhs_t(lmmc_real_t t, const lmmc_real_t *y, lmmc_real_t *y_prime, size_t dim, void *user_data)
ODE 右端函数签名 。
定义 ode.h:26
lmmc_real_t initial_step
定义 ode.h:92
@ LMMC_ODE_FAILURE_NUMERICAL_ISSUE
定义 ode.h:40
@ LMMC_ODE_FAILURE_INVALID_STEP
定义 ode.h:38
@ LMMC_ODE_FAILURE_NONE
定义 ode.h:36
@ LMMC_ODE_FAILURE_RHS_EVAL_FAILED
定义 ode.h:41
@ LMMC_ODE_FAILURE_INVALID_DIMENSION
定义 ode.h:37
@ LMMC_ODE_FAILURE_MAX_STEPS
定义 ode.h:39
lmmc_real_t final_t
定义 ode.h:50
lmmc_real_t abs_tol
定义 ode.h:95
lmmc_ode_dfdt_t time_derivative
定义 ode.h:101
lmmc_real_t rel_tol
定义 ode.h:96
lmmc_status_t lmmc_ode_rosenbrock_grk4t_solve(lmmc_ode_rhs_t rhs, void *user_data, size_t dim, lmmc_real_t t_start, lmmc_real_t t_end, lmmc_real_t *y, const lmmc_ode_config_t *cfg, lmmc_ode_result_t *out_result)
Rosenbrock-Wanner GRK4T 求解器(线性隐式,四阶,每步一次 LU)。
lmmc_ode_failure_t failure_reason
定义 ode.h:51
lmmc_real_t max_step
定义 ode.h:94
lmmc_ode_jac_t jacobian
定义 ode.h:100
lmmc_real_t min_step
定义 ode.h:93
lmmc_status_t(*) lmmc_ode_dfdt_t(lmmc_real_t t, const lmmc_real_t *y, lmmc_real_t *dfdt, size_t dim, void *user_data)
ODE 对时间偏导回调签名 .
定义 ode.h:81
ODE 求解配置。
定义 ode.h:91
ODE 求解结果统计。
定义 ode.h:46
ODE 求解器共享的内部辅助函数。
lmmc_status_t lmmc_ode_rhs_eval(lmmc_ode_rhs_t rhs, lmmc_real_t t, const lmmc_real_t *y, lmmc_real_t *y_prime, size_t dim, void *user_data, size_t *io_eval_count, int *out_callback_failed)
lmmc_status_t lmmc_ode_jacobian_eval(const lmmc_ode_jacobian_request_t *request)
lmmc_real_t lmmc_ode_next_step(lmmc_real_t h, lmmc_real_t error_norm, const lmmc_ode_config_t *cfg)
lmmc_status_t lmmc_ode_values_are_finite(const lmmc_real_t *values, size_t count)
lmmc_status_t validate_and_init_ode_config(lmmc_ode_rhs_t rhs, size_t dim, lmmc_real_t t_start, lmmc_real_t t_end, const lmmc_real_t *y, const lmmc_ode_config_t *cfg, lmmc_ode_config_t *out_cfg, lmmc_ode_result_t *out_result, size_t *out_work_bytes)
void lmmc_ode_do_log(const lmmc_ode_config_t *cfg, size_t step, lmmc_real_t t, const lmmc_real_t *y, size_t dim)
lmmc_status_t lmmc_ode_weighted_rms(const lmmc_real_t *error, const lmmc_real_t *y_old, const lmmc_real_t *y_new, size_t dim, lmmc_real_t abs_tol, lmmc_real_t rel_tol, lmmc_real_t *out_norm)
lmmc_real_t * k[ROS_STAGES]
#define ROS_STAGES
#define ROS_VECTORS
lmmc_ode_result_t * out_result
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_CONVERGENCE_FAILED
@ LMMC_STATUS_OK
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT