Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain the starting index of a Fortran array?

Define an array in Fortran:

real, dimension(a,b) :: matrix

How do I obtain a and b given matrix?

like image 555
tgoossens Avatar asked Mar 04 '14 17:03

tgoossens


2 Answers

Read about Fortran 90 intrinsic functions SHAPE, SIZE, UBOUND, LBOUND.

Probably you want size(matrix,1) and size(matrix,2) or ubound(matrix,1) and ubound(matrix,2). However, that is the last index of the array (upper bound).

The starting index for the array you show is implicitly 1. Arrays that start at a different index are declared like:

real, dimension(0:a,0:b) :: matrix

You get the starting indexes (lower bounds) using lbound(matrix,1) and lbound(matrix,2).

like image 124
Vladimir F Героям слава Avatar answered Oct 18 '22 12:10

Vladimir F Героям слава


Vladimir F's answer says all we really need to know about the array matrix of the question. We can, however, be more general and cover other cases and their limitations.

Before that, some terminology. Arrays have rank (the number of dimensions or subscripts), extents (the number of elements in each dimension), and upper and lower bounds. Scalars have rank zero.

matrix question has:

  • rank 2
  • extents a and b
  • lower bounds 1 and 1; upper bounds a and b.

Each of these properties can be queried (rank only from Fortran 2018) using intrinsic functions:

  • RANK(a) returns a scalar integer with the rank of a
  • SIZE(a,dim=i) returns a scalar integer with the extent of a's i-th dimension (SIZE(a) returns the total number of elements in all of a)
  • SHAPE(a) returns an integer array, with size equal to the rank of a (zero for scalar a), with each element corresponding to one dimension's extent
  • LBOUND(a) and UBOUND(a) return similar integer arrays with each element the dimension's lower and upper bounds
  • LBOUND(a,i) and UBOUND(a,i) return scalar integers with the lower and upper bounds of the i-th dimension.

For an explicit shape array, unless the lower bound of a dimension is specified it will be 1 and the dimension's extent will be the same as the specified upper bound. Similarly, for an assumed shape dummy argument array the lower bound is 1 unless otherwise given, regardless of the bound of the actual argument:

real, intent(in) :: a(:,:)   ! Lower bounds 1

The extents are the same as for the actual argument.

Deferred shape arrays (allocatable and pointer) can also inquired of using these intrinsics, but allocatables must be allocated and pointers must be pointer associated:

real, intent(in), allocatable :: a(:,:)   ! Same bounds as the actual argument if allocated
real, intent(out), allocatable :: b(:,:)  ! Definitely not allocated: no bounds

Here a, unlike an assumed shape argument, may have lower bounds different from 1, but LBOUND will safely tell us.

For assumed size arguments, things are different:

real, intent(in) :: a(2:5,*)

Here, we can't use SHAPE to ask about a, but we can safely use LBOUND, and we can use UBOUND and SIZE in some ways:

LBOUND(a)    ! Allowed: can ask about lower bound for all dimensions
LBOUND(a,1)
LBOUND(a,2)  ! Both allowed individually

UBOUND(a)    ! Not allowed: this would include asking about the second upper bound
UBOUND(a,1)  ! Allowed: first bound is defined
UBOUND(a,2)  ! Not allowed: bad second bound

SIZE(a)      ! Not alllowed: as for UBOUND
SIZE(a,1)    ! Allowed
SIZE(a,2)    ! Not allowed

RANK(a)      ! Allowed (we know it will be 2).

(Fortran 2018) Assumed rank arguments are slightly different still:

real, dimension(..), intent(in) :: a

print *, RANK(a)     ! Allowed
print *, SHAPE(a)    ! ""
print *, LBOUND(a)   ! ""
print *, UBOUND(a)   ! ""
print *, SIZE(a)     ! ""

print *, LBOUND(a,1) ! Allowed only if a is rank at least 1
print *, UBOUND(a,1) ! ""
print *, SIZE(a,1)   ! ""

If the assumed rank variable is a scalar, no value for the dimension is allowed (0, which would be necessary, is not a valid dimension in any case).

But things can get weird: SHAPE(a) may return -1 for some element:

  implicit none

  real a(6)
  call s1(a)
  
contains

  subroutine s1(a)
    real a(2,*)
    call s2(a)
  end subroutine s1

  subroutine s2(a)
    real a(..)
    print *, SHAPE(a)
  end subroutine s2
  
end program

If you do get a -1 you know you cannot use UBOUND to get the upper bound of the corresponding dimension or SIZE to get its extent. You may use LBOUND, however, to get its lower bound.

Finally, array expressions always have lower bound 1 in each dimension and upper bound equal to the extent:

real a(4:7)

print *, LBOUND(a), UBOUND(a)
print *, LBOUND(a(:)), UBOUND(a:))
print *, LBOUND(a+1), UBOUND(a+1)
like image 33
francescalus Avatar answered Oct 18 '22 11:10

francescalus