Fortrans 90

56
CHBE 303 Fortran 90 Manual Introduction to Programming in Fortran 90 for Chemical and Biomolecular Engineering Students by Pradeep P. Bhat, revision/format: Michail Stamatakis Department of Chemical and Biomolecular Engineering Rice University Houston, TX © Copyright 2006 Rice University Page 1 of 56

Transcript of Fortrans 90

Page 1: Fortrans 90

CHBE 303

 Fortran 90 Manual     

Introduction to Programming in Fortran 90

for Chemical and Biomolecular Engineering Students    

by

Pradeep P. Bhat, revision/format: Michail Stamatakis 

Department of Chemical and Biomolecular EngineeringRice UniversityHouston, TX

   

© Copyright 2006 Rice University

Page 1 of 43

Page 2: Fortrans 90

Fortran 90

Manual Title page

Textooks and References  

Chapter 1:   Introduction to Fortran 90

1.1 A very brief history1.2 Why Fortran? 1.3 Coding in UNIX1.4 Compiling in UNIX1.5 Fortran 90 v. FORTRAN 77

Chapter 2:   Basic Concepts

2.1 Basic Fortran 2.2 Program Format 2.3 Data Types, Declaration, and Parameterization2.4 Operations and Logical Expressions2.5 Precision2.6 Intrinsic Functions2.7 Input, Output and Format Descriptors

Chapter 3:  Control Structure

3.1 Branches3.2 Loops3.3 Pseudocode and Flowcharts

Chapter 4:   Subroutines, External Functions, and Modules

4.1 External Functions 4.2 Subroutines

Chapter 5:  Arrays

5.1 One Dimensional Arrays5.2 Allocatable Arrays5.3 Multi-Dimensional Arrays5.4 Derived Data Types

APPENDICES

A.1:  Helpful information

A.1.1 Fortran Character SetA.1.2 OperationsA.1.3 Random number generator

Page 2 of 43

Page 3: Fortrans 90

A.1.4 Debugging Guide 

TEXTBOOKS:

The following books are recommended:

Fortran 90/95 for Scientists and Engineers Chapman, Steven J.  WCB/McGraw-Hill, 1998.

This is the primary reference in developing the notes for this course.  

Fortran 90/95 explained  Metcalf, M. and Reid, J.  Oxford University Press, 1996.

A good reference.  Not as comprehensive, nor does it include as many examples as the others, but it is a good reference for questions of syntax and structure.  The other options give more examples and better explanations.

 

Fortran 90 for Engineers and Scientists  Nyhoff, L. and Leestma, S.  Prentice Hall, 1997.

Basically equivalent to Chapman's book, just arranged differently.  Offers many examples of an engineering nature.  The pages referenced in the index are not always accurate and explanations are not as clear as Chapman (that's my opinion).

Fortran 90 handbook: complete ANSI/ISO reference Adams J.C.  McGraw-Hill, 1992.

Fortran 90 programming  Ellis T.M.R., Philips I.R., Lahey T.M.   Addison-Wesley, 1994.

 

WEBPAGES:

http://wwwasdoc.web.cern.ch/wwwasdoc/f90.html

Michael Metcalf's Fortran 90 CNL Articles

http://www.ibiblio.org/pub/languages/fortran/

A more in depth fortran guide if you want to really get involved!

http://www.polyhedron.com/salford/products/other/ftn95_personal.html

A free fortran compiler running under windows (click DOWNLOAD NOW at the bottom of the page).

http://gcc.gnu.org/wiki/GFortran

A free GNU fortran compiler running under windows (click Binaries under "Quick links" and then installer).

   1.1    A very brief history

Page 3 of 43

Page 4: Fortrans 90

   Fortran from its development was intended for translating scientific equations into computer code.   It's name is derived from FORmula TRANslation.  Developed between 1954 and 1957 by IBM, it was the first program that converted an algorithm into machine language that the computer could read and execute.  It was revolutionary and made programming much easier than the generating of machine language by hand.

    Fortran went through many revisions over the years.  FORTRAN II came out in 1958 and FORTRAN IV in 1962 (I am not sure what happened to III).  FORTRAN IV was renamed FORTRAN 66 when it became an ANSI standard in 1966.    The next major update came in 1977 with FORTRAN 77.  This is the version that has been used for the last 20 or so years and is still used by the hard-core, crazy engineers who resist change and enjoy difficult programming.

    Fortran 90 was developed in 1991 and addresses most of the problems with FORTRAN 77, incorporates most of the new features of languages developed in newer programming languages, attempts to phase out some archaic programming features from previous versions by offering more direct commands, and abandons the tradition of writing Fortran in all upper case.  Fortran 90 is a big improvement.  Fortran 95 was an update in 1997 that offered a few new features and makes obsolete those awkward options that 90 was attempting to phase out.  Although developed early in the 90's, compilers have only recently become available for widespread use of Fortran 90.  The resistance of many to the newer version and the simple and versatile (even though less powerful) features of many new computer languages  made Fortran/FORTRAN fall out of favor with many during the 90's.  Now that Fortan 90/95 compilers are readily available, lucky students like you will be able to have all the advantages of Fortran compilers with much simpler programming syntax.

    Also, a newer version of Fortran is in development that will allow more modern features like object oriented programming and will be able to run more efficiently when used for parallel computing.

1.2    Why Fortran?

   Probably many of you are wondering why you need to learn Fortran with all the seemingly more simple alternatives, such as MATLAB (in fact, this is hardly an alternative.  Fortran is much more powerful than MATLAB.  A better argument may be C++ v/s Fortran 90).  In fact many universities have dropped Fortran from their Chemical Engineering curriculum.  The first reason this occurred was the resitance in the engineering community to moving from FORTRAN 77 to Fortran 90.  While many languages were being created and modified for simplicity and for use in specific applications, Fortran lagged behind.  However, Fortran remained throughout this time as the superior language for numerical, scientific, and engineering applications.  With the improvements in Fortran from version 77 to 90, it remains the language of choice for computational science.   Fortran 90  is more powerful than C++ in the areas of numerical robustness, data parallelism, data abstraction, and functional programming.  C++ leads only in object-oriented programming, which the next

version of Fortran hopes to address.

1.3    Coding in UNIX

    When writing code in UNIX you can use any of the text editors (emacs, vi & pico for instance) and write the program.  When complete, the program must be saved with a filename and an extension .f90, for instance if you write a program, with name my_code, you have to save that file as my_code.f90. This is important as .f implies fixed format file, while Fortran 90 files (.f90 files) are free format files.

    An alternative is using Sun Workshop.   Those of you who like windows type applications with a nice GUI this is the one for you.  I am a novice in using Workshop and prefer the old UNIX way; so, I can offer little advice.  It allows you to creat programs, debug them,and build executables.  This program is invoked in UNIX by typing workshop &. More information can be found at http://www.ictp.trieste.it/~manuals/programming/sun/.  Found there are .html files introducing workshop and also a Fortran handbook (http://www.ictp.trieste.it/~manuals/programming/sun/fortran/user_guide/index.html)

.

Page 4 of 43

Page 5: Fortrans 90

Practice: Open a text editor and write the following simple fortran program. Then save this in a file named code.f90.

PROGRAM joke WRITE(*,*) "Hello world!" END

1.4    Compiling in UNIX

    Once you have written your code you must compile it before running.  Compiling translates the written source code into machine language, or an object program.  In order to compile in UNIX, at the prompt  type f90 followed by the program name (e.g  % f90 progname.f90). This should create an executable file named a.out. You should then be able to run the program by typing a.out at the UNIX prompt (i.e % a.out, should run the program).  Every time you compile a program without  the -o option (discussed in the next paragraph) a new a.out file will be created and if a previous a.out file exists it will be overwritten.

    Many options are available when compiling code and some of these will be discussed later in the notes.  One option (-o) allows you to define the name for your executable file.  You do not have to use the default executable named a.out.  In this way you can compile a program once and have the executable available whenever it is needed.  Also, in more advanced cases, two or more executables will need to be linked.  In these cases, you must have different names for all executables.  For example:

   % f90 -o progname progname.f90

    This command compiles the program progname.f90 and creates an executable file named progname.  The typical convention is to name your executable file with the same name as your program, but without an extension.

    Again, compiling and running in Sun Workshop will be different.  Refer to the manuals if interested.

Practice: Compile and run the program written previously in 1.3.

1.5    Fortran 90 v/s FORTRAN 77

    Although you probably have never seen FORTRAN 77, I will give you a brief summary of some of the changes and obsolete features.  Keep in mind that Fortran 90 is upwardly compatible with FORTRAN 77, meaning all features present in FORTRAN 77 are present in Fortran 90.  Some FORTRAN 77 features have been designated obsolete and should never be used because of better alternatives.  The features deemed obsolete in Fortran 90 are not available in Fortran 95 (they are actually obsolete).

    The first, and most obvious, change from FORTRAN 77 to Fortran 90 is the conversion from fixed source code to free source.  In fixed source form (which dates back to punch cards) statement labels had to appear in the first five columns, column six was used for a continuation indicator, and statements appeared on lines 7-72.   In Fortran 90 free source form means you are free to type comments and commands wherever you want.  An exclamation point, ! (also known as a "bang"), is used to indicate a comment statement in Fortran 90.

    Obsolete features include the arithmetic IF statement, ASSIGN and GO TO statements. Avoid use of these features in your code.  In fact, don't learn them.

Chapter 2:   Basic Concepts

Page 5 of 43

Page 6: Fortrans 90

2.1    Basic Fortran

    There is some basic information that everyone should know when beginning to use Fortran.  First of all, Fortran 90 is case insensitive, meaning A is the same as a, WriTe is the same as WRITe, etc..  However, when programming it is common (i.e. good) practice to use uppercase when writing Fortran keywords (i.e. WRITE, REAL, PARAMETER, etc.).  Also, you should always be consistent when using upper of lowercase.  It makes your code more readable and less confusing to others (like the graders) when deciphering your code.

      The available character set for Fortran 90 is given in A.1.1.

    Fortran 90 is free source form, unlike FORTRAN 77 which was fixed source.  Fixed form, which dates back to the use of punch cards, meant that statement labels had to appear in the first five columns, column six was used for a continuation indicator, and statements appeared on lines 7-72.   In Fortran 90 free source form means you are free to type comments and commands wherever you want. An exclamation point, ! (also known as a "bang"), is used to indicate a comment statement.  The comment statement follows the bang and continues to the end of the line.  Comment statements are ignored by the compiler, but are very important for documenting your program.  It is important to use comments frequently to clarify the procedures intended in a program.  Comments can be of great assistance to debugging and revising computer programs.

    A line of Fortran 90 code can have a maximum of 132 characters.  An ampersand (&) is placed at the end of a line to indicate that it continues on the next line.  At most 39 continuation lines are permitted.  If continuing a character string an ampersand must be placed at the end of the first line and the beginning of the next.  Only with character strings is the ampersand needed at the start of the next line. 

Example:

PROGRAM test ! This line is a comment ! Comments are ignored by the compiler a = 3.0 + 4.0 + &      13.0 ! After execution variable a will have the value 20.0 PRINT* a END

    2.2    Program Format

In general, a Fortran program should have the following form:  

heading IMPLICIT NONE specification section execution section internal subprograms END PROGRAM

HEADING - The heading has the form PROGRAM name, where name is any legal identifier (an identifier includes any of the legal Fortran characters (A1.1) but without blank spaces.  Program names must begin with a letter, followed by up to thirty letters, digits, or underscores.  This is not mandatory, but it is highly recommended (meaning points will be taken off if you do not have a program name).  Use a name that has some relation to the program task.  This way it can assist you or others when looking at your code in the future. A program name will distinguish your code from other codes, modules, and subprograms.

Page 6 of 43

Page 7: Fortrans 90

IMPLICIT NONE - Although not required for a program to run and compile this statement is required in any program written for this course.  Most languages require that all variables be specified; however, Fortran will assign a type to any variable whose type is not declared.  IMPLICIT NONE cancels this naming convention.  This will help guard against errors associated with variable type that occur due to the default type convention implicit in Fortran.

SPECIFICATION SECTION - Following the IMPLICIT NONE declaration it is important to declare the environment of the program.  All variables and constants need to be explicitly declared in this portion of the program.  The data type must be stated for all constants, variables, parameters, etc.

EXECUTION SECTION - This is the section where the program actions are specified.

INTERNAL SUBPROGRAMS - If needed subprograms can be contained within the body of the program (internally).

END PROGRAM - This is the only required part of the program.  It indicates to the compiler the end of the program and also halts execution.  This statement can be labeled.

Here is a simple example program.

    PROGRAM introduction       !  heading with name = introduction

    IMPLICIT NONE                !  statement that all data types must be declared

    !  Declare variables and constants in the specification section

    INTEGER :: age = 26                       !  age is integer type data and has the initial value of 26     CHARACTER (4) :: name = "Eric"    !  name is character type, length 4, and is Eric

    !  Now here is the execution section.     !  The output is:  My name is Eric and I am 26 years old.

    PRINT *, "My name is ", name, " and I am ", age, "years old."

    !  There are no internal subprograms in this program

    !  Here is the END PROGRAM statement.     !  It has been labeled with the program name.

    END PROGRAM introduction

2.3    Data Types, Declaration, and Parameterization

    Fortran 90 allows manipulations of various types of data.   The data or variable determines the manipulations, operations, or functions allowed to them.  Fortran allows five basic data types, plus the ability to define your own types (Section 5.4: Derived Data Types).  The available data types are:

    Real     Integer     Complex     Character     Logical

The type for all constants and variables should be declared in the specification section of the program.  Data types are declared in statements like the following:

Page 7 of 43

Page 8: Fortrans 90

    TYPE :: var

Where TYPE is the data type (i.e. real, integer, etc) and var is the variable name.  Examples:  

    REAL :: temp                            !  temp is a real variable     CHARACTER :: answer, name    !  answer and name are variables of the character type     INTEGER :: A = 4                     !  A is integer type and initialized as the value 4  

REAL

Real data can be represented in decimal form as exponents.  Real constants written in decimal form must contain a decimal point.  A real constant written as "43" is not valid as it is recognized as integer type.  "43.", however, is acceptable.  Exponential representation in Fortran involves either an integer or decimal number followed by an exponent that is written as an E with an integer following (i.e. 4.56E2).

The default precision for real data is typically about seven decimal digits and the range around -10-38 to 1038

(although this is machine dependent).  Processors must provide an option to represent the data with more precision than the default.  This is termed double precision.  Techniques for checking and assuring the precision needed for an application can be seen in another section  (2.5 Precision).

Example declaration:

    REAL :: A, B, C

A, B and C are of real type.  

INTEGER

Integers are positive or negative whole numbers (including 0) represented by a string of numbers not including commas or decimal points.  Integers can be preceded by a negative (-) sign.

Ex:

    INTEGER :: A = 4, B

A and B are integer type and A has been given an initial value of 4.  B has not been given an initial value.  Be careful because some compilers will assign it a value.  

COMPLEX

Fortran allows variables to be declared as complex numbers.  Variables such as this are declared with their first value as the real component and the second as the imaginary.  The following statements show an example of a complex variable declaration in a portion of a program.  Remember that !'s are comment statements explaining the coding logic.

    !  Declare A as a complex variable

    COMPLEX :: A

    !  Set the value of A to 4.2 -3.1i

Page 8 of 43

Page 9: Fortrans 90

    A = (4.2, 3.1)

A has been specified as a complex variable and then it's values set as real part = 4.2, imaginary part = 3.1.  

CHARACTER

Character strings are a sequence of Fortran symbols enclosed within quotes or apostrophes (either quotes or apostrophes can be used but it must be the same at beginning and end).  The number of characters in a sequence is the length.  Blanks are counted as characters.  By default, the length of any character string is one.  To avoid this, a length should be specified.

    CHARACTER (LEN = n) :: name     CHARACTER (n) :: name

In both cases name is of character type with length = n.  If an apostrophe or quotes are desired within the string then the alternative should be used to enclose the string.  As an alternative the desired symbol can be entered double.  As an example:

    word = "can't"     word = 'can''t'

Both of these declarations will produce the same character definition, can't.  

LOGICAL

Logical variables have one of two values: .TRUE. or .FALSE.   Logical values can be displayed but are represented by only a T or and F, preceded by a space.  the values can also be read but are only assigned according to the first letter represented.

For example:

    LOGICAL :: A, B

    !  Ask the user for the values of A and B

    PRINT *, "What are the values of A and B?"     READ (*,*) A, B

Here A and B have been declared logical variables.  The user is prompted for the values of A and B. If the input for those statements are

    .TRUE, .Turtle

both A and B will be assigned the value of  .TRUE.

Logical expressions can be used for selection and repetition.  A list of logical expressions can be seen in the next chapter and A.1.4.  

PARAMETER DECLARATION

Often, a certain constant appears so often in a program it should be declared as a parameter.

Page 9 of 43

Page 10: Fortrans 90

    INTEGER, PARAMETER :: N = 10     REAL, PARAMETER :: pi = 3.141593

This allows one statement to be made at the beginning of the program setting a parameter value to a particular constant. Once a constant is declared a parameter it can no longer be changed.  This prevents errors from occurring later where the parameter may be inadvertently changed.  Also, using a declared constant throughout a program in lieu of the numerical value allows the parameter to be changed in only one line of code.

For example a program may contain statements calculating area throughout the code:

    area = 3.141593 * r ** 2

If statements using 3.14593 occur frequently in the program it is better to declare a constant (i.e. pi) initially.  This way the value is always the same.  Repeated typing increases the chance of typographical errors.  Also, parameterization creates one area at the beginning of your code where a parameter needs to be changed, rather than searching throughout the program for its many entries.

2.4    Operations and Logical Expressions

OPERATIONS

    There are various arithmetic operations that can be used with numeric data.  They are +, -, *, /, and ** (exponential).  The order of priority for these operations are essentially the same as typical mathematical rules:

    1.    Exponents are performed first, from right to left.     2.    Multiplications and divisions are performed next, from left to right.     3.    Addition and subtraction are last.  They are also directed from left to right.

Of course, you can use parentheses to enclose subexpressions.   Subexpressions are evaluated first according to the previous priority rules.

    4 * 5 * 2 - 3 ** 2 = 40 - 9 = 31     4 * (5 * 2 - 3) ** 2 = 4 * 7 ** 2 = 4 * 49 = 196

    A concern with using arithmetic operations is the use of mixed-mode expressions (i.e. combining real and integer quantities).  Mixed-mode expressions should typically be avoided as it is considered bad programming.  When an integer quantity is combined with a real quantity, the integer is converted to its real equivalent and the expression is then evaluated.  For example:

    3 + 4.2 = 7.2     5.0 / 10 = 0.5

However, this can lead to problems because the conversion only occurs when the real quantity is encountered in the sequence of operations.  the following gives an example of the problems that may occur with mixed-mode expressions.

    3.2 + 9.0 / 5 = 5.0     3.2 + 9 / 5 = 4.2

The value for 9 / 5 is 1 because it is the division of two integers and the fractional part is truncated.

    Another problem can occur when using real numbers and exponents.  Real exponents should never be used in place of integer exponents.  2.0 ** 3 is evaluated as 2.0 * 2.0 * 2.0 which is 8.0.  However, if the exponent is real it is performed using logarithms:

Page 10 of 43

Page 11: Fortrans 90

    2.0 ** 3.0 = e3.0 ln (2.0)

This will not be 8.0 because of roundoff errors.  This also causes problems when raising a negative number to a real exponent.  A negative logarithm is undefined.  (-2.0) ** 2.0 is undefined, while (-2.0) ** 2 is 4.0.    Real exponents are ok to use, but only when integer values cannot be used in its place.  

LOGICAL EXPRESSIONS

    Logical expressions are expressions that result in either logical constants (.TRUE. or .FALSE.) or logical variables (variables that can take the values of .TRUE. or .FALSE.).  Simple logical expressions consist of the following:

         SYMBOL         MEANING             <   or .LT.           Is less than             >   or .GT.           Is greater than             == or .EQ.           Is equal to             <= or .LE.           Is less than or equal to             >= or .GE.           Is greater than or equal to             /=  or .NE.           Is not equal to

The following expressions can be evaluated with logical results (.TRUE. or .FALSE.)

    A .NE. 6     C * A >= 3

It is important to realize that many real numbers are not stored exactly; so, be cautious when comparing real values using == or /=.  These operators may result in a .FALSE. result due to precision errors.  It is usually better to use a range of threshold values when analyzing real numbers.

    Character variables can also be compared logically.  Characters are ranked in alphabetic order (with a blank ranked ahead of "a") beginning with the first character.  All of the following statements are true:

    "A" > "B"     "better" > "between"     "good year" > "goodyear"

    Compound logical expressions are formed using one of the following operators applied to simple logical expressions:

        .NOT.         .AND.         .OR.         .EQV.         .NEQV.

If exp1 and exp2 are simple logical expression then

.NOT. exp1 returns the opposite result (i.e. if exp1 is .TRUE. then .NOT. exp1 is .FALSE. and vice versa).

exp1 .AND. exp2 returns a value of .TRUE. only if both values are .TRUE.  If either one, or both arguments are              .FALSE.  then the compound result is .FALSE.

exp1  .OR. exp2 is the opposite.  If either value is .TRUE. then the compound result is .TRUE. exp1  .EQV. exp2 returns a value of .TRUE. if both arguments are the same and is .FALSE. otherwise. exp1  .NEQV. exp2  is the opposite of .EQV., returning a value of .TRUE. if the two expressions are

different.

Page 11 of 43

Page 12: Fortrans 90

 

2.5    Precision

    One of the biggest concerns with using real quantities is precision.  Often real numbers cannot be stored exactly in the computer's memory, and this can lead to error when looking at real results.  The default precision for real data is known as single-precision.  Although the exact accuracy is compiler dependent, in general single precision for real data is typically about seven decimal digits and the range around -1038 to 1038.   For some applications higher precision is desired. All compilers have at least two kinds of real types, single-precision and double-precision.  Single precision is the default for any real number, but double precision can be indicated for values in many ways.     Exponentials declared with D rather than E for the exponent are immediately of kind double-precision real by default.  For example:

    3.0D1

is given double-precision because D is used to indicate the exponent.  If an E was used the value would have the default accuracy of single-precision.

    Real declaration statements can be used to indicate the precision for parameters as follows:

    REAL(KIND = kind_number)  :: vars

Numbers that indicate to the compiler what precision of real number is being used are known as kind numbers.  Just as the exact accuracy of single and double precision varies from one compiler to the next, so do the kind numbers associated with them.  Typically if single will be KIND = 1 and double KIND = 2.  Another common option is single-precision KIND = 4 and double-precision KIND = 8.  So this brings us naturally to the question of how we can determine the kind numbers for our compiler.  Useful for this purpose is the function SELECTED_REAL_KIND.  Its general form is:

    SELECTED REAL KIND (p, r)

Where p is the precision desired (number of digits needed to the right of the decimal point) and r is the range (-10r to 10r).  p and r are both integer values.  This function will return a kind type parameter with at least precision of p and range r.  p and r do not have to both be specified.  Only one is sufficient for selecting a kind number.

    Another intrinsic function, KIND (x), can be used to find kind numbers for particular expressions.  For example:

    KIND (4.13)

will return the kind number for single-precision, while

    KIND (1.0D1)

will return the kind number for double precision because D implies a double-precision exponent.

    Another concern is writing your programs so they can be carried from one compiler to the next without the need for reprogramming compiler dependent statements.  In choosing kind numbers there are ways to make your codes "portable" (meaning they can be executed on any Fortran 90 compiler without compiler dependent errors).  You can do this by declaring a kind number for single and double-precision in the declaration section of your program.

    INTEGER, PARAMETER  ::  double = SELECTED_REAL_KIND (13)

Page 12 of 43

Page 13: Fortrans 90

    REAL (KIND = double) :: A, B

In this series of commands the parameter double has been assigned the kind value for double-precision (p = 13 will require double precision).  The kind for A and B has been assigned the number for double-precision.  Code written with such declarations are portable without corrections.

    An underscore followed by a kind number appended to a constant is an indicator of the kind of that constant.  In general:

    constant_kindnumber

For example:

    3.453_2

The number 3.453 is of kind number 2.  Again, for portability it is better to use parameters rather than actual numerical values for appending your constants.

    3.453_double

Now 3.453 has the kind number double.  If appropriate statements are made in the declaration section (as previously discussed) then double will be the kind number for double-precision regardless of the compiler used.

If double-precision is required for the output of an expression then all variables and constants in that expression should be of double-precision kind.  If constants are single-precision and other values double-precision the result will not be as accurate.  For example:

    PROGRAM accuracy

    IMPLICIT NONE

    INTEGER, PARAMETER  ::  double = SELECTED_REAL_KIND (13)     REAL (KIND = double) :: A, B, C

    A = 2.0_double     B = 0.1 * A     C = 0.1_double * A

    PRINT *, B     PRINT *, C

    END PROGRAM

Depending on your system the output for your program could give the following:

    0.2000000029802322     0.2000000000000000

Although the output for B and C should be the same, they are not due to the accuracy of the multiplicative constant (0.1).  The precision for C is double-precision because both the constant (as indicated by the underscore (_) followed by double kind number) and the value for A have double precision.  However, B has lost precision because the constant used to multiply A has only default single precision.  Accuracy has been lost.  Note that the value for B will vary for compiler, but will not be as accurate as C. Similarly the commands

a = 0.745

Page 13 of 43

Page 14: Fortrans 90

b = 0.745D0

may result in a and b having different values because 0.745 is of single precision but a, b and 0.745D0 are of double precision. Thus variable a, could finally have a value like 0.7450000035810196.

2.6    Intrinsic Functions

    Fortran 90 has a library of functions  available for many common mathematical operations.  Including in the available functions are absolute value (ABS(x)), exponential (EXP(x)), logarithm (LOG(x)), and square root (SQRT(x)).  A complete list of these functions can be found in the appendices of the reference books (Appendix A of Metcalf, Appendix D of Nyhoff).     It is important to pay attention to the types of data that can be used with these functions.  For example, the argument (x) in ABS(x) can be real or integer.  The result of the function will be of the same data type as the argument.  ABS(9.0) = 9.0, but ABS(9) = 9.  Some functions require real arguments (EXP(x), COS (x), LOG(x), etc.), while others may have real arguments and integer results (INT(x) is one as it returns the integer portion of a real number, x).     Some functions allow definition of the output type.  The default value for INT(x) is integer, but this can be changed as follows:

    INT(x, KIND = kind_number)

The output will be the integer portion of x, but it will be of type kind_number.  As discussed in 2.5 different data types have compiler-dependent (kind) numbers associated with them.   INT can be used to return the integer portion of a number, but the output can have double or single real precision if desired.  This is not an option on all functions.

2.7    Input, Output, and Format Descriptors

    Obviously, one of the important features of programming is being able to read input (from the keyboard, a data file, etc.) and the output results (to the screen, a data file, etc.).  The general commands available for these actions are:

    OPEN     CLOSE     READ     WRITE     PRINT

All of these commands allow for the input or output to be formatted to the programmers specifications.  At the bottom of this chapter is a discussion of format specifiers.    

OPEN

    Often it is useful in programs to be able to open files for manipulation and use A unit number must be supplied to a file being opened.  the general form of an OPEN statement is as follows:

    OPEN (open-specifiers)

The first item in the open -specifiers is the unit number.  This number will be used in following READ and WRITE statements if these statements are to be applied to the opened file.

The next item is the filename, listed as FILE = filename. Also included can be STATUS = status expression.  The status expression can be either "OLD",

"NEW", or "REPLACE".  OLD means the file already exists.  NEW means that a new, blank file is

Page 14 of 43

Page 15: Fortrans 90

being created.  REPLACE means that a new blank file is created and will replace an older version if it exists.

ACTION = action expression describes the actions allowed to the opened program.  It can be either "READ", "WRITE", or "READWRITE".  READ means the opened file can only be read and modified.  This prohibits any changes fro occurring to a file.  WRITE means the file can only be written.  This can keep you from inadvertently reading data from a wrong file.  READWRITE means that both actions are allowed with this file.

IOSTAT = var is a good safety net for assuring that files are opened properly.  A number is assigned var that defines the status of the file opened.  If the file is opened properly then a 0 is typically assigned to var.  If an error occurs then the number assigned to var is associated with an error message.  This can be used as a check within the execution of a program to verify a file was opened properly.

Example:

    OPEN(UNIT = 15, FILE = 'input.dat', STATUS = "OLD", &                 ACTION = "READWRITE", IOSTAT = Open_Status)     IF (Open_Status > 0) STOP "------------Error, File not opened properly------------"

The file input.dat is opened and assigned a unit number of 15.  If this file is referenced in future READ or WRITE statements then it should be referenced by this unit number.  The file is OLD, meaning it already exists, and it is accessible for reading and writing (READWRITE).  A number is assigned to the variable Open_Status that reflects the ability of the program to open the file.  If it is not opened properly (i.e. Open_Status /= 0) then the next statement halts execution and returns the message "------------Error, File not opened properly------------". It is advisable to use the IOSTAT option whenever opening a file.  In this manner you can halt execution at the point where an error occurs and this will assist with debugging.  

CLOSE

    Opened files are closed whenever an END of STOP statement is encountered. Alternatively they can be closed at any point of the program by using a CLOSE statement. The general CLOSE statement is:

    CLOSE (close-list)

The close-list must include a unit specifier to indicate what file is to be closed.  Other data can be included but are rarely needed.  If you are interested in other options check the reference material.

Example:

    CLOSE (13)

Closes the file with unit number 13.

READ

    The form of a READ statement is as follows:

    READ (control -specifiers) input-list

    The control-specifiers can contain many items.  A unit specifier is used to indicate the input device (the default is the keyboard).  If a file is opened (with the OPEN command as discussed further down the page) a unit specifier can be assigned to that file.  If data is read from that file then its unit specifier must be indicated.  A format specifier can be the next control-list item.  Input and output data can be formatted as desired and these commands are discussed at the bottom of the page.   Other items that are useful in processing files are available and these can be found in the referenced material.

Page 15 of 43

Page 16: Fortrans 90

    The general form of READ statements:

    READ (*,*)    time, concentration     READ *, time, concentration

The stars (*) indicate the use of default values.  When ()'s are used, the first value is the unit specifier (in this case there is a * so it is the default device, typically the keyboard) and the second value is the format specifier (the * indicates the default, or unformatted data).  The variables time and concentration are read from the default input device and are unformatted.  The second command is the same as the first, just a type of shorthand.     A typical READ statement:

    READ (15, '(I6, 2F6.2)'), time, conc(1), conc(2)

Here, unit number 15 is specified and the second part is a format descriptor.  The variables read are time, conc(1), and conc(2).

WRITE

    The WRITE command can be used to output data to various devices.  The default (*) for output is the screen.  The general form for a WRITE statement is similar to the other input/output options:

    WRITE (write-specifiers) write-list

The options for write-specifiers are essentially the same as the two previous options.  The first option is the unit identifier which tells which output source is written (* indicates the default screen).  The next option is output format (again, the commands for this will be discussed at the bottom of the page).  By default (*), the output is unformatted.  ADVANCE = expression is an option that indicates where to place the next output. The expression term can be either "NO" or "YES"  If ADVANCE = "NO" then following WRITE statements will begin on the same line as this current output.  If ADVANCE = "YES" then the output is advanced one line and any following output begins on that following line.  If a value for ADVANCE is not indicated then the value of "YES" is used as default.

The write-list consists of the data to be written.  Any data type is allowable in the write-list.  The expressions can be constants, variables, formulas, etc.  The list of expressions are separated by commas.  If no write-list is included then a blank is inserted at the indicated WRITE location.

Example:

    WRITE(*,*, ADVANCE = "NO") "The liquid level in the tank is", Level     WRITE(*,*) " A level greater than", Level_Max, " indicates a high level alarm."

The output for these commands is:

    The liquid level in the tank is (Level) A level greater than (Level_Max) indicates a high level alarm.

Level and Level_Max are variables.  ()'s are used here to indicate that we do not know the values of these variables.  In truth they will be replaced by numerical values.   Notice that the second WRITE statement begins its output on the same line as the first.  This occurs because the first statement indicates ADVANCE = "NO".  If a third WRITE statement was included then it's output would begin on a new line.  

PRINT

    The PRINT statement is less versatile than the WRITE statement.  The general PRINT statement is:

    PRINT format-specifier, print-list Page 16 of 43

Page 17: Fortrans 90

PRINT only uses the standard (default) output device.  The print-list  is the data to printed.  Just like the write-list of the WRITE statement the print-list allows use of any data type and the list must be separated by commas.   The output can be formatted using the format-specifier.  A * indicates unformatted data.    A character indicating a format type or a format statement can be used to describe the format.  Again, format statements are described below.

Each PRINT statement begins on a new line of output.  

FORMAT STATEMENTS

    As previously mentioned input and output can be formatted such that the output is more aesthetically pleasing.  Without format statements output will take on a compiler-dependent form that is generally not appealing.

    The first specification in a format statement is the declaration of the vertical spacing.  The following options are available:

        1X or " " for normal spacing         "0" for double spacing         "1" for advancing to the next page before any action         "+" for overwriting the last line written

    integer formatting

        The letter I is used to describe the format of integer data.  The general form is:

            rIw.m

        Where r is a repetition indicator.  It instructs the number of times this field should be applied.  It is a shorthand (i.e. 3I5.2 = I5.2 I5.2 I5.2).  w determines the width of the field (or number of spaces) used to display the integer.  Blanks are placed in the front of the field (i.e. the output is right justified).  If the number is 4353 and w = 5 then the letter will be written (~ indicates a blank space) ~4353 instead of 4353~.  m is the minimum number of digits displayed. A declaration for m is not required.  For the number 4353, if m = 5 then it will be displayed as 04353.

        Example:

        INTEGER :: A = 12, B = 600, C = 12345         PRINT '(1X, 2I5.3, I6)', A, B, C

        Output (| indicates the edge of the output area, and ~ are spaces):

        |~~~012~~600~12345

        Here the 1X indicates the vertical single spacing.  A and B are displayed with a minimum of three characters in a field of width five.  Notice that there is always an additional space at the front; so, there are three instead of two spaces in front of A.  C is displayed in a field of width 6, with no declaration of the minimum number of characters.

        If the example were written this way:

        INTEGER :: A = 12, B = 600, C = 12345         PRINT '(1X, 3I4.3)', A, B, C

        The output would be as follows:

Page 17 of 43

Page 18: Fortrans 90

        |~~012~600****

        If the integer number is larger than the field width then the field is filled with *'s.

    real formatting

F is one of the descriptors used to format real data.  It's general form is:

          rFw.d

        r is the repetition indicator and w the total field width as described before.  d indicates the number of digits to the right of the decimal point.  Simply:

        REAL :: A = -12.5, B = 100.678, C = 3.3         WRITE (*, '(1X, 2F7.2, F7.3)') A, B, C

        Output:

        |~~-12.50~100.68~~3.300

        Obviously, both the negative sign (-) and the decimal point (.) took up a space in the field.  Also, notice that the value for C was rounded because d = 2 when three numbers were available outside the decimal point.

E can also be used as a format descriptor.  It has the general form:

          rEw.dEe

        Most of the form is similar to the F descriptor, but the output is in exponential form. e indicates the number of positions included in the exponent, but is not required.

       Example:

        REAL :: A = 112.3E8, B = .078e-7         PRINT '(1X, 2E10.3)', A, B

        Output:

        |~~0.112E+11~0.780E-08

        The exponent indicator (E) and the neg/pos sign require a space in the field.  Also, all exponents are converted so that there is a 0 to the left of the decimal point.  

ES can also be used.

          rESw.dEe

        It has the same options as E, but the result is modified so that the value to the left of the decimal point is at least 1 but less than 10.

        In the same example as used for E:

        REAL :: A = 112.3E8, B = .078e-7         PRINT '(1X, 2ES10.3)', A, B

        Output:

Page 18 of 43

Page 19: Fortrans 90

        |~~1.120E+08~7.800E-07

        This gives more precision.

    character formatting

        Character data can be included in format descriptors.  For example:

        INTEGER :: A = 3         REAL :: B = 0.2         PRINT '(1X, "A =", I5.2, " B =", F5.2)', A, B

        Output:

        | A =   03 B = 0.20          -or (with ~ as a blank indicator)-         |~A~=~~~03~B~=~0.20

        A can also be used as a format descriptor for character data.  In general:

            rAw

        r is a repetition indicator and w the field width.  Neither are required.  Without w the field width is determined by the character size.  If w is greater than the character size then the output is right justified.  If it less than the character size then the output is the leftmost w characters.

        The A format desccriptor can be used as a place keeper when producing output.  The same PRINT statement from above could be written:

        PRINT '(1X, A, I5.2, A, F5.2)', "A =", A, " B =", B

3.1    Branches

    Another important technique when writing Fortran code is the ability to select different paths of execution.  Your code may need to branch depending on different criteria.  The most important of these are:

IF (IF-THEN) IF-ELSE IF-ELSE IF SELECT CASE

IF

    The simplest form is the logical IF statement.  In general:

    IF (logical -criteria) execution statement

If the logical-criteria is TRUE then the execution is performed.  If not the execution statement is bypassed.  An example:

    IF (2.0 < x .AND x < 3.0) PRINT *, x

In this case if x is between 2 and 3 then it will be printed.

    Another IF form used when multiple statements are required for the TRUE case is:

Page 19 of 43

Page 20: Fortrans 90

    IF (logical -criteria) THEN         execution statements     END IF

Notice that all execution statements depending on the IF statement are indented.  This is not required, but it makes your code more readable.  All the execution statements are performed if the logical statement is TRUE.  Otherwise, all information between the IF and END IF statements are ignored.  An example:

    IF (x  >= 0) THEN         z = x * y         PRINT *, "x is a positive number."     END IF  

IF-ELSE

    The ELSE statement allows specification of execution statements for the case that the logical-criteria of the IF statement is FALSE.

    IF (logical -criteria) THEN         execution statements for true result     ELSE         execution statements for false result     END IF

If the logical-criteria is TRUE then the first set of statements are performed and the second are bypassed.   If the logical-criteria is FALSE then the first set of statements are bypassed and the second statements performed.  As an example:

    IF (x > 0) THEN         PRINT *, "The value is greater than zero."     ELSE         PRINT *, "The value is not greater than zero."     END IF  

IF-ELSE IF

   Nested IF statements  (IF statements within IF statements )can allow for many selection criteria.  For example:

    IF (x >= 1) THEN         PRINT *, "The value is greater than or equal to one."     ELSE         IF (x > 0) THEN             PRINT *, "The value is between zero and one."         ELSE             PRINT *, "The value is less than or equal to zero."         END IF     END IF

Although nested loops are allowed, they can frequently become very complex if many selection options are desired.  The ELSE IF statement allows for multialternative selection in a more simple and easier to read format.   In general:

    IF (logical -criteria1) THEN         execution statements 1

Page 20 of 43

Page 21: Fortrans 90

    ELSE IF (logical -criteria2) THEN         execution statements 2     ELSE IF (logical -criteria3) THEN         execution statements 3     .....     ELSE         execution statements n     END IF

The ELSE statement is optional, but it indicates the statements to be performed if none of the IF statements are TRUE.  Only one set of execution statements are performed.  The expressions are evaluated in order and when a TRUE statement is found, its execution statements will be performed and execution continues with the next statement following the END IF statement.  For example:

    IF (x > 0) THEN         PRINT *, "Value is greater than zero."     ELSE IF (x < 0) THEN        PRINT *, "Value is less than zero."     ELSE IF (x == 1) THEN         PRINT *, "Value is one."     ELSE         PRINT *, "Value is zero."     END IF

Notice if x is equal to one the output of this series of commands will be:

    Value is greater than zero.

It will not be "Value is one." because the first true IF statement is that it is less than zero.  That statement was executed and execution proceeded outside of the IF-ELSE IF construct.  

SELECT CASE

    The SELECT CASE construct is not as general as the IF constructs, but it is of use for some specific applications.  In general:

    SELECT CASE (selector)         CASE (list1)             execution statements 1         CASE (list2)             execution statements 2         ...          CASE (listn)            execution statements n     END SELECT

The selector is either an integer, character, or logical expression.  It cannot be real.  List1 to listn are the possible values for the selector.  Say you wanted to associate output a letter grade for a known a numerical score.  Say the numerical score is associated with the real variable named grade:

    SELECT CASE (INT(grade))    !  The real value grade is converted to an integer.         CASE (90:)                          !  90: indicates values of 90 or above.             PRINT *, "Your grade is an A."         CASE (80:89)                       ! 80:89 means 80 to 89.

Page 21 of 43

Page 22: Fortrans 90

            PRINT *, "Your grade is a B."         CASE (70:79)             PRINT *, "Your grade is a C."         CASE (60:69)             PRINT *, "Your grade is a D."         CASE (:59)                          !  59: indicates 59 or below.             PRINT *, "Your grade is an F."     END SELECT  

NAMING

    All of these branching options can be named in order to improve the readability of your code.  For the previous example of a nested IF:

    positive: IF (x >= 1) THEN         PRINT *, "The value is greater than or equal to one."     ELSE         negative:  IF (x > 0) THEN             PRINT *, "The value is between zero and one."         ELSE             PRINT *, "The value is less than or equal to zero."         END IF negative     END IF positive  

    SELECT CASE constructs can be named in much the same way.

       name:  SELECT CASE (selector)         CASE (list1)             execution statements 1         CASE (list2)             execution statements 2         ...          CASE (listn)             execution statements n     END SELECT name  

  3.2    Loops

    Often it is useful to have repeated execution of a particular set of Fortran expressions.  This can often be accomplished using the DO command.  There are various ways for loops to function, but in general they are either based on counters where loops are continued for a certain number of iterations, or logical expressions where the loop terminates based on the value of a logical expression.

Counter Loops

    Counter loops perform repetitive execution a number of times based on a  control-variable.  The control-variable is initialized to a value and incremented a step-size every time a particular list of commands is executed.  When the control variable surpasses a specified threshold the execution halts.    The general form of the counter controlled DO loop is:

    DO control-variable = initial value, limit, step-size         execution list     END DO

Page 22 of 43

Page 23: Fortrans 90

Initial-value, limit, and step-size are all integer values that indicate the number of loops to be performed.  These values can also be variables indicated previous to execution of the loop.  Step-size is not required.  If not indicated, the default step-size is one.  The values for initial-value, limit, and step-size are indicated at the beginning of the loop by either numerical values of variables.  These values cannot be changed during execution of the loop.

The execution list within a DO loop should be indented.  This makes your code more readable, and it is easier to follow the logic.  Often you will have DO loops within DO loops (nested DO loops), and in these cases indenting each new loop within the other loops allows you to follow the sequence of loop execution.  Here is an example of a counter DO LOOP.

    INTEGER :: max = 5

    DO n=1, max         PRINT *, n, n*2     END DO

This output:

    1    2     2    4     3    6     4    8     5    10

Step-size was not indicated; so, it is one.  The control-variable cannot be modified in the execution section of the loop, but it can be used in the execution statements.  The following DO loop shows a loop nested within another loop:

    DO n = 5, 1, -1    !    From 5 to 1 with a step size of minus 1         DO m = 1,2             PRINT *, n, m         END DO     END DO

Notice how by indenting the loops the order of execution is indicated.  The most indented loop is performed in completion first.  The output would be:

    5    1     5    2     4    1     4    2     3    1     3    2     2    1     2    2     1    1     1    2

Loops can be labeled as another way to organize your nested loops.  The previous nested loops could have been written:

    outer: DO n = 5, 1, -1    !    From 5 to 1 with a step size of minus 1                 inner: DO m = 1,2                         PRINT *, n, m                 END DO inner     END DO outer

Page 23 of 43

Page 24: Fortrans 90

If you have many nested loops this could assist in helping you and others follow your code.  

LOGICAL LOOPS

    Logical loops are loops that require fulfilling a logical criteria for completion of the loop.  These can also be called DO-EXIT loops.  The general form is:

    DO         execution statements         IF (logical criteria) EXIT         execution statements     END DO

The execution statements can be before and/or after the EXIT statement.  When the IF statement is TRUE repetition is halted.   Be careful when determining the logical criteria for your IF statement.  If it never becomes TRUE you will be left with an infinite loop.

    The most common use for a logical loop involves halting execution once a calculated value reaches a threshold.  For example:

    n = 1     DO         IF (n > 10) EXIT         n = n + 1     END DO

You can also use user input to halt repetition.  For example:

    DO         PRINT *, "Enter the radius of your circle."         READ *, r         PRINT *, "Area is ", pi*r**2         PRINT *, "Do you want to calculate another area?"         READ *, response         IF (response == "n") EXIT     END DO

Granted, the parameter pi must have been defined previously and response would need to be defined as a character variable of length = 1 in the specification section of the program, but you see how the user input was used as a decision criteria.

A more modern and structured way of realizing a logical loop is with use of the DO WHILE - END DO expression: 

      DO WHILE expression        execution statements       END DO

Here the execution statements are performed as long as expression returns TRUE. When expression becomes FALSE the loop is broken and execution continues with the following statements. The equivalence between DO-EXIT and DO WHILE loops is portrayed below:

n = 1 DO      IF (n > 10) EXIT      n = n + 1

← these two command list are equivalent → n = 1 DO WHILE (n <= 10)     n = n + 1 END DO

Page 24 of 43

Page 25: Fortrans 90

END DO

3.3    Pseudocode and Flowcharts

    Good, logical programming is developed through good pre-code planning and organization.  This is assisted by the use of pseudocode and program flowcharts.

    Flowcharts are written with program flow from the top of a page to the bottom.  Each command is placed in a box of the appropriate shape, and arrows are used to direct program flow.  The following  shapes are often used in flowcharts:

    Pseudocode is a method of describing computer algorithms using a combination of natural language and programming language.  It is essentially an intermittent step towards the development of the actual code.  It allows the programmer to formulate their thoughts on the organization and sequence of a computer algorithm without the need for actually following the exact coding syntax.  Although pseudocode is frequently used there are no set of rules for its exact implementation.  In general, here are some rules that are frequently followed when writing pseudocode:

The usual Fortran symobols are used for arithmetic operations (+, -, *, / , **). Symbolic names are used to indicate the quantities being processed. Certain Fortran keywords can be used, such as PRINT, WRITE, READ, etc.

Page 25 of 43

Page 26: Fortrans 90

Indentation should be used to indicate branches and loops of instruction.

Here is an example problem, including a flowchart, pseudocode, and the final Fortran 90 program.  This problem and solution are from Nyhoff, pg 206:

For a given value, Limit, what is the smallest positive integer Number for which the sum

    Sum = 1 + 2 + ... + Number

is greater than Limit.  What is the value for this Sum?

Pseudocode:

    Input:    An integer Limit     Ouput:   Two integers: Number and Sum

1.  Enter Limit 2.  Set Number = 0. 3.  Set Sum = 0. 4.  Repeat the following:     a.  If Sum > Limit, terminate the repitition, otherwise.     b.  Increment Number by one.     c.  Add Number to Sum and set equal to Sum. 5.  Print Number and Sum.

Flowchart:

Page 26 of 43

Page 27: Fortrans 90

Fortran 90 code:

    PROGRAM Summation

    !  Program to find the smallest positive integer Number     !  For which Sum = 1 + 2 + ... + Number     !  is greater than a user input value Limit.

Page 27 of 43

Page 28: Fortrans 90

    IMPLICIT NONE

    !  Declare variable names and types

    INTEGER :: Number, Sum, Limit

    !  Initialize Sum and Number

    Number = 0     Sum = 0

    !  Ask the user to input Limit

    PRINT *, "Enter the value for which the sum is to exceed:"     READ *, Limit

    !  Create loop that repeats until the smallest value for Number is found.

    DO         IF (Sum > Limit) EXIT    !  Terminate repetition once Number is found         !  otherwise increment number by one         Number = Number + 1         Sum = Sum + 1     END DO

    !  Print the results

    PRINT *, "1 + ... + ", Number, "=", Sum, ">", Limit

    END PROGRAM

Chapter 4:   Subroutines, External Functions, and Modules

4.1    External Functions

    Functions can be defined and accessed outside of the main code structure.  Functions are basically similar to subroutines (discussed in 4.2), just simpler.  Functions return either a number, array, logical result, or character array.  The FUNCTION option exists so you can create mathematical functions that are not explicitly defined (as ABS, SQRT, etc.) in the Fortran 90 library.  Once a function is defined it is used in the same way as any of the library functions.  Functions can only return one value or one array of values.  The basic structure for using and defining a function is as follows:

    PROGRAM name     ...     ...     variable = functionname (argument_list1)     ...     ...     END PROGRAM

    FUNCTION function_name(argument_list2)

    type declarations

Page 28 of 43

Page 29: Fortrans 90

    functionname = expression

    RETURN

    END FUNCTION

Argument_list1 and argument_list2 do not have to be the same, but they do have to contain the same number and type of variable.  If their names are different then argument_list1 is mapped to the values of argument_list2.

An example program using a function:

    PROGRAM testfunc

    IMPLICIT NONE

    REAL :: a, b, c, func

    a = 3.0     b = 4.0

    c = func(a,b)

    END PROGRAM testfunc

    FUNCTION func(x,y)

    REAL :: func     INTEGER, INTENT (IN) :: x, y

    func = x ** 2 + 2 * y

    END FUNCTION func

This program will take the values of a and b and input them into the function func(x,y) returning a value for c of 17.0. It is important to define the type for the function, in this case it is real (as seen by the definition "REAL :: func(x,y)").  You can also choose your function to be of type INTEGER, CHARACTER (as needed for the hmwk), or LOGICAL.

Tip: Use functions wisely! Innapropriate use may dramatically but unnecessarily increase the computational time. Consider the following example:

z = f(x)/(1.0 + f(x))

where f(x) is a REAL valued function that has been defined. Here, to compute z we will need two function evaluations, that is f is evaluated two times. But if we wrote:

y = f(x)z = y/(1.0 + y)

we now need to evaluate f only once. This means that we decrease the computational time by a factor of two! This can be very significant if the function to be evaluated is "tough"...

      

  4.2    Subroutines

Page 29 of 43

Page 30: Fortrans 90

    Subroutines are similar to, but more versatile than, external functions.  Subroutines can be defined internally (following a CONTAINS statement) or externally (after the END PROGRAM statement).  Functions are essentially simplified subroutines.  The major differences between functions and subroutines are as follows:

Functions take input and return a single number, character string, logical result, or array to the program that referenced it.  Subroutines can return a large amount of output or no data (i.e. they can just perform a task such as printing results or displaying output) to the referencing program.

The name of a function is set to the returning value.  A subroutine name does not contain a value.  Output from a subroutine is returned via the arguments contained in the output list (meaning if you want to return three values you must have one argument in the argument list for each output value).

Functions are referenced in the main program structure by using their name in an expression.  Subroutines are referenced using a CALL statement.

The basic format of a subroutine description is as follows:

    SUBROUTINE name(dummy argument-list)     specification part     execution part     END SUBROUTINE

The formal argument-list is a list of identifiers for the input and output to the subroutine.  These values are called dummy because they are used to pass information between the subroutine and the main program.

Subroutines are referenced in main programs using a CALL statement.

    CALL name(actual argument-list)

The actual argument-list contains the variables, constants, or expressions that are to be used by the subroutine.  The variables can be returned to the referencing program with values determined by  the subroutine, or they can be used as input to the subroutine's execution.  The arguments contained in the actual argument-list and the arguments contained in the dummy argument-list do not have to be the same; however, there does have to be the same number of arguments and their types must match.

Here is an example of a program calling a subroutine.  The subroutine receives the name of a file, opens it, reads data, and returns that data to the referencing program.

    MAIN PROGRAM

    IMPLICIT NONE

    CHARACTER(20) :: file_name     REAL :: vel, dens, conc

    !  Calling the subroutine.     !  The arguments do not need to be the same as     !  the dummy arguments in the subroutine.     ! values for vel, dens, and conc will be returned.

    CALL Openfile(file_name, vel, dens, conc)

    END PROGRAM

    SUBROUTINE Openfile(name, a, b, c)

Page 30 of 43

Page 31: Fortrans 90

    CHARACTER(20), INTENT(IN) :: name     REAL, INTENT (OUT) :: a, b, c     INTEGER :: OpenStatus

    OPEN (UNIT = 10, FILE = name, ACTION = "READ", &                 IOSTAT = Openstatus)     IF (OpenStatus /= 0) STOP "error opening file"

    READ (10,*) a, b, c

    END SUBROUTINE

Chapter 5:  Arrays

 5.1    One Dimensional Arrays

    One of the most important features of Fortran 90 is that you can declare data as arrays.  Fortran 90 also allows manipulation and operation of intrinsic functions on these arrays (discussed in section 5.3).  First we will consider one dimensional arrays.

    Data is declared as an array in the following manner:

    type, DIMENSION(min:max) :: array names

    Type is the data type for all the items in the array.  Arrays can be any of the data types described in 2.1.  In section 5.4 the possibility of derived data types (where different items in an array are different types) is discussed.  Min and max are the minimum and maximum subscripts used by the arrays.  If the minimum subscript is one then min can be excluded. Array names is a list of arrays that will have this type with the specified DIMENSION.  The names are separated by a comma.

    Examples:

    REAL, DIMENSION(1:20) :: A, B     REAL, DIMENSION(20) :: A, B     INTEGER, DIMENSION(-1:3) :: C

    All items in the arrays A and B are of type REAL.  Space will be allocated for these array during compilation.  A and B has space for 20 REAL numbers.  C has space for 5 INTEGER numbers, subscripted -1, 0, 1, 2, and 3.  Because arrays can require large amounts of memory, sometimes it is useful to be able to allocate (and deallocate) space in memory for the array during execution.  This will be discussed in 5.2.

    For now, we will consider one dimensional, compile-time allocated arrays with items all of the same type.  

POPULATING ARRAYS

    Populating arrays (i.e. assigning values to their elements) can be performed in many ways.  An easy and compact way is by using explicit DO loops with the subscript changing on each pass through the loop.

    REAL, DIMENSION(5) :: A

    DO I = 1, 5         READ (10, *) A(I)     END DO

Page 31 of 43

Page 32: Fortrans 90

In this case the data comes from UNIT = 10 (which we will assume is a data file).  The data must be on separate lines because each READ statement will start on a separate line.

    Arrays can also be read be using the array name without subscripts.  Array A could have been read from UNIT 10:

    READ (10, *) A

Now the READ statement is used only once so the data can be on one line (separated by spaces or commas), on five separate lines, three numbers on one line and then two on the next, or whatever you desire.

    Finally, arrays can be read using an implied DO loop:

    READ (10, *) (A(I), I = 1, 5)

Again, the READ statement is encountered only once the date does not have to be on separate lines.  

Practice: Create a text file and type the following data:

1.0 7.2 5.9 -7.8 2.74.9 -3.1 7.8 2.9 1.23.9 4.8 9.1 10.3 0.0

Save the file and write a program to read the first line. Then write a program that reads the first column.

ACCESSING INDIVIDUAL ELEMENTS

    As implied above, accessing single elements of an array is performed using the array name followed by the subscript contained within parentheses ().  You can set add two elements of an array:

    Sum = A(3) + A(5)

here the value for Sum is the third element of array A plus the fifth element.   A sum of all the elements in an array could be accessed using a DO loop:

    Sum = 0     DO I = 1,5         Sum = Sum + A(I)     END DO  

DIRECT ACCESS

    One advantage of arrays over multiple single variables is direct access to items in an array.  For example if you want to read 20 values and store them in the memory, you could store them as 20 separate values:

    REAL :: input_1, input_2, ... input_20     READ (10, *) input_1, input_2, ... input_20   !  .. are not legal Fortran commands, just an indication of repetition

Or you could create an array:

    REAL, DIMENSION (20)  :: input     READ (10, *) (input (I), I = 1, 20)

Page 32 of 43

Page 33: Fortrans 90

In the first case, if you want to access item 20 then it is accessed in the memory sequentially, starting from the beginning.  The first 19 must be looked at first before input_20 is encountered.  In the case of the array,  Input(20) is direct access.  The 20 specifies its location and the first 19 are skipped.  From this example you can see the space and time saved by using arrays.  

ARRAY ASSIGNMENT

    Arrays can be assigned values within your program by containing them within (/ and /).  Only values can be contained within these symbols or implied DO loops can be used.  For example:

    INTEGER, DIMENSION (5) :: A     A = (/ 2, 4, 6, 8, 10/)     A = (/  (2*I, I = 1,5) /)     A = (/ 2, (2*I, I = 2, 4), 10 /)

All of these A declarations created the same array A.  Arrays can also be assigned using a simple value:

    A = 0

this assigns the value of 0 to all elements of A.  

SUBSETS

    Arrays can be broken down into smaller components, or subsets.  This is done as follows:

    array_name(min:max: step)

Where min is the minimum subscript of the array, max is the maximum subscript considered, and step is the step size for the subscripts indicating the subscripts contained within your subarray.  For example:

    REAL, DIMENSION (5) :: A     REAL, DIMENSION (3) :: B, C     A = (/ 10, 20, 30, 40, 50/)     B = A(1:5:2)     C = A(2:4)

then B contains the first, third, and fifth elements of A (i.e. B = (/ 10, 30, 50/)).  C contains the middle three elements of A (i.e. C = (/ 20, 30, 40 /)).  

INTRINSIC FUNCTIONS

    Fortran 90 allows various intrinsic functions to be used on arrays.  Some of the more common ones are:

    DOT_PRODUCT(A, B)           Returns the dot product of A and B     MAXVAL(A)                           Returns the maximum value in array A     MINVAL(A)                            Returns the minimum value in array A     PRODUCT(A)                         Returns the product of all the elements in A     SIZE(A)                                   Returns the number of elements in A     SUM(A)                                  Returns the sum of all the elements in A

5.2    Allocatable Arrays

     Arrays can be very large and require a lot of memory; therefore, it is often useful to reserve this space only during the times that the array is required.  This cannot be done when the array size is declared during compilation.  For this reason it is useful to use the programs available run time memory called "free store" to

Page 33 of 43

Page 34: Fortrans 90

allocate the memory for the array during program execution.  This memory can be used and restored using the following commands.

    An array is declared as ALLOCATABLE by:

    type, DIMENSION(:), ALLOCATABLE :: array names

for example:

    INTEGER, DIMENSION(:), ALLOCATABLE :: A

creates an integer array A that will have memory allocated to it (i.e. have it's size determined) during execution.

    Allocation occurs using the ALLOCATE command:

    ALLOCATE (array name(min:max))

Min  and max are the limits of the subscripts used.  If min is one then it need not be included in the declaration.  For example:

    ALLOCATE (A(20))

now the array A has space for 20 elements.  A STAT clause can be used to verify that  the allocation has been successful (much like READ or OPEN statements):

    ALLOCATE (A(20), STAT = allocate_status)     IF (allocate_status /= 0) STOP "*** Not enough memory ***"

Program execution will stop if the allocation is not successful.  This is a good safeguarding tool.

    Once the array is no longer needed it is important to deallocate the memory so it can be used.  this involves the DEALLOCATE command.  Again, it is useful to use the STAT option to verify that the deallocation was successful.

    DEALLOCATE (A)

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

Page 34 of 43

Page 35: Fortrans 90

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             READ (10,*) array (row, col)         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             READ (10,*) array (row, col)         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:

Page 35 of 43

Page 36: Fortrans 90

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

And your program says:

    INTEGER, DIMENSION(3,4) :: array     READ (10,*) 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:

Page 36 of 43

Page 37: Fortrans 90

    RESHAPE (one-dimensionalspecifier, shape, pad, order)

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

5.4    Derived Data Types

    You have seen in previous chapters the six intrinsic data types of Fortran 90: INTEGER, REAL, CHARACTER, COMPLEX, LOGICAL and arrays.  Some times it is useful to define new data types, or derived data types.  New types are define using the TYPE command:

    TYPE name         declaration_1         declaration_2         ...         declaration_n     END TYPE name

The declarations define the components in this type.  It declares both the name and type of each component.  For example:

    TYPE course_list         CHARACTER (15) :: Last_name, First_name         CHARACTER (1) :: Middle         INTEGER :: Student_ID         REAL :: average         CHARACTER(1) :: grade     END TYPE course_list

Page 37 of 43

Page 38: Fortrans 90

Variables or constants can be defined as a certain type using the following declaration:

    TYPE(name) :: var

Using the type defined above:

    TYPE(course_list) :: A, B

Now A and B will have 6 components each:  Last_name, First_name, Middle, Student_ID, average, grade, and list.  You can also define an array so that all its components are of derived type:

    TYPE(course_list), DIMENSION(10) :: A

Now A is a single dimension array with 10 elements all of the derived type course_list.  We can assign a value to an element of A as follows:

    A(1) = couse_list("Smith", "Joe", "J", 11111, 95.5, "A")

The first element of A contains all this information.  What if you want to access only a portion of A(1)?  Then you use the component selector character (%).

    PRINT *, A(1)%Student_ID

will look at element 1 of A and find the component defined in the TYPE declaration as Student_ID; so, it will print:

    11111

By the same token, the following statements:

    PRINT '(1x, A5, F7.2)', A(1)%First_name, A(1)%average

will produce:

     Joe  95.50

Of course you can use the selector with READ statements, assignment statements, executions, etc.  The values can be treated like any other variable or constant.

APPENDICES

A.1:  Helpful information

A.1.1    Fortran Character Set

ANSI standard available characters for use with Fortran 90.  Note:  Fortran is case insensitive.

Available Characters:

0,...,9    A,...,Z    a,...,z    '    "    (    )    *    +    -        =     / blank    :    !    &    $    ;    <    >    %    ?    ,    .  

Page 38 of 43

Page 39: Fortrans 90

ANSI Character Codes  

 

ASCII Character Codes

Page 39 of 43

Page 40: Fortrans 90

Page 40 of 43

Page 41: Fortrans 90

   

Page 41 of 43

Page 42: Fortrans 90

A.1.2    Operations  

Available mathematic operations for Fortran 90

Operator Description+ Addition- Subtraction* Multiplication/ Division

** Exponentiation______________________________________

Order of actions:

1. Exponents are perform first, from right to left. 2. Multiplications and divisions are performed next, from left to right with the order they are

encountered. 3. Addition and subtraction are last.  They are also performed from left to right with the order they are

encountered. 

Available logical opertations for Fortran 90

Operator

.NOT.

.AND.

.OR.

.EQV.

.NEQV.

______________

.NOT.a returns .TRUE. if a is .FALSE. and vice-versa. The values of Logical Expressions that involve two variables are given below:

If operands a and b are:Then the expressions below evaluate as shown:

a .AND. b a .OR. b a .EQV. b a .NEQV. b

Both true .TRUE. .TRUE. .TRUE. .FALSE.

One true, one false .FALSE. .TRUE. .FALSE. .TRUE.

Both false .FALSE. .FALSE. .TRUE. .FALSE.

 

Note 1: Operator .NEQV. is sometimes referred as .XOR.

Note 2: Remember:

.NOT.(a.AND.b) = (.NOT.a) .OR. (.NOT.b)Page 42 of 43

Page 43: Fortrans 90

.NOT.(a.OR.b) = (.NOT.a) .AND. (.NOT.b)

A.1.3    Random Number Generator

    Often problems arise that require generation of a random number or a series of random numbers.  Fortran 90 contains a subprogram for this purpose.  The random number generator produces a pseudorandom (it is impossible to have an algorithm that is truly random) number distributed between 0 and 1.   The random number generator is initiated by the subprogram RANDOM_SEED.  RANDOM_SEED, when called, initializes the random number generator.  Three arguments are possible when calling RANDOM_SEED.

    CALL RANDOM_SEED (SIZE, GET, PUT)

If called without an argument then RANDOM_SEED restarts the number generator.  If an argument is present it queries the random number generator.  SIZE will output the number of integers used to hold the seed.  GET  will give the current value of the seed.  PUT allows for control of the seed.  PUT is the only command that provides input.  It indicates the value to be used as the initial seed for the random number generator.  PUT must be a one-dimensional array.  random seed only needs to be called once in a program.  It is used to generate the first random number.  Any random numbers generated after the first will use the previous random number as its seed.

    RANDOM_NUMBER is the actual random number generator.  It takes a seed (or more then one if creating an array of random numbers)  and generates a pseudorandom number between 0 and 1.  The  general form is:

    CALL RANDOM_NUMBER(argument)

Argument can be a single variable, an array, or items within an array.  It will contain the pseudorandom number based on the seed generated using RANDOM_SEED.  If an array is given then the array will be filled with random numbers.  Here is an example for generating 5 random numbers using a predetermined seed.

    INTEGER, DIMENSION (1) :: seed = (/3/)     REAL :: num

    CALL RANDOM_SEED (PUT=seed)

    DO n = 1, 5

        CALL RANDOM_NUMBER(num)

        PRINT *, num

    END DO

This program will generate and print five random numbers.  The first is found using 3 as the seed, and the following ones use the preciously generated number as the seed.  num contains the value of the random number generated and is updated for each loop.  By controlling the seed the random numbers generated will be the same every time.  A compiler will produce the same random number given the same seed.

 

Page 43 of 43