现代Fortran中用于二阶微分方程的通用Runge-kutta函数

时间:2018-06-30 13:47:09

标签: function fortran numerical-methods runge-kutta

如何使一个函数func2(func1,t,y0)接收另一个函数func1作为参数,但是其中func1是一个返回一维实数(kind = 8),dimension(:)数组的函数?

我用Matlab编写了以下代码,出于速度和便携性的考虑,我想在Modern Fortran中编写等效的代码。我已经为一阶微分方程编写了一个代码,但是由于为对应于微分方程的外部变量必须返回带有维数(:)的数组,因此我正在为编写用于二阶和更高阶微分方程的代码而奋斗。我希望代码具有通用性,即我想要一个可以传递任何微分方程的函数或子例程。

MatLab代码为:

%---------------------------------------------- -----------------------------

listOfList[0][0] = 0
listOfList[0][1] = 1
listOfList[0][2] = 2
listOfList[0][3] = 3
listOfList[0][4] = 4
listOfList[1][0] = 0
listOfList[1][1] = 1
listOfList[1][2] = 2
listOfList[1][3] = 3
listOfList[1][4] = 4
listOfList[2][0] = 0
listOfList[2][1] = 1
listOfList[2][2] = 2
listOfList[2][3] = 3
listOfList[2][4] = 4
listOfList[3][0] = 0
listOfList[3][1] = 1
listOfList[3][2] = 2
listOfList[3][3] = 3
listOfList[3][4] = 4

%---------------------------------------------- -----------------------------

1 个答案:

答案 0 :(得分:2)

如果函数返回数组,则其接口必须在调用方中是显式的。对于虚拟参数函数而言,最简单的方法是使用PROCEDURE语句从可用作实际参数的函数中克隆接口。从您的代码开始,翻译为Fortran并添加声明,我们得到:

module everything
   use ISO_FORTRAN_ENV, only : wp => REAL64
   implicit none
   contains
function func_my_ode_1(t,y) result(dy)
    ! Second order differential equation y'' - (1-y**2)*y'+y = 0
real(wp) t
real(wp) y(:)
real(wp) dy(size(y))
    dy(1) = y(2);
    dy(2) = (1-y(1)**2)*y(2)-y(1);
end

function func_runge_kutta(func_my_ode,t,y0) result(y)
   procedure(func_my_ode_1) func_my_ode
   real(wp) t(:)
   real(wp) y0(:)
   real(wp) y(size(t),size(y0))
   integer i
   real(wp) h
   real(wp) F_1(size(y0)),F_2(size(y0)),F_3(size(y0)),F_4(size(y0))
    y(1,:) = y0;
    do i=1,(size(t)-1)
        h = t(i+1)-t(i);
        F_1 = func_my_ode(t(i),y(i,:));
        F_2 = func_my_ode(t(i)+h/2,y(i,:)+h/2*F_1);
        F_3 = func_my_ode(t(i)+h/2,y(i,:)+h/2*F_2);
        F_4 = func_my_ode(t(i)+h,y(i,:)+h*F_3);
        y(i+1,:) = y(i,:)+h/6*(F_1+2*F_2+2*F_3+F_4);
    end do
end
end module everything

program main
!clear all
!close all
!clc
use everything
implicit none
real(wp), allocatable :: t(:)
real(wp), allocatable :: y0(:)
real(wp), allocatable :: y(:,:)
integer i
integer iunit

t = [(0+0.01_wp*i,i=0,nint(20/0.01_wp))];
y0 = [2, 0];

y = func_runge_kutta(func_my_ode_1,t,y0);
open(newunit=iunit,file='rk4.txt',status='replace')
do i = 1,size(t)
   write(iunit,*) t(i),y(i,1)
end do
end program main

我让Matlab读取了数据文件,并绘制了与原始Matlab程序相同的图片,并绘制了结果。