Chapter 9 - Illinois State Chemistry

51
Chapter 9. More Fortran Elements: Arrays
9.1 Introduction
In computer programming, it is often useful to be able to work with structures that involve
r
ordered sets of numbers. For example, a program might be written to manipulate a vector A . Since
a vector has three components, Ax , Ay , and Az, one way to manipulate the components of the vector
in a Fortran program might be to define three variables, AX, AY, and AZ, and then perform
calculations
between two
r withr those three variables. For example, to calculate the dot product€
vectors A and B , the Fortran code would be
PRODUCT = AX*BX + AY*BY + AZ*BZ
€
€
The code above is perfectly acceptable; however, a better way to deal with the components of a
vector is to use a Fortran structure called an array. An array consists of an indexed variable in
which the elements
are stored in consecutive memory areas. The index is an integer. For example,
r
for the vector A , an array might be defined that
r contains the elements A(1), A(2), and A(3) to
r
A . A similar array might be defined for the vector B .
represent the three components of the vector
r
r
Then, the dot product in Fortran between A and B could be defined in the following way,
€
PRODUCT€= 0.0
€
DO 100€I = 1, 3€
PRODUCT = PRODUCT + A(I)*B(I)
100
CONTINUE
While this code is clearly longer than the single line of code shown above, it is much more flexible.
Imagine how tedious it would be if you had two data sets containing 20 elements or even 500
elements to manipulate. Then, to calculate a quantity analogous to a dot product, or even to calculate
an average, would require lots of typing. For example, suppose you measured the temperature
outside each hour for a period of 24 hours. If each temperature reading were assigned to a variable
T(I) in the array T, then the average is computed in Fortran simply as the following:
100
SUM = 0.0
DO 100 I = 1, 24
SUM = SUM + T(I)
CONTINUE
AVERAGE = SUM/24.
Note that this code is quite similar to that used for calculating the dot product above. Thus, the use
of arrays allows the easy storage and manipulation of data sets.
In scientific programming, arrays are very important. One-dimensional arrays can be used
to store and manipulate vectors. One-dimensional arrays are also useful for storing quantities that
change in time (for example, positions and momenta expressed as functions of time). They are also
helpful for storing functions on a grid in coordinate space (for example, Y(I) might contain the
52
values of the function y(x) evaluated at a series of different x values). Two-dimensional arrays can
be used in scientific programming to store matrices and two-dimensional functions.
9.2 One-Dimensional Arrays
One-dimensional arrays have a single integer index. Each array must be declared at the
beginning of the Fortran program as containing INTEGER, CHARACTER, or REAL (either
REAL*4 or REAL*8) variables. For example, to declare an array named A which consists of 10
real elements, the following declaration statement is used,
REAL A(10)
This array consists of 10 real numbers, designated by default A(1), A(2), A(3), …, and A(10).
In some cases, it might be more appropriate to start the index of the array at something other
than 1. The starting index may be set to a value different than 1. For example, to start the index of
the real array A at 0 and include ten elements in the array the following notation is used,
REAL A(0:9)
This designation again provides an array consisting of 10 real elements, but now they are indexed
as A(0), A(1), A(2), …, and A(9). The most general declaration statement allows the minimum and
maximum index to take any integer value; for example,
INTEGER X(–10:20)
REAL*8 ACCEL(50:150)
Each element of the array may be thought of as an individual variable. An individual
element of an array may be referred to in a Fortran program by specific index; for example, A(3) or
A(198). In addition, the variable stored in the nth indexed position may be referred to as A(N). The
values of elements in an array may be assigned directly or they may be computed using the usual
algebraic expressions within Fortran. Some examples of assigning values to one-dimensional
arrays include:
A(1) = 2.0
B(J) = X/Y
Z(I+1) = Z(I)
In the first example, the value of element 1 in the one-dimensional array A is set to 2.0. In the
second example, element J in the one-dimensional array B is defined in terms of two other variables,
X and Y. In the final example, the I+1st element in the array is defined to be the same as the Ith
element.
A common bug occurs in Fortran when a program tries to reference an element of an array
that is out of bounds. For example, consider the following Fortran code:
53
100
INTEGER I
REAL X, DT, A(20)
:
V = 0.0
DO 100 I = 1, 20
V = V + 0.5 * ( A(I) + A(I+1) )*DT
CONTINUE
On the 20th iteration of the loop, the program attempts to access A(I+1), which for I=20 equals
A(21). However, the array A was defined in the declaration statement to run from A(1) only to
A(20). Hence, A(21) is undefined and the result for the variable V when calculated using the code
above is questionable. Some compilers would assign A(21) the value 0.0, but others may just
produce garbage.
It is allowable to declare an array to be larger than is actually used in the program. For
example, we might declare an array X to have the potential to hold 5000 elements but in the actual
code, we might only use 100 of those. This allows the programmer flexibility in changing the
number of elements without having to change the declaration statements.
For example, consider the following code to generate a harmonic oscillator potential energy
function on the range x = [–1.0, 1.0]:
INTEGER M, NSTEP
REAL*8 K, DELTAX, X(5000), V(5000)
WRITE(*,*) 'Enter the step size for x: '
READ(*,*) DELTAX
WRITE(*,*) 'Enter the force constant: '
READ(*,*) K
20
NSTEP = 2.0/DELTAX + 1
DO 20 M = 1, NSTEP
X(I) = –1.0 + DELTAX*(M – 1)
V(I) = 0.5 * K * X(I)**2
CONTINUE
In the code shown above, the user has the option of how fine a grid in the x coordinate to create by
entering the variable DELTAX, which dictates how many elements are used in the X and V arrays.
By specifying an array size for X and V that is quite large, any reasonable value of DELTAX can be
accommodated without any change to the declaration statement. For example, if DELTAX is
chosen to be 0.01, then the first 201 elements of the arrays X and V would be used. The other
elements are not used and therefore are assigned no arithmetic value.
The values of variables to be stored in arrays not only may be defined within the program
(for example, A(1) = 15.0) or entered from the screen (for example, READ(*,*) A(1)), but they
also may be read from a file. This is convenient when there are a large number of elements in the
array. Sample code for reading in arrays T and V, each of length 500, from a file is shown below.
54
INTEGER I
REAL T(500), V(500)
OPEN(UNIT=10, FILE='velocity.dat', STATUS='unknown')
50
DO 50 I = 1, 500
READ(10,*) X(I), V(I)
CONTINUE
9.3 Two-Dimensional Arrays
An array in Fortran may have more than one dimension. In fact, most Fortran compilers
typically allow up to seven dimensions. The most common types of multidimensional arrays are
two-dimensional arrays.
A two-dimensional array must be declared as INTEGER, CHARACTER, or REAL in the
same way that a one-dimensional array is declared. In the case of two-dimensional arrays, however,
two indices are employed to label the array elements. An example of declaring a two-dimensional
array to hold 20 REAL*8 variables is
REAL*8 B(5,4)
By default, in the declaration statement above, the first index runs from 1 to 5 and the second index
runs from 1 to 4. In the same way that was done for one-dimensional arrays, the indices may be set
to start at other values. For example, to start both indices at 0 but keep the 20 total elements, the
declaration statement would be
REAL*8 B(0:4, 0:3)
A two-dimensional array is laid out in the same format as are the elements of a matrix. In
the first example above, the array B has twenty REAL*8 elements laid out in the following way:
B(1,1)
B(1,2)
B(1,3)
B(1,4)
B(2,1)
B(2,2)
B(2,3)
B(2,4)
B(3,1)
B(3,2)
B(3,3)
B(3,4)
B(4,1)
B(4,2)
B(4,3)
B(4,4)
B(5,1)
B(5,2)
B(5,3)
B(5,4)
In the computer's memory, these elements are stored columnwise. That is, B(1,1) is stored first,
followed by B(2,1), B(3,1), B(4,1), and B(5,1). Next comes B(1,2) through B(5,2). The element
B(5,4) is stored last. This is sometimes important when writing code to run at optimum speed on a
system.
55
To reference an array with two dimensions, two integers are required to indicate the specific
elements of the array. The following sample code illustrates the declaration of a real 2×2 array A
and the use of two nested DO loops to read in the elements from the screen:
INTEGER I, J
REAL A(2, 2)
200
100
DO 100 I = 1, 2
DO 200 J = 1, 2
WRITE(*,*) ' Enter A', I, J
READ(*,*) A(I, J)
CONTINUE
CONTINUE
9.4 Multi-Dimensional Arrays
Multi-dimensional arrays of up to seven dimensions may be specified in Fortran. Working
with arrays of higher dimension is not much different than working with two-dimensional arrays.
Each dimension is assigned its own integer index. For example, the following declaration
statements define a three-dimensional array A and a four-dimensional array B:
REAL A(100, 3, 3), B(5, 2, 2, 2)
Here, the array A is designated to hold as many as 100×3×3 = 900 elements that would be indexed
by three integers, such as A(I, J, K). Array B is defined to hold as many as 5×2×2×2 = 40
elements, with each element indexed by four integers, such as B(I, J, K, L).
56
Chapter 9 Review Problems
1. Determine which of the following Fortran statements are valid for arrays. Assume that the array
X is defined as a REAL one-dimensional array and that the array Y is defined as a REAL twodimensional array. The variables I and J are defined as INTEGERs.
a.) X(5.5) = 0.2
b.) X(I+1) = X(I) + 0.5
c.) Y(1, 1)*2.0 = Y(2, 2)
d.) Y(1, J) = Y(1, J–1) + 1.0
2. Determine the values stored in the variables A(1) through A(5) in the following code.
REAL A(5)
PI = 3.14159265
DO 100 I = 1, 5
A(I) = SIN(PI*(I–1.0)/2.0)
CONTINUE
100
STOP
END
3. Write a segment of Fortran code that reads in the components of two vectors into two onedimensional arrays and then calculates the componentsr of a third
r vector that represents the cross
product. Recall that the cross product of two vectors A and B is
r r
A × B = Ay Bz − Az By iˆ + ( Az B x − A x Bz ) ˆj + A x By − Ay B x kˆ .
€ r €
r
A
Here, A x , y , and Az are the components of A , B x , By , and Bz are the components of B , and
iˆ€
, ˆj , and kˆ are unit vectors in the x, y, and z directions, respectively.
(
€
€€
€
€
€
)
€ € €
(
€
)
€
57
4. Consider a data set given as:
1.23
0.457
–0.989
1.02
0.554
0.623
–0.787
–0.033
1.48
A Fortran program is constructed to read in the data set above from a file into a REAL twodimensional array X. A segment of code to do this is shown below.
REAL X(3, 3)
OPEN(UNIT=10, file='data', status='unknown')
200
100
DO 100 I = 1, 3
DO 200 J = 1, 3
READ(10, *) X(I, J)
CONTINUE
CONTINUE
STOP
END
What value is stored in each of the elements of the array X at the end of the program?