後退差分公式を用いた常微分方程式

C言語によるサンプルソースコード : 使用関数名:nag_ode_ivp_bdf_gen (d02ejc)

ホーム > 製品 > nAG数値計算ライブラリ > サンプルソースコード集 > 後退差分公式を用いた常微分方程式 (C言語/C++)

Keyword: 後退差分公式, 常微分方程式

概要

本サンプルは後退差分公式を用いた常微分方程式を求めるC言語によるサンプルプログラムです。 本サンプルは以下に示される常微分方程式について5つのケースの計算をし、出力します。

後退差分公式を用いた常微分方程式のデータ 

※本サンプルはnAG Cライブラリに含まれる関数 nag_ode_ivp_bdf_gen() のExampleコードです。本サンプル及び関数の詳細情報は nag_ode_ivp_bdf_gen のマニュアルページをご参照ください。
ご相談やお問い合わせはこちらまで

出力結果

(本関数の詳細はnag_ode_ivp_bdf_gen のマニュアルページを参照)

この出力例をダウンロード
nag_ode_ivp_bdf_gen (d02ejc) Example Program Results

Case 1: calculating Jacobian internally
 intermediate output, root-finding


 Calculation with tol =    1.0e-03
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
(User-supplied callback g, first invocation.)
(User-supplied callback fcn, first invocation.)
    2.00       0.9416      0.00003       0.0583
    4.00       0.9055      0.00002       0.0945
  Root of Y(1)-0.9 at 4.377
  Solution is  0.9000  0.00002  0.1000

 Calculation with tol =    1.0e-04
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
    2.00       0.9416      0.00003       0.0584
    4.00       0.9055      0.00002       0.0945
  Root of Y(1)-0.9 at 4.377
  Solution is  0.9000  0.00002  0.1000

Case 2: calculating Jacobian by pederv
 intermediate output, root-finding


 Calculation with tol =    1.0e-03
     X         Y(1)         Y(2)         Y(3)
(User-supplied callback pederv, first invocation.)
    0.00       1.0000      0.00000       0.0000
    2.00       0.9416      0.00003       0.0583
    4.00       0.9055      0.00002       0.0945
  Root of Y(1)-0.9 at 4.377
  Solution is  0.9000  0.00002  0.1000

 Calculation with tol =    1.0e-04
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
    2.00       0.9416      0.00003       0.0584
    4.00       0.9055      0.00002       0.0945
  Root of Y(1)-0.9 at 4.377
  Solution is  0.9000  0.00002  0.1000

Case 3: calculating Jacobian internally
 no intermediate output, root-finding


 Calculation with tol =    1.0e-03
  Root of Y(1)-0.9 at 4.377
  Solution is  0.9000  0.00002  0.1000

 Calculation with tol =    1.0e-04
  Root of Y(1)-0.9 at 4.377
  Solution is  0.9000  0.00002  0.1000

Case 4: calculating Jacobian internally
 intermediate output, no root-finding


 Calculation with tol =    1.0e-03
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
    2.00       0.9416      0.00003       0.0583
    4.00       0.9055      0.00002       0.0945
    6.00       0.8793      0.00002       0.1207
    8.00       0.8586      0.00002       0.1414
   10.00       0.8414      0.00002       0.1586
   10.00       0.8414      0.00002       0.1586

 Calculation with tol =    1.0e-04
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
    2.00       0.9416      0.00003       0.0584
    4.00       0.9055      0.00002       0.0945
    6.00       0.8793      0.00002       0.1207
    8.00       0.8585      0.00002       0.1414
   10.00       0.8414      0.00002       0.1586
   10.00       0.8414      0.00002       0.1586

Case 5: calculating Jacobian internally
 no intermediate output, no root-finding (integrate to xend)


 Calculation with tol =    1.0e-03
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
   10.00       0.8414      0.00002       0.1586

 Calculation with tol =    1.0e-04
     X         Y(1)         Y(2)         Y(3)
    0.00       1.0000      0.00000       0.0000
   10.00       0.8414      0.00002       0.1586

  • 3〜21行目にはケース1の結果が出力されています。ケース1ではy=0.9となるデータ点が見つかるまで 2.0の間隔でx=10.0まで計算を行い、中間結果を出力しています。ヤコビ行列を数値的に計算しています。
  • 9〜11行目にxの値と許容値 1.0e-003 で計算したyの値が出力されています。
  • 12行目にy=0.9となるデータ点が出力されています。
  • 13行目に常微分方程式の解が出力されています。
  • 15〜19行目にxの値と許容値 1.0e-004 で計算したyの値が出力されています。
  • 20行目にy=0.9となるデータ点が出力されています。
  • 21行目に常微分方程式の解が出力されています。
  • 23〜41行目にはケース2の結果が出力されています。ケース2ではケース1と同様の計算を行い、中間結果を出力し解が見つかったら終了します。ヤコビ行列を分析的に計算しています。
  • 43〜53行目にケース3の結果が出力されています。ケース3ではケース1と同様の計算を行いますが、中間結果の出力を行わず、解が見つかったら終了します。
  • 55〜77行目にケース4の結果が出力されています。ケース4ではケース1と同様の計算を行いますが、中間結果を出力し、x=10.0まで計算を行っています。
  • 79〜91行目にケース5の結果が出力されています。ケース5ではケース1と同様の計算を行いますが中間結果の出力を行わず、x=10.0まで計算を行っています。

ソースコード

(本関数の詳細はnag_ode_ivp_bdf_gen のマニュアルページを参照)

※本サンプルソースコードはnAG数値計算ライブラリ(Windows, Linux, MAC等に対応)の関数を呼び出します。
サンプルのコンパイル及び実行方法


このソースコードをダウンロード
/* nag_ode_ivp_bdf_gen (d02ejc) Example Program.
 *
 * CLL6I261D/CLL6I261DL Version.
 *
 * Copyright 2017 Numerical Algorithms Group.
 *
 * Mark 26.1, 2017.
 *
 */

#include <nag.h>
#include <math.h>
#include <stdio.h>
#include <nag_stdlib.h>
#include <nagd02.h>

#ifdef __cplusplus
extern "C"
{
#endif
  static void nAG_CALL fcn(Integer neq, double x, const double y[],
                           double f[], Nag_User *comm);
  static void nAG_CALL pederv(Integer neq, double x, const double y[],
                              double pw[], Nag_User *comm);
  static double nAG_CALL g(Integer neq, double x, const double y[],
                           Nag_User *comm);
  static void nAG_CALL out(Integer neq, double *tsol, const double y[],
                           Nag_User *comm);
#ifdef __cplusplus
}
#endif

struct user
{
  double xend, h;
  Integer k;
  Integer *use_comm;
};

#define NEQ 3
int main(void)
{
  static Integer use_comm[4] = { 1, 1, 1, 1 };
  Integer exit_status = 0, j, neq;
  NagError fail;
  Nag_User comm;
  double tol, x, *y = 0;
  struct user s;

  INIT_FAIL(fail);

  printf("nag_ode_ivp_bdf_gen (d02ejc) Example Program Results\n");

  /* For communication with user-supplied functions
   * assign address of user defined structure
   * to comm.p.
   */
  s.use_comm = use_comm;
  comm.p = (Pointer) &s;

  neq = NEQ;
  if (neq >= 1) {
    if (!(y = nAG_ALLOC(neq, double)))
    {
      printf("Allocation failure\n");
      exit_status = -1;
      goto END;
    }
  }
  else {
    exit_status = 1;
    return exit_status;
  }
  s.xend = 10.0;
  printf("\nCase 1: calculating Jacobian internally\n");
  printf(" intermediate output, root-finding\n\n");

  for (j = 3; j <= 4; ++j) {
    tol = pow(10.0, -(double) j);
    printf("\n Calculation with tol = %10.1e\n", tol);
    x = 0.0;
    y[0] = 1.0;
    y[1] = 0.0;
    y[2] = 0.0;
    s.k = 4;
    s.h = (s.xend - x) / (double) (s.k + 1);
    printf("     X         Y(1)         Y(2)         Y(3)\n");
    /* nag_ode_ivp_bdf_gen (d02ejc).
     * Ordinary differential equations solver, stiff, initial
     * value problems using the Backward Differentiation
     * Formulae
     */
    nag_ode_ivp_bdf_gen(neq, fcn, NULLFN, &x, y, s.xend, tol, Nag_Relative,
                        out, g, &comm, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_bdf_gen (d02ejc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }
    printf("  Root of Y(1)-0.9 at %5.3f\n", x);
    printf("  Solution is ");
    printf("%7.4f %8.5f %7.4f\n", y[0], y[1], y[2]);
  }
  printf("\nCase 2: calculating Jacobian by pederv\n");
  printf(" intermediate output, root-finding\n\n");

  for (j = 3; j <= 4; ++j) {
    tol = pow(10.0, -(double) j);
    printf("\n Calculation with tol = %10.1e\n", tol);
    x = 0.0;
    y[0] = 1.0;
    y[1] = 0.0;
    y[2] = 0.0;
    s.k = 4;
    s.h = (s.xend - x) / (double) (s.k + 1);
    printf("     X         Y(1)         Y(2)         Y(3)\n");
    /* nag_ode_ivp_bdf_gen (d02ejc), see above. */
    nag_ode_ivp_bdf_gen(neq, fcn, pederv, &x, y, s.xend, tol, Nag_Relative,
                        out, g, &comm, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_bdf_gen (d02ejc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }
    printf("  Root of Y(1)-0.9 at %5.3f\n", x);
    printf("  Solution is ");
    printf("%7.4f %8.5f %7.4f\n", y[0], y[1], y[2]);
  }
  printf("\nCase 3: calculating Jacobian internally\n");
  printf(" no intermediate output, root-finding\n\n");
  for (j = 3; j <= 4; ++j) {
    tol = pow(10.0, -(double) j);
    printf("\n Calculation with tol = %10.1e\n", tol);
    x = 0.0;
    y[0] = 1.0;
    y[1] = 0.0;
    y[2] = 0.0;

    /* nag_ode_ivp_bdf_gen (d02ejc), see above. */
    nag_ode_ivp_bdf_gen(neq, fcn, NULLFN, &x, y, s.xend, tol, Nag_Relative,
                        NULLFN, g, &comm, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_bdf_gen (d02ejc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

    printf("  Root of Y(1)-0.9 at %5.3f\n", x);
    printf("  Solution is ");
    printf("%7.4f %8.5f %7.4f\n", y[0], y[1], y[2]);
  }
  printf("\nCase 4: calculating Jacobian internally\n");
  printf(" intermediate output, no root-finding\n\n");

  for (j = 3; j <= 4; ++j) {
    tol = pow(10.0, -(double) j);
    printf("\n Calculation with tol = %10.1e\n", tol);
    x = 0.0;
    y[0] = 1.0;
    y[1] = 0.0;
    y[2] = 0.0;
    s.k = 4;
    s.h = (s.xend - x) / (double) (s.k + 1);
    printf("     X         Y(1)         Y(2)         Y(3)\n");
    /* nag_ode_ivp_bdf_gen (d02ejc), see above. */
    nag_ode_ivp_bdf_gen(neq, fcn, NULLFN, &x, y, s.xend, tol, Nag_Relative,
                        out, NULLDFN, &comm, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_bdf_gen (d02ejc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }
    printf("%8.2f", x);
    printf("%13.4f%13.5f%13.4f\n", y[0], y[1], y[2]);
  }

  printf("\nCase 5: calculating Jacobian internally\n");
  printf(" no intermediate output, no root-finding (integrate to xend)\n\n");

  for (j = 3; j <= 4; ++j) {
    tol = pow(10.0, -(double) j);
    printf("\n Calculation with tol = %10.1e\n", tol);
    x = 0.0;
    y[0] = 1.0;
    y[1] = 0.0;
    y[2] = 0.0;
    printf("     X         Y(1)         Y(2)         Y(3)\n");
    printf("%8.2f", x);
    printf("%13.4f%13.5f%13.4f\n", y[0], y[1], y[2]);
    /* nag_ode_ivp_bdf_gen (d02ejc), see above. */
    nag_ode_ivp_bdf_gen(neq, fcn, NULLFN, &x, y, s.xend, tol, Nag_Relative,
                        NULLFN, NULLDFN, &comm, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_bdf_gen (d02ejc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }
    printf("%8.2f", x);
    printf("%13.4f%13.5f%13.4f\n", y[0], y[1], y[2]);
  }
END:
  nAG_FREE(y);
  return exit_status;
}

static void nAG_CALL fcn(Integer neq, double x, const double y[], double f[],
                         Nag_User *comm)
{
  struct user *s = (struct user *) comm->p;

  if (s->use_comm[0]) {
    printf("(User-supplied callback fcn, first invocation.)\n");
    s->use_comm[0] = 0;
  }

  f[0] = y[0] * -0.04 + y[1] * 1e4 * y[2];
  f[1] = y[0] * 0.04 - y[1] * 1e4 * y[2] - y[1] * 3e7 * y[1];
  f[2] = y[1] * 3e7 * y[1];
}

static void nAG_CALL pederv(Integer neq, double x, const double y[],
                            double pw[], Nag_User *comm)
{
#define PW(I, J) pw[((I) -1)*neq + (J) -1]
  struct user *s = (struct user *) comm->p;

  if (s->use_comm[1]) {
    printf("(User-supplied callback pederv, first invocation.)\n");
    s->use_comm[1] = 0;
  }

  PW(1, 1) = -0.04;
  PW(1, 2) = y[2] * 1e4;
  PW(1, 3) = y[1] * 1e4;
  PW(2, 1) = 0.04;
  PW(2, 2) = y[2] * -1e4 - y[1] * 6e7;
  PW(2, 3) = y[1] * -1e4;
  PW(3, 1) = 0.0;
  PW(3, 2) = y[1] * 6e7;
  PW(3, 3) = 0.0;
}

static double nAG_CALL g(Integer neq, double x, const double y[],
                         Nag_User *comm)
{
  struct user *s = (struct user *) comm->p;

  if (s->use_comm[2]) {
    printf("(User-supplied callback g, first invocation.)\n");
    s->use_comm[2] = 0;
  }

  return y[0] - 0.9;
}

static void nAG_CALL out(Integer neq, double *xsol, const double y[],
                         Nag_User *comm)
{
  struct user *s = (struct user *) comm->p;

  printf("%8.2f", *xsol);
  printf("%13.4f%13.5f%13.4f\n", y[0], y[1], y[2]);

  *xsol = s->xend - (double) s->k * s->h;
  s->k--;
}


関連情報
Privacy Policy  /  Trademarks