1

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.

2
  • Have you tried using an if statement to select which velocity update to use? Commented Mar 18, 2014 at 16:20
  • I assume you mean inside the RK4 subroutine, if so then yes, that is what I used previous code and worked. But would like to make it easier to add more velocity functions for the future. So I thought it would be easiest to define which velocity function I would like to use in the call of the RK4 subroutine. Commented Mar 18, 2014 at 16:33

1 Answer 1

4

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
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this works. And it also make kind of sense, since using external seemed a strange choice because modules should make them unnecessary, but at first did not know how else to declare the function (I thought interfaces where only for programs).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.