Question

I wanted to make it easier to change a certain function which will be used by a subroutine in a fortran project. However I can not get it to work. I have seen quite a few examples which use the external, however I am not sure if I have to use it, since I put all my function and subroutines in modules.

Here is a simplified example of the problem I am dealing with:

I have the program in a separate file:

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

I put each subroutine and all the functions in a separate module and each module has its own file: The module Parameters just defines constants and variable types:

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

Module circArrayConstructer contains the subroutine circArray which has the output error, coor and topo, the last two have dimensions N by 2 and since N in an input they have to be allocated.

Module RungeKutta4 contains the subroutine RK4 which is an implementation of the 4th order Runge Kutta method:

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

And module velocity contains multiple functions:

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

Currently when I try to compile the program I get the error: Interface mismatch in dummy procedure 'vel': Type/rank mismatch in function result.

I have tried all kinds of things, such as changing the declaration of vel in RungeKutta4 to real(fd), external :: vel(:,:) but that gives conflicting attributes. But I have run out of ideas on how to make the code work.

Was it helpful?

Solution

With the function in a module, you don't want to use external. The problem is that RK4 doesn't know the properties of the function that it is receiving. You can declare the function with an interface block:

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top