因效率而摆脱分配

时间:2014-03-25 08:02:42

标签: arrays fortran

我在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

2 个答案:

答案 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 ....


   ...