module qRKmod
!developer => sikino
!date : 2016/07/30 (yyyy/mm/dd)
implicit none
interface qrkf45
module procedure &
qrkf451, &
zrkf451
end interface qrkf45
interface qrkf45_e
module procedure &
qrkf451_e, &
zrkf451_e
end interface qrkf45_e
!For Butcher table
integer,private::s
real*16,private,allocatable::a(:,:),b1(:),b2(:),c(:),Rc(:)
!-----------------------------
contains
subroutine qrk_preparation(method)
!set Butcher table
implicit none
character(*)::method
if(trim(method).eq."rk4")then
s=4
allocate(a(1:s,1:s),b1(1:s),c(1:s))
a=0q0; b1=0q0; c=0q0
c(1:4)=(/0q0,0.5q0,0.5q0,1q0/)
a(1,1:4)=(/0q0,0q0,0q0,0q0/)
a(2,1:4)=(/0.5q0,0q0,0q0,0q0/)
a(3,1:4)=(/0q0,0.5q0,0q0,0q0/)
a(4,1:4)=(/0q0,0q0,1q0,0q0/)
b1(1:4)=(/1q0/6q0, 1q0/3q0, 1q0/3q0, 1q0/6q0/)
elseif(trim(method).eq."rkf45")then
s=6
allocate(a(1:s,1:s),b1(1:s),b2(1:s),c(1:s),Rc(1:s))
a=0q0; b1=0q0; b2=0q0; c=0q0; Rc=0q0
c(1:6)=(/0q0, 0.25q0, 3q0/8q0, 12q0/13q0, 1q0, 0.5q0/)
a(1:6,1:6)=0q0
a(1,1:6)=(/0q0, 0q0, 0q0, 0q0, 0q0, 0q0/)
a(2,1:6)=(/0.25q0, 0q0, 0q0, 0q0, 0q0, 0q0/)
a(3,1:6)=(/0.09375q0, 0.28125q0, 0q0, 0q0, 0q0, 0q0/)
a(4,1:6)=(/1932q0/2197q0, -7200q0/2197q0, 7296q0/2197q0, 0q0, 0q0, 0q0/)
a(5,1:6)=(/439q0/216q0, -8q0, 3680q0/513q0, -845q0/4104q0, 0q0, 0q0/)
a(6,1:6)=(/-8q0/27q0, 2q0, -3544q0/2565q0, 1859q0/4104q0, -11q0/40q0, 0q0/)
b2(1:6)=(/16q0/135q0, 0q0, 6656q0/12825q0, 28561q0/56430q0, -9q0/50q0, 2q0/55q0/)
b1(1:6)=(/25q0/216q0, 0q0, 1408q0/2565q0, 2197q0/4104q0, -0.2q0, 0q0/)
Rc(1:6)=(/1q0/360q0,0q0,-128q0/4275q0,-2197q0/75240q0,1q0/50q0,2q0/55q0/)
else
write(6,*)"program stop at rk_preparation"
stop
end if
return
end subroutine qrk_preparation
!------------------------------
subroutine qrk_deallocation(method)
implicit none
character(*)::method
if(trim(method).eq."rk4")then
deallocate(a,b1,c)
elseif(trim(method).eq."rkf45")then
deallocate(a,b1,b2,c,Rc)
else
write(6,*)"program stop at rk_deallocation"
stop
end if
return
end subroutine qrk_deallocation
!-------------------
subroutine rk41_Nstep(func,Nstep,N,x,h,y)
implicit none
interface
function func(iN,ix,iy,is)
implicit none
integer,intent(in)::iN,is
real*16,intent(in)::ix,iy(1:iN)
real*16::func
end function func
end interface
integer,intent(in)::N,Nstep
real*16,intent(inout)::x,h,y(1:N)
integer::i,j,l
real*16::tx,tmp(1:N),K(1:s,1:N)
do l=1,Nstep
tx=x
do j=1,s
tx=x+c(j)*h
tmp(1:N)=y(1:N)
do i=1,j-1
tmp(1:N)=tmp(1:N)+K(i,1:N)*a(j,i)
enddo
do i=1,N
K(j,i)=h*func(N,tx,tmp,i)
enddo
enddo
x=x+h
do i=1,s
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
enddo
return
end subroutine rk41_Nstep
!-------------------
subroutine rk42_Nstep(func,Nstep,N,x,h,y,dy)
implicit none
interface
function func(iN,ix,iy,idy,isig,is)
implicit none
integer,intent(in)::iN,is,isig
real*16,intent(in)::ix,iy(1:iN),idy(1:iN)
real*16::func
end function func
end interface
integer,intent(in)::N,Nstep
real*16,intent(inout)::x,h,y(1:N),dy(1:N)
integer::i,j,l
real*16::tx,tmp(1:N),tmp2(1:N),K(1:2,1:s,1:N)
do l=1,Nstep
tx=x
do j=1,s
tx=x+c(j)*h
tmp(1:N)=y(1:N)
tmp2(1:N)=dy(1:N)
do i=1,j-1
tmp(1:N)=tmp(1:N)+K(1,i,1:N)*a(j,i)
tmp2(1:N)=tmp2(1:N)+K(2,i,1:N)*a(j,i)
enddo
do i=1,N
K(1,j,i)=h*func(N,tx,tmp,tmp2,1,i)
K(2,j,i)=h*func(N,tx,tmp,tmp2,2,i)
enddo
enddo
x=x+h
do i=1,s
y(1:N)=y(1:N)+b1(i)*K(1,i,1:N)
dy(1:N)=dy(1:N)+b1(i)*K(2,i,1:N)
enddo
enddo
return
end subroutine rk42_Nstep
!----------------
subroutine qrkf451(func,x,h,y,xbound,info,tol,SS)
!sikinote
! if h < hmin, propagate forcibly with warning.
!
!-----------------
!info = -1 (maybe path the discontinue points)
! = 0 (Running now)
! = 1 (x reach xbound)
!-----------------
!
! xbound
! /
! SS(i) = | func_i(x) dx
! /
! x
!
implicit none
interface
function func(iN,ix,iy,is)
implicit none
integer,intent(in)::iN,is
real*16,intent(in)::ix,iy(1:iN)
real*16::func
end function func
end interface
integer::N
real*16,intent(in)::xbound
real*16,intent(in)::tol
real*16,intent(out),optional::SS(:)
real*16,intent(inout)::x,h,y(:)
integer,intent(inout)::info
real*16,parameter::hmin=1q-25,hmax=1.q0
integer::i,j,FLAG,key
real*16::R,delta,tx,Sy,err
real*16,allocatable::tmp(:),K(:,:)
key=0
N=size(y,1)
allocate(tmp(1:N),K(1:s,1:N))
tmp=0q0; K=0q0
if(present(SS))SS(1:N)=0q0
if(abs(h).ge.hmax)then
h=sign(1q0,h)*hmax
endif
FLAG=1
if(abs(x-xbound).le.hmin*0.1q0)then
info=1
FLAG=0
endif
do while(FLAG.eq.1)
tx=x
do j=1,s
tx=x+c(j)*h
tmp(1:N)=y(1:N)
do i=1,j-1
tmp(1:N)=tmp(1:N)+K(i,1:N)*a(j,i)
enddo
do i=1,N
K(j,i)=h*func(N,tx,tmp,i)
enddo
enddo
!step 4
R=0q0
do i=1,N
R=R+(Rc(1)*K(1,i)+Rc(3)*K(3,i)+Rc(4)*K(4,i)+Rc(5)*K(5,i)+Rc(6)*K(6,i))**2
enddo
R=abs(sqrt(R)/h)
Sy=0q0
do i=1,N
Sy=Sy+(y(i)*y(i))
enddo
Sy=sqrt(Sy)
if(Sy.ge.1q0)then
err=tol*Sy
else
err=tol
endif
!step 5
if(R.le.err.or.key.eq.1)then
if(present(SS))then
SS(1:N)=0q0
x=x+h
do i=1,s
SS(1:N)=SS(1:N)+b1(i)*K(i,1:N)
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
else
x=x+h
do i=1,s
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
endif
FLAG=0
endif
!step 6
! Avoid zero deviding.
if(R.ge.1q-40)then
delta=(err/(2q0*R))**0.25q0
else
delta=4q0
endif
!step 7
if(delta.le.0.1q0)then
!function changes dramatically.
h=0.1q0*h
elseif(delta.ge.4q0)then
!function changes loosely.
h=4q0*h
else
!function changes moderately.
h=delta*h
endif
!step 8
if(abs(h).ge.hmax)then
h=sign(1q0,h)*hmax
elseif(abs(h).lt.hmin)then
h=sign(1q0,h)*hmin
key=1
endif
!step 9
if(abs(xbound-x).le.abs(h))then
h=xbound-x
if(abs(h).le.hmin)then
info=1
FLAG=0
endif
end if
if(h.le.0q0.and.xbound-x.ge.0q0)then
info=1
FLAG=0
elseif(h.ge.0q0.and.xbound-x.le.0q0)then
info=1
FLAG=0
endif
!if(FLAG.eq.1)write(6,*)"mis,h",h
enddo
if(key.eq.1)then
write(6,'(A,f10.5,A,f10.5)')"Maybe path the singlar, discontinue points, or computation error between ",x-h," and ",x
info=-1
endif
deallocate(tmp,K)
return
end subroutine qrkf451
!-------------------
subroutine qrkf451_e(func,x,y,xbound,info,tol,SS)
!sikinote
! propagate from y(x) to y(xbound) without interval
!
! info = -1 : h < hmin. Maybe path the singular point.
! = 1 : x reach xbound.
!
implicit none
interface
function func(iN,ix,iy,is)
implicit none
integer,intent(in)::iN,is
real*16,intent(in)::ix,iy(1:iN)
real*16::func
end function func
end interface
integer::N
real*16,intent(in)::xbound
real*16,intent(in)::tol
real*16,intent(out),optional::SS(:)
real*16,intent(inout)::x,y(:)
integer,intent(inout)::info
real*16,parameter::hmin=1q-25,hmax=1.q0
integer::i,j,FLAG,key,disc
real*16::R,delta,tx,Sy,err,h,h0
real*16,allocatable::tmp(:),K(:,:)
disc=0
key=0
h0=999q0
N=size(y,1)
allocate(tmp(1:N),K(1:s,1:N))
tmp=0q0; K=0q0
if(present(SS))SS(1:N)=0q0
h=xbound-x
if(abs(h).ge.hmax)then
if(h.le.0q0)then
h=-hmax
else
h=hmax
endif
endif
FLAG=1
if(abs(x-xbound).le.hmin*0.1q0)then
info=1
FLAG=0
endif
do while(FLAG.eq.1)
tx=x
do j=1,s
tx=x+c(j)*h
tmp(1:N)=y(1:N)
do i=1,j-1
tmp(1:N)=tmp(1:N)+K(i,1:N)*a(j,i)
enddo
do i=1,N
K(j,i)=h*func(N,tx,tmp,i)
enddo
enddo
!step 4
R=0q0
do i=1,N
R=R+(Rc(1)*K(1,i)+Rc(3)*K(3,i)+Rc(4)*K(4,i)+Rc(5)*K(5,i)+Rc(6)*K(6,i))**2
enddo
R=abs(sqrt(R)/h)
Sy=0q0
do i=1,N
Sy=Sy+(y(i)*y(i))
enddo
Sy=sqrt(Sy)
if(Sy.ge.1q0)then
err=tol*Sy
else
err=tol
endif
!step 5
if(R.le.err.or.key.eq.1)then
if(present(SS))then
x=x+h
do i=1,s
SS(1:N)=SS(1:N)+b1(i)*K(i,1:N)
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
else
x=x+h
do i=1,s
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
endif
key=0
endif
!step 6
! Avoid zero deviding.
if(R.ge.1q-40)then
delta=(err/(2q0*R))**0.25q0
else
delta=4q0
endif
!step 7
if(delta.le.0.1q0)then
!function changes dramatically.
h=0.1q0*h
elseif(delta.ge.4q0)then
!function changes loosely.
h=4q0*h
else
!function changes moderately.
h=delta*h
endif
!step 8
if(abs(h).ge.hmax)then
h=sign(1q0,h)*hmax
elseif(abs(h).lt.hmin)then
h=sign(1q0,h)*hmin
key=1
disc=1
endif
!step 9
if(abs(xbound-x).le.abs(h))then
h=xbound-x
if(abs(h).le.hmin)then
info=1
FLAG=0
endif
end if
enddo
if(disc.eq.1)then
info=-1
endif
deallocate(tmp,K)
return
end subroutine qrkf451_e
!-----------------------
subroutine zrkf451(func,x,h,y,xbound,info,tol,SS)
!sikinote
! if h < hmin, propagate forcibly with warning.
!
!-----------------
!info = -1 (maybe path the discontinue points)
! = 0 (Running now)
! = 1 (x reach xbound)
!-----------------
!
! xbound
! /
! SS(i) = | func_i(x) dx
! /
! x
!
implicit none
interface
function func(iN,ix,iy,is)
implicit none
integer,intent(in)::iN,is
real*16,intent(in)::ix
complex*32,intent(in)::iy(1:iN)
complex*32::func
end function func
end interface
integer::N
real*16,intent(in)::xbound
real*16,intent(in)::tol
complex*32,intent(out),optional::SS(:)
real*16,intent(inout)::x,h
complex*32,intent(inout)::y(:)
integer,intent(inout)::info
real*16,parameter::hmin=1q-25,hmax=1.q0
integer::i,j,FLAG,key
real*16::R,delta,tx,Sy,err
complex*32,allocatable::tmp(:),K(:,:)
key=0
N=size(y,1)
allocate(tmp(1:N),K(1:s,1:N))
tmp=cmplx(0q0,0q0,kind=16); K=cmplx(0q0,0q0,kind=16)
if(present(SS))SS(1:N)=cmplx(0q0,0q0,kind=16)
if(abs(h).ge.hmax)then
h=sign(1q0,h)*hmax
endif
FLAG=1
if(abs(x-xbound).le.hmin*0.1q0)then
info=1
FLAG=0
endif
do while(FLAG.eq.1)
tx=x
do j=1,s
tx=x+c(j)*h
tmp(1:N)=y(1:N)
do i=1,j-1
tmp(1:N)=tmp(1:N)+K(i,1:N)*a(j,i)
enddo
do i=1,N
K(j,i)=h*func(N,tx,tmp,i)
enddo
enddo
!step 4
R=0q0
do i=1,N
R=R+abs(Rc(1)*K(1,i)+Rc(3)*K(3,i)+Rc(4)*K(4,i)+Rc(5)*K(5,i)+Rc(6)*K(6,i))**2
enddo
R=sqrt(R)/h
Sy=0q0
do i=1,N
Sy=Sy+abs(y(i))**2
enddo
Sy=sqrt(Sy)
if(Sy.ge.1q0)then
err=tol*Sy
else
err=tol
endif
!step 5
if(R.le.err.or.key.eq.1)then
if(present(SS))then
x=x+h
do i=1,s
SS(1:N)=SS(1:N)+b1(i)*K(i,1:N)
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
else
x=x+h
do i=1,s
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
endif
FLAG=0
endif
!step 6
! Avoid zero deviding.
if(R.ge.1q-40)then
delta=(err/(2q0*R))**0.25q0
else
delta=4q0
endif
!step 7
if(delta.le.0.1q0)then
!function changes dramatically.
h=0.1q0*h
elseif(delta.ge.4q0)then
!function changes loosely.
h=4q0*h
else
!function changes moderately.
h=delta*h
endif
!step 8
if(abs(h).ge.hmax)then
h=sign(1q0,h)*hmax
elseif(abs(h).lt.hmin)then
h=sign(1q0,h)*hmin
key=1
endif
!step 9
if(abs(xbound-x).le.abs(h))then
h=xbound-x
if(abs(h).le.hmin)then
info=1
FLAG=0
endif
end if
if(h.le.0q0.and.xbound-x.ge.0q0)then
info=1
FLAG=0
elseif(h.ge.0q0.and.xbound-x.le.0q0)then
info=1
FLAG=0
endif
enddo
if(key.eq.1)then
write(6,'(A,f10.5,A,f10.5)')"Maybe path the singlar, discontinue points, or computation error between ",x-h," and ",x
info=-1
endif
deallocate(tmp,K)
return
end subroutine zrkf451
!-------------------
subroutine zrkf451_e(func,x,y,xbound,info,tol,SS)
!sikinote
! propagate from y(x) to y(xbound) without interval
!
! info = -1 : h < hmin. Maybe path the singular point.
! = 1 : x reach xbound.
!
implicit none
interface
function func(iN,ix,iy,is)
implicit none
integer,intent(in)::iN,is
real*16,intent(in)::ix
complex*32,intent(in)::iy(1:iN)
complex*32::func
end function func
end interface
integer::N
real*16,intent(in)::xbound
real*16,intent(in)::tol
complex*32,intent(out),optional::SS(:)
real*16,intent(inout)::x
complex*32,intent(inout)::y(:)
integer,intent(inout)::info
real*16,parameter::hmin=1q-25,hmax=1.q0
integer::i,j,FLAG,key,disc
real*16::R,delta,tx,Sy,err,h,h0
complex*32,allocatable::tmp(:),K(:,:)
disc=0
key=0
h0=999q0
N=size(y,1)
allocate(tmp(1:N),K(1:s,1:N))
tmp=cmplx(0q0,0q0,kind=16); K=cmplx(0q0,0q0,kind=16)
if(present(SS))SS(1:N)=cmplx(0q0,0q0,kind=16)
h=xbound-x
if(abs(h).ge.hmax)then
if(h.le.0q0)then
h=-hmax
else
h=hmax
endif
endif
FLAG=1
if(abs(x-xbound).le.hmin*0.1q0)then
info=1
FLAG=0
endif
do while(FLAG.eq.1)
tx=x
do j=1,s
tx=x+c(j)*h
tmp(1:N)=y(1:N)
do i=1,j-1
tmp(1:N)=tmp(1:N)+K(i,1:N)*a(j,i)
enddo
do i=1,N
K(j,i)=h*func(N,tx,tmp,i)
enddo
enddo
!step 4
R=0q0
do i=1,N
R=R+abs(Rc(1)*K(1,i)+Rc(3)*K(3,i)+Rc(4)*K(4,i)+Rc(5)*K(5,i)+Rc(6)*K(6,i))**2
enddo
R=sqrt(R)/h
Sy=0q0
do i=1,N
Sy=Sy+abs(y(i))**2
enddo
Sy=sqrt(Sy)
if(Sy.ge.1q0)then
err=tol*Sy
else
err=tol
endif
if(R.le.err.or.key.eq.1)then
if(present(SS))then
x=x+h
do i=1,s
SS(1:N)=SS(1:N)+b1(i)*K(i,1:N)
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
else
x=x+h
do i=1,s
y(1:N)=y(1:N)+b1(i)*K(i,1:N)
enddo
endif
key=0
endif
!step 6
! Avoid zero deviding.
if(R.ge.1q-40)then
delta=(err/(2q0*R))**0.25q0
else
delta=4q0
endif
!step 7
if(delta.le.0.1q0)then
!function changes dramatically.
h=0.1q0*h
elseif(delta.ge.4q0)then
!function changes loosely.
h=4q0*h
else
!function changes moderately.
h=delta*h
endif
!step 8
if(abs(h).ge.hmax)then
h=sign(1q0,h)*hmax
elseif(abs(h).lt.hmin)then
h=sign(1q0,h)*hmin
key=1
disc=1
endif
!step 9
if(abs(xbound-x).le.abs(h))then
h=xbound-x
if(abs(h).le.hmin)then
info=1
FLAG=0
endif
end if
enddo
if(disc.eq.1)then
info=-1
endif
deallocate(tmp,K)
return
end subroutine zrkf451_e
end module qRKmod