Lectures_on_FORTRAN by stariya

VIEWS: 3 PAGES: 21

									Chapter 1 Fortran Primer
Follow Donev‘s .pdf file except to
    a. add F90 updates on the fly then again as a partial review
    b. quiz the class on new examples
    c. create new homework to have them write pieces of FORTRAN code.

Introduction

The basic Structure of a Program:

1. Program name starting line
       PROGRAM name

2. preset environment (optional, but recommended)
        IMPLICIT NONE

3. Non-executable statements, such as type declaration, storage assignment, initialization.
There can be almost any number. The order can matter for PARAMETER statements
since a variable defined by the statement must precede its use by another non-executable
statement such as:
        PARAMETER etc.
        REAL etc.
        INTEGER etc.
        CHARACTER etc,
        DIMENSION etc.

4. Executable statements such as:
       OPEN etc.
       READ etc.
       WRITE etc.
       FORMAT etc.
       DO etc., END DO
       IF etc., THEN, ELSE
       CALL subname
       CLOSE etc.
       STOP
       END PROGRAM
       SUBROUTINE subname
       RETURN
       END SUBROUTINE

5. a termination statement like END PROGRAM name. Though a STOP can do this.

Other executable and non-ex statements are used, above are some common examples.


                                            1-1
Somewhat different from the scripting environment of Mathematica, Mathcad, and
probably Matlab, you must indicate the variable type and you must set aside storage and
how it is organized for each variable.

If you are familiar with C/C++ then you are familiar with declaring the type and
allocating space for the variables you use. For example, in C:
         int I ;       /* declare I of type integer */
         float x ;     /* declare x of type floating point */
         short i ;     /* declare I of type short integer -32,768 <i<32,767 */
// note that C & C++ are case sensitive where fortran is not, I /= i
         char cGrade /* character string (using integer character codes from -128 to 128.

Fortran does a similar thing with its statements:
       INTEGER I
       REAL x
       INTEGER*2 LITTLEI
       character*5, chr                           (being phased out with F95)

We will discuss these later. At the moment we are drawing analogies to other languages.
There are short-cuts, by default, fortran will assume that variables beginning with the
letter I,j,k,m,or n are type integer. A name beginning with any other letter is floating
point by default. You can override these defaults by using integer and real statements.

A basic part of C/C++ is the ability to have local and global variables. This separation
was cumbersome in older versions of fortran. In f90 there are streamlined ways of doing
the same thing (using a module subprogram).

Executable statements are present in any programming environment. What varies is the
syntax.
For example. In EXCEL you use the carat (^) to designate a power or ―exponentiation‖.
In fortran it is a double asterisk (**). Hence 2.**3 = 8.
Fortran provides you with a collection of mathematical functions by default as do
scripting environs and spreadsheet programs. In fortran, we call these intrinsic
functions. Examples include: sin, cos, tan, atan, asin, acos, sinh, cosh, tanh, sqrt, alog,
exp, …
In C you must include them manually with a #include <libname> statement.

Scripting environs like Mathematica purport to have many other mathematical operations
than the list of fortran intrinsic functions. But be aware that what Mathematica does in
those cases is either look up a table or perform a numerical analysis calculation such as
the ones we‘ll discuss in this course. For example, solving an integral.

With this introduction, let us go to Donev‘s .pdf file.




                                             1-2
1.1 A Few Logistics
       The unix command to do a fortran compile on moe uses pgf90

1.2 Program Layout
       Six guidelines are given. Be aware that 3rd, 4th, & 5th are altered in true f90 though
our compiler is forgiving.
       We have already discussed the basic structure.

<<<< start of 2nd lecture in F 03>>>>

1.3 Variables
       Use of IMPLICIT NONE was already recommended

1.3.1 Naming convention.
       3 rules are given. Note that UNIX & C/C++ distinguishes upper and lower case.
       Fortran does not except in output—printing and plotting.
       The reserved words refers to default names. Don‘t name a variable ―float‖ say.

1.3.2 Data types
       INTEGER – only whole numbers allowed for the listed variable. Default is
integer*4 though that declaration method is being phased out with f90 (discussed later)
This means ―integer m‖ accomplishes the same thing as ―integer*4 m‖
               F77: integer*8 k              ! makes k double precision
               F90: integer (8) :: k         ! makes k double precision

        REAL – floating point numbers for the listed variable, could be whole or have a
fractional part…. Default is real*4 again being phased out. See section 2.2 (p.20-21) The
syntax is similar to integer examples above.
                F77: real x_2, y(2)
                F90: real :: x_2, y(2)          ! alternative
! Note that underlines and numbers are allowed inside variable names, but not at the start.
        Distinguishing the type is important because the typical machine stores an integer
different than a floating point number. Accordingly, intrinsic functions often require an
input variable to be of a certain type: e.g. SIN(x) x must be floating pt.
        Note that there are ranges for all number types; the range depends on the word
length used by the machine. If you exceed the range then the program stops and an error
message with wording such as ―overflow‖ or ―underflow‖ is generated.
        Other types

        CHARACTER, COMPLEX likely to be used in exercises at some point.
        Important note: F90 does this very different now and some forms allowed in F77
and F90 are obsolete in F95. More is said when we discuss section 2.21 of Donev‘s .pdf
file. The format is similar to the F90 examples above, except you have a length
parameter:
               F77: character*10 chr10



                                            1-3
               F90:    character (len=10) :: chr10

1.3.3 Variable Declaration
        Recall the default type declaration based on the first letter of the name.
        Oddly, the Donev‘s guide (.pdf) does not discuss arrays at this point. I think it
should, since type declaration is often done at the same time as array declaration.
Furthermore type and array declaration are non-executable statements and so are done in
the same region in the code. Finally, our examples are more interesting if we know about
arrays. So, briefly we jump to 1.9 before returning to the order in the fortran guide.

1.9.1 Declaration of Arrays
       Arrays are a collection of data to be housed inside one variable. For example, you
might want all the temperature values this year at Davis housed in a variable ―T‖. You
assign T to have a size of 365. You have a variety of ways to do this:
               DIMENSION T(365)               ! F77
       Or      REAL T(365)                    !F77
       Or      REAL T(1:365)                  !F77
These are the same. Note the use of a colon to define the range start:end

        We call this example T a 1-dimensional array. Arrays can have more dimensions.
Usually you choose the dimensions based on a logical ordering of your information. For
example, you may have velocity U on an array that is 24 points in x, 13 points in y, 5
points in z, and at 10 time intervals. In that case, you may want to define
                DIMENSION U(24, 13, 5, 10)
Jargon: 24 is the length of the 1st dimension, etc.

       One final note. Arrays are used in C though there are key differences. Fortran
increments arrays oppositely to C in storage. And, by default fortran arrays start with
index 1 whereas C arrays start at 0 by default.

(end of 1.9.1, return to section 1.3.3)

       Some basic F77 type declarations are given here. F90 does this differently as
noted above.

        You can use the parameter statement to assign dimensional values efficiently:
        PARAMETER (N=5)
        DIMENSION A(N), B(N), C(2*N)
but the variable must defined before it is used. You cannot switch the order of the 2
statements above.

      In F90 you do this even more cleverly by means of MODULES (with SAVE and
USE statements). We can illustrate that later.

1.4 Basic Expressions




                                            1-4
1.4.1 Arithmetic Operators & Expressions
       You can have rational powers. You can use a variable for a power, for example
potential temperature:
       xkappa = R/C_p
       theta = T * (p/p0)**xkappa
       FYI: whereas Excel and some scripting languages use ^ to indicate
exponentiation, ** is used here (and in C)
       Note: if you have a choice, always use integer powers.
       Note: you can take an integer power of a negative number, you cannot raise a
negative number to a real power (Real powers use ln; ln(neg #) not defined). But,
multiplying a number by itself ―n‖ times is well defined.

        Order of evaluation: when in doubt, use parentheses.
        Be careful about mixing mode: having an expression with a mixture of floating
and integer variables. See example of i=1/5 vs x=1./5.

1.4.2 Assignment statement
       Do not confuse the assignment (=) from the equivalence (= =) operator. The
former assigns a new value, the latter checks for equivalence.

1.4.3 Relational Operators
       F77 uses abbreviations, F90 allows symbols
       F77: .EQ. .GE. .GT. .LE. .LT. .NE.
       F90: = =       >=      >        <=      <       /=
       Common pitfall: remember to include those periods to either side.
               example: if(1..ne.x) etc. the first entry is floating point 1.
       If you are familiar with C all but the last one are the same (C uses !=)

1.4.4 Logical Expressions
       F90/F95 uses the same nomenclature
       Use to combine multiple tests. For example: ―If this and that are true, then do
something else...‖
               F77: if(x.gt.2..and.y.ne.3.) nxy=nxy+1
               F90: if(x>2..and.y/=3.) nxy=nxy+1

1.5 Characters and Strings

1.5.1 String Declaration
        CHARACTER is non-executable statement
        CHARACTER as defined in Donev‘s .pdf guide for F77 is obsolete in F95
        F77: CHARACTER*8 first_word
        F90: CHARACTER (LEN=8) :: first_word

1.5.2 Character Operations
       Better concatenation example:
       F90: CHARACTER (LEN=3) :: CHR1,CHR2



                                            1-5
       F90: CHARACTER (LEN=6) :: CHR3
       CHR1 = ‗Atm‘
       CHR2 = ‗150‘
       CHR3 = chr1 // chr2
!        CHR3 is now Atm150 --- note preservation of upper/lower case


1.5.2 Character Functions
       These are not required in this course.

1.6 Input and Output

The discussion here is somewhat inverted in terms of your code. In general, you want to
read or write to a file. In that case you must first assign the file to a “unit number‖ so
that the code knows where to retrieve (READ) or send (WRITE) information. You assign
the unit number of your choosing with an OPEN statement. Since you have to start with
the open statement, I start with 1.6.4

1.6.4 File Input and Output (I/O)
         There is an OPEN example in the class webpage on formatted printing.
I have never used ‗SCRATCH‘ as an option. I usually use ‗UNKNOWN‘. Why? Because
it may not exist the first time I run my job, but might on subsequent runs.
         Not shown is the optional declaration of the format: form=‘formatted‘ is used in
the demo_ptline.f file. Other option: ‗unformatted‘
         You should avoid certain unit numbers like 5 and 6 since the system may want to
reserve those for compiler use. Unit numbers from 7 to 99 are popular choices.
         There is a CLOSE example in the class webpage on formatted printing
         The ―STATUS‖ declaration is optional in my experience. You could use the unit
for temporary storage and then declare the status delete when you are done.
         A recommended option is IOSTAT (which checks the i/o status after open
executed); Example (F90):
         OPEN(UNIT=8,FILE=‘TEST.OUT‘,STATUS=‘UNKNOWN‘,IOSTAT=IOTST)
!        CHECK FOR OPEN ERROR
! IF statement discussed in 1.8.1, it checks if iotst does not = 0, then print error message
         IF(IOTST /= 0 )THEN
                PRINT *,‘COULD NOT OPEN TEST.OUT‘
         ENDIF

        There are other options that are sometimes useful: ACTION (can designate if file
is read only, write only, etc.); ERR (a statement label to jump to if the OPEN fails); to
name just some.
        Implied Do-loops – save this for moment until discuss READ and WRITE

1.6.1 READ
       See the formatted printing primer.
       After assigning a unit number (9 say) by means of an OPEN statement



                                            1-6
       READ(9, [format statement number]) {input list}
       The format statement number is used to specify the line where the organization of
the input data (i.e. the data‘s format ) is spelled out.
The format is optional. If you have an * there, then it uses ‗free format‘ and you can vary
how you enter information. Note that this is ‗quick & dirty‘ (i.e. it is easy but sloppy) it
works best for simplifying keyboard input.

        If you don‘t have the format but have, say:
        READ(9) {input list}
then fortran assumes the data is in binary form. While binary is more compact than
formatted writes, different machines store data differently and you may have
incompatibility issues to contend with.
        If the unit is * then it usually expects you to input the data from the keyboard (or
―screen‖ in the terminology of some documentation).

1.6.2 WRITE (writing information)
         Similar syntax as READ.
         There are 2 options, PRINT & WRITE. Both can do formatting. PRINT sends
stuff to the screen. WRITE sends stuff to a file you specified with your open statement.

1.6.3 FORMAT
        You give the FORMAT a statement number, such as:
        READ (9,4) x
   4    FORMAT(f6.2)
        See the formatted printing web page for examples and use. The sample program
for problem 1 also compares PRINT and WRITE with slight variation so you can tell
them apart. Go to that….

       You can also put the formatting inside the READ command. For example:
             READ (9, FMT=‘(f6.2)‘) x

1.6.4 – implied Do-loops
        You use this to read or to write a collection of things at one time, such as all or
part of an array. You have a counter, starting point, end point, and skip interval (by
default, skip interval = 1)
        DIMENSION x(25)
        PRINT *,(x(i),i=3,10,2)
This prints out x(3), x(5), x(7), x(9) to the screen in free format.

<<<<< End of 2nd FORTRAN lecture F03, Start of 3rd >>>>

1.7 Functions and Subroutines

1.7.1 Intrinsic functions
       These are functions supplied automatically. A few are listed here; there are many
more. Note that no ―appendix A‖ is in Donev‘s .pdf file!



                                             1-7
       It is crucial to match the type expected by the intrinsic function (or any function)
       There can be some subtle variation between different fortran packages. The
Portland Group fortran on moe is available online, I posted the link on the course
webpage. (see student exercises page)

1.7.2 Intrinsic Subroutines
        Note distinction: functions return a value: x=sin(y) and don’t change the
argument of the function. In contrast subroutines can return information in one of
more arguments and may change the value of an input argument. Subroutines can
perform an action without returning anything, for example the plotting subs.
        Intrinsic subroutines also may differ between fortran packages. For example, pgf
has a routine called ―RAN‖ which may or may not access random_number through an
alias as well (like the random_number function listed in Donev‘s .pdf file)

1.7.3 External Functions
        Functions you define.
        Donev‘s .pdf guide has a good example.
        A source of confusion: what is being sent in the ―dummy arguments‖ or simply
the ―arguments‖ that are input to the function. These are not numeric values (or
characters if of that type), but address locations on the disk. Even if you put a ―number‖
in for an argument, you are sending a location on the disk where that number has been
placed. We identify those locations on the disk with ―pointers‖. Those familiar with C
will recognize a similar concept by the same name. However, we don‘t access the
pointers in the same way in F77.
        Since pointers to locations in storage are being sent, you can imagine that nasty
errors occur if you do not match the type between function and calling units. This is why
we emphasized that with intrinsic functions.
        There are a couple of ways in which you could have this type of nasty error. For
example, scrambling the order of the arguments: USE DEFAULT TYPES HERE:
                S = DUMB(X,Y,I)
                ….
                FUNCTION DUMB(K,S,T)
                Etc.
This is a severe error. Another common error is to request something outside of the
bounds defined for an array. For example:
                DIMENSION R(5)
                …
                S=SUM2(R(5))
                …
                FUNCTION SUM2(X)
                DIMENSION X(2)
                SUM2=X(1)+X(2)
                RETURN
                END
This tries to add R(5) and ―R(6)‖ but R does not encompass R(6). This example is easily
seen to be incorrect. In practice this error is more subtle and commonly occurs when



                                            1-8
information about the arrays does not match between program units…AND… when you
ask for something outside the bounds. The error message is something like: ―address out
of bounds‖ or ―operand range error‖ in this case.
        Also note how we pointed to the 5th element in R in the argument of the CALL to
SUM2 and passed that address to the SUBROUTINE.

1.7.4 Statement function
      These have been declared obsolete by F95, so we won‘t discuss them.

1.7.4 External Subroutines

         The structure is like a mini version of your program. The program statement is
replaced with a SUBROUTINE statement. You have non-executable statements then
executable statements. You have an END or END SUBROUTINE statement to mark the
end of the routine.
         Some differences:
         You invoke the subroutine by a CALL statement
         You have a RETURN statement in the subroutine to go back to where you made
the last CALL to the subroutine.
         Some compilers save the values of local variables inside your subroutine between
calls, some don‘t. Local variables are not passed through the subroutine argument list, nor
are they in a PARAMETER statement. (You can‘t explicitly SAVE those, but they are
saved automatically). To ensure a variable is saved you can specifically save it with F90 a
SAVE call
         F90: SAVE :: nmbrcount
I am told that simply have a line with just SAVE on it is sufficient to save all local
variables.
         There seems to be a typo here: INTERNAL should be INTRINSIC.
         The example here (page 14 in Donev‘s guide) illustrates how a function can be
passed as an argument. The function needs to be recognized as such in the arguments of
the CALL statement by means of the non-executable EXTERNAL statement, or in this
case INTRINSIC.
         The example is a poor one because it uses a labeled DO loop, and those have not
been discussed yet. A simpler example:
         REAL A, B, C,D,MAX1,MAX2
         …
         C= - 1.e30
         CALL FNDMAX(A, B, MAX1)
         …
         CALL FNDMAX(C, D, MAX2)
         …
         STOP
         END
         SUBROUTINE FndMax(x1, x2, x3)
         REAL x1, x2,x3, count
! bad practice to use COUNT undefined before 1st use



                                           1-9
       COUNT=COUNT+1.            ! local variable
       X3=x2
       IF(x1.gt.x2) x3=x1
       RETURN
       END SUBROUTINE            or END SUBROUTINE FndMax or END FndMax
In F90 use the SAVE command in the subroutine.

1.8 Control Structures

     Include branching (IF-THEN and IF-THEN-ELSE blocks of statements as well as
GO TO statements) and looping.

1.8.1 IF-Blocks
        The discussion and example are good here.
        It is easy to get confused if you have several nested IF tests. One recommended
practice is to indent the contents of each IF block. So an IF block nested inside another is
indented twice. Note: do not use the tab key to indent!
        Logical IF statements are a shortcut when you have a simple operation to perform.
For example:
        F90: IF(x = = 0.) x=0.01               ! doesn‘t allow x to = 0.
Is the same as:
                 IF(x = = 0.) then
                 X=0.01
                 END IF

        F90 allows one to name IF blocks which can facilitate identifying which IF-block
is being terminated by a particular end if.

       F90 also has alternative branching via CASE statements (see 2.4.1)
       If you are familiar with C, the IF and ELSE statements are similar. Also note that
in C you might prefer to use SWITCH statements where FORTRAN might nest IF-
THEN statements. The SWITCH statements use CASE blocks similar to F90, though C
terminates each case with a BREAK; and F90 does not bother to do so.

        There is another kind of if statement, the ―arithmetic if‖. Instead of a logical
expression, you have an arithmetic expression. Depending upon the result: negative, zero,
or positive you could go to 1 of 3 different places. This is obsolete in F95 and may be
removed from later Fortran. Do not use.

1.8.2 DO - Loops
        Used for repetitive actions. A common use is when you want to perform a similar
calculation for each element of an array.

        In Donev‘s guide, we have a numeric DO loop. Essentially, the number ―10‖ is a
label. The loop is ended with the statement number 10.




                                           1-10
        ―counter‖ is called the loop index. It has value ―start‖ the first pass through the
statements inside the loop; it is incremented by amount ―step‖ each successive time, until
it exceeds ―limit‖. When it exceeds ―limit‖ the program moves to the next statement after
the loop‘s end.
        ―limit‖ in the DO statement refers to the end value of the counter
        ―step‖ in the DO statement refers to the skip interval.
        ―counter, start, limit and step‖ used to be integer only, then were allowed to float,
and in F95 they now must be integer! Unfortunately, Donev used float ranges on p. 14 in
an earlier example!

      Use of numeric label is being phased out. There are two popular variations
promoted now. The counting loop would look as follows for Donev‘s example:
             Integer NX
             NX=101
             DO J=1,nx
                X=float(j-1)/float(nx-1)
                CALL PLOT(x,my_func(x))
             END DO

The numeric label (as in the example) is very useful in practice and has been brought
back in a different form as a labeled DO. The above could be repeated as:
                Integer NX
                NX=101
                RGloop : DO J=1,nx
                   X=float(j-1)/float(nx-1)
                   CALL PLOT(x,my_func(x))
                END DO RGloop

        Exiting a DO loop used be by means of the ―unconditional GO TO statement.‖
This is GO TO ## statement paired with a ## CONTINUE statement. F90 has the EXIT
command which simply moves control to the next statement after the END DO for the
current DO loop. Unfortunately, you can‘t exit out of more than one loop at a time this
way. If you want to exit more than one loop, then you use a labeled Exit for a labeled
loop.
        Accordingly, the unconditional go to is still allowed. Example:
               DO i=1,nx
                       DO j=1,ny
                               If(F(I,j).eq.0.) go to 25
                       END DO
               END DO
               …
        25     CONTINUE
               Print *,‘F has at least one zero value‘

       Note: CONTINUE statements do nothing but provide a place holder




                                            1-11
       Skipping the rest of a DO loop used be by means of unconditional GO TO ##
statement branching. F90 has a better way using the CYCLE command which simply
increments the counter and moves control to the next statement after the DO

       Good practice:
             1. use indentation as was mentioned in IF-then discussion
             2. never depend on loop index value to be retained after exiting loop
             3. assign names to large and to nested loops

       Pitfalls
                1. never modify a loop index inside a DO loop!
                2. don‘t use statement label DO loops (Donev‘s example) they are
                    obsolete in F95 and could be deleted in later fortran
<<<< save rest of discussion in this section for later >>>>>
        Fortran 90 books discuss two other types of loops: the ―while loop‖ and the ―do
while‖ loop. The former keeps repeating an action indefinitely until some criterion is
satisfied and the program exits the loop.
        Example of F90 ―while‖ loop:
                DO
                …
                IF (x>2.) EXIT
                …
                END DO

The ―do while‖ loop is not recommended for use. Both have the advantage of handling a
situation where you don‘t know how many times you will need to do the action. Both
have the disadvantage of potential for an infinite loop – the program becomes stuck doing
that action inside the loop until you kill the job. As for the advantage, we will see
numerical schemes where iteration is used for which you don‘t know how many times
you‘ll need to perform the action. As for the disadvantage, infinite loops are a common
error!
<<<< pick up discussion here >>>>

1.8.2 GO TO statement
       The unconditional GO TO is discussed above. The example shows a looping use
which is common but some consider it ‗bad‘ programming. It is a convenient way to have
an indefinite loop, though again, there is a danger of getting an infinite loop.
       The computed GO TO is obsolescent in F95. Avoid it.

1.8.3 STOP statement
        Adding a message is useful to know where your program stopped. For example if
a test you pose is failed, such as the iostat value above.

1.9 Arrays

1.9.1 Declaration of arrays



                                          1-12
       We have discussed F77 array declaration already.

1.9.2 Using arrays
        In F77 and before, arrays were accessed element by element as stated. You
specify the value of each index. In a do loop you can use the loop indices to identify
those index values. Here are some simple examples:
               DIMENSION X(21), ODD_X(11)
               DO I=1,11
               ODD_X(I) = X(2*I-1)            ! every other location
               END DO

               DIMENSION F(nx,ny)
               CALL EZY(F(1,3),nx)
       ! pass the location of 1,3 in F…*warning* must have ny >= 3

               DIMENSION F(nx,ny)
               CALL EZY(F,nx) is the same as          CALL EZY(F(1,1),nx)

        The default starting location is 1 in Fortran. But you can choose other starting
locations with those numbers separated by a colon. These numbers must be integers.
They must be specified in a non-executable statement. Examples:
                DIMENSION F(-21:-1, 0:30)
        ! F has 21 elements in the first dimension, and 31 in the second

Some care is needed in F90 when using MODULES since the starting and ending
information might not be automatically passed, only the length.

<<< skip >>>
       In F90 one can do simple forms of array arithmetic. See 2.5.4 and 2.5.5 (p. 27-28)
in Donev‘s guide. Note use of ―:‖ by itself to mean use that entire dimension in the
implied loop.
<<< end skip >>>

1.9.3 Arrays as Arguments to Sub-programs
        Matching use between subprogram and calling unit is crucial. Most errors are due
to a mismatch. It could be asking for a point out of bounds.
        You can change the dimensions of the array, and the rank between program units.
Just: 1.) don‘t exceed the range of the array and
        2.) ensure you actually use what you intend to use

Types of arrays in a subprogram:
Fixed size – specified numeric ranges either using numbers in the dimension or variables
defined in parameter statements.
Adjusted size – pass array dimensions as arguments in the call statement
Assumed size – in F77 you could only do this in the last dimension using a ―*‖ or even a
―1‖ as in REAL F(nx,ny,*) you are free to have different values for that third dimension



                                            1-13
but not outside the range originally defined for F. In F90, the other dimensions can be
handled this way as well, using ―:‖ not ―*‖. You can even define temporary arrays (so
called ―automatic arrays‖ in 2.5.1)


CHAPTER 2: Overview of New Features in Fortran 90

2.1 Program Layout

       keywords here are ―up to‖ 132 columns. By default in my experience, you usually
have 80 columns.
       semi-colon to have more than one statement on a line
       trailing ampersand (&) continues text onto the next line with free
format…Caution! & does not continue a comment!
       statement labels can have up to 5 digits (same as earlier Fortran)
       comment lines begin with ! as can trailing comments – useful for labeling an
expression. For example:
               REAL, PARAMETER :: XKAP=1.e3                 ! 2nd order diffusion coef.

2.2 Variables

2.2.1 Variable Declaration
        We already noted the use of the double colon. ::
        Examples shown by Donev are typical.
        One thing missing here is the INTENT attribute. This is useful in a subprogram in
order to check what is input only (cannot be modified in the subprogram), output only
(will be modified, but the input value will not be used), or could be input & output both.
These are set with the intent attribute. For example:
               …
               CALL PRCNTERR(f, fcor,perr)
               …
               SUBROUTINE PRCNTERR(f,cor,pcnt)
               REAL, INTENT(IN) :: f,cor
               REAL, INTENT(OUT) :: pcnt
               If(cor/=0.) then
               Pcnt=((f-cor)/cor)*100.
               ELSE
               Pcnt = 0.
               Print *,‘Correct value is zero‘
               END IF
               RETURN
               END

2.2.2 Data Types
       How to set word length is shown. Modules referred to is coming up shortly.




                                           1-14
2.2.3 Derived Data Types
       This allows you to set up your own combinations of intrinsic data types. For
example, you might want to associate an integer and a floating point number:
               TYPE StationDat
                 CHARACTER (len=12) :: sta_name
                 INTEGER :: Day
                 REAL :: Temp, Pres
               END TYPE StationDat

              TYPE (StationDat) :: F
              F = StationDat(      Davis,54 , 288., 1004.5)
       ! Davis is station name, the day is the 54th, the Temperature=288.K, the Pressure
= 1004.5 hPa.

        The % sign in Donev‘s example allows addressing of a specific component of the
variable. The ―%x_component‖ is a pointer.
        A realistic use for derived data types might be to set up arrays similar to the
StationDat type. It might allow you to enter information for a station on a given date all at
once. Then you would be able to group the data by some category, such as all T data at
Davis, T data for all stations on a given day, range of days, etc. by sorting by %Temp

2.3 Functions and Subprograms

2.3.1 Program Units
        Variables in a program unit are separate from other units:
               Avoids variable conflicts
               Requires passing some information
               Works best when an isolated calculation is isolated in a unit

Sharing information/data
       To share data between various program units, you have several tools:
CONTAINS, INTERFACE, dummy argument lists, labeled COMMON, unlabeled
COMMON, and MODULES.
       Unlabelled common is quite a relic and has little utility today. Labelled
COMMON remains useful, though modules are intended to improve upon and ultimately
replace it.

<<< end of lecture 3 >>>

2.3.2 CONTAINS
        Use this when you want a subprogram to know information in the main program.
Note in the example how the i-n integers do not need to be declared, nor passed to the
subroutine Zero_counters because they are already declared in the main program. Any
variable not already declared in the unit but used inside the code bracketed by the
CONTAINS must be declared.            (e.g. p.475 in Chapman book)
        The things in a CONTAINS must be placed at the end of the unit.



                                            1-15
2.3.3 INTERFACE & INTENT
        The idea here is to provide information about a subprogram to ensure proper use
of the subprogram. There actually are 4 types of interface blocks and they are most
powerful for derived data types. Since that is a bit beyond what we require for this
course, I‘m going to skip this and instead focus on modules. It is generally recommended
that one use interfaces when a module won‘t do the job.

2.3.4 MODULES
       The block of code contained within a named MODULE is accessible from any
other part of the program by means of the USE command referencing that name. Modules
are similar to labeled COMMON in that you can share information between different
subprograms this way. Some ads & disads:
       i. Unlike labeled COMMON, you do not need to duplicate the information on the
labeled common; mismatches can create hard-to-find errors in labeled common.
       ii. the USE command can be far more compact than duplicating a block of labeled
common lines.
       iii. In both cases, you need to be careful that your variable naming does not
unintentionally change something in either unit. With a labeled common in your
subprogram you can change variable names; also, you have them displayed right there in
the subprogram. In the case of a USE statement you don‘t have those names right there,
but must check the module to ensure it does not have a name conflict. Be extra careful
when altering the module by changing or adding variable names… For example, don‘t
have variable I storing a constant in a module and as a loop counter in another unit that
USEs that module.
       iv. unlike labeled COMMON, a module can contain executable commands

      If you are familiar with C, ―global variables‖ are like using a named MODULE +
USE statements.

Modules have a variety of uses:
1. Global data sharing of values or variable typing information (including array sizing)
with other program units. Example:
               MODULE dat
                       IMPLICIT NONE
                       SAVE
                       INTEGER, Parameter :: nx = 21
                       REAL :: F(nx), x(nx)
               END MODULE dat
               PROGRAM TestDat
                       USE dat
                       IMPLICIT NONE
                       REAL :: pi
                       INTEGER :: i
                       Pi = acos(-1.)
                       Do I = 1, nx



                                           1-16
                           X(i) = float(i-1)*pi*2./float(nx)
                           f(i) = cos(x(i))
                    END DO
                    CALL PRINTY
                    STOP
               END PROGRAM
               SUBROUTINE PRINTY
                    USE dat
                    INTEGER :: i
                    DO I = 1,nx
                           PRINT *, ‗ F(i) = ‗,F(i),‘ at x(i)‘, x(i)
                    END DO
                    RETURN
               END SUBROUTINE

Notice the repeated use of the implicit none statement. The module is separately
compiled from the main program.

2. Module Procedures (p. 347 in Chapman, not in Donev‘s guide)
        One can include a procedure within a module, for example: a subroutine. The
advantage in doing so is the compiler will explicitly check every argument in the
subroutine as to type, number, intent, etc. In contrast, when a subroutine is appended to a
program these are not necessarily checked and difficult to find errors may occur: operand
range errors, mixed mode errors, or worse.
        The structure is similar to the prior example. Just that a function or subroutine is
inside the MODULE definition block of code. Note that:
        i. your subprogram follows the nonexecutable statements in the module
        ii. a CONTAINS statement precedes the Subroutine statement. (Note: p. 492 in
Chapman; that INTERFACE statement may replace the CONTAINS to start an
―Interface Block‖ which requires an END INTERFACE before the END MODULE.
        iii. You would have the same USE statement in the unit where you want to call
the subroutine in the module.

For example:
        MODULE sub
        IMPLICIT NONE
        SAVE
        INTEGER, Parameter :: nx = 21
        REAL, DIMENSION (nx) :: F, x
   CONTAINS
   SUBROUTINE SIGN_CHG(A)
   REAL :: A(:)
   A=-A
   RETURN
   END
        END MODULE sub



                                           1-17
        PROGRAM TestDat
        USE sub
        IMPLICIT NONE
        REAL :: pi
   INTEGER :: I
        PI = ACOS(-1.)
        DO I = 1, NX
        X(I) = FLOAT(I-1)*PI*2/FLOAT(NX)
        F(I) = COS(X(I))
        END DO
        CALL PRINTY
   CALL SIGN_CHG(F)
   CALL PRINTY
   STOP
   END PROGRAM
        SUBROUTINE PRINTY
        USE sub
   INTEGER :: I
        DO I = 1,nx
        PRINT *, ' F(i) = ',F(i),' at x(i)', x(i)
        END DO
        RETURN
        END

       Notice in the example above, that a module can include subroutines that use
assumed-shape arrays just like regular subroutines.
       Following this practice ends up making all your subroutines come first in a series
of MODULES and your main program being the last thing in the file! The program then
looks kinda ―upside down‖ in that case.

2.4 Control Structures

2.4.1 CASE blocks
        F90 has an alternative to branching by means of IF-THEN-ELSE.
        Donev‘s example is a good one. Note that you can have ranges or one or more
single values. Ranges denoted by : (colon).
        The CASE arguments must be character, integer, or logical
        Example for chaos problem:
           INTEGER :: RB
           R=RAN(JJJ)
           RB = int(3.*R)
           Vbranch : SELECT CASE (RB)
            CASE(0)
              XG=(X+A(2))*0.5
              YG=(Y+B(2))*0.5
             CASE(1)



                                          1-18
               XG=(X+A(3))*0.5
               YG=(Y+B(3))*0.5
              CASE DEFAULT
               XG=(X+A(1))*0.5
               YG=(Y+B(1))*0.5
             END SELECT Vbranch

       If you are familiar with C, you will recognize a similar feature also named case.
Notice that in C you end each Case segment with a ―break;‖ Otherwise it is similar.

2.4.2 DO loops
        Donev‘s example is what is known as a ―While Loop‖ (p. 109 in Chapman).
Notice how the DO statement has no limits. You exit by means of the EXIT and can skip
the rest of the loop and return to the start by means of the CYCLE command. Notice that
the EXIT can branch out more than one nested loop if you have the loops properly named
and EXIT to a specific name. The default EXIT is on the outside of the current loop.
        Donev‘s critique of the GO TO is not quite accurate. The computed GO TO is
being phased out: it is obsolescent in F95 and may be deleted in the future. The
Unconditional GO TO , such as GO TO 12 is still OK, but one should use it with care. (p.
774 in Chapman)

2.5 Arrays

2.5.1 Declaration of Arrays
        We have already discussed dimensioning in F90 above.
        ―cound‖ in 2nd line under DIMENSION bullet should be ―bound‖
        The ―ellipse symbol‖ means colon, as near as I can tell.
        ―Automatic arrays‖ are mentioned. This is a F90 innovation that again might
also exist in C. This allows a temporary array, used only in a subroutine say, to have
variable size. Prior Fortran required you to specify the bounds explicitly. Now it can be
done dynamically. Example:
                SUBROUTINE sub1 (x,n)
                IMPLICIT NONE
                INTEGER, INTENT(IN) :: n
                REAL, INTENT(INOUT), DIMENSION(n) :: x               ! dummy array
                REAL, DIMENSION(n) :: temp                           ! automatic array
                Temp = 0.
                ….
                END SUBROUTINE

        Before F90, you defined arrays explicitly. This is known as ―static memory‖. If
your arrays were very large, you might have trouble fitting your program onto the
machine. To overcome this, you might re-use a particular array for different purposes in
different parts of your code. This can be tedious, tricky, or unsatisfactory to implement.
Alternatively, you might use an EQUIVALENCE statement; but that statement is being
phased out and is strongly discouraged. A better form of this is to define one huge array



                                           1-19
for the minimum you will need for all your arrays at any time during the execution. Then
dynamically assign data to parts of this array and use memory pointers to find the array
you need at any one point in the execution. The NCAR CCM used this procedure. As a
final option you might roll information in and out of memory as needed. The CCM did
this as well. (with BUFFER IN and BUFFER OUT)
        F90 gives you another option. F90 allows you to take advantage of ―dynamic
memory”. This is memory that can change while the program is executing. The
procedure is broadly as follows. ―Allocatable‖ is an attribute that can be applied to arrays.
It defines the rank of the array (i.e. the number of dimensions) and the type (Real say). It
does not define the size. For example:
                REAL, ALLOCATABLE, DIMENSION(:,: ) :: T
When you actually need the array, you specify the precise size with an ALLOCATE
statement, such as:
                ALLOCATE (T(0:100,3), STAT=status)
The STAT clause returns zero if there is memory enough to add the array T at that point
in the execution. When you no longer need the array, you can DEALLOCATE it
                DEALLOCATE (T, STAT=status)
This frees up the memory. In this way you can run your job on a machine with smaller in-
core memory. Donev has more on this in section 2.5.9.

       TARGET – skip this

2.5.2 Vectors
        Interesting example here, but Donev appears to have a typo:
                INTEGER :: vector(10)=(1:9:2,6,(2**I,i=1,4)/)
I believe this makes 10 elements, not 6.

2.5.3 Using Arrays
       This and the next section illustrate powerful innovations in F90 over previous
Fortran. While it simplifies the syntax, there new issues requiring your care when you
implement this syntax.

        Note use of the colon : and the comma as placeholders to know what range or the
entire range and what dimension you are referring to.
        The examples seem pretty good, except there appears to be an error with the last
one. I believe that array vector must be integer. F95 no longer allows non-integer indices
for arrays.

2.5.4 Array Operations
       span in time – means go through a sequence of operations. E.g. the nested DO
loops example
       span in space – means operate on a range in memory, the order may vary from
one machine architecture to another.

2.5.5 Elemental Functions




                                            1-20
       This is an amazing example of the power of the method. But like anything in
computing, you have a trade off between compact & complex versus long & simple. Use
these operations with care and always have a check upon your results.

2.5.6 WHERE construct
        Use is similar to IF-THEN-ELSE, or even CASE, except that you operate on an
array at a time, not just one element of it.
If doing this in F77:
                DO i=1,nx
                  DO j=1,ny
                   If(x(I,j)>10.) then
                     X(I,j)=10.
                   End if
                   If(x(I,j)<-10.) then
                     X(I,j)=-10.
                   End if
                  END do
                END DO

One can do the same thing in F90 with this:
              Tst: WHERE (x>10.)
                 X=10.
              END WHERE Tst
              Tst2: WHERE (x<-10.)
                 X=-10.
              END WHERE Tst2


Skip rest of the guide. But note that Allocatable arrays are discussed above.

****************************************************************




                                           1-21

								
To top