SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
mmid.c File Reference

Detailed Description

Modified midpoint method for integrating ordinary differential equations (ODEs).

This file implements the modified midpoint method for integrating ODEs, based on algorithms presented in "Numerical Recipes in C" by Press et al.

License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
M. Borland, C. Saunders, R. Soliday

Definition in file mmid.c.

#include "mdb.h"

Go to the source code of this file.

Functions

void mmid (double *yInitial, double *dydxInitial, long equations, double xInitial, double interval, long steps, double *yFinal, void(*derivs)(double *_dydx, double *_y, double _x))
 Integrates a system of ODEs using the modified midpoint method.
 
void mmid2 (double *y, double *dydx, long equations, double x0, double interval, long steps, double *yFinal, void(*derivs)(double *_dydx, double *_y, double _x))
 Enhances the modified midpoint method with error correction.
 
long mmid_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)
 Integrates ODEs until a condition is met or the interval is reached.
 

Function Documentation

◆ mmid()

void mmid ( double * yInitial,
double * dydxInitial,
long equations,
double xInitial,
double interval,
long steps,
double * yFinal,
void(* derivs )(double *_dydx, double *_y, double _x) )

Integrates a system of ODEs using the modified midpoint method.

This function performs numerical integration of a system of ordinary differential equations using the modified midpoint method. It computes the final values of the dependent variables after a specified number of steps over a given interval.

Parameters
yInitialStarting values of dependent variables.
dydxInitialDerivatives of the dependent variables at the initial point.
equationsNumber of equations in the system.
xInitialStarting value of the independent variable.
intervalSize of the integration interval in the independent variable.
stepsNumber of steps to divide the interval into.
yFinalArray to store the final values of the dependent variables.
derivsFunction pointer to compute derivatives.

Definition at line 42 of file mmid.c.

51 {
52 long i, j;
53 double x = 0, ynSave, h, hTimes2;
54 static MDB_THREAD_LOCAL double *ym = NULL, *yn = NULL;
55 static MDB_THREAD_LOCAL long last_equations = 0;
56 double *dydxTemp;
57
58 if (equations > last_equations) {
59 if (last_equations) {
60 free(ym);
61 free(yn);
62 }
63 /* allocate arrays for solutions at two adjacent points in x */
64 ym = tmalloc(sizeof(*ym) * equations);
65 yn = tmalloc(sizeof(*yn) * equations);
66 last_equations = equations;
67 }
68
69 hTimes2 = (h = interval / steps) * 2;
70
71 /* Copy starting values and compute first set of estimated values */
72 for (i = 0; i < equations; i++) {
73 ym[i] = yInitial[i];
74 yn[i] = yInitial[i] + h * dydxInitial[i];
75 }
76
77 dydxTemp = yFinal; /* use yFinal for temporary storage */
78 for (j = 1; j < steps; j++) {
79 x = xInitial + h * j;
80 (*derivs)(dydxTemp, yn, x);
81 for (i = 0; i < equations; i++) {
82 ynSave = yn[i];
83 yn[i] = ym[i] + hTimes2 * dydxTemp[i];
84 ym[i] = ynSave;
85 }
86 }
87
88 /* Compute final values */
89 (*derivs)(dydxTemp, yn, x + interval);
90 for (i = 0; i < equations; i++)
91 yFinal[i] = (ym[i] + yn[i] + h * dydxTemp[i]) / 2;
92}
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:65

◆ mmid2()

void mmid2 ( double * y,
double * dydx,
long equations,
double x0,
double interval,
long steps,
double * yFinal,
void(* derivs )(double *_dydx, double *_y, double _x) )

Enhances the modified midpoint method with error correction.

This function applies the modified midpoint method with an additional correction step to improve the accuracy of the integration. It performs integration with a specified number of steps and then refines the result by integrating with half the number of steps, combining both results to achieve higher precision.

Parameters
yStarting values of dependent variables.
dydxDerivatives of the dependent variables at the initial point.
equationsNumber of variables in the system.
x0Starting value of the independent variable.
intervalSize of the integration interval in the independent variable.
stepsNumber of steps to divide the interval into.
yFinalArray to store the final values of the dependent variables.
derivsFunction pointer to compute derivatives.

Definition at line 111 of file mmid.c.

120 {
121 static MDB_THREAD_LOCAL double *yFinal2 = NULL;
122 static MDB_THREAD_LOCAL long last_equations = 0;
123 long i;
124
125 if (steps % 2)
126 steps += 1;
127 if (steps < 8)
128 steps = 8;
129
130 if (equations > last_equations) {
131 if (last_equations) {
132 free(yFinal2);
133 }
134 /* allocate arrays for second solution */
135 yFinal2 = tmalloc(sizeof(*yFinal2) * equations);
136 last_equations = equations;
137 }
138
139 mmid(y, dydx, equations, x0, interval, steps, yFinal, derivs);
140 mmid(y, dydx, equations, x0, interval, steps / 2, yFinal2, derivs);
141 for (i = 0; i < equations; i++)
142 yFinal[i] = (4 * yFinal[i] - yFinal2[i]) / 3;
143}
void mmid(double *yInitial, double *dydxInitial, long equations, double xInitial, double interval, long steps, double *yFinal, void(*derivs)(double *_dydx, double *_y, double _x))
Integrates a system of ODEs using the modified midpoint method.
Definition mmid.c:42

◆ mmid_odeint3_na()

long mmid_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 )

Integrates ODEs until a condition is met or the interval is reached.

This function integrates a set of ordinary differential equations using the modified midpoint method until either the upper limit of the independent variable is reached or a user-supplied exit condition is satisfied (i.e., a specified function becomes zero).

Parameters
yifInitial and final values of dependent variables.
derivsFunction pointer to compute derivatives.
n_eqNumber of equations in the system.
accuracyDesired accuracy for each dependent variable.
accmodeDesired accuracy-control mode.
tinyIgnored parameter.
missesIgnored parameter.
x0Initial value of the independent variable (updated to final value).
xfUpper limit of integration for the independent variable.
x_accuracyDesired accuracy for the final value of the independent variable.
h_stepInitial step size for integration.
h_maxIgnored parameter.
h_recIgnored parameter.
exit_funcFunction to determine when to stop integration.
exit_accuracyDesired accuracy for the exit condition function.
Returns
  • Returns a positive value (>=1) on successful integration.
  • Returns 0 or a negative value on failure.
  • Specific return values indicate different outcomes, such as zero found or stepping outside the interval.

Definition at line 174 of file mmid.c.

194 {
195 static MDB_THREAD_LOCAL double *y0 = NULL, *yscale = NULL;
196 static MDB_THREAD_LOCAL double *dydx0 = NULL, *y1 = NULL, *dydx1 = NULL, *dydx2 = NULL, *y2 = NULL, *accur = NULL;
197 static MDB_THREAD_LOCAL long last_neq = 0;
198 double ex0, ex1, ex2, x1, x2;
199 double xdiff;
200 long i, n_exit_iterations;
201#define MAX_N_STEP_UPS 10
202
203 if (*x0 > xf)
204 return (DIFFEQ_XI_GT_XF);
205 if (FABS(*x0 - xf) < x_accuracy)
206 return (DIFFEQ_SOLVED_ALREADY);
207
208 if (last_neq < n_eq) {
209 if (last_neq != 0) {
210 tfree(y0);
211 tfree(dydx0);
212 tfree(y1);
213 tfree(dydx1);
214 tfree(y2);
215 tfree(dydx2);
216 tfree(yscale);
217 tfree(accur);
218 }
219 y0 = tmalloc(sizeof(double) * n_eq);
220 dydx0 = tmalloc(sizeof(double) * n_eq);
221 y1 = tmalloc(sizeof(double) * n_eq);
222 dydx1 = tmalloc(sizeof(double) * n_eq);
223 y2 = tmalloc(sizeof(double) * n_eq);
224 dydx2 = tmalloc(sizeof(double) * n_eq);
225 last_neq = n_eq;
226 }
227
228 for (i = 0; i < n_eq; i++)
229 y0[i] = yif[i];
230
231 /* calculate derivatives and exit function at the initial point */
232 (*derivs)(dydx0, y0, *x0);
233 ex0 = (*exit_func)(dydx0, y0, *x0);
234
235 do {
236 /* check for zero of exit function */
237 if (FABS(ex0) < exit_accuracy) {
238 for (i = 0; i < n_eq; i++)
239 yif[i] = y0[i];
240 return (DIFFEQ_ZERO_FOUND);
241 }
242
243 /* adjust step size to stay within interval */
244 if ((xdiff = xf - *x0) < h_step)
245 h_step = xdiff;
246 /* take a step */
247 x1 = *x0;
248 mmid2(y0, dydx0, n_eq, x1, h_step, 8, y1, derivs);
249 x1 += h_step;
250 /* calculate derivatives and exit function at new point */
251 (*derivs)(dydx1, y1, x1);
252 ex1 = (*exit_func)(dydx1, y1, x1);
253 if (SIGN(ex0) != SIGN(ex1))
254 break;
255 /* check for end of interval */
256 if (FABS(xdiff = xf - x1) < x_accuracy) {
257 /* end of the interval */
258 for (i = 0; i < n_eq; i++)
259 yif[i] = y1[i];
260 *x0 = x1;
261 return (DIFFEQ_END_OF_INTERVAL);
262 }
263 /* copy the new solution into the old variables */
264 SWAP_PTR(dydx0, dydx1);
265 SWAP_PTR(y0, y1);
266 ex0 = ex1;
267 *x0 = x1;
268 } while (1);
269
270 if (!exit_func) {
271 printf("failure in mmid_odeint3_na(): solution stepped outside interval\n");
272 return (DIFFEQ_OUTSIDE_INTERVAL);
273 }
274
275 if (FABS(ex1) < exit_accuracy) {
276 for (i = 0; i < n_eq; i++)
277 yif[i] = y1[i];
278 *x0 = x1;
279 return (DIFFEQ_ZERO_FOUND);
280 }
281
282 /* The root has been bracketed. */
283 n_exit_iterations = MAX_EXIT_ITERATIONS;
284 do {
285 /* try to take a step to the position where the zero is expected */
286 h_step = -ex0 * (x1 - *x0) / (ex1 - ex0) * ITER_FACTOR;
287 x2 = *x0;
288 mmid2(y0, dydx0, n_eq, x2, h_step, 8, y2, derivs);
289 x2 += h_step;
290 /* check the exit function at the new position */
291 (*derivs)(dydx2, y2, x2);
292 ex2 = (*exit_func)(dydx2, y2, x2);
293 if (FABS(ex2) < exit_accuracy) {
294 for (i = 0; i < n_eq; i++)
295 yif[i] = y2[i];
296 *x0 = x2;
297 return (DIFFEQ_ZERO_FOUND);
298 }
299 /* rebracket the root */
300 if (SIGN(ex1) == SIGN(ex2)) {
301 SWAP_PTR(y1, y2);
302 SWAP_PTR(dydx1, dydx2);
303 x1 = x2;
304 ex1 = ex2;
305 } else {
306 SWAP_PTR(y0, y2);
307 SWAP_PTR(dydx0, dydx2);
308 *x0 = x2;
309 ex0 = ex2;
310 }
311 } while (n_exit_iterations--);
312 return (DIFFEQ_EXIT_COND_FAILED);
313}
int tfree(void *ptr)
Frees a memory block and records the deallocation if tracking is enabled.
Definition array.c:243
void mmid2(double *y, double *dydx, long equations, double x0, double interval, long steps, double *yFinal, void(*derivs)(double *_dydx, double *_y, double _x))
Enhances the modified midpoint method with error correction.
Definition mmid.c:111