1

I'm writing a subroutine that can take function names are argument. In my example, it is call call_test(ga), where ga is a function ga(x).

My old practice works fine if x is a scalar. The problem is the program failed if x is an array.

The minimal sample that can reproduce the problem is the code below:


module fun

    implicit none
    private
    public    ::  ga, call_test

     contains

     subroutine call_test(fn)
        double precision,external::fn
        double precision::f
        double precision,dimension(0:2)::x0


        x0 = 0.111d0
        print*,'Input x0=',x0
        print*,'sze x0:',size(x0)


        f = fn(x0)
        print*,'fn(x0)=',f

    end subroutine call_test


     function ga(x) result(f)
        double precision,dimension(0:)  :: x
        double precision::f

        print*,'size x inside ga:',size(x)
        print*,'x in ga is:=',x

        f = sum(x)
     end function ga

end module


program main
    use fun

    call call_test(ga)

end program main

Using latest ifort, my execution result is:

 Input x0=  0.111000000000000       0.111000000000000       0.111000000000000     
 sze x0:                     3
 size x inside ga:       140732712329264
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image              PC                Routine            Line        Source             
a.out              000000010C6EC584  Unknown               Unknown  Unknown
libsystem_platfor  00007FFF20610D7D  Unknown               Unknown  Unknown
a.out              000000010C6C62B2  _MAIN__                    32  main.f90
a.out              000000010C6C5FEE  Unknown               Unknown  Unknown

Using gfortran the result is

 Input x0=  0.11100000000000000       0.11100000000000000       0.11100000000000000     
 sze x0:           3
 size x inside ga:           0
 x in ga is:=
 fn(x0)=   0.0000000000000000

My question is why is this, and how to make it work. A functional code solution based on my code is highly appreciated.

Kiyomine
  • 33
  • 5
  • 2
    Don't declare fn as external - give it a proper interface. You're invoking a subprogram with an assumed shape dummy argument after all, so you will need to tell the invoking subprogram that the argument it is being passed has this property. – Ian Bush Mar 28 '21 at 21:26

1 Answers1

1

@IanBush is right in his comment. You need an explicit interface as the function argument takes an assumed-shape dummy argument. Since you have some other deprecated features in your code, here is a modern reimplementation of it in the hope of improving Fortran community coding practice,


module fun

    use iso_fortran_env, only: RK => real64
    implicit none
    private
    public    ::  ga, call_test

    abstract interface
        function fn_proc(x) result(f)
            import RK
            real(RK), intent(in) :: x(0:)
            real(RK) :: f
        end function fn_proc
    end interface

contains

    subroutine call_test(fn)

        implicit none
        procedure(fn_proc) :: fn
        real(RK) :: f
        real(RK) :: x0(0:2)

        x0 = 0.111_RK
        write(*,"(*(g0,:,' '))") 'Input x0 =',x0
        write(*,"(*(g0,:,' '))") 'sze x0:',size(x0)
        f = fn(x0)
        write(*,"(*(g0,:,' '))") 'fn(x0) =', f

    end subroutine call_test

     function ga(x) result(f)
        real(RK), intent(in) :: x(0:)
        real(RK) :: f

        write(*,"(*(g0,:,' '))") 'size x inside ga:',size(x)
        write(*,"(*(g0,:,' '))") 'x in ga is:',x

        f = sum(x)
     end function ga

end module


program main
    use fun
    call call_test(ga)
end program main

Note the use of the abstract interface. The import statement merely imports the symbol RK for usage within the abstract. Without it, you will have to use iso_fortran_env to declare RK as real64. Do not use double precision, it is deprecated and does not necessarily mean 64bit real number. Also, note the conversion of 0.111d0 to 0.111_RK. Also, I strongly recommend not using single-letter variable names. They are ugly, error-prone, and non-informative. Modern Fortran allows variable names up to 63 characters long. There is no harm in having long but descriptive variable names. Here is the code output,

$main
Input x0 = 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 3
x in ga is: 0.11100000000000000 0.11100000000000000 0.11100000000000000
fn(x0) = 0.33300000000000002
Scientist
  • 1,767
  • 2
  • 12
  • 20
  • 1
    This works. Thanks! In addition, thanks for the tips for the best practice of modern Fortran. This might be off the topic, but do you know where is a good place to look for these practices? – Kiyomine Mar 29 '21 at 00:40
  • The first few hits with "Fortran best practices" are good. I do not post direct links to them here since they are often not permanent web links. The tutorial page of the official Fortran language is also good, but it is a work in progress: https://fortran-lang.org/learn/ – Scientist Mar 29 '21 at 01:15
  • @Kiyomine I just stumbled upon this page and I agree with much of their advice if not all: https://github.com/Fortran-FOSS-Programmers/Best_Practices – Scientist Mar 29 '21 at 03:16
  • This is great. I hope this also help other Fortran programmers in the future. – Kiyomine Mar 29 '21 at 18:48