1

I have the following code, where I call a function from a subroutine, all of them in the same module:

      module mymodule
      implicit none
      contains  

      subroutine mycode
      real :: y0(3), a = 0.0, b = 1.0
      integer :: i, N = 10
      real, allocatable :: y(:,:)
      y0(:) = [1.0, 1.0, 1.0]
      y = AB2(od, a, b, N, y0)
      do i = 1, N
          print *, y(:,i)
      end do      
      end subroutine mycode

      function AB2(f, a, b, N, y0)
          real, allocatable :: AB2(:,:)
          interface
              function f(x, y)
                  real, allocatable :: f(:)
                  real, intent(in) :: x, y(:)
              end function
          end interface
          real, intent(in) :: a, b
          integer, intent(in) :: N
          real, intent(in) :: y0(:)
          real :: xn0, xn1, step
          real, allocatable :: yn0(:), yn1(:)
          integer :: i
          allocate(AB2(size(y0),N))
          step = (b-a)/(N-1)
          AB2(:,1) = y0
          AB2(:,2) = y0 + step*f(a, y0)
          do i = 3, N
              xn0 = a+(i-2)*step
              xn1 = a+(i-1)*step
              yn0 = AB2(:,i-2)
              yn1 = AB2(:,i-1)
              AB2(:,i) = AB2(:,i-1) + step*(3.0/2.0*f(xn1,yn1)
     &             -0.5*f(xn0,yn0))
          end do
      end function

      function od(x, y)
          real, allocatable :: od(:)
          real, intent(in) :: x, y(:)
          allocate(od(3))
          od(1) =  x + y(1)
          od(2) = -y(3) - y(2) - x
          od(3) =  x - y(1) + y(3)
      end function

      end module mymodule

If I want to give another parameter to the function od, say c, I have to include it on this line

real, intent(in) :: x, c, y(:)

and also

   function od(x,c,y)

However, where do I provide the value for this argument? There is no option in the call

y = AB2(od, a, b, N, y0)
Hans
  • 361
  • 1
  • 3
  • 9
  • 1
    What error message do you get? How do you call your function? some more details (argument list, return value etc.) of the function are required. – albert Jan 07 '18 at 18:06
  • Please show the complete code. Not just a module, but also the program that uses it. Compile your code with error checking debugging options like `gfortran -g -traceback -Wall -fcheck=all` and show the **complete** output. Your current error message is useless. If those options I showed don't help, you should at least identify at which line of code does the crash happen. – Vladimir F Героям слава Jan 07 '18 at 19:15
  • Why do you even make the function to return an allocatable array? Let it just return fixed-size array, it is simpler. Also, why is `N=3` and `od` size 3? Shouldn't they be compatible? – Vladimir F Героям слава Jan 07 '18 at 19:17
  • 1
    Maybe need `-standard-semantics` (or `-assume realloc_lhs`) because auto-reallocation of allocatable arrays are used ? (e.g. yn0 = AB2(:,i-2)). – roygvib Jan 07 '18 at 19:23
  • @roygvib did you manage to get it running? – Hans Jan 07 '18 at 20:00
  • Yes, it ran without segfault with the above options (for ifort) or gfortran-7.2 (without options). Attaching "-check all" also shows the run-time error message that "y is not allocated" etc. – roygvib Jan 07 '18 at 20:14
  • What version of Intel Fortran are you using? If an old one, there may be different problems... (FYI I'm using v14--16, which seem OK.) – roygvib Jan 07 '18 at 20:20
  • I am using v11.1. The thing is I don't get any error, but warnings. What do you recommend to fix the problem? – Hans Jan 07 '18 at 20:43
  • Did you try compiling `ifort -assume realloc_lhs yourcode.f90`? Because I don't have v11.1 in hand, I can't test it right now... If this does not work, we may need explicit `allocate()` statement for `y`, `yn0`, `yn1`, etc. – roygvib Jan 07 '18 at 20:49
  • If you are using Intel please compile with `-g -traceback -warn -check`. I recommend to use them always when developing or debugging. – Vladimir F Героям слава Jan 07 '18 at 21:31
  • @francescalus I've been using ifort-14 and 16.0.2 with "-check all", then the run-time error is "forrtl: severe (408): fort: (8): Attempt to fetch from allocatable variable Y when it is not allocated" (which goes away with "-assume realloc_lhs"). FYI, ifort14-16 (with -assume...), gfortran-7.2, PGI17.4 (with -Mallocatable=03), and Oracle/Sun12.5 all give the same numerical results. – roygvib Jan 07 '18 at 21:42
  • @Hans If you possibly have gfortran-4.8 on your machine, it may be useful to try "gfortran -frealloc-lhs yourcode.f". – roygvib Jan 07 '18 at 21:50
  • Alright, now it works. I have another question about the input parameters (I just edited the post) – Hans Jan 10 '18 at 15:37
  • Your question is now very different. Since you have no answer yet, it is not a big problem, but please rewrite your question completely about the new problem. Make the whole question about the **Another question** and change the title as well. Remove the old problem, it is not worth keeping it there. – Vladimir F Героям слава Jan 10 '18 at 16:20
  • I just changed the question! ;) – Hans Jan 10 '18 at 16:51
  • See https://stackoverflow.com/questions/26297170/fortran-minimization-of-a-function-with-additional-arguments https://stackoverflow.com/questions/24127313/passing-external-function-of-multiple-variables-as-a-function-of-one-variable-in?noredirect=1&lq=1 https://stackoverflow.com/questions/37714406/implementing-anonymous-functions-in-fortran and other related questions. This might be a duplicate. – Vladimir F Героям слава Jan 10 '18 at 18:41
  • I had a look but I couldn't understand. My question is, why should I y = AB2(od, a, b, N, y0) and not y = AB2(od(c), a, b, N, y0) ? Why is this not possible in FORTRAN? – Hans Jan 10 '18 at 19:16

1 Answers1

1

This answer does not try to duplicate answers to Fortran minimization of a function with additional arguments Passing external function of multiple variables as a function of one variable in Fortran or Implementing anonymous functions in Fortran but to introduce the problem on a very basic level.

Suppose you have a function AB2 and another small function od.

They are used in such a way that AB2 accepts od as an argument, so you call

y = AB2(od)

the functions look like

real function AB2(f)
  interface
    real function f(x)
      real x
    end function
  end interface
  ... call f(x) here ...
end function

real function od(x)
  real x
end function

You need to pass additional data c to od. How to do that?

You cannot just change od by adding an argument for c and keep AB2 unchanged. AB2 contains a description of the interface of the argument f and od(x,c) would not be compatible with f(x).

Also, you would not be able to pass the data to AB2. You certainly cannot do

y = AB2(od(c))

by doing od(c) you are computing a number by calling od(x) you would then try to pass this number to AB2 instead of the function that should be passed.

There are several ways how to mitigate this. They are described in the answers linked above. I will show one simple possibility.

Let's say we nave have function od(b,x) and wee need to pass c to b, but we don't know how to do that with our AB2.

 real function od(b,x)
   real b, x
 end function

In our calling code we create a wrapper function that calls od with c for us. It can be an internal function or a module function. And we pass the wrapper to AB2.

subroutine caller(c)
  y = AB2(wrapper)
contains
  real function wrapper(x)
    real x
    !we must be able to see c from here, by host association or by using a module
    wrapper = od(c,x)
  end function
end subroutine