SDDSlib
Loading...
Searching...
No Matches
mmid.c File Reference

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

#include "mdb.h"

Go to the source code of this file.

Macros

#define MAX_EXIT_ITERATIONS   400
 
#define ITER_FACTOR   0.995
 
#define TINY   1.0e-30
 
#define MAX_N_STEP_UPS   10
 

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.
 

Detailed Description

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

This file implements the modified midpoint method for integrating ODEs, based on the algorithms presented in "Numerical Recipes in C" by Michael Borland (1995).

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.

Macro Definition Documentation

◆ ITER_FACTOR

#define ITER_FACTOR   0.995

Definition at line 23 of file mmid.c.

◆ MAX_EXIT_ITERATIONS

#define MAX_EXIT_ITERATIONS   400

Definition at line 22 of file mmid.c.

◆ TINY

#define TINY   1.0e-30

Definition at line 24 of file mmid.c.

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 double *ym, *yn;
55 static 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:59

◆ 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 double *yFinal2;
122 static long i, last_equations = 0;
123
124 if (steps % 2)
125 steps += 1;
126 if (steps < 8)
127 steps = 8;
128
129 if (equations > last_equations) {
130 if (last_equations) {
131 free(yFinal2);
132 }
133 /* allocate arrays for second solution */
134 yFinal2 = tmalloc(sizeof(*yFinal2) * equations);
135 last_equations = equations;
136 }
137
138 mmid(y, dydx, equations, x0, interval, steps, yFinal, derivs);
139 mmid(y, dydx, equations, x0, interval, steps / 2, yFinal2, derivs);
140 for (i = 0; i < equations; i++)
141 yFinal[i] = (4 * yFinal[i] - yFinal2[i]) / 3;
142}
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 173 of file mmid.c.

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