21#include "mdb_thread.h"
24#define MAX_EXIT_ITERATIONS 400
25#define ITER_FACTOR 0.995
29void new_scale_factors_dp(
40 for (i = 0; i < n_eq; i++) {
47 (y0[i] + dydx0[i] * h_start + tiny[i]) * accuracy[i];
51 (dydx0[i] * h_start + tiny[i]) * accuracy[i];
54 yscale[i] = accuracy[i];
57 yscale[i] = accuracy[i] * h_start;
60 printf(
"error: accmode[%d] = %ld (new_scale_factors_dp)\n", i, accmode[i]);
65 printf(
"error: yscale[%d] = %e\n", i, yscale[i]);
71void initial_scale_factors_dp(
84 for (i = 0; i < n_eq; i++) {
85 if ((accur[i] = accuracy[i]) <= 0) {
86 printf(
"error: accuracy[%d] = %e (initial_scale_factors_dp)\n", i, accuracy[i]);
94 yscale[i] = (y0[i] + dydx0[i] * h_start + tiny[i]) * accur[i];
97 yscale[i] = (dydx0[i] * h_start + tiny[i]) * accur[i];
100 yscale[i] = accur[i];
103 yscale[i] = (accur[i] /= (xf - x0)) * h_start;
106 printf(
"error: accmode[%d] = %ld (initial_scale_factors_dp)\n", i, accmode[i]);
110 if (yscale[i] <= 0) {
111 printf(
"error: yscale[%d] = %e (initial_scale_factors_dp)\n", i, yscale[i]);
117void report_state_dp(FILE *fp,
double *y,
double *dydx,
double *yscale,
long *misses,
118 double x,
double h,
long n_eq) {
120 fputs(
"integration state:\n", fp);
121 fprintf(fp,
"%ld equations, indep.var.=%e, step size=%e",
123 fprintf(fp,
"\ny : ");
124 for (i = 0; i < n_eq; i++)
125 fprintf(fp,
"%e ", y[i]);
126 fprintf(fp,
"\ndydx : ");
127 for (i = 0; i < n_eq; i++)
128 fprintf(fp,
"%e ", dydx[i]);
129 fprintf(fp,
"\ntol.scale: ");
130 for (i = 0; i < n_eq; i++)
131 fprintf(fp,
"%e ", yscale[i]);
132 fprintf(fp,
"\nmisses : ");
133 for (i = 0; i < n_eq; i++)
134 fprintf(fp,
"%ld ", misses[i]);
149 void (*derivs)(
double *dydx,
double *y,
double x)
152 static MDB_THREAD_LOCAL
long last_n_eq = 0;
153 static MDB_THREAD_LOCAL
double *k1 = NULL, *k2 = NULL, *k3 = NULL, *yTemp = NULL, *dydxTemp = NULL;
158 if (last_n_eq < n_eq) {
159 if (last_n_eq != 0) {
167 k1 =
tmalloc(
sizeof(*k1) * n_eq);
168 k2 =
tmalloc(
sizeof(*k2) * n_eq);
169 k3 =
tmalloc(
sizeof(*k3) * n_eq);
170 yTemp =
tmalloc(
sizeof(*yTemp) * n_eq);
171 dydxTemp =
tmalloc(
sizeof(*dydxTemp) * n_eq);
182 for (i = 0; i < n_eq; i++) {
184 yTemp[i] = yi[i] + k1[i] / 2;
189 (*derivs)(dydxTemp, yTemp, x1);
190 for (i = 0; i < n_eq; i++) {
191 k2[i] = h * dydxTemp[i];
192 yTemp[i] = yi[i] + k2[i] / 2;
196 (*derivs)(dydxTemp, yTemp, x1);
197 for (i = 0; i < n_eq; i++) {
198 k3[i] = h * dydxTemp[i];
199 yTemp[i] = yi[i] + k3[i];
204 (*derivs)(dydxTemp, yTemp, x1);
205 for (i = 0; i < n_eq; i++)
206 yf[i] = yi[i] + (k1[i] / 2 + k2[i] + k3[i] + h * dydxTemp[i] / 2) / 3;
216static double safetyMargin = 0.9;
217static double increasePower = 0.2;
218static double decreasePower = 0.25;
219static double maxIncreaseFactor = 4.0;
220static MDB_THREAD_LOCK rk_qctune_lock = MDB_THREAD_LOCK_INITIALIZER;
222void rk4_qctune(
double newSafetyMargin,
double newIncreasePower,
223 double newDecreasePower,
double newMaxIncreaseFactor) {
224 mdb_thread_lock(&rk_qctune_lock);
225 if (newSafetyMargin > 0 && newSafetyMargin < 1)
226 safetyMargin = newSafetyMargin;
227 if (newIncreasePower > 0)
228 increasePower = newIncreasePower;
229 if (newDecreasePower > 0)
230 decreasePower = newDecreasePower;
231 if (newMaxIncreaseFactor > 1)
232 maxIncreaseFactor = newMaxIncreaseFactor;
233 mdb_thread_unlock(&rk_qctune_lock);
243 double *hRecommended,
246 void (*derivs)(
double *dydx,
double *y,
double x),
252 static MDB_THREAD_LOCAL
long last_equations = 0;
253 static MDB_THREAD_LOCAL
double *dydxTemp = NULL, *yTemp = NULL;
254 double hOver2, h, xTemp;
255 double error, maxError, hFactor;
256 double localSafetyMargin, localIncreasePower, localDecreasePower, localMaxIncreaseFactor;
257 long i, iWorst = 0, minStepped = 0, noAdaptation = 0;
259 mdb_thread_lock(&rk_qctune_lock);
260 localSafetyMargin = safetyMargin;
261 localIncreasePower = increasePower;
262 localDecreasePower = decreasePower;
263 localMaxIncreaseFactor = maxIncreaseFactor;
264 mdb_thread_unlock(&rk_qctune_lock);
267 if (last_equations < equations) {
268 if (last_equations != 0) {
272 last_equations = equations;
273 dydxTemp =
tmalloc(
sizeof(*dydxTemp) * equations);
274 yTemp =
tmalloc(
sizeof(*yTemp) * equations);
277 for (i = 0; i < equations; i++)
278 if (yScale[i] != DBL_MAX)
286 printf(
"x = %e, h = %e\n", *x, h);
292 puts(
"warning: step-size underflow in rk_qcstep()");
293 report_state_dp(stdout, yInitial, dydxInitial, yScale, misses, *x, h, equations);
294 if ((h = 2 * fabs(*x) * DBL_EPSILON) == 0)
306 rk4_step(yTemp, xTemp, yInitial, dydxInitial, hOver2, equations, derivs);
309 (*derivs)(dydxTemp, yTemp, xTemp);
311 rk4_step(yFinal, xTemp, yTemp, dydxTemp, hOver2, equations, derivs);
314 rk4_step(yTemp, xTemp, yInitial, dydxInitial, h, equations, derivs);
317 for (i = 0; i < equations; i++)
318 yTemp[i] = yFinal[i] - yTemp[i];
322 for (i = 0; i < equations; i++) {
324 printf(
"%ld: yTemp=%e yFinal=%e yScale=%e, ", i, yTemp[i], yFinal[i], yScale[i]);
326 if (maxError < (error = fabs(yTemp[i]) / yScale[i])) {
331 printf(
" error = %e\n", error);
346 hFactor = localSafetyMargin * pow(maxError, -localIncreasePower);
349 hFactor = localMaxIncreaseFactor;
351 printf(
"maxError = %e, hFactor = %e\n", maxError, hFactor);
353 if (hFactor > localMaxIncreaseFactor)
354 hFactor = localMaxIncreaseFactor;
355 else if (hFactor < 1)
360 *hRecommended = hFactor * h;
365 for (i = 0; i < equations; i++)
366 yFinal[i] += yTemp[i] / 15;
379 hOver2 = (h = localSafetyMargin * h * pow(maxError, -localDecreasePower)) / 2;
412 void (*derivs)(
double *dydx,
double *y,
double x),
428 double (*exit_func)(
double *dydx,
double *y,
double x),
429 double exit_accuracy,
433 void (*store_data)(
double *dydx,
double *y,
double x,
double exval)) {
435 double *dydx0, *y1, *dydx1, *dydx2, *y2;
436 double ex0, ex1, ex2, *yscale, *accur;
437 double h_used, h_next, x1, x2, xdiff;
438 long i, n_exit_iterations, n_step_ups = 0, is_zero;
439#define MAX_N_STEP_UPS 10
442 return (DIFFEQ_XI_GT_XF);
443 if (FABS(*x0 - xf) < x_accuracy)
444 return (DIFFEQ_SOLVED_ALREADY);
458 for (i = 0; i < n_eq; i++) {
459 if (accmode[i] < -1 || accmode[i] > 3)
460 bomb(
"accmode must be on [-1, 3] (rk_odeint)", NULL);
461 if (accmode[i] < 2 && tiny[i] < TINY)
467 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
468 y1 =
tmalloc(
sizeof(
double) * n_eq);
469 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
470 y2 =
tmalloc(
sizeof(
double) * n_eq);
471 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
472 yscale =
tmalloc(
sizeof(
double) * n_eq);
475 (*derivs)(dydx0, y0, *x0);
480 accur =
tmalloc(
sizeof(
double) * n_eq);
481 initial_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
482 accuracy, accur, *x0, xf, n_eq);
484 ex0 = exit_func ? (*exit_func)(dydx0, y0, *x0) : 0;
486 (*store_data)(dydx0, y0, *x0, ex0);
491 if (exit_func && FABS(ex0) < exit_accuracy) {
493 if (n_to_skip == 0) {
495 (*store_data)(dydx0, y0, *x0, ex0);
496 for (i = 0; i < n_eq; i++)
510 return (DIFFEQ_ZERO_FOUND);
519 if ((xdiff = xf - *x0) < h_start)
523 if (!rk_qcstep(y1, &x1, y0, dydx0, h_start, &h_used, &h_next,
524 yscale, n_eq, derivs, misses)) {
525 if (n_step_ups++ > MAX_N_STEP_UPS)
526 bomb(
"cannot take initial step (rk_odeint--1)", NULL);
527 h_start = (n_step_ups - 1 ? h_start * 10 : h_used * 10);
531 (*derivs)(dydx1, y1, x1);
532 ex1 = exit_func ? (*exit_func)(dydx1, y1, x1) : 0;
534 (*store_data)(dydx1, y1, x1, ex1);
536 if (exit_func && SIGN(ex0) != SIGN(ex1) && !is_zero) {
546 if (FABS(xdiff = xf - x1) < x_accuracy) {
549 (*derivs)(dydx1, y1, x1);
550 ex1 = exit_func ? (*exit_func)(dydx1, y1, x1) : 0;
551 (*store_data)(dydx1, y1, x1, ex1);
553 for (i = 0; i < n_eq; i++)
568 return (DIFFEQ_END_OF_INTERVAL);
572 SWAP_PTR(dydx0, dydx1);
577 h_start = (h_next > h_max ? (h_max ? h_max : h_next) : h_next);
579 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
586 printf(
"failure in rk_odeint(): solution stepped outside interval\n");
598 return (DIFFEQ_OUTSIDE_INTERVAL);
602 n_exit_iterations = MAX_EXIT_ITERATIONS;
605 h_start = -ex0 * (x1 - *x0) / (ex1 - ex0) * ITER_FACTOR;
608 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
610 if (!rk_qcstep(y2, &x2, y0, dydx0, h_start, &h_used, &h_next,
611 yscale, n_eq, derivs, misses))
612 bomb(
"step size too small (rk_odeint--2)", NULL);
614 (*derivs)(dydx2, y2, x2);
615 ex2 = (*exit_func)(dydx2, y2, x2);
616 if (FABS(ex2) < exit_accuracy) {
617 for (i = 0; i < n_eq; i++)
631 return (DIFFEQ_ZERO_FOUND);
634 if (SIGN(ex1) == SIGN(ex2)) {
636 SWAP_PTR(dydx1, dydx2);
641 SWAP_PTR(dydx0, dydx2);
645 }
while (n_exit_iterations--);
646 return (DIFFEQ_EXIT_COND_FAILED);
674 void (*derivs)(
double *dydx,
double *y,
double x),
691 double *dydx0, *y1, *dydx1, *dydx2, *y2;
692 double *yscale, *accur;
694 double h_used, h_next, xdiff;
695 long i, n_step_ups = 0;
696#define MAX_N_STEP_UPS 10
699 return (DIFFEQ_XI_GT_XF);
700 if (FABS(*x0 - xf) < x_accuracy)
701 return (DIFFEQ_SOLVED_ALREADY);
715 for (i = 0; i < n_eq; i++) {
716 if (accmode[i] < -1 || accmode[i] > 3)
717 bomb(
"accmode must be on [-1, 3] (rk_odeint)", NULL);
718 if (accmode[i] < 2 && tiny[i] < TINY)
724 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
725 y1 =
tmalloc(
sizeof(
double) * n_eq);
726 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
727 y2 =
tmalloc(
sizeof(
double) * n_eq);
728 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
729 yscale =
tmalloc(
sizeof(
double) * n_eq);
732 (*derivs)(dydx0, y0, *x0);
737 accur =
tmalloc(
sizeof(
double) * n_eq);
738 initial_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
739 accuracy, accur, *x0, xf, n_eq);
743 if ((xdiff = xf - *x0) < h_start)
747 if (!rk_qcstep(y1, &x1, y0, dydx0, h_start, &h_used, &h_next,
748 yscale, n_eq, derivs, misses)) {
749 if (n_step_ups++ > MAX_N_STEP_UPS) {
750 puts(
"error: cannot take step (rk_odeint1--1)");
751 printf(
"xf = %.16e x0 = %.16e\n", xf, *x0);
752 printf(
"h_start = %.16e h_used = %.16e\n", h_start, h_used);
753 puts(
"dump of integration state:");
754 puts(
" variable value derivative scale misses");
755 puts(
"---------------------------------------------------------------");
756 for (i = 0; i < n_eq; i++)
757 printf(
" %5ld %13.6e %13.6e %13.6e %5ld \n",
758 i, y0[i], dydx0[i], yscale[i], misses[i]);
761 h_start = (n_step_ups - 1 ? h_start * 10 : h_used * 10);
765 if (FABS(xdiff = xf - x1) < x_accuracy) {
767 for (i = 0; i < n_eq; i++)
782 return (DIFFEQ_END_OF_INTERVAL);
785 (*derivs)(dydx1, y1, x1);
787 SWAP_PTR(dydx0, dydx1);
791 h_start = (h_next > h_max ? (h_max ? h_max : h_next) : h_next);
793 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
827 void (*derivs)(
double *dydx,
double *y,
double x),
845 double exit_accuracy,
848 double *y_return, *accur;
849 double *dydx0, *y1, *dydx1, *dydx2, *y2;
850 double ex0, ex1, ex2, x1, x2, *yscale;
851 double h_used, h_next, xdiff;
852 long i, n_exit_iterations, n_step_ups = 0, is_zero;
853#define MAX_N_STEP_UPS 10
856 return (DIFFEQ_XI_GT_XF);
857 if (FABS(*x0 - xf) < x_accuracy)
858 return (DIFFEQ_SOLVED_ALREADY);
859 if (i_exit_value < 0 || i_exit_value >= n_eq)
860 bomb(
"index of variable for exit testing is out of range (rk_odeint2)", NULL);
874 for (i = 0; i < n_eq; i++) {
875 if (accmode[i] < -1 || accmode[i] > 3)
876 bomb(
"accmode must be on [-1, 3] (rk_odeint2)", NULL);
877 if (accmode[i] < 2 && tiny[i] < TINY)
883 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
884 y1 =
tmalloc(
sizeof(
double) * n_eq);
885 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
886 y2 =
tmalloc(
sizeof(
double) * n_eq);
887 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
888 yscale =
tmalloc(
sizeof(
double) * n_eq);
891 (*derivs)(dydx0, y0, *x0);
896 accur =
tmalloc(
sizeof(
double) * n_eq);
897 initial_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
898 accuracy, accur, *x0, xf, n_eq);
900 ex0 = exit_value - y0[i_exit_value];
904 if (FABS(ex0) < exit_accuracy) {
906 if (n_to_skip == 0) {
907 for (i = 0; i < n_eq; i++)
921 return (DIFFEQ_ZERO_FOUND);
930 if ((xdiff = xf - *x0) < h_start)
934 if (!rk_qcstep(y1, &x1, y0, dydx0, h_start, &h_used, &h_next,
935 yscale, n_eq, derivs, misses)) {
936 if (n_step_ups++ > MAX_N_STEP_UPS) {
937 bomb(
"error: cannot take initial step (rk_odeint2--1)", NULL);
939 h_start = (n_step_ups - 1 ? h_start * 10 : h_used * 10);
943 (*derivs)(dydx1, y1, x1);
944 ex1 = exit_value - y1[i_exit_value];
946 if (SIGN(ex0) != SIGN(ex1) && !is_zero) {
955 if (FABS(xdiff = xf - x1) < x_accuracy) {
957 for (i = 0; i < n_eq; i++)
972 return (DIFFEQ_END_OF_INTERVAL);
975 SWAP_PTR(dydx0, dydx1);
980 h_start = (h_next > h_max ? (h_max ? h_max : h_next) : h_next);
982 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
989 n_exit_iterations = MAX_EXIT_ITERATIONS;
992 h_start = -ex0 * (x1 - *x0) / (ex1 - ex0) * ITER_FACTOR;
995 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
997 if (!rk_qcstep(y2, &x2, y0, dydx0, h_start, &h_used, &h_next,
998 yscale, n_eq, derivs, misses))
999 bomb(
"step size too small (rk_odeint2--2)", NULL);
1001 (*derivs)(dydx2, y2, x2);
1002 ex2 = exit_value - y2[i_exit_value];
1003 if (FABS(ex2) < exit_accuracy) {
1004 for (i = 0; i < n_eq; i++)
1005 y_return[i] = y2[i];
1018 return (DIFFEQ_ZERO_FOUND);
1021 if (SIGN(ex1) == SIGN(ex2)) {
1023 SWAP_PTR(dydx1, dydx2);
1028 SWAP_PTR(dydx0, dydx2);
1032 }
while (n_exit_iterations--);
1033 return (DIFFEQ_EXIT_COND_FAILED);
1061 void (*derivs)(
double *dydx,
double *y,
double x),
1076 double *dydx2, *dydx1, *ytemp, *dydx0;
1077 double xh, hh, h6, x;
1081 return (DIFFEQ_XI_GT_XF);
1083 return (DIFFEQ_ZERO_STEPSIZE);
1084 if (!(n = (xf - x) / h + 0.5))
1088 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
1089 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
1090 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
1091 ytemp =
tmalloc(
sizeof(
double) * n_eq);
1097 for (j = 0; j < n; j++) {
1106 (*derivs)(dydx0, y0, x);
1107 for (i = n_eq; i >= 0; i--)
1108 ytemp[i] = y0[i] + hh * dydx0[i];
1111 (*derivs)(dydx1, ytemp, xh);
1112 for (i = n_eq; i >= 0; i--)
1113 ytemp[i] = y0[i] + hh * dydx1[i];
1116 (*derivs)(dydx2, ytemp, xh);
1117 for (i = n_eq; i >= 0; i--) {
1118 ytemp[i] = y0[i] + h * dydx2[i];
1119 dydx2[i] += dydx1[i];
1123 (*derivs)(dydx1, ytemp, x = xh + hh);
1124 for (i = n_eq; i >= 0; i--)
1125 y0[i] += h6 * (dydx0[i] + dydx1[i] + 2 * dydx2[i]);
1133 return (DIFFEQ_END_OF_INTERVAL);
1161 void (*derivs)(
double *dydx,
double *y,
double x),
1177 double (*exit_func)(
double *dydx,
double *y,
double x),
1179 double exit_accuracy
1181 static MDB_THREAD_LOCAL
double *y0 = NULL, *yscale = NULL;
1182 static MDB_THREAD_LOCAL
double *dydx0 = NULL, *y1 = NULL, *dydx1 = NULL, *dydx2 = NULL, *y2 = NULL, *accur = NULL;
1183 static MDB_THREAD_LOCAL
long last_neq = 0;
1184 double ex0, ex1, ex2, x1, x2;
1185 double h_used, h_next, xdiff;
1186 long i, n_exit_iterations, n_step_ups = 0;
1187#define MAX_N_STEP_UPS 10
1190 return (DIFFEQ_XI_GT_XF);
1191 if (FABS(*x0 - xf) < x_accuracy)
1192 return (DIFFEQ_SOLVED_ALREADY);
1206 for (i = 0; i < n_eq; i++) {
1207 if (accmode[i] < -1 || accmode[i] > 3)
1208 bomb(
"accmode must be on [-1, 3] (rk_odeint)", NULL);
1209 if (accmode[i] < 2 && tiny[i] < TINY)
1214 if (last_neq < n_eq) {
1215 if (last_neq != 0) {
1225 y0 =
tmalloc(
sizeof(
double) * n_eq);
1226 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
1227 y1 =
tmalloc(
sizeof(
double) * n_eq);
1228 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
1229 y2 =
tmalloc(
sizeof(
double) * n_eq);
1230 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
1231 yscale =
tmalloc(
sizeof(
double) * n_eq);
1232 accur =
tmalloc(
sizeof(
double) * n_eq);
1236 for (i = 0; i < n_eq; i++)
1240 (*derivs)(dydx0, y0, *x0);
1245 initial_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
1246 accuracy, accur, *x0, xf, n_eq);
1248 ex0 = (*exit_func)(dydx0, y0, *x0);
1252 if (FABS(ex0) < exit_accuracy) {
1253 for (i = 0; i < n_eq; i++)
1256 return (DIFFEQ_ZERO_FOUND);
1260 if ((xdiff = xf - *x0) < h_start)
1264 if (!rk_qcstep(y1, &x1, y0, dydx0, h_start, &h_used, &h_next,
1265 yscale, n_eq, derivs, misses)) {
1266 if (n_step_ups++ > MAX_N_STEP_UPS)
1267 bomb(
"error: cannot take initial step (rk_odeint3--1)", NULL);
1268 h_start = (n_step_ups - 1 ? h_start * 10 : h_used * 10);
1272 (*derivs)(dydx1, y1, x1);
1273 ex1 = (*exit_func)(dydx1, y1, x1);
1274 if (SIGN(ex0) != SIGN(ex1))
1277 if (FABS(xdiff = xf - x1) < x_accuracy) {
1279 for (i = 0; i < n_eq; i++)
1283 return (DIFFEQ_END_OF_INTERVAL);
1286 SWAP_PTR(dydx0, dydx1);
1291 h_start = (h_next > h_max ? (h_max ? h_max : h_next) : h_next);
1293 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
1299 printf(
"failure in rk_odeint3(): solution stepped outside interval\n");
1300 return (DIFFEQ_OUTSIDE_INTERVAL);
1303 if (FABS(ex1) < exit_accuracy) {
1304 for (i = 0; i < n_eq; i++)
1307 return (DIFFEQ_ZERO_FOUND);
1311 n_exit_iterations = MAX_EXIT_ITERATIONS;
1314 h_start = -ex0 * (x1 - *x0) / (ex1 - ex0) * ITER_FACTOR;
1317 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
1319 if (!rk_qcstep(y2, &x2, y0, dydx0, h_start, &h_used, &h_next,
1320 yscale, n_eq, derivs, misses))
1321 bomb(
"step size too small (rk_odeint3--2)", NULL);
1323 (*derivs)(dydx2, y2, x2);
1324 ex2 = (*exit_func)(dydx2, y2, x2);
1325 if (FABS(ex2) < exit_accuracy) {
1326 for (i = 0; i < n_eq; i++)
1329 return (DIFFEQ_ZERO_FOUND);
1332 if (SIGN(ex1) == SIGN(ex2)) {
1334 SWAP_PTR(dydx1, dydx2);
1339 SWAP_PTR(dydx0, dydx2);
1343 }
while (n_exit_iterations--);
1344 return (DIFFEQ_EXIT_COND_FAILED);
1377 void (*derivs)(
double *dydx,
double *y,
double x),
1395 double exit_accuracy,
1397 void (*store_data)(
double *dydx,
double *y,
double x,
double exf)
1399 double *y_return, *accur;
1400 double *dydx0, *y1, *dydx1, *dydx2, *y2;
1401 double ex0, ex1, ex2, x1, x2, *yscale;
1402 double h_used, h_next, xdiff;
1403 long i, n_exit_iterations, n_step_ups = 0, is_zero;
1404#define MAX_N_STEP_UPS 10
1407 return (DIFFEQ_XI_GT_XF);
1408 if (fabs(*x0 - xf) < x_accuracy)
1409 return (DIFFEQ_SOLVED_ALREADY);
1410 if (i_exit_value < 0 || i_exit_value >= n_eq)
1411 bomb(
"index of variable for exit testing is out of range (rk_odeint4)", NULL);
1425 for (i = 0; i < n_eq; i++) {
1426 if (accmode[i] < -1 || accmode[i] > 3)
1427 bomb(
"accmode must be on [-1, 3] (rk_odeint4)", NULL);
1428 if (accmode[i] < 2 && tiny[i] < TINY)
1434 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
1435 y1 =
tmalloc(
sizeof(
double) * n_eq);
1436 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
1437 y2 =
tmalloc(
sizeof(
double) * n_eq);
1438 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
1439 yscale =
tmalloc(
sizeof(
double) * n_eq);
1442 (*derivs)(dydx0, y0, *x0);
1447 accur =
tmalloc(
sizeof(
double) * n_eq);
1448 initial_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
1449 accuracy, accur, *x0, xf, n_eq);
1451 ex0 = exit_value - y0[i_exit_value];
1453 (*store_data)(dydx0, y0, *x0, ex0);
1457 if (fabs(ex0) < exit_accuracy) {
1459 if (n_to_skip == 0) {
1461 (*store_data)(dydx0, y0, *x0, ex0);
1462 for (i = 0; i < n_eq; i++)
1463 y_return[i] = y0[i];
1476 return (DIFFEQ_ZERO_FOUND);
1485 if ((xdiff = xf - *x0) < h_start)
1489 if (!rk_qcstep(y1, &x1, y0, dydx0, h_start, &h_used, &h_next,
1490 yscale, n_eq, derivs, misses)) {
1491 if (n_step_ups++ > MAX_N_STEP_UPS) {
1492 bomb(
"error: cannot take initial step (rk_odeint4--1)", NULL);
1494 h_start = (n_step_ups - 1 ? h_start * 10 : h_used * 10);
1498 (*derivs)(dydx1, y1, x1);
1499 ex1 = exit_value - y1[i_exit_value];
1501 (*store_data)(dydx1, y1, x1, ex1);
1503 if (SIGN(ex0) != SIGN(ex1) && !is_zero) {
1512 if (fabs(xdiff = xf - x1) < x_accuracy) {
1515 (*derivs)(dydx1, y1, x1);
1516 ex1 = exit_value - y0[i_exit_value];
1517 (*store_data)(dydx1, y1, x1, ex1);
1519 for (i = 0; i < n_eq; i++)
1520 y_return[i] = y1[i];
1534 return (DIFFEQ_END_OF_INTERVAL);
1537 SWAP_PTR(dydx0, dydx1);
1542 h_start = (h_next > h_max ? (h_max ? h_max : h_next) : h_next);
1544 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
1550 n_exit_iterations = MAX_EXIT_ITERATIONS;
1553 h_start = -ex0 * (x1 - *x0) / (ex1 - ex0) * ITER_FACTOR;
1556 new_scale_factors_dp(yscale, y0, dydx0, h_start, tiny, accmode,
1558 if (!rk_qcstep(y2, &x2, y0, dydx0, h_start, &h_used, &h_next,
1559 yscale, n_eq, derivs, misses))
1560 bomb(
"step size too small (rk_odeint4--2)", NULL);
1562 (*derivs)(dydx2, y2, x2);
1563 ex2 = exit_value - y2[i_exit_value];
1564 if (fabs(ex2) < exit_accuracy) {
1565 for (i = 0; i < n_eq; i++)
1566 y_return[i] = y2[i];
1579 return (DIFFEQ_ZERO_FOUND);
1582 if (SIGN(ex1) == SIGN(ex2)) {
1584 SWAP_PTR(dydx1, dydx2);
1589 SWAP_PTR(dydx0, dydx2);
1593 }
while (n_exit_iterations--);
1594 return (DIFFEQ_EXIT_COND_FAILED);
1623 void (*derivs)(
double *dydx,
double *y,
double x),
1638 double (*exit_func)(
double *dydx,
double *y,
double x),
1640 double exit_accuracy,
1642 void (*stochastic)(
double *y,
double x,
double h)) {
1643 static MDB_THREAD_LOCAL
double *y0 = NULL, *yscale = NULL;
1644 static MDB_THREAD_LOCAL
double *dydx0 = NULL, *y1 = NULL, *dydx1 = NULL, *dydx2 = NULL, *y2 = NULL, *accur = NULL;
1645 static MDB_THREAD_LOCAL
long last_neq = 0;
1646 double ex0, ex1, ex2, x1, x2;
1648 long i, n_exit_iterations;
1649#define MAX_N_STEP_UPS 10
1652 return (DIFFEQ_XI_GT_XF);
1653 if (FABS(*x0 - xf) < x_accuracy)
1654 return (DIFFEQ_SOLVED_ALREADY);
1656 if (last_neq < n_eq) {
1657 if (last_neq != 0) {
1667 y0 =
tmalloc(
sizeof(
double) * n_eq);
1668 dydx0 =
tmalloc(
sizeof(
double) * n_eq);
1669 y1 =
tmalloc(
sizeof(
double) * n_eq);
1670 dydx1 =
tmalloc(
sizeof(
double) * n_eq);
1671 y2 =
tmalloc(
sizeof(
double) * n_eq);
1672 dydx2 =
tmalloc(
sizeof(
double) * n_eq);
1676 for (i = 0; i < n_eq; i++)
1680 (*derivs)(dydx0, y0, *x0);
1682 ex0 = (*exit_func)(dydx0, y0, *x0);
1686 if (FABS(ex0) < exit_accuracy) {
1687 for (i = 0; i < n_eq; i++)
1689 return (DIFFEQ_ZERO_FOUND);
1693 if ((xdiff = xf - *x0) < h_step)
1697 rk4_step(y1, x1, y0, dydx0, h_step, n_eq, derivs);
1700 (*stochastic)(y1, x1, h_step);
1703 (*derivs)(dydx1, y1, x1);
1704 ex1 = (*exit_func)(dydx1, y1, x1);
1705 if (SIGN(ex0) != SIGN(ex1))
1708 if (FABS(xdiff = xf - x1) < x_accuracy) {
1710 for (i = 0; i < n_eq; i++)
1713 return (DIFFEQ_END_OF_INTERVAL);
1716 SWAP_PTR(dydx0, dydx1);
1723 printf(
"failure in rk_odeint3_na(): solution stepped outside interval\n");
1724 return (DIFFEQ_OUTSIDE_INTERVAL);
1727 if (FABS(ex1) < exit_accuracy) {
1728 for (i = 0; i < n_eq; i++)
1731 return (DIFFEQ_ZERO_FOUND);
1735 n_exit_iterations = MAX_EXIT_ITERATIONS;
1739 h_step = -ex0 * (x1 - *x0) / (ex1 - ex0) * ITER_FACTOR;
1741 rk4_step(y2, x2, y0, dydx0, h_step, n_eq, derivs);
1744 (*derivs)(dydx2, y2, x2);
1745 ex2 = (*exit_func)(dydx2, y2, x2);
1746 if (FABS(ex2) < exit_accuracy) {
1747 for (i = 0; i < n_eq; i++)
1750 return (DIFFEQ_ZERO_FOUND);
1753 if (SIGN(ex1) == SIGN(ex2)) {
1755 SWAP_PTR(dydx1, dydx2);
1760 SWAP_PTR(dydx0, dydx2);
1764 }
while (n_exit_iterations--);
1765 return (DIFFEQ_EXIT_COND_FAILED);
int tfree(void *ptr)
Frees a memory block and records the deallocation if tracking is enabled.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
long rk_odeint1(double *y0, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h_start, double h_max, double *h_rec)
Integrate ODEs without exit conditions or intermediate output.
long rk_odeint(double *y0, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h_start, double h_max, double *h_rec, double(*exit_func)(double *dydx, double *y, double x), double exit_accuracy, long n_to_skip, void(*store_data)(double *dydx, double *y, double x, double exval))
Integrate a set of ODEs until the upper limit or an exit condition is met.
long rk_odeint_na(double *y0, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h, double h_max, double *h_rec)
Integrate ODEs without adaptive step-size control.
long rk_odeint2(double *y0, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h_start, double h_max, double *h_rec, double exit_value, long i_exit_value, double exit_accuracy, long n_to_skip)
Integrate ODEs until a specific component reaches a target value.
long rk_odeint4(double *y0, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h_start, double h_max, double *h_rec, double exit_value, long i_exit_value, double exit_accuracy, long n_to_skip, void(*store_data)(double *dydx, double *y, double x, double exf))
Integrate ODEs until a specific component reaches a target value with intermediate storage.
long rk_odeint3(double *yif, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h_start, double h_max, double *h_rec, double(*exit_func)(double *dydx, double *y, double x), double exit_accuracy)
Integrate ODEs with an exit condition.
long rk_odeint3_na(double *yif, void(*derivs)(double *dydx, double *y, double x), long n_eq, double *accuracy, long *accmode, double *tiny, long *misses, double *x0, double xf, double x_accuracy, double h_step, double h_max, double *h_rec, double(*exit_func)(double *dydx, double *y, double x), double exit_accuracy, void(*stochastic)(double *y, double x, double h))
Integrate ODEs without adaptive step-size and with stochastic processes.