changeset 0:5bd0f2a15d2a

import from https://qiita.com/sakamoti/items/de851e0d07aeef5be310
author "uncorrelated zombie" <uncorrelated@yahoo.co.jp>
date Tue, 23 Jul 2024 02:30:57 +0900
parents
children 954faa9f6837
files .hgignore rkmain.f90 rungekutta.f90
diffstat 3 files changed, 135 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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
+
--- /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
--- /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