Fortran subroutine pointers for mismatched array sizes

I have a problem with Fortran and function / subroutine pointers. I have two functions that take an array as an argument. In f1 it's (n, n), in f2 it's a (n * n). When I call the subroutine manually, I can do it with the same array:

real :: a(5, 5)
call f1(a, 5)
call f2(a, 5)

      

But when I try to do it with a pointer, the compiler gives me back this error:

ptr => f2
       1
Error: Interface mismatch in procedure pointer assignment at (1): Type/rank missmatch in argument 'a'

      

Is there a way to get around this? I was thinking about pointers but there I have the same problem, to create it I need to know the number of dimensions.

For reference, here's the complete code (hopefully it's not too long ..)

program ptrtest
implicit none

interface
    subroutine fnc(a, n)
        integer :: n
        real :: a(n, n)
    end subroutine

    subroutine f1(a, n)
        integer :: n
        real :: a(n, n)
    end subroutine

    subroutine f2(a, n)
        integer :: n

        real :: a(n*n)
    end subroutine
end interface

procedure(fnc), pointer :: ptr => null()
real :: a(5, 5)
real :: b(4, 4)

ptr => f1

call ptr(a, 5)
write(*,*) a

!this one does not work..

!ptr => f2
!
!call ptr(b, 4)
!write(*,*) b

call f2(b, 4)
write(*,*) b
end program

subroutine f1(a, n)
integer :: n
real :: a(n, n)
integer :: i

a = 1
end subroutine

subroutine f2(a, n)
integer :: n
real :: a(n*n)

a = 2
end subroutine

      

I really hope there is a way to do this. I cannot rewrite all the subroutines so that the array sizes match every time: /

Regards, Kaba

+2


source to share


4 answers


If I change your example program to use explicit interfaces (via an interface block) to use implicit interfaces (via procedure declarations without mentioning an interface), it works for me.

So, remove the interface block, slightly change the declaration ptr

and add procedure declarations for f1

and f2

, for example:

procedure(), pointer :: ptr => null()
procedure() :: f1, f2

      



(Alternatively, you can use the external

for f1

and operator f2

instead of the procedure statement.)

I don't know how this is possible for a real program, because you might need explicit interfaces if real subroutines use some of the functionality introduced in Fortran 90 and later.

+2


source


Edit: The dot, as written in other answers, indicates that the actual and dummy arguments are not the same. Instead of trying to work on my proposal, I need to create a pointer that converts the rank of the array so that the arguments match. This method is "overriding pointer bindings" (see also resizing an array in fortran ). Here's a more complete example:

module my_subs

contains

subroutine f1 (array)

   real, dimension (:,:), intent (in) :: array
   write (*, *) "f1:", ubound (array, 1), ubound (array, 2)

end subroutine f1


subroutine f2 (array)

   real, dimension (:), intent (in) :: array
   write (*, *) "f2:", ubound (array, 1)

end subroutine f2

end module my_subs


program test_ranks

   use my_subs
   real, dimension (2,2), target :: a2d
   real, dimension (:), pointer :: a4

   a2d = reshape ( [1., 2., 3., 4.], [2,2] )
   call f1 (a2d)

   a4 (1:4) => a2d
   call f2 (a4)

end program test_ranks

      



I have subroutines in the module to make the interface explicit automatically - I think this is the safest practice as it allows the compiler to find argument consistency errors and is necessary for Fortran 90 "advanced" features such as form-sizing (colon) presumably. which I have used.

Perhaps this example does not meet the needs of the question, since it does not use a pointer to procedures. It passes the same array to procedures expecting arrays of different ranks.

+2


source


You are passing a 2D array (:, :) to a routine that expects a 1D array (:). This is why Fortran is complaining. One way is to write a module with multiple functions with the same name that take different arrays of ranks as arguments, for example:

  module test 

  interface fnc1
      module procedure fnc1_1d, fnc1_2d
  end interface

  contains

  subroutine fnc1_1d(ar,b,ar_out)

  real :: ar(:), ar_out(:)
  integer :: b

  ar_out = ar*b

  end subroutine fnc1_1d

  subroutine fnc1_2d(ar,b,ar_out)

  real :: ar(:,:), ar_out(:,:)
  integer :: b

  ar_out = ar*b

  end subroutine fnc1_2d

  end module test

      

now when you call fnc1 it is called fnc1_1d if you are passing a 1D array, and fnc_2d if you are passing a 2d array.

Program modify_value

use test

implicit none

real :: a1(5), a1_out(5)
real :: a2(5,5), a2_out(5,5)
integer :: j

a1 = 1.
a2 = 2.

call fnc1(a1,4,a1_out)
call fnc1(a2,4,a2_out)

open(1,file="out.txt")

write(1,'(5F5.1)') a1_out
do j=1,5
    write(1,'(5F5.1)') a2_out(j,:)
end do


close(1)

End Program

      

in out.txt

now:

4.0 4.0 4.0 4.0 4.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

Hope it helps.

+2


source


In this section:

subroutine f2 (a, n) integer :: n real :: a (n * n)

you are using a 1D array when fortran expects a 2D array in the main program.

0


source







All Articles