# HG changeset patch # User "uncorrelated zombie" # Date 1721669457 -32400 # Node ID 5bd0f2a15d2a2192efdcd4ddd7e93ef8dd52ed4c import from https://qiita.com/sakamoti/items/de851e0d07aeef5be310 diff -r 000000000000 -r 5bd0f2a15d2a .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Jul 23 02:30:57 2024 +0900 @@ -0,0 +1,4 @@ +syntax: glob +*.mod +*.o + diff -r 000000000000 -r 5bd0f2a15d2a rkmain.f90 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rkmain.f90 Tue Jul 23 02:30:57 2024 +0900 @@ -0,0 +1,31 @@ +program rkmain + use rungekutta !ルンゲクッタ解法をまとめたモジュール + implicit none + real(kind=dpkind),dimension(3) :: x !状態変数 + type(rk) :: rktype !ルンゲクッタ法ソルバに関連する型 + + !微分方程式の右辺を計算する関数、解法、時間刻みの指定 + call rktype%setup(rhside,"rk4",1d-5) + !初期値の指定 + x=[0.5e0,0.5e0,0.5e0] + !時刻0?50秒まで、0.01秒毎に標準出力へ書き出し。 + !ただし、内部的には刻み幅1e-5秒としている。 + do + if(rktype%time>5e1)exit + call rktype%solver(rktype%time+1e-2,x) !積分実行 + print*,rktype%time,x + enddo + !======================================== + contains + !微分方程式の右辺を定義 + function rhside(self,time,wk) + class(rk),intent(inout) :: self !parameter + real(kind=dpkind) :: time + real(kind=dpkind),dimension(:) :: wk + real(kind=dpkind),dimension(size(wk)) :: rhside + real(kind=dpkind),parameter :: a=10e0,b=28e0,c=8e0/3e0 + rhside(1)=a*(wk(2)-wk(1)) + rhside(2)=b*wk(1)-wk(2)-wk(1)*wk(3) + rhside(3)=wk(1)*wk(2)-c*wk(3) + end function +end program diff -r 000000000000 -r 5bd0f2a15d2a rungekutta.f90 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rungekutta.f90 Tue Jul 23 02:30:57 2024 +0900 @@ -0,0 +1,100 @@ +module rungekutta + use,intrinsic :: iso_fortran_env + private + !--- + integer,parameter,public :: dpkind=real64 + real(kind=dpkind),public,parameter :: PI=3.1415926535897932384626433_dpkind + !--- + type,public :: rk + real(kind=dpkind) :: time=0e0 !<險育ョ鈴幕蟋九°繧峨ョ邱冗オ碁℃譎る俣 + real(kind=dpkind) :: dt=1e-4 !<譎る俣蛻サ縺ソ + procedure(rhside),pass,pointer :: fun => null() + !<蠕ョ蛻譁ケ遞句シ上ョ蜿ウ霎コ繧定ィ育ョ励☆繧矩未謨ー + procedure(rksol),pass,pointer :: solver => null() + !<蠕ョ蛻譁ケ遞句シ上ョ隗」豕 + contains + final :: final_rk !<讒矩菴薙ョ繝輔ぃ繧、繝翫Λ繧、繧コ蜃ヲ逅 + procedure :: setup !<謨ー蛟、遨榊縺ョ蛻晄悄蛟、縲∬ァ」豕輔r繧サ繝繝医☆繧区焔邯壹″ + end type + !------------- + interface + !--- + ! Right hand side function interface + function rhside(self,time,wk) + import :: dpkind,rk + class(rk),intent(inout) :: self !parameter + real(kind=dpkind) :: time + real(kind=dpkind),dimension(:) :: wk + real(kind=dpkind),dimension(size(wk)) :: rhside + end function + !--- + ! Solver interface + subroutine rksol(self,tnext,wk) + import :: dpkind,rk + class(rk),intent(inout) :: self + real(kind=dpkind),intent(in) :: tnext !output time + real(kind=dpkind),dimension(:) :: wk + end subroutine + end interface + !============================-- + contains + !--- + pure elemental subroutine final_rk(self) + type(rk),intent(inout) :: self + if(associated(self%fun))nullify(self%fun) + if(associated(self%solver))nullify(self%solver) + end subroutine + !--- + subroutine setup(self,fun,solver,dt) + class(rk),intent(inout) :: self + procedure(rhside) :: fun !蠕ョ蛻譁ケ遞句シ上ョ蜿ウ霎コ繧定ィ育ョ励☆繧矩未謨ー + character(len=*),intent(in) :: solver !繧ス繝ォ繝舌シ縺ョ驕ク謚 + real(kind=dpkind),intent(in),optional :: dt !譎る俣蛻サ縺ソ蟷 + !譎る俣蛻サ縺ソ縺ョ繧サ繝繝 + if(present(dt))then + self%dt=dt + endif + self%fun=>fun + !繧ス繝ォ繝舌シ縺ョ驕ク謚 + select case(solver) + case("rk4") + !繝ォ繝ウ繧イ繧ッ繝繧ソ豕 + self%solver=>rk4 + case("rkf45") + !繝ォ繝ウ繧イ繧ッ繝繧ソ繝サ繝輔ぉ繝ォ繝吶Ν繧ー豕(蛻サ縺ソ蟷閾ェ蜍戊ェソ謨エ蝙) + !self%solver=>rkf45 + case default + write(error_unit,*) "solver must one of the 'rk4, rkf45'" + endselect + end subroutine + !--- + subroutine rk4(self,tn,wk) + class(rk),intent(inout) :: self + real(kind=dpkind),intent(in) :: tn !谺。縺ォ蜃コ蜉帙@縺溘>譎る俣 + real(kind=dpkind),dimension(:) :: wk + real(kind=dpkind),dimension(size(wk)) :: k1,k2,k3,k4 + real(kind=dpkind) :: dt_tmp + real(kind=dpkind) :: dthalf + associate(time=>self%time,dt=>self%dt) + dt_tmp=dt + do + if(time+dt>tn)dt_tmp=tn-time + dthalf=dt_tmp/2e0 + !!$OMP workshare + k1=self%fun(time,wk) + k2=self%fun(time+dthalf,wk+k1*dthalf) + k3=self%fun(time+dthalf,wk+k2*dthalf) + k4=self%fun(time+dt_tmp,wk+k3*dt_tmp) + !迥カ諷句、画焚繧呈峩譁ー + wk=wk+dt_tmp*(k1+2e0*k2+2e0*k3+k4)/6e0 + !!$OMP end workshare + !1繧ケ繝繝繝玲ャ。縺ョ隗」縺瑚ィ育ョ励〒縺阪◆縺ョ縺ァ縲∵凾髢薙r騾イ繧√k + time=time+dt_tmp + !譎る俣縺ョ險育ョ礼ッ蝗イ縺荊n繧定カ縺医◆繧芽ィ育ョ礼オゆコ + if(time>=tn)then + exit + endif + enddo + end associate + end subroutine +end module