F90 Subroutine that accepts any array of any dimension

AI Thread Summary
Creating a subroutine in Fortran that accepts an array of any number of dimensions is challenging due to the language's design, which requires specific type and dimension declarations for pointers. While Fortran does not allow for a generic array input like C, it is possible to handle multidimensional arrays by passing the dimensions and calculating the appropriate index for a one-dimensional representation of the array. Fortran arrays are stored in column-major order, contrasting with C's row-major order, which affects how indices are calculated. The discussion highlights the formula for accessing elements based on their dimensions, emphasizing the need to convert multidimensional indices into a single index. An alternative approach involves creating a module with generic interfaces for different dimensional arrays, allowing for a single subroutine call while still requiring prior declaration of the array dimensions. This method provides flexibility in handling arrays of various dimensions while adhering to Fortran's constraints.
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.
 
Technology news 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 DrClaude

Similar threads

Replies
5
Views
8K
Replies
8
Views
3K
Replies
5
Views
13K
Replies
5
Views
3K
Replies
22
Views
3K
Replies
4
Views
2K
Replies
2
Views
3K
Replies
18
Views
6K
Replies
2
Views
8K
Back
Top