pass function as argument to subroutine using interface doesn't work in Plato Fortran 90

1.2k Views Asked by At

I created a fortran 90 program that I used on a linux machine and compiled using gfortran. It worked fine on the linux machine with gfortran but provides the error

error 327 - In the INTERFACE to SECANTMETHOD (from MODULE SECMETH), the ninth dummy argument (F) was of type REAL(KIND=2) FUNCTION, whereas the actual argument is of type REAL(KIND=2)

when using the Plato compiler (FTN95). Does anyone know how I would need to change my code to work in Plato? I tried to read up on this error and there was some mention of pointers but from what I tried that did not work. I have figured out some workarounds but they make it so that the subroutine can no longer accept any function as an argument - which is pretty much useless. Any help would be greatly appreciated. My code is below.

!--! A module to define a real number precision.
module types
  integer, parameter :: dp=selected_real_kind(15)
end module types

module secFuncs
  contains

  function colebrookWhite(T)
    use types

    real(dp) :: colebrookWhite
    real(dp), intent(in) :: T

    colebrookwhite=25-T**2

    return
  end function colebrookWhite
end module secFuncs

module secMeth
  contains

  subroutine secantMethod(xolder,xold,xnew,epsi1,epsi2,maxit,exitFlag,numit,f)
    use types
    use secFuncs
    implicit none

    interface
      function f(T)
        use types
        real(dp) :: f
        real(dp), intent(in) :: T
      end function f
    end interface

    real(dp), intent(in) :: epsi1, epsi2
    real(dp), intent(inout) :: xolder, xold
    real(dp), intent(out) :: xnew
    integer, intent(in) :: maxit
    integer, intent(out) :: numit, exitFlag
    real(dp) :: fxold, fxolder, fxnew
    integer :: i

    fxolder = f(xolder)
    fxold = f(xold)

    i = 0

    do
      i = i + 1

      xnew = xold - fxold*(xold-xolder)/(fxold-fxolder)

      fxnew = f(xnew)

      if (i == maxit) then
        exitFlag = 1
        numit = i
        return
      else if (abs(fxnew) < epsi1) then
        exitFlag = 2
        numit = i
        return
      else if (abs(xnew - xold) < epsi2) then
        exitFlag = 3
        numit = i
        return
      end if

      xolder = xold
      xold = xnew
      fxolder = fxold
      fxold = fxnew
    end do
  end subroutine secantMethod

end module secMeth

program secantRoots
  use types
  use secMeth
  use secFuncs
  implicit none

  real(dp) :: x1, x2, xfinal, epsi1, epsi2
  integer :: ioerror, maxit, numit, exitFlag

  do
    write(*,'(A)',advance="no")"Please enter two initial root estimates, 2epsi's, and maxit: "
    read(*,*,iostat=ioerror) x1, x2, epsi1, epsi2, maxit

    if (ioerror /= 0) then
      write(*,*)"Invalid input."
    else
      exit
    end if
  end do

  call secantMethod(x1,x2,xfinal,epsi1,epsi2,maxit,exitFlag,numit,colebrookWhite)

  if (exitFlag == 1) then
    write(*,*)"The maximum number of iterations was reached."
  else if (exitFlag == 2) then
    write(*,'(a,f5.3,a,i3,a)')"The root is ", xfinal, ", which was reached in ", numit, " iterations."
  else if (exitFlag == 3) then
    write(*,'(a,i3,a)')"There is slow or no progress at ", numit, " iterations."
  end if

end program secantRoots
2

There are 2 best solutions below

1
IanH On

Current gfortran detects the error in the call to the secantMethod procedure, where you have parentheses, but no argument list, following the colebrookWhite function name.

If you want to pass a function as an argument (as opposed to the result of evaluating a function), which is what you want to do here, you do not follow the function name with a parenthesis pair.

call secantMethod(x1,x2,xfinal,epsi1,epsi2,maxit,exitFlag,numit,colebrookWhite )
!                                                                             ^
1
ryanDavid On

I ended up just switching from Plato to Geany IDE (I actually like Geany WAY better now that I've used it for a couple hours), setting up gfortran with Geany, and the code works with that setup. I'm guessing the reason I'm getting the error with Plato is that its compiler is actually a fortran95 compiler while gfortran is a fortran90 compiler. It took a while to get everything working but once I downloaded mingw-w64 for gfortran and set the path user (not system) environment variable to the correct location everything works great. I would still be interested in seeing if there is a way to get the code working with the FTN95 compiler, but in the end I'm still sticking with gfortran and Geany.