« previous next»

5.3    Multi-Dimensional Arrays

Although it is useful to have data in one-dimensional arrays, it is sometimes useful to arrange data into rows and columns (two dimensional arrays), rows columns and ranks (three-dimensional), or even higher dimensionality.  In this chapter we will consider multidimensional arrays.

Multidimensional arrays are declared in much the same way as single arrays.  They can be real, integer, logical, complex, or character..  Derived types again can be created but that is discussed in the next chapter.  A comma is used to indicate another dimension.  Colons are again used to indicate subscript divisions.  In general, for n-dimensional arrays:

type, DIMENSION(min1:max1, min2:max2, ..., minn:maxn) :: array_names

where mini and maxi are a pair of integers determining the subscript ranges for the ith dimension.  If the minimum subscript of any dimension is one then mini can be omitted.  For example:

REAL, DIMENSION(0:4, 3:12, 5) :: A       ! A is a 5 x 10 x 5 array
INTEGER, DIMENSION(3, 4) :: B            ! B is 3 x 4

These arrays can also be declared:

REAL :: A (0:4, 3:12, 5)        ! A is a 5 x 10 x 5 array
INTEGER :: B (3, 4)             ! B is 3 x 4

Two dimensional arrays are the most common and the subscripts are just as indicated in most math textbooks.  The first subscript represents row number, and the second column number.

A(1,1)    A(1,2) . . .    A(1,m)
A(2,1)    A(2,2) . . .    A(2,m)
......
A(n,1)    A(n,2) . . .    A(n,m)

INPUT and OUTPUT

Just as with one-dimensional arrays, multi-dimensional arrays can be read using explicit DO loops, the array name without subscripts, and implied DO loops.  Explicit DO loops of course require a nested DO loop for every additional dimension.  In the case of a two-dimensional array:

DO row = 1, max_rows
DO col = 1, max_cols
END DO
END DO

In this case, if read from a data file the  data must be no separate lines.  The array will be read "row-wise", meaning the all of the first row is read, then the second row, then third, etc. until completed.  The loops could be read "column-wise":

DO col = 1, max_cols                        !  Now col is the outer loop
DO row = 1, max_rows                    !  and row is the inner
END DO
END DO

In this case the first column is read (from row 1 to max_rows) then column 2, then 3, until completed.  Using DO loops you can control the way in which you array is read.

This is much the same for implied DO loops.  For "row-wise" input:

READ (10,*) ((array(row,col), col = 1, max_cols), row = 1, max_rows)

col = 1, max_cols is the nested, or inner, loop.  This means row is held constant at 1 and the inner loop is performed, then row is 2 and the inner loop repeated, then row = 3, etc.  "Column-wise" input requires only switching the inner and outer loops:

READ (10,*) ((array(row,col), row = 1, max_rows), col = 1, max_cols)

Finally, the array name without subscripts can be used to input arrays.  If another format is not specified it is the Fortran 90 convention to input and output arrays "column-wise"!  When data is input it is assigned to the first  column until all the rows in that column are filled and then to the next column and so forth.   The importance of knowing this can be seen in an example.  If you have a data file (assumed to be UNIT=10) with data presented as:

1     2     3      4
5     6     7      8
9    10   11    12

INTEGER, DIMENSION(3,4) :: array

Array will be read like this array(1,1) = 1, array(2,1) = 2, array(3,1) = 3, array(2,1) = 4, etc.  Which means that array will truly be:

1    4    7    10
2    5    8    11
3    6    9    12

Fortran reads data sequentially like you read (from left to right, top to bottom), but it will assign values by columns, the first column will be complete before the second column is read.  This can be corrected by using an implied DO loop that reads "row-wise".

Mistakes can also be seen when you try to print an array.  Say the previous array was read properly with an implied DO loop.  Then it would actually be contained in memory as:

1     2     3      4
5     6     7      8
9    10   11    12

When you try to print this array formatted as 3 rows and 4 columns of integer data.

PRINT '(1x, 4I5/)', array

The output will be:

1      5    9     2
6    10    3     7
11     4    8    12

because it prints from left to right, top to bottom, but the order it chooses from the array is "column-wise" just as it reads.  Column 1 is printed first, then column 2, then 3, etc.  This can be corrected using a combination of DO loops and implied DO loops that is "row-wise" in the print statement:

DO row = 1, max_rows
PRINT '(1x, 4I5)', (array(row,col), col = 1, max_cols)
END DO

Since each PRINT statement begins on a new line you are given:

1     2     3      4
5     6     7      8
9    10   11    12

Assigning Values

Arrays can be assigned values using one-dimensional array constants, but they must be given the dimensions of the array using the intrinsic RESHAPE command.  In general:

The one-dimensional specifier gives all the elements of the array.  The shape tells the dimensions of the array. Pad are the values to fill parts of the array not given in the one-dimensional specifier.  These may be repeated if necessary. Order specifies the order in which subscripts should be varied. Pad and order are optional.  An example:

A = RESHAPE ((/ 1, 2, 3, 4, 5, 6/), (/2,3/))

gives a 2 x 3 array:

1    3    5
2    4    6

By reversing the order:

A = RESHAPE ((/ 1, 2, 3, 4, 5, 6/), (/2,3/), ORDER = (/2, 1/))

Subscript to is varied and then one so the 2 x 3 array is:

1    2    3
4    5    6

Pad is used to fill blanks.

A =  RESHAPE ((/ 1, 2, 3, 4/), (/2,3/), PAD = (/0/), ORDER = (/2, 1/))

The mixing elements are replaced by repeated elements of PAD:

1    2    3
4    0    0

 « previous next»