How to pass array to a procedure which is passed as an argument to another procedure using Fortran

房东的猫 提交于 2021-02-05 08:49:12

问题


I am trying to pass the name of another subroutine_b and an array to a generic subroutine_a. This subroutine_a is supposed to pass the array to subroutine_b and get back its computed value.

Following is the code that I have written:

module pass_subroutine_mod1
    implicit none
    private
    public :: ave_value, fx

    contains
        subroutine ave_value( func, x, y, ave )
            ! Calculate average of y which is passed on from another function `func`.
            !
            external :: func
            double precision, intent(in), dimension(:) :: x
            double precision, intent(inout), dimension(:) :: y
            double precision, intent(inout) :: ave

            integer :: n

            N = size( x )

            call func( x, y )
            ave = sum( y ) / dble( N )

            return
        end subroutine ave_value


        subroutine fx( x, y )
            double precision, dimension(:), intent(in) :: x
            double precision, dimension(:), intent(inout) :: y

            y = x ** 3
            return
        end subroutine fx
end module pass_subroutine_mod1


program main
    use :: pass_subroutine_mod1
    implicit none

    integer :: i, N = 101
    double precision :: ave
    double precision, allocatable, dimension(:) :: x, y
    allocate( x(N), y(N), source=0.0d0 )

    do i = 1, N
        x(i) = dble( i - 1 )
    end do

    call ave_value( fx, x, y, ave )
    write( *, '(A, ES15.6E3)' ) "Average value of y (from fx) = ", ave

    deallocate( x, y )
end program main

Here ave_value() is the subroutine_a and fx() is subroutine_b.

When I compile and run the above code, it throws the following error:

At line 28 of file pass_subroutine.f90
Fortran runtime error: Array bound mismatch for dimension 1 of array 'y' (1/1125899906842625)

Line 28 is the line y = x ** 3 in subroutine fx( x, y ). It thus seems that the arrays x and y are not properly passed to fx() because when I try to print x from within fx(), it is unable to do so.

If, instead of arrays x and y, I use scalars (and update the code accordingly) the code is able to run properly and output the desired result.

Additionally, after going through this thread, if I modify the ave_value by adding an interface block, the code runs properly again. Following is the modification with ave_value:

        subroutine ave_value( func, x, y, ave )
            ! Calculate average of y which is passed on from another function `func`.
            !
            external :: func
            double precision, intent(in), dimension(:) :: x
            double precision, intent(inout), dimension(:) :: y
            double precision, intent(inout) :: ave

            integer :: n

            interface
                subroutine func( ip, op )
                    double precision, dimension(:), intent(in) :: ip
                    double precision, dimension(:), intent(inout) :: op
                end subroutine func
            end interface

            N = size( x )

            call func( x, y )
            ave = sum( y ) / dble( N )

            return
        end subroutine ave_value

Thus, my questions are:

a) Is the above modification correct?

b) If yes, then why do I need an interface block when working with arrays and not when working with scalars?


回答1:


It's the assumed-shape array dummy arguments dimension(:) that require an explicit interface. This is because the compiler has to do something different for these, typically passing a descriptor. It doesn't matter what's on the calling side, it's the dummy arguments of the called procedure that matter.

For more information see my old blog post Doctor Fortran Gets Explicit - Again!

You may want to look at the language feature abstract interface, along with procedure, to make the code look a bit cleaner.




回答2:


When you have a dummy procedure argument, as func in ave_value is, there is no "assumed interface". While the array dummy arguments x and y are assumed-shape (they take their shape from the actual argument when the procedure is invoked) there's nothing similar for procedures.

Instead, the procedure func has the interface it's declared with. In this case, you have the declaration

external :: func

so that func is an external procedure with implicit interface. As we know, an implicit interface is not suitable when we want to reference it and it has assumed-shape array arguments ip and op.

You need somehow to explicitly give the dummy argument the correct interface. One way, as you've seen, is to use an interface block to give the external procedure an explicit interface. Alternatively, you can use a procedure declaration statement like

procedure(iface) func

where iface is an appropriate interface. There are several ways to make that interface available, but I won't go into them here.



来源:https://stackoverflow.com/questions/57579287/how-to-pass-array-to-a-procedure-which-is-passed-as-an-argument-to-another-proce

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!