LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
ode_implicit.c
浏览该文件的文档.
1
5#include <math.h>
6#include <string.h>
7
8#include "memory_bridge.h"
9#include "internal.h"
10#include "ode_internal.h"
11#include "lmmc/ode.h"
12#include "lmmc/optimize.h"
13#include "lmmc/dense.h"
14#include "lmmc/linear_algebra.h"
15
30
31static lmmc_status_t implicit_euler_residual(
32 const lmmc_vec_t* x, lmmc_vec_t* F, void* ud
33) {
35 size_t i;
37 ctx->rhs, ctx->t_next, x->data, F->data, ctx->dim, ctx->user_data,
39 if (st != LMMC_STATUS_OK) { return st; }
40 /* G(z) = z - y_n - h*f(t_{n+1}, z) */
41 for (i = 0; i < ctx->dim; ++i) {
42 F->data[i] = x->data[i] - ctx->y_n[i] - ctx->h * F->data[i];
43 }
44 return LMMC_STATUS_OK;
45}
46
47static lmmc_status_t implicit_euler_jacobian(
48 const lmmc_vec_t* x, lmmc_mat_t* J, void* ud
49) {
51 size_t i, j, n = ctx->dim;
52 lmmc_real_t* jac_data = J->data;
53
54 {
56 ctx->rhs, ctx->jac_cb, ctx->user_data, ctx->t_next, x->data,
57 NULL, n, jac_data, ctx->jac_base_rhs, ctx->jac_y_perturbed,
59 &ctx->callback_failed});
60 if (st != LMMC_STATUS_OK) { return st; }
61 }
62 /* J_G = I - h * J_f */
63 for (i = 0; i < n; ++i) {
64 for (j = 0; j < n; ++j) {
65 jac_data[i * J->stride + j] = -ctx->h * jac_data[i * J->stride + j];
66 }
67 jac_data[i * J->stride + i] += 1.0;
68 }
69 return LMMC_STATUS_OK;
70}
71
72static lmmc_status_t implicit_euler_integrate(
74 const lmmc_optimize_config_t* opt_cfg, lmmc_real_t* y,
76 const lmmc_ode_config_t* cfg, lmmc_ode_result_t* out_result
77) {
78 const size_t dim = ctx->dim;
80 while (t < t_end && out_result->num_steps < cfg->max_steps) {
81 lmmc_real_t rem = t_end - t;
83 if (rem <= 0.0) { break; }
84 if (h > rem) h = rem;
85
86 ctx->t_next = t + h;
87 ctx->h = h;
88 ctx->y_n = y;
89
91 memcpy(x_vec->data, y, dim * sizeof(lmmc_real_t));
92
93 st = lmmc_nleq_newton(implicit_euler_residual, implicit_euler_jacobian,
94 ctx, x_vec, opt_cfg, &opt_res);
95 if (st != LMMC_STATUS_OK || !opt_res.converged) {
96 out_result->failure_reason =
100 }
101
102 memcpy(y, x_vec->data, dim * sizeof(lmmc_real_t));
103
104 if (!lmmc_ode_state_is_finite(y, dim)) {
107 }
108
109 t += h;
110 out_result->num_steps += 1;
111 out_result->final_t = t;
112 lmmc_ode_do_log(cfg, out_result->num_steps, t, y, dim);
113 }
114 if (t >= t_end) {
115 out_result->converged = 1;
117 } else {
118 out_result->converged = 0;
120 }
122}
123
125 lmmc_ode_rhs_t rhs,
126 void* user_data,
127 size_t dim,
128 lmmc_real_t t_start,
129 lmmc_real_t t_end,
130 lmmc_real_t* y,
131 const lmmc_ode_config_t* cfg,
132 lmmc_ode_result_t* out_result
133) {
134 lmmc_ode_config_t local_cfg = {0};
135 size_t work_bytes = 0;
136 size_t total_work_bytes = 0;
137 lmmc_real_t t = t_start;
138 lmmc_real_t h = 0.0;
139 lmmc_status_t init_st;
140 lmmc_vec_t x_vec = {0};
142 lmmc_real_t* work = NULL;
144
145 init_st = validate_and_init_ode_config(rhs, dim, t_start, t_end, y,
146 cfg, &local_cfg, out_result, &work_bytes);
147 if (init_st != LMMC_STATUS_OK) { return init_st; }
148
149 h = lmmc_clamp(local_cfg.initial_step, local_cfg.min_step, local_cfg.max_step);
150 { lmmc_real_t span = t_end - t_start; if (h > span) h = span; }
151
152 /* Setup Newton config */
154 opt_cfg.abs_tol = local_cfg.abs_tol;
155 opt_cfg.rel_tol = local_cfg.rel_tol;
156 opt_cfg.max_iter = 50;
157
158 if (!lmmc_safe_mul_size(work_bytes, 4, &total_work_bytes)) {
161 }
162 work = (lmmc_real_t*)lmmc_memory_alloc(total_work_bytes);
163 if (work == NULL) {
166 }
167 x_vec.size = dim;
168 x_vec.data = work;
169 x_vec.owns_data = 0;
170
171 ctx.rhs = rhs;
172 ctx.user_data = user_data;
173 ctx.jac_cb = local_cfg.jacobian;
174 ctx.dim = dim;
175
176 ctx.jac_base_rhs = work + dim;
177 ctx.jac_y_perturbed = work + 2 * dim;
178 ctx.jac_rhs_perturbed = work + 3 * dim;
179 ctx.rhs_eval_count = &out_result->num_rhs_evals;
180 ctx.callback_failed = 0;
181 lmmc_ode_do_log(&local_cfg, 0, t, y, dim);
182 init_st = implicit_euler_integrate(&ctx, &x_vec, &opt_cfg, y,
183 t, h, t_end, &local_cfg, out_result);
184 lmmc_memory_free(work);
185 return init_st;
186}
187
203
204static lmmc_status_t trapezoidal_residual(
205 const lmmc_vec_t* x, lmmc_vec_t* F, void* ud
206) {
208 size_t i;
210 ctx->rhs, ctx->t_next, x->data, F->data, ctx->dim, ctx->user_data,
211 ctx->rhs_eval_count, &ctx->callback_failed);
212 if (st != LMMC_STATUS_OK) { return st; }
213 /* G(z) = z - y_n - h/2*(f_n + f(t_{n+1}, z)) */
214 for (i = 0; i < ctx->dim; ++i) {
215 F->data[i] = x->data[i] - ctx->y_n[i]
216 - 0.5 * ctx->h * (ctx->f_n[i] + F->data[i]);
217 }
218 return LMMC_STATUS_OK;
219}
220
221static lmmc_status_t trapezoidal_jacobian(
222 const lmmc_vec_t* x, lmmc_mat_t* J, void* ud
223) {
225 size_t i, j, n = ctx->dim;
226 lmmc_real_t* jac_data = J->data;
227
228 {
230 ctx->rhs, ctx->jac_cb, ctx->user_data, ctx->t_next, x->data,
231 NULL, n, jac_data, ctx->jac_base_rhs, ctx->jac_y_perturbed,
233 &ctx->callback_failed});
234 if (st != LMMC_STATUS_OK) { return st; }
235 }
236 /* J_G = I - (h/2) * J_f */
237 for (i = 0; i < n; ++i) {
238 for (j = 0; j < n; ++j) {
239 jac_data[i * J->stride + j] *= -0.5 * ctx->h;
240 }
241 jac_data[i * J->stride + i] += 1.0;
242 }
243 return LMMC_STATUS_OK;
244}
245
246static lmmc_status_t trapezoidal_integrate(
248 const lmmc_optimize_config_t* opt_cfg, lmmc_real_t* y,
250 const lmmc_ode_config_t* cfg, lmmc_ode_result_t* out_result
251) {
252 const size_t dim = ctx->dim;
254 while (t < t_end && out_result->num_steps < cfg->max_steps) {
255 lmmc_real_t rem = t_end - t;
256 lmmc_status_t st;
257 if (rem <= 0.0) { break; }
258 if (h > rem) h = rem;
259
261 ctx->rhs, t, y, ctx->f_n, dim, ctx->user_data, &out_result->num_rhs_evals,
262 &ctx->callback_failed);
263 if (st != LMMC_STATUS_OK) {
264 out_result->failure_reason =
267 return st;
268 }
269
270 ctx->t_next = t + h;
271 ctx->h = h;
272 ctx->y_n = y;
273
275 memcpy(x_vec->data, y, dim * sizeof(lmmc_real_t));
276
277 st = lmmc_nleq_newton(trapezoidal_residual, trapezoidal_jacobian,
278 ctx, x_vec, opt_cfg, &opt_res);
279 if (st != LMMC_STATUS_OK || !opt_res.converged) {
280 out_result->failure_reason =
284 }
285
286 memcpy(y, x_vec->data, dim * sizeof(lmmc_real_t));
287
288 if (!lmmc_ode_state_is_finite(y, dim)) {
291 }
292
293 t += h;
294 out_result->num_steps += 1;
295 out_result->final_t = t;
296 lmmc_ode_do_log(cfg, out_result->num_steps, t, y, dim);
297 }
298 if (t >= t_end) {
299 out_result->converged = 1;
301 } else {
302 out_result->converged = 0;
304 }
306}
307
309 lmmc_ode_rhs_t rhs,
310 void* user_data,
311 size_t dim,
312 lmmc_real_t t_start,
313 lmmc_real_t t_end,
314 lmmc_real_t* y,
315 const lmmc_ode_config_t* cfg,
316 lmmc_ode_result_t* out_result
317) {
318 lmmc_ode_config_t local_cfg = {0};
319 size_t work_bytes = 0;
320 size_t total_work_bytes = 0;
321 lmmc_real_t t = t_start;
322 lmmc_real_t h = 0.0;
323 lmmc_status_t init_st;
324 lmmc_vec_t x_vec = {0};
325 lmmc_real_t* f_n = NULL;
326 lmmc_real_t* work = NULL;
329
330 init_st = validate_and_init_ode_config(rhs, dim, t_start, t_end, y,
331 cfg, &local_cfg, out_result, &work_bytes);
332 if (init_st != LMMC_STATUS_OK) { return init_st; }
333
334 h = lmmc_clamp(local_cfg.initial_step, local_cfg.min_step, local_cfg.max_step);
335 { lmmc_real_t span = t_end - t_start; if (h > span) h = span; }
336
338 opt_cfg.abs_tol = local_cfg.abs_tol;
339 opt_cfg.rel_tol = local_cfg.rel_tol;
340 opt_cfg.max_iter = 50;
341
342 if (!lmmc_safe_mul_size(work_bytes, 5, &total_work_bytes)) {
345 }
346 work = (lmmc_real_t*)lmmc_memory_alloc(total_work_bytes);
347 if (work == NULL) {
350 }
351 x_vec.size = dim;
352 x_vec.data = work;
353 x_vec.owns_data = 0;
354 f_n = work + dim;
355
356 ctx.rhs = rhs;
357 ctx.user_data = user_data;
358 ctx.jac_cb = local_cfg.jacobian;
359 ctx.dim = dim;
360 ctx.f_n = f_n;
361 ctx.jac_base_rhs = work + 2 * dim;
362 ctx.jac_y_perturbed = work + 3 * dim;
363 ctx.jac_rhs_perturbed = work + 4 * dim;
364 ctx.rhs_eval_count = &out_result->num_rhs_evals;
365 ctx.callback_failed = 0;
366
367 lmmc_ode_do_log(&local_cfg, 0, t, y, dim);
368 init_st = trapezoidal_integrate(&ctx, &x_vec, &opt_cfg, y,
369 t, h, t_end, &local_cfg, out_result);
370 lmmc_memory_free(work);
371 return init_st;
372}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_real_t * data
lmmc_real_t * data
行优先存储的稠密矩阵。
一维稠密向量。
LMMC 内部使用的公共工具(仅源文件可见).
稠密矩阵直接分解接口(LU、Cholesky、QR)。
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_status_t lmmc_ode_implicit_euler_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)
隐式 Euler 法求解器(A-稳定,适用于刚性问题)。
@ LMMC_ODE_FAILURE_NUMERICAL_ISSUE
定义 ode.h:40
@ 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_status_t(*) lmmc_ode_jac_t(lmmc_real_t t, const lmmc_real_t *y, lmmc_real_t *J, size_t dim, void *user_data)
ODE Jacobian 回调签名 。
定义 ode.h:64
lmmc_status_t lmmc_ode_trapezoidal_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)
梯形法求解器(A-稳定,二阶精度)。
lmmc_real_t rel_tol
定义 ode.h:96
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
ODE 求解配置。
定义 ode.h:91
ODE 求解结果统计。
定义 ode.h:46
const lmmc_real_t * y_n
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_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)
int lmmc_ode_state_is_finite(const lmmc_real_t *y, size_t dim)
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_nleq_newton(lmmc_opt_func_t F, lmmc_opt_jac_t J, void *user_data, lmmc_vec_t *x, const lmmc_optimize_config_t *cfg, lmmc_optimize_result_t *out)
Newton 法求解非线性方程组 F(x) = 0。
lmmc_status_t lmmc_optimize_default_config(lmmc_optimize_config_t *cfg)
初始化默认优化配置。
优化算法配置参数。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_CONVERGENCE_FAILED
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT