Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

F90 Subroutine that accepts any array of any dimension

  1. Dec 8, 2015 #1

    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.
  2. jcsd
  3. Dec 9, 2015 #2


    User Avatar

    Staff: Mentor

    You can do the same in Fortran, although you lose the ability to address the elements in a multidimentional way.
    Code (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
  4. Dec 9, 2015 #3
    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.
  5. Dec 9, 2015 #4


    User Avatar

    Staff: Mentor

    You're right, what I wrote won't work in F90.
  6. Dec 9, 2015 #5
    DrClaude: what you wrote will work in F90, but it will not be what the OP is asking ;-)
  7. Dec 9, 2015 #6


    User Avatar
    Science Advisor
    Gold Member
    2017 Award

    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 in to calculate the position in the FORTRAN array. Keep in mind the reversed order of index progression in C versus FORTRAN.
  8. Dec 10, 2015 #7
    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:

    Code (Fortran):

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

        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
Share this great discussion with others via Reddit, Google+, Twitter, or Facebook