1

My minimum, reproducible example looks like this: in my program mymain I call a subroutine which has as arguments an external function f1 and a variable result. Within the subroutine something is done with the function (for this example it is just being evaluated at a specific point) and the result is given back via the argument result.

PROGRAM mymain

    IMPLICIT NONE

    REAL(KIND=8)    f1
    REAL(KIND=8)    result

    EXTERNAL f1


    CALL sub1(f1,result)

    PRINT *,result

END PROGRAM mymain

SUBROUTINE sub1(f1,result)

    IMPLICIT NONE

    REAL(KIND=8)                ::f1
    REAL(KIND=8), INTENT(OUT)   ::result
    REAL(KIND=8)                ::input

    EXTERNAL f1

    input=0.5

    result=f1(input)

END SUBROUTINE sub1

REAL(KIND=8) FUNCTION f1(x)

    REAL(KIND=8), INTENT(IN)    ::x
    REAL(KIND=8)                ::const

    const=1.

    f1=x**2+const

END FUNCTION f1

My problem is that I want to change the variable const in the function f1 from within mymain.

In my real world problem the subroutine is one of a Fortran library that takes the integral of an external function and I need to call this subroutine many times but always with a different parameter in the external function.

I have no idea how to do this because I cannot call the subroutine from mymain like this

CALL sub1(f1(x,const),result)

francescalus
  • 30,576
  • 16
  • 61
  • 96
JoHe
  • 13
  • 3

1 Answers1

1

There a few ways to achieve what you want, but I will recommend that you learn to use Fortran's module feature. This will allow you to encapsulate the information for the function. In the following, I introduce two modules. The first is used to set a named constant for the kind type parameter for the real type. In your code, you are using a compiler specific value when you use real(kind=8). The second defines the function f(x) and a method for setting const

!
! Set kind type parameter for double precision
!
module mytype
  implicit none
  integer, parameter :: dknd = kind(1.d0)
end module mytype
!
! Module defining the function
!
module fcn
 use mytype
 implicit none
 private                  ! Make everything private
 public f, set_const      ! Only allow access to f() and set_const().
 real(dknd) :: const = 0  ! Default constant value
 contains
   !
   ! Subroutine to set const.  Can be generalized to multiple constants.
   ! Call this prior to invoking f(x).
   !
   subroutine set_const(val)
     real(dknd), intent(in) :: val
     const = val
   end subroutine
   !
   ! Obviously, the function f(x)
   !
   function f(x)
     real(dknd) f
     real(dknd), intent(in) :: x
     f = x**2 + const
   end function f 
end module fcn

program mymain
  use fcn                  ! Use fcn to get access f and set_const
  use mytype               ! Use mytype to get access to dknd
  implicit none
  real(dknd) result

  call set_const(1._dknd)  ! Set const = 1
  call sub1(f, result)
  print *, result

  call set_const(2._dknd)  ! Set const = 2
  call sub1(f, result)
  print *, result
end program mymain
!
! Your subroutine.  DO NOT "USE FCN", here!
!
subroutine sub1(f1, result)
  use mytype                 ! Use mytype to get access to dknd
  implicit none
  real(dknd), external :: f1 ! f1 is external real(dknd) function
  real(dknd), intent(out) :: result
  real(dknd) input
  input = 0.5_dknd
  result = f1(input)
end subroutine sub1
evets
  • 996
  • 1
  • 5
  • 6
  • First of all: sorry for responding so late and thank you so much!! I have just a few quick questions: I tried to run your code and i got 2 errors within ```sub1```: at ```real(dknd), intent(out) result``` "invalid character" after the comma and at ```subroutine sub1(f1, result)``` "result has no IMPLICIT type". I guess they are related... – JoHe Apr 08 '20 at 06:15
  • Sorry again, i just added ```::``` into the line ```real(dknd), intent(out) result```, i.e.: ```real(dknd), intent(out) :: result``` and now all works fine! Thank you so much that you gave me a ready to run code that is so well documented! – JoHe Apr 08 '20 at 06:18
  • Just to add if you are learning about modules it would be best (in fact I would fail my students if they didn't do it) to put the subroutine sub in a module which protects against various common programming errors, and to use an interface block to declare the function, which protects against the same errors – Ian Bush Apr 08 '20 at 07:11
  • @IanBush Thank you! I'll look into it. The thing is that the sub in the example is in reality a subroutine that i call from a library that i didn't code. But your comment is very useful since i really need to learn fortran. So i will look into modules and interfaces! – JoHe Apr 08 '20 at 08:08
  • Whoops, sorry about the missing `::` in the answer. IT's odd in that I compiled and tested the code. Must of lost it in translation. Fixed now. – evets Apr 08 '20 at 21:24