Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Function 现代Fortran语言中二阶微分方程的通用runge-kutta函数_Function_Fortran_Numerical Methods_Runge Kutta - Fatal编程技术网

Function 现代Fortran语言中二阶微分方程的通用runge-kutta函数

Function 现代Fortran语言中二阶微分方程的通用runge-kutta函数,function,fortran,numerical-methods,runge-kutta,Function,Fortran,Numerical Methods,Runge Kutta,如何生成一个函数func2(func1,t,y0),该函数接收另一个函数func1作为参数,但其中func1是一个返回一维实数(kind=8)、维度(:)数组的函数 我有以下用Matlab编写的代码,为了速度和可移植性,我想用现代Fortran编写一个等效的代码。我已经为一阶微分方程写了一个,但是我正在努力为二阶和更高阶微分方程写代码,因为微分方程对应的外部变量必须返回一个维数为(:)的数组。我想要一个通用的代码,也就是说,我想要一个可以传递任何微分方程的函数或子程序 MatLab代码为: %-

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

我有以下用Matlab编写的代码,为了速度和可移植性,我想用现代Fortran编写一个等效的代码。我已经为一阶微分方程写了一个,但是我正在努力为二阶和更高阶微分方程写代码,因为微分方程对应的外部变量必须返回一个维数为(:)的数组。我想要一个通用的代码,也就是说,我想要一个可以传递任何微分方程的函数或子程序

MatLab代码为:

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

clear all
close all
clc

t = [0:0.01:20]';
y0 = [2, 0]';

y = func_runge_kutta(@func_my_ode,t,y0);

function dy=func_my_ode(t,y)
    % Second order differential equation y'' - (1-y^2)*y'+y = 0
    dy = zeros(size(y));
    dy(1) = y(2);
    dy(2) = (1-y(1)^2)*y(2)-y(1);
end

function y = func_runge_kutta(func_my_ode,t,y0)
    y = zeros(length(t),length(y0));
    y(1,:) = y0';
    for i=1:(length(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
end

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

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

clear all
close all
clc

t = [0:0.01:20]';
y0 = [2, 0]';

y = func_runge_kutta(@func_my_ode,t,y0);

function dy=func_my_ode(t,y)
    % Second order differential equation y'' - (1-y^2)*y'+y = 0
    dy = zeros(size(y));
    dy(1) = y(2);
    dy(2) = (1-y(1)^2)*y(2)-y(1);
end

function y = func_runge_kutta(func_my_ode,t,y0)
    y = zeros(length(t),length(y0));
    y(1,:) = y0';
    for i=1:(length(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
end
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程序相同的图片,如果它绘制了结果。

那么,你的问题是“如何编写一个Fortran函数来返回自动大小的1D数组?”不是真的,我的问题是如何生成函数func2(func1,t,y0)它接收另一个函数func1作为参数,但其中func1是一个返回一维实数(种类=8),维度(:)数组的函数。到目前为止,您尝试了什么?对于一阶微分方程,即func1返回单个实数值时,我有以下代码。但是,当我使用返回数组的func1尝试以下代码时,编译器会抱怨不匹配。我也不接受维数为的外部变量。函数func_runge_kutta(func,t,y0)结果(y)!i/o变量real(8),external::func real(8),allocatable,intent(in)::t(:)real(8),intent(in)::y0 real(8),allocatable::y(:)!内部变量。。。结束函数func_runge_kutta+1。如果您在模块中为
func\u my\u ode\u 1
使用一个接口块,并将程序中声明的匹配过程作为参数传递给
func\u runge\u kutta
,则会更清楚,这样OP就会知道该函数是泛型的,以及在一般情况下如何使用它。