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--;
}
