F90 Subroutine that accepts any array of any dimension

Join the discussion
Ask a follow-up here, or get your own question answered by working scientists, mathematicians and engineers — people, not an autocomplete.
Real named experts · corrections over time · the nuance an AI answer skips
6 replies · 2K views
Yascho Bob
Messages
1
Reaction score
0
Hi,

I need to write a subroutine that accepts as an argument an array of any number of dimensions, where each dimensions has any size. The array is contiguously allocated.

In C, I can do this pretty cleanly.

void array_func(int ndims, int *dims, int *array)
{
// do stuff with the array
// in C, using *array is okay so long as the array was allocated contiguously.
}

Any advice on how to do this with fortran? I'm a total newb at Fortran.
 
on Phys.org
You can do the same in Fortran, although you lose the ability to address the elements in a multidimentional way.
Fortran:
subroutine foobar(ndims, dims, array)

  implicit none

  integer, intent(in) :: ndims
  integer, dimension(ndims), intent(in) :: dims
  integer, dimension(:), intent(inout) :: array

  ! Your code here
end subroutine foobar
 
Fortran was not quite designed like and on purpose; so, you cannot have some kind of generic array or pointer that can accept an incoming matrix of any number of dimensions. In Fortran, pointers have specific targets that are declared by type and number of dimensions if arrays.

Having said that, I think I saw a paper somewhere where they explain some acrobatics with type definitions where they manage to do a couple of good tricks, but I can't quite recall what. Let's see if I remember.
 
gsal said:
In Fortran, pointers have specific targets that are declared by type and number of dimensions if arrays.
You're right, what I wrote won't work in F90.
 
DrClaude: what you wrote will work in F90, but it will not be what the OP is asking ;-)
 
You have to pass all the dimensions and calculate the proper position in the array as a one-dimensional array. Keep in mind that FORTRAN runs through the first dimension fastest. It is the opposite of C, which runs through the last dimension fastest.

The (i,j) position in an array of dimensions dim1, dim2 is at (j-1)*dim1 + i
The (i,j,k) position in an array of dimensions dim1, dim2, dim3 is at (k-1)*dim2*dim1 + (j-1)*dim1 + i
The (i,j,k.l) position in an array of dimensions dim1, dim2, dim3, dim4 is at
(l-1)*dim3*dim2*dim1 + (k-1)*dim2*dim1 + (j-1)*dim1 + i

You can see how you can handle any number of indices.
An alternative would be to compile a C subroutine and link that into calculate the position in the FORTRAN array. Keep in mind the reversed order of index progression in C versus FORTRAN.
 
Example using Fortran90 Generic Interfaces.

This may not be exactly what the OP wants as, again, the argument needs to have been declared ahead of time with the correct number of dimensions. The calling of the subruotine, though, kind of meets what the OP requests...a single "subroutine" call that takes a matrix of "any" number of dimensions:

Fortran:
module multi
    interface mdarray
        module procedure m1d, m2d, m3d, m4d, m5d
    end interface
   
contains

    subroutine m1d(m)
        real, dimension(:) :: m
        write(*,'(5f6.1)') m
    end subroutine m1d
   
    subroutine m2d(m)
        real, dimension(:,:) :: m
        write(*,'(5f6.1)') m
    end subroutine m2d
   
    subroutine m3d(m)
        real, dimension(:,:,:) :: m
        write(*,'(5f6.1)') m
    end subroutine m3d
   
    subroutine m4d(m)
        real, dimension(:,:,:,:) :: m
        write(*,'(5f6.1)') m
    end subroutine m4d
   
    subroutine m5d(m)
        real, dimension(:,:,:,:,:) :: m
        write(*,'(5f6.1)') m
    end subroutine m5d
   
end module multi

program crazy
    use multi
   
    real :: a1d(2)    , a2d(2,2)  , a3d(2,2,2), a4d(2,2,2,2), a5d(2,2,2,2,2)    

    a1d = 1.0  ; call mdarray(a1d) ; write(*,*)
    a2d = 2.0  ; call mdarray(a2d) ; write(*,*)
    a3d = 3.0  ; call mdarray(a3d) ; write(*,*)
    a4d = 4.0  ; call mdarray(a4d) ; write(*,*)
    a5d = 5.0  ; call mdarray(a5d) ; write(*,*)
   
end program crazy
 
  • Like
Likes   Reactions: DrClaude