我在fortran 2003中构建了以下RK4代码。在这两个函数中,我分配了内存。由于我的步骤和正弦函数将被称为很多,这对我来说似乎效率低下。什么是最好/最干净的方法来摆脱这些分配,但不会失去插入任何满足接口'fi'的功能的能力?
我仍然希望我的rk4能够处理任何大小的状态向量x
module rk4
interface
function fi(t,x) result (fx)
real, dimension(:), intent(in) :: x
real, intent(in) :: t
real, allocatable, dimension(:) :: fx
end function fi
end interface
contains
pure function sine(t,x) result (fx)
real, dimension(:), intent(in) :: x
real, intent(in) :: t
real, allocatable, dimension(:):: fx
allocate(fx(size(x)))
fx(1) = x(2)
fx(2) = -x(1)
end function sine
function step(x,f,dt) result(xn)
real, intent(in) :: dt
real, intent(in), dimension(:) :: x
real, allocatable, dimension(:) :: k1,k2,k3,k4,xn
procedure(fi) :: f
integer :: N
N = size(x)
allocate(k1(N))
allocate(k2(N))
allocate(k3(N))
allocate(k4(N))
k1 = f(dt,x)
k2 = f(dt+0.5*dt,x+0.5*k1*dt)
k3 = f(dt+0.5*dt,x+0.5*k2*dt)
k4 = f(dt+dt,x+dt*k3)
allocate(xn(N))
xn = x + (dt/6.)*(k1 + 2*k2 + 2*k3 + k4)
deallocate(k1)
deallocate(k2)
deallocate(k3)
deallocate(k4)
end function step
end module rk4
答案 0 :(得分:1)
使用自动函数结果(即取决于函数参数特征的函数结果)。同样,在step
过程中使用自动变量进行中间计算。
(编译器仍然可以使用类似于分配的内部内存分配例程来实现自动变量,但是这回答了你提出的问题;)或者(或者在某种组合中),编译器可以为自动变量放置存储和堆栈上的结果。如果放在堆栈上的自动内容的大小很大,那么你可能会用完堆栈。)
module rk4
abstract interface ! clearer if this is abstract.
function fi(t,x) result (fx)
real, dimension(:), intent(in) :: x
real, intent(in) :: t
! Automatic function result - size of the result is
! the size of the x argument.
real, dimension(size(x)) :: fx
end function fi
end interface
contains
pure function sine(t,x) result (fx)
real, dimension(:), intent(in) :: x
real, intent(in) :: t
real, dimension(size(x)):: fx
fx(1) = x(2)
fx(2) = -x(1)
end function sine
function step(x,f,dt) result(xn)
real, intent(in) :: dt
real, intent(in), dimension(:) :: x
! xn is an automatic result, the others are just automatic.
real, dimension(size(x)) :: k1,k2,k3,k4,xn
procedure(fi) :: f
k1 = f(dt,x)
k2 = f(dt+0.5*dt,x+0.5*k1*dt)
k3 = f(dt+0.5*dt,x+0.5*k2*dt)
k4 = f(dt+dt,x+dt*k3)
xn = x + (dt/6.)*(k1 + 2*k2 + 2*k3 + k4)
end function step
end module rk4
答案 1 :(得分:0)
如果调用之间的大小没有差异,则可以创建数组模块变量。同时调用过程时要小心,例如,可能需要在OpenMP threadprivate
中。
您还需要另一个子程序来进行数组的初始化(分配)和终止(deallocation)。分配可以在第一次通话时完成。
在Fortran 2003 OOP中,您可以将分配移动到构造函数,释放到final
过程并创建求解器类的数组组件。
您不需要Fortran 2003,您可以使用缓冲区创建派生类型,并将其作为type
而不是class
传递。
type Solver
integer :: n
real, allocatable, dimension(:) :: fx
real, allocatable, dimension(:) :: k1,k2,k3,k4
contains
procedure :: sine
procedure :: step
final :: finalize
end type
interface Solver
Solver_init
end interface
....
function Solver_init(n) result(S)
type(Solver) :: S
S%n = n
allocate(S%k1(n) ....
...
pure function sine(S,t,x) result (fx)
class(Solver), intent(inout) :: S
real, dimension(:), intent(in) :: x
real, intent(in) :: t
real, dimension(b%n):: fx
....
function step(b,x,f,dt) result(xn)
class(Solver), intent(inout) :: S
real, intent(in) :: dt
real, intent(in), dimension(:) :: x
real, dimension(b%n) :: xn
...
subroutine finalize(S)
class(Solver), intent(inout) :: S
deallocate(B%k1 ....
...