⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ode.c

📁 gridgen是一款强大的网格生成程序
💻 C
字号:
/****************************************************************************** * * File:           ode.c * * Created         27.06.2001 * * Author:         Pavel Sakov *                 CSIRO Marine Laboratories * * Purpose:        ODE integration. * * Description:    Contains dopri8 ODE integrator ported from FORTRAN77 *                 -- see E.Hairer, S.P. Norsett, G. Wanner, "Solving Ordinary *                 Differential Equations I. Nonstiff Problems",  *                 Springer-Verlag, 1987. * * Revisions:      none *	     *****************************************************************************/#include <stdlib.h>#include <stdio.h>#include <math.h>#include <limits.h>#include <float.h>#include "ode.h"#if !defined(max)#define max(x,y) ((x)>(y) ? (x) : (y) )#endif#if !defined(min)#define min(x,y) ((x)<(y) ? (x) : (y) )#endifint ode_silent = 0;int ode_stoponnan = 1;int ode_stoponlong = 1;static void stats(int nfcn, int nstep, int naccpt, int nrejct);/* dopri8(): * * Numerical solution of a system of first order ordinary differential * equations Y'=F(X,Y). This is an embedded Runge-Kutta method of order7(8) * due to Dormand & Prince (with stepsize control). *  * Ported from FORTRAN77 code. E.Hairer, S.P. Norsett, G. Wanner, "Solving * Ordinary Differential Equations I. Nonstiff Problems", Springer-Verlag, * 1987. *  * Excellent for intermediate precisions (1e-8 to 1e-13) and smooth functions. * * The call to `dopri8()' normally returns 1; 0 otherwise. * The integration results are stored in the function vector passed. The * procedure also stores the last valid stepsize in the initial stepsize * guess value passed so it could be used at the next call if necessary. * * NOTICE. The derivative arrays supplied as arguments to `calc' may contain * some noise, it is a duty of the derivative calculation routine to set ALL * of the return values. *//* Smallest number satisfying 1.0 + UROUND > 1.0. */#define UROUND 1.11e-16/* Maximal number of steps. */#define NMAX 2000/* Coefficients. */#define C2    (1.0 / 18.0)#define C3    (1.0 / 12.0)#define C4    (1.0 / 8.0)#define C5    (5.0 / 16.0)#define C6    (3.0 / 8.0)#define C7    (59.0 / 400.0)#define C8    (93.0 / 200.0)#define C9    (5490023248.0 / 9719169821.0)#define C10   (13.0 / 20.0)#define C11   (1201146811.0 / 1299019798.0)#define C12   (1.0)#define C13   (1.0)#define A21   (C2)#define A31   (1.0 / 48.0)#define A32   (1.0 / 16.0)#define A41   (1.0 / 32.0)#define A43   (3.0 / 32.0)#define A51   (5.0 / 16.0)#define A53   (-75.0 / 64.0)#define A54   (-A53)#define A61   (3.0 / 80.0)#define A64   (3.0 / 16.0)#define A65   (3.0 / 20.0)#define A71   (29443841.0 / 614563906.0)#define A74   (77736538.0 / 692538347.0)#define A75   (-28693883.0 / 1125.0e+6)#define A76   (23124283.0 / 18.0e+8)#define A81   (16016141.0 / 946692911.0)#define A84   (61564180.0 / 158732637.0)#define A85   (22789713.0 / 633445777.0)#define A86   (545815736.0 / 2771057229.0)#define A87   (-180193667.0 / 1043307555.0)#define A91   (39632708.0 / 573591083.0)#define A94   (-433636366.0 / 683701615.0)#define A95   (-421739975.0 / 2616292301.0)#define A96   (100302831.0 / 723423059.0)#define A97   (790204164.0 / 839813087.0)#define A98   (800635310.0 / 3783071287.0)#define A101  (246121993.0 / 1340847787.0)#define A104  (-37695042795.0 / 15268766246.0)#define A105  (-309121744.0 / 1061227803.0)#define A106  (-12992083.0 / 490766935.0)#define A107  (6005943493.0 / 2108947869.0)#define A108  (393006217.0 / 1396673457.0)#define A109  (123872331.0 / 1001029789.0)#define A111  (-1028468189.0 / 846180014.0)#define A114  (8478235783.0 / 508512852.0)#define A115  (1311729495.0 / 1432422823.0)#define A116  (-10304129995.0 / 1701304382.0)#define A117  (-48777925059.0 / 3047939560.0)#define A118  (15336726248.0 / 1032824649.0)#define A119  (-45442868181.0 / 3398467696.0)#define A1110 (3065993473.0 / 597172653.0)#define A121  (185892177.0 / 718116043.0)#define A124  (-3185094517.0 / 667107341.0)#define A125  (-477755414.0 / 1098053517.0)#define A126  (-703635378.0 / 230739211.0)#define A127  (5731566787.0 / 1027545527.0)#define A128  (5232866602.0 / 850066563.0)#define A129  (-4093664535.0 / 808688257.0)#define A1210 (3962137247.0 / 1805957418.0)#define A1211 (65686358.0 / 487910083.0)#define A131  (403863854.0 / 491063109.0)#define A134  (-5068492393.0 / 434740067.0)#define A135  (-411421997.0 / 543043805.0)#define A136  (652783627.0 / 914296604.0)#define A137  (11173962825.0 / 925320556.0)#define A138  (-13158990841.0 / 6184727034.0)#define A139  (3936647629.0 / 1978049680.0)#define A1310 (-160528059.0 / 685178525.0)#define A1311 (248638103.0 / 1413531060.0)#define B1    (14005451.0 / 335480064.0)#define B6    (-59238493.0 / 1068277825.0)#define B7    (181606767.0 / 758867731.0)#define B8    (561292985.0 / 797845732.0)#define B9    (-1041891430.0 / 1371343529.0)#define B10   (760417239.0 / 1151165299.0)#define B11   (118820643.0 / 751138087.0)#define B12   (-528747749.0 / 2220607170.0)#define B13   (1.0 / 4.0)#define BH1   (13451932.0 / 455176623.0)#define BH6   (-808719846.0 / 976000145.0)#define BH7   (1757004468.0 / 5645159321.0)#define BH8   (656045339.0 / 265891186.0)#define BH9   (-3867574721.0 / 1518517206.0)#define BH10  (465885868.0 / 322736535.0)#define BH11  (53011238.0 / 667516719.0)#define BH12  (2.0 / 45.0)int dopri8(fluxfn calc,         /* function computing the first derivatives */           int n,               /* dimension of the system */           double x,            /* initial X-value */           double* y,           /* Y-values */           double xend,         /* final X-value */           double eps,          /* local tolerance */           double hmax,         /* maximal stepsize */           double* h0,          /* initial stepsize guess */           intout out,          /* output procedure */           intfinal final,      /* final procedure */           void* custom_data){    /*     * number of function evaluations      */    int nfcn = 0;    /*     * number of computed steps      */    int nstep = 0;    /*     * number of accepted steps      */    int naccpt = 0;    /*     * Number of rejected steps. Please note that the number of rejected     * steps does not increase when Dopri8 has to reduce the initial step     * size, while the number of computed steps increases. Hence, it is     * possible to have nstep > naccpt + nrejct.      */    int nrejct = 0;    /*     * direction from x to xmax      */    double posneg = (xend > x) ? 1.0 : -1.0;    /*     * if the step has been rejected      */    int reject = 0;    /*     * work arrays      */    double* k = malloc(sizeof(double) * n * 8);    double* k1 = k;    double* k2 = &k[n];    double* k3 = &k[n * 2];    double* k4 = &k[n * 3];    double* k5 = &k[n * 4];    double* k6 = &k[n * 5];    double* k7 = &k[n * 6];    double* y1 = &k[n * 7];    double h = *h0;    /*     * flag -- whether the step has been truncated to match the end point      */    int trunc = 0;              /* init to eliminate gcc warning */    double xph, err, fac, hnew;    int i;    eps = max(eps, 13.0 * UROUND);    h = min(max(1.0e-10, fabs(h)), hmax) * posneg;    if (out != NULL)        out(1, n, x, y, custom_data);    /*     * main cycle      */    while (((x - xend) * posneg + UROUND) <= 0.0) {        if (ode_stoponlong && nstep > NMAX) {            if (!ode_silent) {                fprintf(stderr, "dopri8(): Could not proceed at x = %.5g: nstep > NMAX.\n", x);                stats(nfcn, nstep, naccpt, nrejct);            }            free(k);            return 0;        }        if ((x + 0.03 * h) == x) {            if (!ode_silent) {                fprintf(stderr, "dopri8(): Could not proceed at x = %.5g : (x + 0.03 * step) == x.\n", x);                stats(nfcn, nstep, naccpt, nrejct);            }            free(k);            return 0;        }        if (!reject) {            if (((x + h - xend) * posneg) > 0.0) {                h = xend - x;                trunc = 1;            } else                trunc = 0;            /*             * First nine stages.              */            calc(x, y, k1, custom_data);        }        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * A21 * k1[i];        calc(x + C2 * h, y1, k2, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A31 * k1[i] + A32 * k2[i]);        calc(x + C3 * h, y1, k3, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A41 * k1[i] + A43 * k3[i]);        calc(x + C4 * h, y1, k4, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A51 * k1[i] + A53 * k3[i] + A54 * k4[i]);        calc(x + C5 * h, y1, k5, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A61 * k1[i] + A64 * k4[i] + A65 * k5[i]);        calc(x + C6 * h, y1, k6, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A71 * k1[i] + A74 * k4[i] + A75 * k5[i] + A76 * k6[i]);        calc(x + C7 * h, y1, k7, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A81 * k1[i] + A84 * k4[i] + A85 * k5[i] + A86 * k6[i] + A87 * k7[i]);        calc(x + C8 * h, y1, k2, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A91 * k1[i] + A94 * k4[i] + A95 * k5[i] + A96 * k6[i] + A97 * k7[i] + A98 * k2[i]);        calc(x + C9 * h, y1, k3, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (A101 * k1[i] + A104 * k4[i] + A105 * k5[i] + A106 * k6[i] + A107 * k7[i] + A108 * k2[i] + A109 * k3[i]);        /*         * compute intermediate sums          */        for (i = 0; i < n; ++i) {            double y11s = A111 * k1[i] + A114 * k4[i] + A115 * k5[i] + A116 * k6[i] + A117 * k7[i] + A118 * k2[i] + A119 * k3[i];            double y12s = A121 * k1[i] + A124 * k4[i] + A125 * k5[i] + A126 * k6[i] + A127 * k7[i] + A128 * k2[i] + A129 * k3[i];            k4[i] = A131 * k1[i] + A134 * k4[i] + A135 * k5[i] + A136 * k6[i] + A137 * k7[i] + A138 * k2[i] + A139 * k3[i];            k5[i] = B1 * k1[i] + B6 * k6[i] + B7 * k7[i] + B8 * k2[i] + B9 * k3[i];            k6[i] = BH1 * k1[i] + BH6 * k6[i] + BH7 * k7[i] + BH8 * k2[i] + BH9 * k3[i];            k2[i] = y11s;            k3[i] = y12s;        }        /*         * last 4 stages          */        calc(x + C10 * h, y1, k7, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (k2[i] + A1110 * k7[i]);        calc(x + C11 * h, y1, k2, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (k3[i] + A1210 * k7[i] + A1211 * k2[i]);        xph = x + h;        calc(xph, y1, k3, custom_data);        for (i = 0; i < n; ++i)            y1[i] = y[i] + h * (k4[i] + A1310 * k7[i] + A1311 * k2[i]);        calc(xph, y1, k4, custom_data);        for (i = 0; i < n; ++i) {            k5[i] = h * (k5[i] + B10 * k7[i] + B11 * k2[i] + B12 * k3[i] + B13 * k4[i]);            k6[i] = k5[i] - h * (k6[i] + BH10 * k7[i] + BH11 * k2[i] + BH12 * k3[i]);            k5[i] += y[i];        }        nfcn += 13;        /*         * error estimation          */        err = 0.0;        for (i = 0; i < n; ++i) {            double denom = max(max(1.0e-6, fabs(k5[i])), max(fabs(y[i]), 2.0 * UROUND / eps));            denom = k6[i] / denom;            err += denom * denom;        }        err = sqrt(err / n);        if (isnan(err)) {            if (ode_stoponnan) {                if (!ode_silent)                    fprintf(stderr, "dopri8: Stopped: NaN detected\n");                free(k);                return 0;            }        }        /*         * New step size. We require 0.333 <= hnew / h <= 6.0.          */        if (isnan(err))            fac = 3.0;        else            fac = max(1.0 / 6.0, min(3.0, pow(err / eps, 0.125) / 0.9));        hnew = h / fac;        if (err < eps) {            naccpt++;            for (i = 0; i < n; ++i)                y[i] = k5[i];            x = xph;            if (out != NULL)                out(naccpt + 1, n, x, y, custom_data);            if (fabs(hnew) > hmax)                hnew = posneg * hmax;            if (reject)                hnew = posneg * min(fabs(hnew), fabs(h));            reject = 0;            h = hnew;            /*             * store back the step size if this step has not been truncated             * to match the end point or it was the first step              */            if (naccpt == 1 || !trunc)                *h0 = fabs(hnew);        } else {            reject = 1;            h = hnew;            if (naccpt >= 1)                nrejct++;            nfcn--;        }        nstep++;    }    if (final != NULL)        final(n, x, y, k1, naccpt, nrejct, nfcn, custom_data);    free(k);    return 1;}static void stats(int nfcn, int nstep, int naccpt, int nrejct){    fprintf(stderr, "  Number of function evaluations = %d.\n", nfcn);    fprintf(stderr, "  Number of computed steps = %d.\n", nstep);    fprintf(stderr, "  Number of accepted steps = %d.\n", naccpt);    fprintf(stderr, "  Number of rejected steps = %d.\n", nrejct);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -