戻る

2階微分方程式の初等的な数値解法

(=連立常微分方程式の数値解法)
!  results are output at  x = x0 + j*ans_dx (j=1, m) 
!   n : ans_dx/n = dx  in Runge Kutta integration
!      d(y1)/dx = func1( x, y1, y2 )
!      d(y2)/dx = func2( x, y1, y2 )
!  y1_0 and y2_0 are initial value at x0
というような仕様の Runge Kutta 法を用いたサンプルプログラムです。 ここでは、
! d^2 y / dx^2 + p dy/dx +qy = f( x )
!   y1 = y; y2 = dy/dx
!
!  d (y1)/dx = y2
!  d (y2)/dx = -p y2 - q y1 + f(x)
のような式を解いています。(2009.7)
ソースコード
program main
implicit none

  real :: x0, y1_0, y2_0, x_end, y1_end, y2_end, ans_dx
  real, external :: func1, func2
  integer :: i, n, m
 
!  results are output at  x = x0 + j*ans_dx (j=1, m) 
!   n : ans_dx/n = dx  in Runge Kutta integration
!      d(y1)/dx = func1( x, y1, y2 )
!      d(y2)/dx = func2( x, y1, y2 )
!  y1_0 and y2_0 are initial value at x0
!      
    ans_dx = 0.1
    m = (15*3.1415/ans_dx);  n=100

    x0=0; y1_0=0; y2_0=0;

   write(*,*) '# n  Euler  Runge-Kutta Answer'
   write(*,*) x0, y1_0, y2_0

    x_end=ans_dx
    do i=1, m
     call dbl_rk(x0, y1_0, y2_0, n, x_end, func1, func2,  y1_end, y2_end)
     write(*,*) x_end, y1_end, y2_end
     x0 = x_end; x_end=x0+ans_dx
     y1_0  = y1_end; y2_0 = y2_end
    end do

end


subroutine dbl_rk( x0, y1_0, y2_0, n, x_end, f1, f2, y1_end, y2_end)
implicit none
  real :: x0, y1_0, y2_0, x_end, y1_end, y2_end
  real, external :: f1, f2
  real ::  k11, k12, k13, k14
  real ::  k21, k22, k23, k24
  real :: x, y1, y2, dx
  integer :: i, n

  dx = (x_end - x0)/n
  x=x0
  y1=y1_0; y2=y2_0
  do i=1, n
    k11 = dx * f1(x, y1, y2)
    k21 = dx * f2(x, y1, y2)
    k12 = dx * f1( x+dx/2, y1+k11/2, y2+k21/2 )
    k22 = dx * f2( x+dx/2, y1+k11/2, y2+k21/2 )
    k13 = dx * f1( x+dx/2, y1+k12/2, y2+k22/2 )
    k23 = dx * f2( x+dx/2, y1+k12/2, y2+k22/2 )
    k14 = dx * f1( x+dx  , y1+k13, y2+k23/2  )
    k24 = dx * f2( x+dx  , y1+k13, y2+k23/2  )
    y1 = y1 + (1.0/6.0)*(k11+2*k12+2*k13+k14)
    y2 = y2 + (1.0/6.0)*(k21+2*k22+2*k23+k24)
    x = x + dx
  end do
  y1_end=y1
  y2_end=y2

!  write(*,*) 'Rungekutta ', x0, dx, n, x_end, y_end
end subroutine

! d^2 y / dx^2 + p dy/dx +qy = f( x )
!   y1 = y; y2 = dy/dx
!
!  d (y1)/dx = y2
!  d (y2)/dx = -p y2 - q y1 + f(x)

real function func1(x, y1, y2)
real :: x, y1, y2

   func1 =  y2

end function

real function func2(x, y1, y2)
real :: x, y1, y2

   func2 =  -y1+sin((sqrt(3.0)/2.0)*x)

end function