matchew (7) [Avatar] Offline
#1
hi,

i am trying to write a subroutine for runge kutta which calls a function.

i searched the meap with no luck.

can you point me in the right direction as i am new to fortran

what am i missing?
Milan Curcic (42) [Avatar] Offline
#2
Hi Matthew,

I need more info. Are you able to write a minimal subroutine that you can call? Are you able to write a function that you can invoke in an expression? What happens if you try to invoke the function from within the subroutine? What is the compiler error that you get? It'd be best if you can post a minimal code example that illustrates your issue.

Cheers,
milan
matchew (7) [Avatar] Offline
#3
   
1 program point
   2       implicit none
   3       integer :: a,b,adder
   4       a = 1
   5       b = 2
   6 
   7      call mu(a, b, adder)
   8      print *, a, b, adder
   9 
  10 
  11 end program point
  12 
  13       subroutine mu(ain, bin, multi)
  14           implicit none
  15           integer :: ain, bin, multi, add
  16           multi = add(ain, bin)
  17       end subroutine mu
  18 
  19       function add(a1, b1)
  20           implicit none
  21           integer, intent(in) :: a1, b1
  22           integer :: add
  23           add  = a1 + b1
  24       end function add

matchew (7) [Avatar] Offline
#4
Is this the correct way to call a function from a subroutine?
Milan Curcic (42) [Avatar] Offline
#5
Yep, that should work. Further, I recommend placing these in the module, and then accessing mu with use/only:

module mod_add

  implicit none ! will apply to all module procedures
  private
  public :: mu, add

contains

  subroutine mu(ain, bin, multi)
    integer, intent(in) :: ain, bin
    integer, intent(out) :: multi
    multi = add(ain, bin)
  end subroutine mu

  function add(a1, b1)
    integer, intent(in) :: a1, b1
    integer :: add
    add = a1 + b1
  end function add

end module mod_add


program point
  use mod_add, only: mu
  implicit none
  integer :: a, b, adder
  a = 1
  b = 2
  call mu(a, b, adder)
  print *, a, b, adder
end program point


The advantage to using a module is that it creates an explicit interface for all procedures defined in the module. This allows the compiler to check whether the actual arguments (those in the caller) match the dummy arguments (those defined in the subroutine or function). Also, when using a module, you can set implicit none once at the top of the module, and it will apply to all procedures defined within.
matchew (7) [Avatar] Offline
#6
Thank you!!!

I thought using a simpler example would be easier.

My assignment is to translate a Runge Kutta from Octave to Fortran and I got stuck at the function call. In the Octave there were function pointers. Since the function does not change I do not need to use pointers to implement the function in the subroutine.

Now I just need to work on the syntax and I should be good.
matchew (7) [Avatar] Offline
#7
Here is an example:

No error:
   1 program scalvec
   2 
   3       real :: a 
   4       real, dimension(2) :: B, C, D, E 
   5 
   6       a = 5 
   7       B = [1, 10]
   8       D = [1,  1]
   9 
  10       E = B * D 
  11       C = a * E 
  12 
  13       print *, C 
  14 
  15       end program scalvec


error:

       1 program scalvec
       2 
       3       real :: a
       4       real, dimension(2) :: B, C, D, E
       5 
       6       a = 5
       7       B = [1, 10]
       8       D = [1,  1]
       9 
 >> 10       E = multy(B,D)
      11       C = a * E
      12 
      13       print *, C
      14 
      15       end program scalvec
      16 
      17       function multy(inA, inB)
      18         real, dimension(2) :: inA, inB, multy
      19         multy = inA * inB
      20         end function multy
      21 

NORMAL scalevec.f90 + 47% 10:20
Return type mismatch of function 'multy' at (1) (INTEGER(4)/REAL(4))

How do I return a vector from a function call?
matchew (7) [Avatar] Offline
#8
how does this look?

 program scalvec
 
       real :: a
       real, dimension(2) :: B, C, D, E
 
       a = 5.0 
       B = [1.0, 10.0]
       D = [1.0,  1.0]
 
       E = multy(B, D)
       C = a * E 
 
       print *, C
 
 
 contains
       function multy(inA, inB)
         real, dimension(2) :: inA, inB, multy
         multy = inA * inB 
         !multy(1) = inA(1) * inB(1)
         !multy(2) = inA(2) * inB(2)
         end function multy
 
       end program scalvec
Milan Curcic (42) [Avatar] Offline
#9
You got it. smilie

For something as simple as scalar times vector, ordinary arithmetic like
C = a * B * D
will work as expected, no need for a custom function.
matchew (7) [Avatar] Offline
#10
Milan,

Thank you again!

Matthew