麻烦使用函数名作为Fortran中的参数

时间:2014-03-18 15:54:16

标签: fortran fortran90 gfortran

我想更容易更改某个函数,该函数将由fortran项目中的子例程使用。但是我无法让它发挥作用。我看过很多使用external的例子,但我不确定是否必须使用它,因为我把所有的函数和子程序放在模块中。

以下是我正在处理的问题的简化示例:

我将程序放在一个单独的文件中:

program test
    use Parameters
    use circArrayConstructer
    use velocity
    use RungeKutta4
    implicit none
    integer(is) :: N, P, nsteps, i, j
    real(fd)    :: D, dt
    real(fd),    allocatable :: coor(:,:)
    integer(is), allocatable :: topo(:,:)
    integer(is) :: error
    read (*,*) D, nsteps, N, P
    dt = 1.0 / nsteps
    call circArray ( 0.5_fd, 0.5_fd, 0.2_fd, 0.2_fd, N, coor, topo, error )
    do i = 1, P
        do j = 1, nsteps
            if ( mod(P,2) > 0 ) then
                call RK4 ( dt, coor, D, vel1, coor )
            else
                call RK4 ( dt, coor, D, vel2, coor )
            end if
        end do
    end do
end program test

我将每个子程序和所有函数放在一个单独的模块中,每个模块都有自己的文件: 模块Parameters只定义常量和变量类型:

module Parameters
    implicit none
    integer, parameter  :: fs = selected_real_kind(6)
    integer, parameter  :: fd = selected_real_kind(15)
    integer, parameter  :: is = selected_int_kind(9)
    integer, parameter  :: id = selected_int_kind(18)
    real(fd), parameter :: PI = 3.141592653589793
end module Parameters

模块circArrayConstructer包含子例程circArray,其输出为errorcoortopo,后两个维度为N 2,因为输入中需要N,所以必须分配它们。

模块RungeKutta4包含子程序RK4,它是4阶Runge Kutta方法的实现:

module RungeKutta4
    use Parameters
    use velocity
    implicit none
    contains
        subroutine RK4 ( dt, coorOld, D, vel, coorNew )
            implicit none
            real(fd), intent(in ) :: dt
            real(fd), intent(in ) :: D
            real(fd), intent(in ) :: coorOld(:,:)
            real(fd), intent(out) :: coorNew(:,:)
            real(fd), dimension(size(coorOld,1), size(coorOld,2)) :: k1, k2, k3, k4
            real(fd), external    :: vel

            k1 = vel ( coorOld                , D )
            k2 = vel ( coorOld + 0.5 * dt * k1, D )
            k3 = vel ( coorOld + 0.5 * dt * k2, D )
            k4 = vel ( coorOld +       dt * k3, D )
            coorNew = coorOld + dt / 6.0 * (k1 + 2 * (k2 + k3) + k4)
        end subroutine RK4
end module RungeKutta4

模块velocity包含多个功能:

module velocity
    use Parameters
    implicit none
    contains
        function vel1 ( coor, D )
            implicit none
            real(fd), intent(in) :: D
            real(fd), intent(in) :: coor(:,:)
            real(fd), dimension(size(coor,1), size(coor,2)) :: vel1
            vel1(:,1) = -2.0 * D * coor(:,2) * sin(PI * coor(:,1)) * cos(PI * coor(:,2) ** 2)
            vel1(:,2) = D * cos(PI * coor(:,1)) * sin(PI * coor(:,2) ** 2)
        end function vel1

        function vel2 ( coor, D )
            implicit none
            real(fd), intent(in) :: D
            real(fd), intent(in) :: coor(:,:)
            real(fd), dimension(size(coor,1), size(coor,2)) :: vel2
            vel2(:,1) = 2.0 * D * (1 - coor(:,2)) * sin(PI * coor(:,1)) * cos(PI * (1 - coor(:,2)) ** 2)
            vel2(:,2) = D * cos(PI * coor(:,1)) * sin(PI * (1 - coor(:,2)) ** 2)
        end function vel2
end module velocity

目前,当我尝试编译程序时,我收到错误:虚拟程序中的接口不匹配' vel':函数结果中的类型/等级不匹配。

我尝试了各种各样的事情,例如将velRungeKutta4的声明更改为real(fd), external :: vel(:,:),但这会产生相互矛盾的属性。但是我已经没有关于如何使代码工作的想法。

1 个答案:

答案 0 :(得分:4)

使用模块中的功能,您不想使用external。问题是RK4不知道它正在接收的函数的属性。您可以使用interface块声明该函数:

interface
   function vel ( corr, D )
      import fd
      real (fd), intent (in) :: D
      real (fd), intent (in) :: corr (:,:)
      real(fd), dimension(size(corr,1), size(corr,2)) :: vel
   end function vel
end interface