Текст подпрограммы и версий
de01r_c.zip , de01d_c.zip , de85r_c.zip , de85d_c.zip
Тексты тестовых примеров
tde01r_c.zip , tde01d_c.zip , tde85r_c.zip , tde85d_c.zip

Подпрограмма:  de01r_c (версия de85r_c)

Назначение

Вычисление решения задачи Коши для устойчивой системы обыкновенных дифференциальных уравнений первого порядка с большой константой Липшица методом Лоусона.

Математическое описание

Решается задача Коши для устойчивой системы M обыкновенных дифференциальных уравнений первого порядка

(1)                             Y '  =  F(X, Y) ,

          Y  =  ( y1,..., yM ) ,   F  =  ( f1( X, y1,..., yM ),..., fM( X, y1,..., yM ) ) 

с начальными условиями, заданными в точке XN:

                         Y(XN)  =  YN ,   YN  =  ( y1,..., yM )  . 

Предполагается, что среди характеристических корней матрицы Якоби ∂F / ∂y функции F имеются большие по модулю корни. Решение вычисляется в одной точке XK, которая является концом интервала интегрирования. Предполагается также, что система (1) может быть достаточно хорошо аппроксимирована линейной однородной системой с кусочнопостоянными коэффициентами, т.е. на каждом из [ xn, xn + H ], на которые разбивается весь интервал интегрирования, она может быть аппроксимирована системой вида

                                     Y '  =   AY  , 

где A - постоянная матрица, вообще говоря, своя для каждого отрезка. Для интегрирования системы применяется метод Лоусона.

Метод Лоусона является одношаговым методом и заключается в следующем. Допустим, что искомое решение системы (1) уже вычислено в некоторой точке  x = xn  интервала интегрирования, т.е. известно  yn ≈ y(xn). Для отыскания решения  y(xn + 1) = y(xn + H) в следующем узле  xn + 1 = xn + H выполняются такие действия. Исходная система уравнений с помощью замены искомой функции  y (x) на  xn ≤ x ≤ xn + H  по формуле

                             y(x)  =  exp [ ( x - xn ) A0 ] Z(x)  ,

где A0 - некоторая постоянная матрица, преобразуется в систему уравнений относительно новой неизвестной функции Z(X):

(2) Z ' (x)  =  F1(x, z)  =  exp [ - ( x - xn ) A0 ] { F(x, exp [ ( x - xn ) A0 ] Z(x)) -
                                      - A0 exp [ ( x - xn ) A0 ] Z(x) } 

Матрица Якоби ∂ F1 / ∂Z системы (2) и матрица Якоби ∂F / ∂y системы (1) связаны между собой соотношением

         ∂ F1 / ∂Z  =  exp [ - (x - xn) A0] { ∂F / ∂y - A0 } exp [ ( x - xn ) A0 ] 

Указанное преобразование выполняется самой подпрограммой. В качестве матрицы A0 подпрограмма выбирает матрицу ∂F / ∂y, вычисленную либо в точке ( xn, yn ), либо в некоторой предыдущей точке ( xn - k, yn - k ). Если шаг H достаточно мал, то данное преобразование позволяет уменьшить характеристические корни матрицы ∂ F1 / ∂Z по сравнению с характеристическими корнями матрицы ∂F / ∂y. А это приводит к уменьшению константы Липшица системы (2) по сравнению с константой Липшица системы (1).

Для решения системы (2) применяются классический метод Рунге - Кутта четвертого порядка точности, причем одновременно с решением (2) производится обратное преобразование от функции Z (x) к функции Y (x).

Все компоненты решения вычисляются с контролем точности по мере погрешности, который заключается в следующем. Если некоторая компонента приближенного решения по абсолютной величине не меньше некоторой наперед заданной константы P, то контроль точности для этой компоненты ведется по относительной погрешности, иначе - по абсолютной. Абсолютная погрешность приближенного решения оценивается по правилу Рунге.

J.Douglas Lowson, Generalized Runge - Kutta processes for stable systems with large lipshitz constants, SIAM Journal on Numerical Analisys, 1967, Vol.4, No 3.

Использование

    int de01r_c (real *f, real *fj, integer *m, real *xn, real *yn,
                 real *xk, real *hmin, real *eps, real *p, integer *n, real *h, 
                 real *y, real *r, integer *ierr)

Параметры

f - подпрограмма вычисления правой части системы в точке x. Первый оператор подпрограммы должен иметь вид:
int f (float *x, float *y, float *dy, int *m).
Здесь x и y - значения независимой и зависимой переменных, соответственно. Вычисленное значение правой части должно быть помещено в dy. В случае системы уравнений, т.е. m ≠ 1, параметры y и dy представляют одномерные массивы длиной m (тип параметров x, y и dy: вещественный);
fj - подпрограмма вычисления матрицы Якоби правой части системы. Первый оператор подпрограммы должен иметь вид:
int fj (float *x, float *y, float *df, int *m).
Здесь x и y - значения независимой и зависимой переменных, соответственно, причем y представляет одномерный массив длины m. df - двумерный массив размера m*m. Вычисленное значение матрицы Якоби ∂F / ∂y должно быть помещено в массив df, при этом частная производная от правой части i - ого уравнения F по j - ой переменной y (j) запоминается в df (i, j), т.е. df (i, j) = ∂Fi / ∂yj (тип параметров x, y и df: вещественный);
m - количество уравнений в системе (тип: целый);
xn, yn - начальные значения аргумента и решения; в случае системы уравнений (т.е. m ≠ 1) yn представляет одномерный массив длины m;
xk - значение аргумента, при котором требуется вычислить решение задачи Коши (конец интервала интегрирования); xk может быть больше, меньше или равно xn (тип: вещественный);
hmin - минимальное значение абсолютной величины шага, которое разрешается использовать при интегрировании данной системы уравнений (тип: вещественный);
eps - допустимая мера погрешности, с которой требуется вычислить все компоненты решения (тип: вещественный);
p - граница перехода, используемая при оценке меры погрешности решения (тип: вещественный);
n - целый параметр, управляющий режимом вычисления матрицы A0 и имеющий следующие значения:
Если n ≤ 0 , (т.е. имеет произвольное отрицательное или нулевое значение), то матрица A0 вычисляется только один раз и полагается равной значению A0 = ∂F / ∂y в точке [x = x0, y = y0]  на протяжении всего интервала интегрировария;
если n > 0, то матрица A0 изменяется периодически, при этом она остается постоянной на протяжении каждого ряда из n последовательных шагов и вычисляется вновь на первом шаге каждого ряда, т.е. матрица A0 = ∂F / ∂y вычисляется только в следующих точках:
[x = x0, y = y0]   при x0 ≤ x ≤ xn;
[x = xn, y = yn]   при xn < x ≤ x2n;
[x = x2n, y = y2n]  при x2n < x≤ x3n;
Чем сильнее меняется матрица Якоби ∂F / ∂y системы при изменении  x, тем меньше должно быть значение параметра n. В частности, если n = 1, то матрица Якоби системы ∂F / ∂y будет вычисляться в каждой точке  xn,  yn .
h - вещественная переменная, содержащая начальное значение шага интегрирования; может задаваться с учетом направления интегрирования, т.е. положительным, если xn < xk, отрицательным, если xn > xk, или без всякого учета в виде абсолютной величины;
y - искомое решение задачи Коши, вычисленное подпрограммой при значении аргумента xk; для системы уравнений (когда m ≠ 1) задается одномерным массивом длины m. В случае совпадения значений параметров xn и xk значение y полагается равным начальному значению yn (тип: вещественный);
r - одномерный рабочий массив вещественного типа длины 5*m*m+7*m+1;
ierr - целая переменная, значение которой в результате работы подпрограммы полагается равным 65, если какая - нибудь компонента решения не может быть вычислена с требуемой точностью eps. В этом случае интегрирование системы прекращается; при желании интегрирование системы можно повторить обращением к подпрограмме с новыми значениями параметров hmin, h и n.

Версии

de01d_c - вычисление решения задачи Коши для устойчивой системы обыкновенных дифференциальных уравнений первого порядка с большой константой Липшица в конце интервала интегрирования методом Лоусона с удвоенным числом значащих цифр. При этом параметры xn, yn, xk, hmin, eps, p, h, y, r и параметры x, y, dy в подпрограмме f и x, y, df в подпрограмме fj должны иметь тип double;
de85r_c - вычисление решения задачи Коши для устойчивой системы обыкновенных дифференциальных уравнений первого порядка с большой константой Липшица в конце интервала интегрирования методом Лоусона. В отличии от подпрограммы de01r_c первый оператор подпрограммы de85r_c не содержит в списке формальных параметров имени подпрограммы вычисления матрицы Якоби и имеет следующий вид:
int de85r_c (real *f, integer *m, real *xn, real *yn, real *xk, real *hmin, real *eps, real *p, integer *n, real *h, real *y, real *r, integer *ierr)
При использовании этой подпрограммы пользователь не составляет подпрограмму вычисления матрицы Якоби. Все параметры подпрограммы de85r_c имеют тот же смысл, что и одноименные параметры подпрограммы de01r_c;
de85d_c - вычисление решения задачи Коши для устойчивой системы обыкновенных дифференциальных уравнений первого порядка с большой константой Липшица в конце интервала интервала интегрирования методом Лоусона с удвоенным числом значащих цифр. Первый оператор подпрограммы имеет тот же вид, что и в подпрограмме de85r_c, при этом параметры xn, yn, xk, hmin, eps, p, h, y, r и параметры x, y, dy в подпрограмме f должны иметь тип double.

Вызываемые подпрограммы

      de00r_c -
      de00d_c  
выполнение одного шага интегрирования системы обыкновенных дифференциальных первого порядка с большой константой Липшица методом Лоусона;
      utde20_c -
      utde21_c  
подпрограммы выдачи диагностических сообщений
  Подпрограммы de00r_c, utde20_c вызываются при работе подпрограммы de01r_c, а подпрограммы de00d_c, utde21_c - при работе de01d_c.

Замечания по использованию

 

Данная подпрограмма предназначена для интегрирования таких нелинейных систем, которые могут быть достаточно хорошо аппроксимированы линейной однородной системой с кусочнопостоянными коэффициентами, т.е. на каждом из отрезков [x, x + H] , на которые разбивается весь интервал интегрирования, они могут быть аппроксимированы системой вида

                     Y '  =  AY 

где A - постоянная матрица, вообще говоря, своя для каждого отрезка.

В общем случае заданная точность не гарантируется.

При работе подпрограммы значения параметров m, xn, yn, xk, hmin, eps, p, n сохраняются.

При работе подпрограмм f и fj значения параметров x, y, m не должны изменяться.

Если после работы подпрограммы нет необходимости иметь начальное значение решения yn, то параметры yn и y при обращении к ней можно совместить. При этом следует иметь в виду, что в случае аварийного выхода из подпрограммы, т.е. со значением ierr = 65, значение параметра yn будет испорчено.

Подпрограммы de01r_c и de01d_c предназначены также для решения задачи Коши для жестких дифференциальных уравнений (1).

Пример использования

                                     
     y1'  =  (- 500 + 2 x) y1  +  (1 - x /10 ) y2  +  (1 + 1/(x +    ) sin y1 ,
     y1(   = 49 
     y2'  =  (- 1000 - 10 x) y1  +  (1 + x /10 ) y2  +  (2  + 1/(x + 2) ) cos y2 ,
     y2(   = 50 

              1 ≤ x ≤ 6  

Приводятся подпрограммы вычисления правой части системы и матрицы Якоби правой части, а также фрагмент вызывающей программы и результаты счета.

int main(void)
{
    /* Local variables */
    extern int de01r_c(U_fp, U_fp, int *, float *, float *, float *,
                       float *, float *, float *, int *, float *, float *,
                       float *, int *);
    static float hmin;
    static int ierr;
    extern int f_c();
    static float h__;
    static int m, n;
    static float p, r__[35], y[2];
    extern int fj_c();
    static float xk, xn, yn[2], eps;

    m = 2;
    xn = 1.f;
    yn[0] = 49.f;
    yn[1] = 50.f;
    hmin = 1e-10f;
    eps = 1e-4f;
    p = 100.f;
    h__ = .01f;
    xk = 6.f;
    n = 2;
    de01r_c((U_fp)f_c, (U_fp)fj_c, &m, &xn, yn, &xk, &hmin, &eps, &p, &n,
            &h__, y, r__, &ierr);

    printf("\n %16.7e %16.7e \n", y[0], y[1]);
    printf("\n %16.7e \n", h__);
    printf("\n %5i \n", ierr);
    return 0;
} /* main */

int f_c(float *x, float *y, float *dy, int *m)
{
    /* Builtin functions */
    double sin(double), cos(double);

    /* Parameter adjustments */
    --dy;
    --y;

    /* Function Body */
    dy[1] = (*x * 2.f - 500.f) * y[1] + (1.f - *x * .1f) * y[2] +
            (1.f / (*x + 1.f) + 1.f) * (float)sin(y[1]);
    dy[2] = (-1e3f - *x * 10.f) * y[1] + (*x * .1f + 1.f) * y[2] +
            (1.f / (*x + 2.f) + 2.f) * (float)cos(y[2]);
    return 0;
} /* f_c */

int fj_c(float *x, float *y, float *df, int *m)
{
    /* Builtin functions */
    double cos(double), sin(double);

#define df_ref(a_1,a_2) df[(a_2)*2 + a_1]

    /* Parameter adjustments */
    df -= 3;
    --y;

    /* Function Body */
    df_ref(1, 1) = *x * 2.f - 500.f +
                   (1.f / (*x + 1.f) + 1.f) * (float)cos(y[1]);
    df_ref(1, 2) = 1.f - *x * .1f;
    df_ref(2, 1) = -1e3f - *x * 10.f;
    df_ref(2, 2) = *x * .1f + 1.f -
                   (1.f / (*x + 2.f) + 2.f) * (float)sin(y[2]);
    return 0;
} /* fj_c */


Результаты: 

             y(1)                                    y(2)                              h 
     -4.175740488392-02       -5.087148371158+01      2.500000000001-03 
      ierr = 0 

Результаты решения этой же задачи, полученные с помощью подпрограммы de85r_c

     -4.175740472033-02       -5.087148363417+01      5.000000000003-03 
      ierr = 0

Результаты решения этой же задачи, полученные с помощью подпрограммы de25r_c

     -4.175740429849-02       -5.087148203468+01      1.756831014061-03 
      ierr = 0