* dynamics-f.f ********************************************************************** ********************************************************************** * * 2 次元の定数係数線形常微分方程式 * x'(t) = a x + b y * y'(t) = c x + d y * に初期条件 * x(0)=x0 * y(0)=y0 * を課した常微分方程式の初期値問題を解いて、相図を描く。 * * このプログラムは次の4つの部分から出来ている。 * program dyna * 主プログラム * 行列の係数の入力、ウィンドウのオープン等の初期化をした後に、 * ユーザーにメニュー形式でコマンドを入力してもらう。 * 実際の計算のほとんどは他の副プログラムに任せている。 * subroutine draworbit(x0,y0,h,tlimit) * (x0,y0) を初期値とする解の軌道を描く。 * 刻み幅を h、追跡時間を tlimit とする。 * 近似解の計算には Runge-Kutta 法を用いる。 * function fx(x,y) * 微分方程式の右辺の x 成分 * function fy(x,y) * 微分方程式の右辺の y 成分 ********************************************************************** ********************************************************************** program dyna * 初期値 real x0,y0 * 時間の刻み幅、追跡時間 real h,tlimit,newh,newT * 係数行列 A の成分(common 文により function fx,fy と共有する) real a, b, c, d common /coef/a,b,c,d * ウィンドウに表示する範囲(common 文により draworbit と共有する) real xleft, xright, ybottom, ytop common /region/xleft, xright, ybottom, ytop * メニューに対して入力されるコマンドの番号 integer cmd * マウスのボタンの状態 integer lbut, mbut, rbut * ウィンドウに表示する範囲の設定 xleft = -1.0 xright = 1.0 ybottom = -1.0 ytop = 1.0 * 時間刻み幅、追跡時間(とりあえず設定) h=0.01 tlimit=10.0 * 行列の成分を入力 write(*,*) ' a,b,c,d=' read(*,*) a,b,c,d * ウィンドウを開く call openpl call fspace(xleft, ybottom, xright, ytop) * x 軸、y 軸を描く call fline(xleft, 0.0, xright, 0.0) call fline(0.0, ybottom, 0.0, ytop) call xsync * メイン・ループの入口 100 continue * メニューを表示して、何をするか、番号で選択してもらう write(*,*) ' したいことを番号で選んで下さい。' * write(*,*) ' -1:finish, 0:keyboard input x0,y0, 1:mouse input,' write(*,*) ' -1:メニュー終了, 0:初期値のキーボード入力,', - ' 1:初期値のマウス入力,' write(*,1000) h,tlimit 1000 format(' 2:change h,T(h=',f7.4,',T=',f7.4,')') * 1000 format(' 2:刻み幅,追跡時間変更(現在 h=',f7.4,',T=',f7.4,')') read(*,*) cmd * 番号 cmd に応じて、指示された仕事をする if (cmd .eq. 0) then * 初期値の入力 write(*,*) ' 初期値 x0,y0=' read(*,*) x0,y0 call draworbit(x0,y0,h,tlimit) else if (cmd .eq. 1) then * 200 continue write(*,*) 'マウスの左ボタンで初期値を指定して下さい', - '(右ボタンで中止)。' call fmouse(lbut, mbut, rbut, x0, y0) if (lbut .eq. 1) then write(*,*) '(x0,y0)=', x0,y0 call draworbit(x0,y0,h,tlimit) goto 200 else if (mbut .eq. 1) then write(*,*) '(x0,y0)=', x0,y0 call draworbit(x0,y0,-h,tlimit) goto 200 endif write(*,*) 'マウスによる初期値の入力を打ち切ります。' else if (cmd .eq. 2) then * 時間刻み幅、追跡時間の変更 write(*,*) ' 時間刻み幅 h, 追跡時間 T=' read(*,*) newh, newT if (newh .ne. 0 .and. newT .ne. 0) then h = newh tlimit = newT write(*,*) ' 新しい時間刻み幅 h = ', h, - ' 新しい追跡時間 T = ', tlimit else write(*,*) ' h=', h, ' T=', newT, ' は不適当です。' endif else if (cmd .eq. -1) then * 終了 -- メイン・ループを抜ける goto 999 endif * メイン・ループの先頭に戻る goto 100 * 999 continue call mkplot("dynamics-f.plot") write(*,*) 'fplotウィンドウを左ボタンでクリックして下さい' call closepl end ********************************************************************** ********************************************************************** * 指示された初期値に対する解軌道を描く subroutine draworbit(x0,y0,h,tlimit) real x0,y0,h,tlimit real x,y,fx,fy real k1x,k1y,k2x,k2y,k3x,k3y,k4x,k4y,t real xleft, xright, ybottom, ytop common /region/xleft, xright, ybottom, ytop * 時刻を 0 にセットする t = 0.0 * 初期値のセット x = x0 y = y0 * 初期点を描く call fpoint(x,y) * ループの入口 100 continue * Runge-Kutta 法による計算 * k1 の計算 k1x = h * fx(x, y) k1y = h * fy(x, y) * k2 の計算 k2x = h * fx(x + k1x / 2.0, y + k1y / 2.0) k2y = h * fy(x + k1x / 2.0, y + k1y / 2.0) * k3 の計算 k3x = h * fx(x + k2x / 2.0, y + k2y / 2.0) k3y = h * fy(x + k2x / 2.0, y + k2y / 2.0) * k4 の計算 k4x = h * fx(x + k3x, y + k3y) k4y = h * fy(x + k3x, y + k3y) * (Xn+1,Yn+1) の計算 x = x + (k1x + 2.0 * k2x + 2.0 * k3x + k4x) / 6.0 y = y + (k1y + 2.0 * k2y + 2.0 * k3y + k4y) / 6.0 * 解軌道を延ばす call fcont(x,y) * 時刻を 1 ステップ分進める t = t + h * まだ範囲内かどうかチェック if (abs(t) .le. abs(tlimit)) goto 100 * サブルーチンを抜ける 999 continue * 確実に描画が終るのを待つ call xsync end ********************************************************************* ********************************************************************* * 微分方程式の右辺のベクトル値関数 f の x 成分 real function fx(x,y) real x,y real a, b, c, d common /coef/a,b,c,d fx = a * x + b * y end * 微分方程式の右辺のベクトル値関数 f の y 成分 real function fy(x,y) real x,y real a, b, c, d common /coef/a,b,c,d fy = c * x + d * y end