我有一个简单的一阶微分方程组在Matlab中求解。它看起来如下:
function passing
y0 = [0; 0];
t = 0:0.05:1;
y = myprocedure(@myfunc,0.05,t,y0);
myans = y'
end
function f = myfunc(t,y)
f = [-y(1) + y(2);
-0.8*t + y(2)];
end
function y=myprocedure(f,h,t,y0)
n = length(t);
y = zeros(length(y0),n);
y(:,1) = y0;
for i=1:n-1
k1 = f(t(i),y(:,i));
k2 = f(t(i)+h/2, y(:,i)+h/2*k1);
k3 = f(t(i)+h/2, y(:,i)+h/2*k2);
k4 = f(t(i)+h, y(:,i)+h*k3);
y(:,i+1) = y(:,i)+h/6*(k1+2*k2+2*k3+k4);
end
end
因此,在运行passing.m文件后,我得到了结果:
>> passing
myans =
0 0
-0.0000 -0.0010
-0.0001 -0.0041
-0.0005 -0.0095
-0.0011 -0.0171
-0.0021 -0.0272
-0.0036 -0.0399
-0.0058 -0.0553
-0.0086 -0.0735
-0.0123 -0.0946
-0.0169 -0.1190
-0.0225 -0.1466
-0.0293 -0.1777
-0.0374 -0.2124
-0.0469 -0.2510
-0.0579 -0.2936
-0.0705 -0.3404
-0.0849 -0.3917
-0.1012 -0.4477
-0.1196 -0.5086
-0.1402 -0.5746
现在,我正在尝试将passing.m代码转换为Fortran 90.我确实尝试了很多东西,但我仍然迷失了 - 特别是在进行数组初始化和将函数传递给其他函数时。
感谢任何帮助。谢谢!
==编辑:
我成功复制了Fortran 90中的上述Matlab代码。我仍然不知道如何构造指针,但“接口”语句似乎有效。如果您查看代码并提供一些输入,我将不胜感激。感谢。
module odemodule
implicit none
contains
function odef(a,b)
implicit none
real::a
real::b(2)
real::odef(2)
odef(1) = -b(1) + b(2)
odef(2) = -0.8*a + b(2)
end function odef
subroutine rk4(f,h,t,y0,y)
implicit none
real,dimension(2,21)::y
real,dimension(2)::k1,k2,k3,k4
real::h
real::t(21)
real::y0(2)
integer::i
interface
function f(a,b)
real::a
real::b(2), f(2)
end function f
end interface
y(1,1)=y0(1)
y(2,1)=y0(2)
do i=1,20
k1 = f(t(i),y(:,i))
k2 = f(t(i)+h/2, y(:,i)+h/2*k1)
k3 = f(t(i)+h/2, y(:,i)+h/2*k2)
k4 = f(t(i)+h, y(:,i)+h*k3)
y(:,i+1) = y(:,i)+h/6*(k1+2*k2+2*k3+k4)
end do
end subroutine rk4
end module odemodule
program passing
use odemodule
implicit none
real,parameter::dt=0.05
real::yinit(2)
real::y(2,21)
integer::i
real::t(21)
t(1)=0.0
do i=2,21
t(i)=t(i-1)+dt
end do
yinit(1)=0
yinit(2)=0
call rk4(odef,dt,t,yinit,y)
do i=1,21
write(*,100) y(1,i), y(2,i)
enddo
100 format(f7.4,3x,f7.4)
end program passing
答案 0 :(得分:6)
Fortran中选择函数传递给其他过程(子例程或函数)的最佳方法是使用过程指针。这样,您可以以一般方式编写过程并使用特定函数调用它。以下是一些示例:How to alias a function name in Fortran和Function pointer arrays in Fortran
有很多方法可以初始化arrrays。例如,您可以将所有元素初始化为相同的值,例如,
array = 0.0
请参阅http://en.wikipedia.org/wiki/Fortran_95_language_features
答案 1 :(得分:1)
还有另一种方法,我想将其制作在一个文件中。
program main
implicit none
integer , parameter :: wp = 8
integer , parameter :: n = 2 ! number of equation
real(kind=wp), parameter :: h = 0.05_wp ! time step
integer , parameter :: m = ceiling(1.0/h) + 1 ! total number of time step
real(kind=wp), dimension(m) :: t
real(kind=wp), dimension(n) :: y0
real(kind=wp), dimension(n, m) :: y
integer :: i
t(1:m) = [ (i*h ,i = 0,m-1) ] ! if h=0.05 m=21 ( t = 0:0.05:1 )
y0(:) = [ 0.0_wp, 0.0_wp ]
y = ode_rk4(f, h, t, y0)
write(*,'(a,10x,a4,20x,a,30x,a)' ) '#', 'time', 'x', 'v'
do i = 1, m
write(*,*) t(i), y(:,i)
end do
contains
function ode_rk4(f, h, t, y0) result(y)
implicit none
real(kind=wp), intent(in), dimension(:) :: y0
real(kind=wp), intent(in), dimension(:) :: t
real(kind=wp), intent(in) :: h
real(kind=wp), dimension(size(y0), size(t)) :: y
interface
pure function f(t, x) result(y)
implicit none
real(kind=8) , intent(in) :: t
real(kind=8), dimension(2), intent(in) :: x
real(kind=8), dimension(2) :: y
end function f
end interface
real(kind=wp), dimension( size(y0) ) :: k1, k2, k3, k4
y(:, :) = 0.0_wp
y(:, 1) = y0
do i = 1, size(t) - 1
k1(:) = f( t(i), y(:,i) )
k2(:) = f( t(i) + h*0.5, y(:,i) + h*k1(:)*0.5 )
k3(:) = f( t(i) + h*0.5, y(:,i) + h*k2(:)*0.5 )
k4(:) = f( t(i) + h, y(:,i) + h*k2(:) )
y(:, i+1) = y(:, i) + h/6.0 * ( k1 + 2.0*k2 + 2.0*k3 + k4 )
end do
end function ode_rk4
pure function f(t, x) result(y)
implicit none
real(kind=wp) , intent(in) :: t
real(kind=wp), dimension(2), intent(in) :: x
real(kind=wp), dimension(2) :: y
y(1:2) = [ -x(1) + x(2), &
-0.8*t + x(2) ]
end function f
end program main
但是函数interface
的块f(t,x)
有问题。
interface
pure function f(t, x) result(y)
implicit none
real(kind=8) , intent(in) :: t
real(kind=8), dimension(2), intent(in) :: x
real(kind=8), dimension(2) :: y
end function f
end interface
我希望所有声明变量都取决于精度变量wp
而不是硬编码值,我可以使用模块,例如创建文件kind_mod.f90
module kind
implicit none
integer, private, parameter :: sp = 4
integer, private, parameter :: dp = 8
integer, private, parameter :: qp = 16
integer, public , parameter :: wp = dp
end module kind
然后
interface
pure function f(t, x) result(y)
use kind, only: wp
implicit none
real(kind=wp) , intent(in) :: t
real(kind=wp), dimension(2), intent(in) :: x
real(kind=wp), dimension(2) :: y
end function f
end interface
代码可以进一步改进,但是我希望这足以说明如何通过使用interface
将函数作为另一个函数的参数来实现,也可以以任意精度执行它。
# time x v
0.0000000000000000 0.0000000000000000 0.0000000000000000
5.0000000000000003E-002 -1.6666666915019357E-005 -1.0166666818161806E-003
0.10000000000000001 -1.3337500198744241E-004 -4.1362920755244432E-003
0.15000000000000002 -4.5043763692761095E-004 -9.4666966267490885E-003
0.20000000000000001 -1.0686681413439925E-003 -1.7121228825211946E-002
0.25000000000000000 -2.0896331089569026E-003 -2.7219048632159955E-002
0.30000000000000004 -3.6159061266336280E-003 -3.9885425439353160E-002
0.35000000000000003 -5.7513242612989464E-003 -5.5252051304658302E-002
0.40000000000000002 -8.6012477060707013E-003 -7.3457370247492326E-002
0.45000000000000001 -1.2272823234869468E-002 -9.4646924427517695E-002
0.50000000000000000 -1.6875252124274188E-002 -0.11897371807220791
0.55000000000000004 -2.2520063212565732E-002 -0.14659860006328257
0.60000000000000009 -2.9321391778745664E-002 -0.17769066613866774
0.65000000000000002 -3.7396264938870084E-002 -0.21242768171568613
0.70000000000000007 -4.6864894273334769E-002 -0.25099652639274433
0.75000000000000000 -5.7850976416828570E-002 -0.29359366124099234
0.80000000000000004 -7.0482002362582521E-002 -0.34042562005441557
0.85000000000000009 -8.4889576254331925E-002 -0.39170952578672846
0.90000000000000002 -0.10120974446313261 -0.44767363346641825
0.95000000000000007 -0.11958333577188944 -0.50855790094749531
1.0000000000000000 -0.14015631351823021 -0.57461458892310990