# An Introduction to Modern Fortran - Oxford e-Research Centre · • 1978 Fortran 77 standard. •...

### Transcript of An Introduction to Modern Fortran - Oxford e-Research Centre · • 1978 Fortran 77 standard. •...

www.oerc.ox.ac.uk

An Introduction to Modern Fortran

Lecture 1

The Basics

Introduction

• In this course we will give an overview of Modern Fortran

• We would need much longer to cover all the syntax, but aim to give you enough

information and practice to start writing your own programs.

• We will guide you to further reading as we go.

Introduction

History of Fortran

• 1957 IBM Fortran.

• 1966 Fortran 66 standard.

• 1978 Fortran 77 standard.

• 1991 Fortran 90 standard. Attempted to modernise the Fortran language and to

bring it closer to modern programming techniques. It also added features to simplify

programming.

• 1997 Fortran 95 standard. Bug fixes and a small number of new features

• 2004 Fortran 2003 standard. Much bigger revision than Fortran 95. Features include

objected orientated programming, error handling and interoperability with C.

• 2009 Fortran 2008 standard. Co-arrays, BITS type, new intrinsics.

Books and Resources

• Lots of good books, find one that suits you.

Metcalf, Reid and Cohen “Modern Fortran” for example.

• man pages often available for Fortran keywords

• Google, of course

• These notes and the comments you make on them!

• Source code

– Readable.

– Changeable.

• Object code

– Intermediary step.

• Machine code

– Executable.

– Definitely not readable.

– Very difficult to change.

PROGRAM hello

IMPLICIT NONE

WRITE (*,*) ’hello world’

END PROGRAM hello

001010110101010101010101101010

010101011010101010101010101001

011010101101010101101010…

011010101111110101010101101010

010001011010101010101010101001

011000011001010101101010…

Programming And Compiled Languages

Compilation

Linking

From Source Code To Executable

Compile (with a compiler called “nagfor”):

nagfor –c hello.f90

Link (to other object code or libraries):

nagfor hello.o –o hello

Or we do both stages together:

nagfor hello.f90 –o hello

Note name of compiler and linker will vary from place to place. Check your local

documentation.

Compilers

• See what is available and recommended for your system.

• The NAG compiler is excellent and is second to none for error checking.

(Developing with more than one compiler is good practise.)

• You have a license for the NAG Compiler.

• The GNU gfortran is also good and free.

• The Intel compiler has a strange licence … but is probably available to you and

most likely creates the fastest executables – use for production!

• For comparisons: http://www.polyhedron.co.uk/compare0html

• Always read documentation for your compiler and pay particular attention to

defaults.

• Compliers DO NOT conform to a particular standard, may only have a subset of

one, or extensions to another.

• NAG compiler available at: http://www.nag.co.uk/nagware/np.asp

Compilers

Compilers are extremely useful.

• They can be used to check for incorrect code.

• (Will however allow code that gives wrong answers!)

• Help you debug your code.

• Make your code faster.

• Give you reports as to how well your code has been optimised.

• Always worth checking what flags are available

nagfor -C -C=undefined -dcfuns -g -gline -info -nan –u hello.f90

Writing Fortran

• Code is a sequence of instructions. These instructions are executed in order, unless

a “decision” in it changes this.

• Fortran codes start and end like this:

Program myprog

… instructions …

End Program myprog

• A lot of Fortran uses blocks that start with a keyword and end with END and that

keyword.

• All Fortran codes must have a main program. They may also use subroutines,

functions and modules

A Simple Program

Program hello

! My first program

Implicit None

Write( *, * ) 'Hello World !'

End Program hello

$ nagfor -o hello hello.f90

$ ./hello

Hello World !

Source Form

• All strictly standard Fortran programs can use only the 26 characters of the English

alphabet and the 10 Arabic numerals 0-9

• Upper and lower case are treated identically (except in character strings) Fortran is

NOT case sensitive.

• The following special characters: =+-*/()_,.$’:!”% &;<>? and space.

• We will use free source form Fortran (as opposed to fixed form, or Fortran 77, style

code.)

• In free source form lines may be up to 132 characters long, but can be broken over

multiple lines.

A More Complicated Program – Data Types

Program arithmetic

Implicit None

Integer :: i, j

Real :: a, b

i = 2 ! Set i to 2

j = 3 ! Set j to 3

a = 2.0 ! Set a to 2.0

b = 3.0 ! Set b to 3.0

i = i * j ! Do arithmetic the obvious way

a = a * b

Write( *, * ) i, a

End Program arithmetic

$ nagfor -o arithmetic arithmetic.f90

$ ./arithmetic

6 6.000000000

Intrinsic Data Types in Fortran

• All data, whether constants or variables, has a type in Fortran

• There are only 5 intrinsic types in Fortran

– Logical - Can only have the values .True. Or .False.

– Integer - Represents whole numbers, e.g. 12, -2

– Real - Represents floating point numbers, e.g. 25.7, -13.8 1e1, -2.3e-1

– Complex - A pair of reals representing a complex number, e.g. (1.0,2.0), i.e. 1+2i

– Character - Representing text, e.g. ‘C’, ‘Ian’

• Note the difference between a real and an integer constant – a real ALWAYS has a

decimal point AND/OR an exponent, and integer always has neither

• Very late on in the course we will see briefly how to create your own types

– But this belongs in a more advanced course really

Variables - Type

• A variable is associated symbol associated with a value that can change (or vary) in

your program

• For instance when solving an equation for x you might think of x as a variable

• Good practice – give a variable a name that indicates what it represents, e.g.

Volume, Density, Charge, Reynolds_Number

• And in Fortran all variables have a type

• And at the declaration or specification stage you say what type the variable has

• The specification stage MUST come before any executable (“doing”) statements

Example Specifications

• LHS of double colons ( :: ) is known as the types and attributes.

• RHS is known as the entity list (the list of variable names.)

• You can also initialise variables at the specification stage

– Note if you do not you can not make any assumption about the initial value of the variable

• Note if you do not have an intialisation strictly the double colons are not needed, but

I strongly recommend you always put them in as that simplifies remembering quite

when you do need them in more complicated cases we will see later

– Putting in the double colons is always write, leaving them out is often wrong

INTEGER :: a

INTEGER :: A=1, b=2, c

LOGICAL :: sym_matrix=.TRUE.

REAL :: f=12.1, m=-1000., p=12.34e10

REAL :: area_under_curve

COMPLEX :: plane_point=(1.0,1.0)

CHARACTER :: ch='a'

CHARACTER (LEN=8) :: string

Variable Names

Variable names

• Case is not important, i.e., the variable my_name is the same as My_Name

• Can have any alphanumeric letters (but must start with an alphabetic character.)

• Can be up to 31 characters long. (63 in F2003)

• Can use the underscore _ character.

Basic Mathematical Operators

• These are as you would expect:

= Assignment, i.e. ‘set to this value’

+ Addition

- Subtraction

* Multiplication

/ Division

** Exponentiation, i.e. ‘to the power of’

• Note that combining two pieces of the data type results in a value of the same type

• Combining data of different types? First convert the “less general” to the more

general type, i.e. integer gets converted to real, and real to complex, and then

perform the operation giving the type of the result as the more general one

A More Complicated Program Revisited

Program arithmetic

Implicit None

Integer :: i, j ! Declare two Integers

Real :: a, b ! Declare two Reals

i = 2 ! Set Integer i to the Integer constant 2

j = 3 ! Set Integer j to the Integer constant 3

a = 2.0 ! Set Real a to the Real constant 2.0

b = 3.0 ! Set Real b to the Real constant 3.0

i = i * j ! Multiplying two Integers gives an Integer

a = a * b ! Multiplying two Reals gives a Real

Write( *, * ) i, a ! Write out an Integer and a Real

End Program arithmetic

$ nagfor -o arithmetic arithmetic.f90

$ ./arithmetic

6 6.000000000 Note the difference – An Integer then a Real

More Complicated Arithmetic - Precedence

i = 3

j = 2

i = 3 * i + 2 * j

• Sets i to 13, i.e. it evaluates as (3*i)+(2*j). The order of evaluation is determined by

‘precedence,’

• () first, then **, then * /, then + -

• Much the same as maths. What if you can’t remember or it’s not clear?

i = j ** 3 * k

• Then use brackets

i = ( j ** 3 ) * k or

i = j ** ( 3 * k ) as required

Integer Division

• Remember integers represent WHOLE NUMBERS.

• And arithmetic combining two integers gives an integer

• So what is the result of

10 / 4 = ?

• The method is to throw away the remainder (equivalent to round toward zero) . So

10 / 4 = 2 remainder 2, so

10 / 4 = 2

• Similarly

1 / 4 = 0

-10 / 4 = -2

-33 / -16= 2

Integer Division – An Easy Bug

Program temperature_convert

Implicit None

Integer :: fahrenheit, celsius

Read( *, * ) fahrenheit

! N.B. NOT 5 / 9 * ...

celsius = 5 * ( fahrenheit - 32 ) / 9

Write( *, * ) celsius

End program temperature_convert

Or you could do it using Reals (probably better here)

Somebody WILL make this mistake in the practicals

A Reminder - Constants have a Data Type

• Before we move away from the basic types a reminder – Constants always have a

Data Type

• So on the previous slide 5 and 9 are integers

– They didn’t have a decimal point or an exponent

• Similarly, the following are integer, real and complex respectively:

1 -99 0 +2

1. -0.1 1e+1 -12.3e-11

(1.09,2.3) (2.0, 1e+1)

• Get used to this - it becomes important when we come on the passing arguments to

subroutines and functions

Implicit None

• Before the declarations you should use the keywords “IMPLICIT NONE”.

• This turns off the implicit typing the variables

– It is possible to use a variable without previously declaring its type and attributes.

– In other languages this is illegal, not in Fortran.

– If we do this the type of a variable is judged by implicit rules.

– It is not a good idea to rely on these rules because of spelling mistakes and to ensure we

have good control over our code.

– Years of experience since Fortran was invented has shown that implicit typing is NOT a

good idea

• Using IMPLICIT NONE avoids this and ensures we have to declare the type of each

variable.

– A little bit more typing up front for a lot less grief later on …

• If you don’t use and are having problems Implicit None I won’t help you until you fix

it!

Source Form – Use of !, The Comment Character

• Whenever the ! character is deployed then the rest of the line is to be ignored by the

compiler.

• These can then be used as comments to describe what important variables are for,

what procedures are for, reminders, what parts of procedures are doing etc.

• Therefore they are extremely important to future users/developers of programs to

understand what you have done and so are highly recommended.

Source Form – Use of &, The Continuation Character

• The “&” symbol is used as the last symbol on a line when the code on the following

line should be appended to it:

area_of_rectangle = height_of_rectangle * &

width_of_rectangle

• If this happens in the middle of a string then an & needs to start the next line to

show where the string starts.

WRITE(*,*) ‘hello &

&world’

hello world

• Useful if lines become very long (remember you are limited to 132 characters per

line)

• Can also make the code more readable, certain expressions look better if

“tabulated”

– Indentation with white space can also help here

Data of Type Character

• So far we have looked at numeric Data Types

• Now lets look at constants and variables of Type Character

• These represent strings of letters

• These strings have a fixed length

– By default 1 character

• And Character constants can be delimited by either ‘ or “ :

Character( Len = 8 ) :: name

name = 'Ian Bush'

Or

name = "Ian Bush"

• Remember character variables have a fixed length

• So …

Program hello2

Implicit None

Character( Len = 8 ) :: greeting

greeting = 'Hello Ian !'

Write( *, * ) greeting

End Program hello2

$ nagfor -o hello2 hello2.f90

$ ./hello2

Hello Ia

Data of Type Character

Operations on Data of Type Character

• Only two operations are allowed on characters

• Concatenation through the // operator:

Character( Len = 8 ) :: full_name

Character( Len = 3 ) :: first_name = ‘Ian’

Character( Len = 4 ) :: last_name = ‘Bush’

full_name = first_name // ‘ ‘ // last_name

Write( *, * ) full_name

Ian Bush

• Substrings

Character( Len = 3 ) :: first_name = ‘Ian’

Write( *, * ) first_name( 1:2 ), first_name( 2: ), first_name( : )

Ia an Ian

Program hello3

Implicit None

Character( Len = 6 ) :: greeting

Character( Len = 6 ) :: name

greeting = 'Hello '

name = 'Cheryl'

Write( *, * ) greeting // name

Write( *, * ) greeting // name( 2:4 )

End Program hello3

$ nagfor -o hello3 hello3.f90

$ ./hello3

Hello Cheryl

Hello her

Character Operations

• Parameters are very useful for code readability – can you remember what value

Euler’s constant takes ?

• Further something like mat_dim is likely to occur many times in a code – much

easier to change in one place than search for every occurrence of 500. And …

Integer , Parameter :: mat_dim = 500

Real , Parameter :: pi = 3.1415927

Real , Parameter :: euler = 0.577216

Character( Len = 2 ), Parameter :: &

mat_type = 'HE'

Symbolic Constants – “Parameters”

• Parameters are constants, you can’t change the value.

Program wrong_params

Implicit None

Integer, Parameter :: mat_dim = 500

mat_dim = mat_dim + 50 ! WRONG – the

! compiler will complain!

End Program wrong_params

Symbolic Constants – “Parameters”

Intrinsic Subprograms

• Fortran has lots of intrinsic subprograms to do useful things for you, like common

mathematical operations.

• These built in routines are called Intrinsics.

• They are either functions that return a result or subroutines that give the result

through one or more if its arguments.

• We will explain these terms in more detail later.

• Some examples ...

Sin( x ) The sine of x (all angles are in radians)

Cos( x ) The cosine of x

Tan( x ) The tangent of x

Asin( x ) The arcsine of x

Acos( x ) The arccosine of x

Atan( x ) The arctangent of x

Exp( x ) The exponent of x

Log( x ) The natural logarithm of x

Sqrt( x ) The square root of x

• Some mathematical functions:

Intrinsic Subprograms

Program trig

Implicit None

Real, Parameter :: pi = 3.1415927

Real :: x

Write( *, * ) Sin( pi ), Cos( pi )

x = Exp( pi )

Write( *, * ) x

End Program trig

$ nagfor -o trig trig.f90

$ ./trig

-0.8742277657E-07 -1.000000000 ! 0 and -1

23.14069557

Trigonometric Functions

Type of The Return Value

Program trig2

Implicit None

Write( *, * ) Sin( 3.1 )

Write( *, * ) Sin( ( 3.1, 0.0 ) )

End Program trig2

$ f90 -o trig2 trig2.f90

$ ./trig2

0.04158076

(0.04158076,0.0E+0)

• Return type is same as the argument

• Similar to multiplying two reals gives a real – you don’t change the type of entities

without being told to do so in Fortran

• So ...

Return Type

Program root

Implicit None

Write( *, * ) Sqrt( -4.0 )

Write( *, * ) Sqrt( ( -4.0, 0.0 ) )

End Program root

$ ifort -o root root.f90

$ ./root

NaN

(0.0000000E+00,2.000000)

Not all compilers are equal!

Program root

Implicit None

Write( *, * ) Sqrt( -4.0 )

Write( *, * ) Sqrt( ( -4.0, 0.0 ) )

End Program root

$ gfortran -o root root.f90

root.f90:3.22:

Write( *, * ) Sqrt( -4.0 )

1

Error: Argument of SQRT at (1) has a negative value

Converting from one Data Type to Another

• We can convert from one type to another:

Int( x ) Convert to integer, round towards zero

Nint( x ) Convert to integer, round to nearest

Real( x ) Convert to real

Cmplx( x ) Convert to complex, imag part = 0

Cmplx( x, y ) Convert to complex

Other Maths Functions

• A few other useful maths functions:

Abs( x ) Absolute value of x

Max( x1, x2, ... ) Maximum

Min( x1, x2, ... ) Minimum

Mod( x, y ) Remainder when x is divided by y

Note that for Max and Min all of the arguments must be of the same type

• If we mixed the types how could we decide upon the type of the returned

value?

Program conv

Implicit None

Real, Parameter :: pi = 3.1415927

Write( *, * ) Int( pi ), &

Real( Int( pi ) ), &

Exp( Cmplx( 0.0, -pi ) )

End Program conv

$ nagfor -o conv conv.f90

$ ./conv

3 3.000000000 ( -1.000000000, -0.8742277657E-07 )

Type conversions

43

Intrinsic Subroutines

• All the intrinsics we have seen so far are functions. There are also intrinsic

subroutines. These are accessed with the call keyword, e.g. for Random_number

Call Random_number( x )

• Returns a random number between 0 and 1 in x. Where x must be of real type.

• Subroutines are very important. We will learn a lot about them in later lectures.

Basic I/O

• We’ve covered some basic input and output, or I/O

Write( *, * ) a, b

Writes a and b to the screen (standard output in Unix terms)

• To read data items in from the keyboard (or standard input) use

Read( *, * ) a, b

• More advance I/O e.g.

– Files

– Making it “pretty”

• Is covered in later lecture notes

Summary of the Basics

• Basic program structure

• Data types

• Constants and Variables

• Basic mathematical operations

• IMPLICIT NONE – always!

• Using comments – often and meaningful

• Some Intrinsics

• Simple I/O

Selection And Repetition

if(a > 0.0)then

log_a=log(a)

else

write(*,*)’Error: a is not positive’

end if

• Much of computing involves the algorithm making a decision, e.g. is this input correct? Is the

error term small enough? Has the algorithm converged?

Selection

IF (logical expression) then

statement

statement

ELSE

statement

END IF

• Fortran provides a data type to help in making decisions: LOGICAL

• Let’s look at Logical data and Logical expressions in some detail first ….

Selection

Logical Variables

• Logical variables can have two values:

– .True.

– .False.

• They are declared as expected

Logical :: error, converged

• They can also have attributes

Logical, Parameter :: debug = .True.

Logical Variables

• Initialization is as expected:

Logical :: verbose = .False.

• Assignment is as expected – they are just a normal Fortran type:

Logical :: converged

Converged = .True.

Program logical_output

Implicit None

Logical :: yes = .True.

Logical :: no = .False.

Write( *, * ) yes, no

End Program logical_output

$ nagfor –o logical_output

logical_output.f90

$ ./logical_output

T F

• Input and output as usual:

write(*,*) converged

• We use T and F for input and output:

Logical variables

n_iter < max_iter

error_flag /= success

’samba’ < ’tiger’

’Oxford’ <= ’Oxfordshire’

• Relational operators:

.eq. == equal to

.ne. /= not equal to

.gt. > greater than

.ge. >= greater than or equal to

.lt. < less than

.le. <= less than or equal to

Logical variables

So we can say:

Logical :: carry_on

carry_on = n_iter < max_iter

Sets carry_on to .true. if n_iter is less than max_iter, .false. otherwise

Logical :: worked

worked = error_flag == success

Sets worked to .true. if error_flag is equal to success, .false. otherwise

Logical Expressions

• Now we've generated our logicals how do we combine them?

• With Logical Operators

.not.

.and.

.or. (inclusive or)

.eqv.

.neqv. (exclusive or)

• Act as one might expect from Boolean algebra.

Logical Expressions

LOGICAL :: log1=.TRUE.

LOGICAL :: log2=.FALSE.

Logical :: log3, log4, lo5, log6

INTEGER :: a=1

log3= .NOT.log1 Evaluates to .FALSE.

log4= log1 .AND. log2 Evaluates to .FALSE.

log5= log1 .OR. log2 Evaluates to .TRUE.

log6= a==2 Evaluates to .FALSE.

Logical Expressions

finished = result < tol .or. &

n_iter > max_iter .or. &

n_iter <= max_iter .and. &

time_taken > max_time

• Long logical expressions frequently get confusing:

• Use brackets for readability and so not to worry about precedence.

Logical Expressions

IF (logical expression) then

statement

statement

ELSE

statement

END IF

• IF Blocks

Conditional Execution

if(a > 0.0)then

log_a=log(a)

else

write(*,*)’Error: a is not positive’

end if

Note indenting - will make code

much easier to read!

Conditional Execution

IF (logical expression) then

statement

if(logical expression) then

statement

else

statement

end if

ELSE

statement

END IF

Which else refers to which if ? See how indenting helps

• Nest IF blocks

Conditional Execution

if (logical expression 1) then

statement

else if(logical expression 2) then

statement

else if(logical expression 3) then

statement

else

statement

end if

Conditional Execution

• Multiple tests with “else if”

• Only one statement can be executed

If( x > 0.0 ) Then

Write( *, * ) ’Positive’

Else If( x == 0.0 ) Then

Write( *, * ) ’Zero’

Else

Write( *, * ) ’Negative’

End If

Conditional Execution

• One use of conditional statements is to detect errors.

• These may be correctable but may not be…

• The command to use for uncorrectable errors is: Stop

• This causes execution of the code to terminate

• Some possible forms of stop:

Stop

Stop ’Invalid Input’

If( error ) Then

Stop

End If

Stop

DO counter = initial, final[, step]

statements

END DO

• By default, i.e. if absent, step is 1 – by far the most common form in practice

Repetitive Execution

program steps_of_one

implicit none

integer :: count

do count = 1, 5

write(*,*) count, count*count

end do

end program steps_of_one

$ ./steps_of_one

1 1

2 4

3 9

4 16

5 25

• Remember no step means step=1 – most important form

Repetitive Execution

program repeating

implicit none

integer :: count

do count = -3, 4, 2

write(*,*) count, count*count

end do

end program repeating

$ nagfor –o rep rep.f90

$ ./rep

-3 9

-1 1

1 1

3 9

Repetitive Execution

Integer :: i, n_in, total, value

Real :: average

Read( *, * ) n_in

total = 0 ! Initialize

Do i = 1, n_in ! Default is step = 1

Read( *, * ) value

total = total + value

End Do

average = Real( total ) / n_in ! Remember integer

! division

Repetitive Execution

INTEGER :: a, b, c

DO a = b, c, 3

READ(*,*) a

a = b-c

END DO

• Do not change the value of the counter. The following is ILLEGAL:

• Likewise don’t change limits or stride.

• Note the stride can be negative, so you can “count down”.

• But it can’t be zero.

Repetitive Execution

Integer :: i, j

Do i = 1, 12

Write( *, * ) ’Multiplication ’, &

’table for ’, i

Do j = 1, 12

Write( *, * ) j, ’ * ’, i, ’ = ’, j * i

End Do

Write( *, * ) ! Write a blank line

End Do

Nested Do Loops

Do i = 1, 10

If( Mod( i, 2 ) == 0 ) Then

Write( *, * ) i, ’ is even’

Else

Write( *, * ) i, ’ is odd’

End If

End Do

Nested Block Structures

• More generally can nest any block structures:

DO

statements

END DO

• There are other forms of the do loop

• Be careful - this is an infinite loop so we will need an exit condition

Repetitive Execution

Two useful commands are exit and cycle

exit exits the do loop

cycle cycles the do loop i.e. go onto the next iteration

Note not restricted to infinite do loops

Perfectly OK in “counting” do loops

Repetitive Execution

REAL :: x, x_sq, x_cube

DO

READ(*,*) x

IF( x < 0.0 ) EXIT

x_sq = x * x

x_cube = x_sq * x

WRITE(*,*)’ value = ’, x

WRITE(*,*)’ square = ’, x_sq

WRITE(*,*)’ cube = ’, x_cube

END DO

Repetitive Execution

DO i = 1, n

DO

If( error ) Exit ! Which loop is exited?

END DO

END DO

• With multiple nested DO loops you will need to be careful which loop you

EXIT/CYCLE:

• By default loop which exit/cycle is directly in is acted upon

Repetitive Execution

Input_loop:Do

…

If( error ) Exit Input_loop

…

If( end_of_line ) Cycle Input_loop

…

End Do Input_loop

Named Do Loops

• Can name any sort of do loop.

• Can also name IF blocks and case statements (less useful in practice)

Outer: DO i = 1, n

Inner: DO

if(condition)then

exit Outer

end if

END DO Inner

END DO Outer

Named Do Loops

Evaluate exp(x) at points from x_init to x_final with a step size of x_step. Use a

power series expansion to converge to within a given tolerance of the intrinsic exp

function. Evaluate the number of terms needed for convergence.

exp(x) = 1 + x/1! + x2/2! + x3/3! + ...

Note: The ith term is the (i-1)th term * x/i

A complete example

READ USER INPUTDO X

IS X IN RANGE?SET INITIAL TERMDO TERMS

IS TERM < TOLERANCE?SUM TERMSGENERATE NEXT TERM

END DO TERMSOUTPUT VALUESINCREMENT X

END DO

A complete example

PROGRAM Exponential

IMPLICIT NONE

INTEGER :: Counter

REAL :: Begin, r_End, Step, X, Tolerance, ExpX, Term, Sums

WRITE(*,*) ’Input Initial, Final, Step and Tol'

READ(*,*) Begin, r_End, Step, Tolerance

X = Begin

DO ! Loop over x values

IF (X > r_End) EXIT

ExpX = EXP(X)

Counter = 1

Term = X

Sums = 1.0

DO ! Do Loop over terms

IF (ABS(Term) < Tolerance) EXIT

Sums = Sums + Term

Counter = Counter + 1

Term = Term * (X / Counter)

END DO

WRITE(*,*) X, ExpX, Sums, Counter

X = X + Step

END DO

END PROGRAM Exponential

A complete example

Summary

• Logical variables can take two states - .TRUE. and .FALSE.

• Condition execution is performed using IF - THEN – ELSE IF - ELSE - END IF

• IF - THEN - ELSE IF can be replaced by SELECT - CASE in some cases

• Use STOP command to terminate a program

• Repetitive execution via DO - END DO construct

• Can also use DO WHILE construct

• CYCLE and EXIT allow control of loops

Further Reading

• Fortran has other selection constructs

– E.g. look at Case – used for comparison against a known possible set of results

• Look at the Fortran intrinsic routines

• These include ones for manipulating strings

• Look at how to compare characters, in particular are number “less than” letters?

Lecture 2

Kind

Kind

• We have seen all constants and variables have a type

– So far one of Integer, Real, Complex, Character, Logical

• Now we shall see all constants and variables of intrinsic type also have a kind

• Consider Integers

– There are an infinite number of Integers

– So to be able to represent all integers on a computer would take an infinite amount of

memory

– We can’t do that

– So the integer type only represents a subset

– Which subset is defined by the kind of the Integer

– And a compiler may support more than one kind

– Essentially the kind specifies the range of the integer

• All Integers are signed in Fortran

• Reals are similar but now the kind specifies the range and the precision

Specifying a Kind

• So far we have only used the default kind for variables

• How do we go about specifying non-default kinds

– Especially important for reals and complex, in computational science you will rarely want to

use the default kind

– It usually only has 6 or 7 significant figures which is almost always not enough for

computational science

Specifying a kind

• Suppose we have a symbolic constant (parameter) wp

• Then we can specify a variable of kind wp by either

REAL (KIND=wp) :: val4

REAL (wp) :: val4

• i.e. the kind = is optional

• Constants of a given kind are specified by

val4 = 1.0_wp

• Remember the kind value MUST be a constant

– i.e. a parameter (much, much, the preferred method)

– Or a literal constant (BAD PRACTICE – not all compilers support the same values for kind

parameters)

• But how do we choose a suitable kind value for each type we want to employ?

Selecting the Real KIND Value

• We can use the intrinsic function SELECTED_REAL_KIND.

• To ask for a kind value for a real with at least 12 decimal digits of precision.

wp = SELECTED_REAL_KIND(12)

• To make sure it also has an exponent range of at least 70.

wp = SELECTED_REAL_KIND(12,70)

• Thus to declare a variable of this type and kind

REAL (wp) :: my_val

• And to specify a constant of a given type and kind

REAL (wp) :: my_val

• Function returns -1 if the precision is unavailable, -2 if exponent range unavailable

and -3 for both.

• Standard says at least 2 real kinds must be supported

– Universally IEEE single and IEEE double are supported

– More may be available

Selecting the Complex Kind Value

• For complex also use selected_real_kind

– Range and precision refer to the real and imaginary parts

• Thus to declare a complex variable where both parts have a precision of at least 12

and have a range of at least 70 we can reuse wp from before and simply say

Complex(wp) :: my_val

• Standard says that for every real kind supported there must be a corresponding

complex

– So at least 2 complex kinds supported

– (Unlike F77)

Selecting The Integer Kind Value

• To ask for an integer type that covers at least the range -1*1012 < x < 1012

ikind_12 = SELECTED_INT_KIND(12)

• Thus to declare a variable of this type

INTEGER (KIND=ikind_12) :: my_val

• And to assign a constant of type integer and kind ikind_12 to it

my_val = 4_ikind_12

• Returns -1 if no corresponding kind is available

• At least 1 Integer kind must be available

– 2 in F2008

– Again more may be supported by a given compiler

Kind for Character and Logical

• You can also use kind with character – used to specify different character sets e.g.

For Greek or Kanji

– But only one set required to be supported

• You can also have kinds for Logical variables

– I have never used this!

KIND Selection: Summary

• Real In computational science it’s almost always right to use what's

returned by Selected_real_kind(12,70), that is IEEE double

• Complex As Real

• Integer Almost always use the default – some exceptions but fairly rare

• Character Use the default

• Logical Use the default

• Looking ahead – store your kind values in a module

Simple Kind Example

Program kind_example

! ( 12, 70 ) This is what you usually want

Integer, Parameter :: wp = selected_real_kind( 12, 70 )

Real :: da

Real( wp ) :: wa

da = 2.0

wa = 2.0_wp

Write( *, * ) da, wa

! Note Intrinsics return same type AND KIND

Write( *, * ) Sqrt( da ), Sqrt( wa )

End Program kind_example

$ f90 -o kind kind.f90

$ ./kind

2.0000000 2.0000000000000000

1.4142135 1.4142135623730951

Just To Make A Point

Program kind_example

! Only this line has changed

Integer, Parameter :: wp = selected_real_kind( 6, 35 )

Real :: da

Real( wp ) :: wa

da = 2.0

wa = 2.0_wp

Write( *, * ) da, wa

Write( *, * ) Sqrt( da ), Sqrt( wa )

End Program kind_example

$ f90 -o kind kind.f90

$ ./kind

2.0000000 2.0000000

1.4142135 1.4142135

Get Your Constants Right

Program conv

Implicit None

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

Real( wp ) :: wa, wb

Real :: da, db

da = 0.3333333333333333333

db = 0.3333333333333333333_wp

wa = 0.3333333333333333333

wb = 0.3333333333333333333_wp

Write( *, * ) 'Default real assigned to default real: ', da

Write( *, * ) 'Default real assigned to working real: ', db

Write( *, * ) 'Working real assigned to default real: ', wa

Write( *, * ) 'Working real assigned to working real: ', wb

End Program conv

> gfortran -std=f95 conv.f90

> ./a.out

Default real assigned to default real: 0.33333334

Default real assigned to working real: 0.33333334

Working real assigned to default real: 0.33333334326744080

Working real assigned to working real: 0.33333333333333331

A more general rule

• This is an instance of the more general rule about assignments and expression

evaluation in Fortran

• Never look at the LHS of the = before you have finished evaluating the RHS. Once

you have finished the evaluation then look and perform any type AND KIND

conversions as required

– Just because you are assigning to a double won't make the expression a double, you have

to specify all the kinds in the RHS carefully yourself – the earlier integer example didn't

magically turn itself into a real

• Even more generally – don’t assume any context for the evaluation of any given part

of an expression, just do exactly as it says

– A given expression always returns the same result

Integer, Parameter :: wp = selected_real_kind( 12, 70 )

Real :: a

Real :: b

Integer :: I

a = 4.0_wp * ( i / 3 + b * 2 )

The Kind Intrinsic function

• We can retrieve the kind of a number:

real :: a

write(*,*) kind(a)

• Will print out the integer value of the real kind.

Type and Kind Conversion

Integer, Parameter :: float = selected_real_kind( 12, 70 )

Integer :: i

Real (float) :: a

a = real(i) ! Convert to default kind, probably will lose precision

Integer, Parameter :: float = selected_real_kind( 12, 70 )

Integer :: i

Real (float) :: a

a = real(i,float) ! OK

a = real(i,kind(a)) ! Better!

Summary

• ALL variables and constants in Fortran have a type and kind

– Remember constants – a very common bug!

• The kind specifies the range and, for reals, the precision of the variable and

constant

• You use a constant to specify the kind

– Preferably a symbolic constant (parameter)

• Choose the kind value using the selected_*_kind intrinsic

– I suggest you use 12, 70 for reals (and complex)

– And default kinds for all the rest

• Except in one or two specialised cases for integers, typically involved with I/O when you may need very large integers when dealing with very large files

• Remember to specify the kind when converting the type

– A very common bug!

• Remember in Fortran all parts of the expression are evaluated in isolation

– There is never any context for an expression , a given expression always returns the same

result

Arrays

Arrays

• An array is a collection of data of the same type and kind. Array elements are

indexed or subscripted, just like x1, x2, ..., xn in mathematics

• Arrays are tables of data

• Arrays can be real, integer, logical, complex etc

Arrays

• Array has the following important components:

– A name (is a variable)

– A type: this is the type of all the array elements.

– A kind: this is the kind of all the array elements

– A rank: the number of dimensions

– A set of extents: The number of elements in each dimension

– A set of bounds: The range of valid subscripts for each dimensions

• Note scalars, i.e. what we have looked at so far, have rank zero.

• This means that all constants and variables have a type, kind and rank (TKR)

– Though we won’t really touch much on constant arrays here but you can have them

Arrays

• The syntax for declaring a one dimensional array is the type as normal followed by

the DIMENSION attribute with the extent in brackets. For example:

Real( wp ), dimension(10) :: x

• Here we have an array of type real, kind wp and rank 1 with extent 10.

– That is, x has space to store 10 real numbers.

• An alternative which some people prefer:

Real( wp ) :: x( 10 )

Arrays

• Multi-dimensional arrays are a simple extension;

Real( wp ), dimension(10,10) :: x

• Elements of the array are referenced within brackets

integer :: j

integer, dimension(100) :: iwork

do j = 1, 100

iwork(j) = 0 ! initialise elements to zero

end do

1 2 3 4 5

5

4

3

2

1

• By default starts at 1.

– The lower bound is 1 and the upper bound is that specified

• But we can choose other bounds.

• We can specify an lower and upper limit for the indices in the array.

• The picture shows an array declared as:

REAL, DIMENSION(5,5)

REAL, DIMENSION(1:5,1:5)

Arrays Indexing

• We can declare extents like this:

REAL, DIMENSION(5,-2:2) :: a

-2 1 0 1 2

5

4

3

2

1

Arrays Indexing

Array Indexing – Out of Bounds

• Note it is always illegal to use an array index outside of the declared bounds

Integer, Dimension( 1:8 ) :: a

a( 3 ) = 1 ! OK

a( 8 ) = 2 ! Still OK

a( 9 ) = 3 ! WRONG

• Commonly called an “out of bounds” array access – possibly THE most common

error in Fortran programming

Out of Bounds – Use of the Compiler

• In Fortran all good compilers can detect out of bounds array accesses

– Check your documentation

Program bounds

Implicit None

Real, Dimension( 1:5 ) :: a

Integer :: i

Do i = 1, 6

a( i ) = i

End Do

Write(*,*) a

End Program bounds

> nagfor –w=all –C=all t.f90 ! Enable NAG warnings and run time checks (-C=array)

> ./a.out

Runtime Error: t.f95(6) : Subscript 1 of A (value 6) is out of range (1:5)

Out of Bounds – Use of the Compiler

• When developing USE THIS, It will save months of your life!

– nagfor –C=all …

– gfortran –fcheck=all …

– ifort –check all

• More generally learn what your compiler can do for you

• And use more than one compiler

– Not all compilers detect the same things

– But the NAG one is very good for debugging

• Intel is likely better for production though

• gfortran is superb value for money!

• But turn these debugging flags off for production as it slows down your program!

Arrays

• The integers in an extent or bounds can be symbolic constants (parameters):

INTEGER, PARAMETER :: MaximumSize = 100

LOGICAL, DIMENSION( MaximumSize ) :: test

INTEGER, PARAMETER :: LowerB = -10

INTEGER, PARAMETER :: UpperB = 10

REAL, DIMENSION( LowerB:UpperB ) :: Score

Array Inquiry Functions

• You can also enquire properties of the array

• Not so useful now but when we start writing our own subprograms they become very useful!

• Some useful ones are

Integer, Dimension( 0:1, 2:4 ) :: a

Size( a ) returns the total number of elements in a, i.e. 6

Size( a, Dim = 1 ) returns the extent of the given dimension of a, i.e. 2

Lbound( a ) returns an array containing the lower bounds of a, i.e. 0, 2

Lbound( a, Dim = 2 ) returns the lower bound of the given dimension of a, i.e. 2

Ubound( a ) as Lbound but deals with upper rather than lower bounds

A(1,1) A(2,1) A(3,1) etc

Storage of Arrays in Memory

REAL, DIMENSION(3,2) :: a

• Left most index varies most rapidly

• Storage is “column major” order

• This is not a course on optimisation

• However the number 1 tip for good performance in Fortran is that accessing an

array in the order it is stored makes for more efficient code

• So get used to writing loops so the inner most loop goes over the first index where

possible

– Different from C!

Do i = 1, n

Do j = 1, n

a( j, i ) = i + j

End Do

End Do

Storage

Array Expressions and Elemental Operations

• So far we have only looked at scalar expressions

• Fortran allows array expressions as well

• The operations are applied element by element to the array to give an array result

– These are called elemental operations

• Obviously all the arrays must have the same extent

– Must be conformable

– But note don’t need to have the same bounds

• So the following are equivalent

Integer, Parameter :: n

Real, Dimension( 1:n ) :: a, b, c

Integer :: i

…

Do i = 1, n

a( i ) = b( i ) + 2.0 * c( i )

End Do

a = b + 2.0 * c ! Equivalent to the loops above

Multiple Dimensions

• The above extends naturally to multiple dimensions

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

Integer, Parameter :: m = 50

Integer, Parameter :: n = 35

Real( wp ), Dimension( 1:m, 1:n ) :: a, b, c

a = 5.0_wp * b + 3.0_wp * c

Array Expressions and Scalars

• Note how the scalars in the previous example “filled out” to apply to the whole array

• This leads to some very convenient ways of initialising arrays:

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

Integer, Parameter :: m = 20

Integer, Parameter :: n = 65

Real( wp ), Dimension( 1:m, 1:n ) :: a, b, c

a = 0.0_wp ! Set all of a to 0.0_wp

b = 2.0_wp ! Set all of b to 2.0_wp

c = 3.0_wp ! Set all of c to 3.0_wp

Array Expression and Intrinsic Functions

• We can even do the following if the intrinsic is an elemental function

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

Integer, Parameter :: m = 90

Integer, Parameter :: n = 45

Real( wp ), Dimension( 1:m, 1:n ) :: a, b

a = Sqrt( b ) ! Set all of a to the sqrt of b

Accessing Part of An Array

• So far we have only used array expression where the whole array is accessed

• However Fortran also permits array sections where you only access part of the

array

• Referencing a complete row:

– A(3,1:5)

– The 3 indicates the 3rd row.

– The 1 indicates the lowest index and

5 the highest.

• Or equivalently:

– A(3,:)

– The colon on its own picks up the default values for the lowest & highest indices.

• Equally:

– A(3,1:5:1) ! NOT like MATLAB!

– first : last : increment

Accessing Array Sections

• Here we use the 3rd value separated by another colon to indicate a stride.

– a(1::2, 2:4)

• Or:

– a(1:5:2, 2:4:1)

Accessing Array Sections – Multiple Dimensions

Array Sections

• So we can do things like

Integer, Dimension( 1:100 ) :: a

Integer, Dimension( 1:50 ) :: b

a( 1:10 ) = 0 ! Set the first 10 elements of a to 0

a( 11::2 ) = 1 ! Set the remaining odd numbered elements to 1

a( 12::2 ) = 2 ! And set the remaining even numbered elements to 2

b = a( 1:50 ) + a( 51:100 ) ! Note the extents are the same

Masked Elemental Operations – Where

1.0 -2.0 -2.0 6.0

5.0 3.0 4.0

2.0 2.0 -2.0 3.0

0.0 -3.0 0.0

ra rb

REAL, DIMENSION(4,4) :: ra, rb

WHERE (rb > 0.0)

ra = ra/rb

ELSEWHERE (rb < 0.0)

ra = ra/-rb

ELSEWHERE

ra = 0

END WHERE

0.5 -1.0 -1.0 2.0

0.0 1.0 0.0

ra after• Each element in “ra” will be divided by

the absolute value of the corresponding element in “rb”, unless that is zero where the element in “ra” will be set to zero.

Array Reduction Functions

• So far we have looked at elemental operations

• Sometimes we want a reduction operation

• This takes a whole array and reduces it to a single value

– E.g. The sum of the array values, the maximum value …

• Some useful ones in Fortran

Real, Dimension( 1:20 ) :: a

Real :: a_max, a_min, a_av_odd

a_max = Maxval( a )

a_min = Minval( a )

a_av_odd = Sum( a( 1::2 ) ) / Size( a( 1::2 ) )

Logical Array Reduction Functions

• The functions any, all and count apply to logical arrays

• Occasionally useful for things like

Real, Dimension( 1:1000 ) :: a, b

If( all( a >= 0.0 ) ) Then

b = Sqrt( a )

Else

Write( *, * ) ”Error: Some of a are negative so can’t take the sqrt”

End If

real, dimension(10) :: x

integer :: i

do i = 1,10

x(i) = real(i)

end do

write(*,*)x

$ nagfor -o array.f90

$ ./a.out

1.000000 2.000000 3.000000 4.000000

5.000000 6.000000 7.000000 8.000000

9.000000 10.00000

Array I/O

• Another elemental operation Fortran allows is array I/O

• Output:

INTEGER, DIMENSION(1:10) :: x

INTEGER :: n, i

READ(*,*) n ! Hope not > 10

DO i = 1, n

READ(*,*) x(i)

END DO

INTEGER, DIMENSION(1:10) :: x

INTEGER :: n, i

READ(*,*) n

READ(*,*) x

Expects hard return between inputs, at each read.

Can input values one line, space or comma separated.

• Input is a little more complicated, we’ll find out why the following are different later

Array I/O

Input #1 Input #2

-------- --------

3 3

10 10 30

30 40

40

INTEGER,DIMENSION(1:10) :: x

INTEGER :: n, I

READ(*,*) n

READ(*,*) x

Array I/O

Multidimensional Array I/O

• Multidimensional array I/O is performed in storage order

• “Down the columns first”

Allocatable Arrays

• Sometimes we don’t know before we run the program what size our arrays need to be

• Consider this piece of code below.

• We have decided in advance that the array x will hold at most 10 elements.

• But this is not practical for large arrays, particularly if the amount of memory available

is an issue. And what if we the user types 11?

• We would like to delay the decision until we know how much storage is actually

required.

real, dimension(10) :: x

integer :: n,i

read(*,*)n

do i = 1, n

read(*,*)x(i)

end do

Allocatable Arrays

• We can allocate memory for arrays as required.

• Still need to declare the number of dimensions at the specification stage.

• The attribute required is ALLOCATABLE.

• At some stage we need to allocate space for this array. This is done via the

ALLOCATE command

• Another benefit of allocatable arrays is that they reduce the overall storage

requirement as we can free up the memory after we have finished with it so that it

can be used for something else.

Allocatable Arrays

real, dimension(:), allocatable :: x

integer :: n, i, alloc_error

read(*,*)n

allocate(x(n), stat=alloc_error) ! stat optional

if(alloc_error.ne.0)then

stop ’Error during allocation’

end if

do i = 1, n

read(*,*) x(i)

end do

Deallocation

real, dimension(:,:),allocatable :: x ! rank 2

integer :: n,i,alloc_error

read(*,*)n

allocate(x(n,n), stat=alloc_error)

...

...

deallocate(x)

Summary

• Arrays

– Ranks, Extents and Bounds

– Subscripting

– Use of the compiler to detect array problems

• Array storage

• Elemental operations and the Where construct

• Array sections

• Reduction operations

• Array I/O

• Allocatable arrays

Further Reading

• We have very much glossed over what Fortran can do with arrays, covering only the most

commonly used features

• Eventually

– You should read up more on array syntax and practice it

– You should learn about elemental intrinsic functions

– You should learn about array constructors

– You should learn about vector subscripts

– You should learn more about intrinsic reduction functions

– You should learn about intrinsic array manipulation functions

Program Structure

Subprograms

• Real programs can be 1000’s of lines long

• The solution is to break up the program into subprograms: Each subprogram performs one

(and ideally ONLY one) of the tasks the code requires

• This helps by increasing code comprehensibility

• If well written you need only understand that subprogram, not the whole program

• It also enables reusability

• Common operations need only be coded once and then may be used many times – or by a

different program

Subprograms

Program means

! Program to read in data and calculate the arithmetic, harmonic

! and geometric means of that data.

Implicit None

Real, Dimension( : ), Allocatable :: data

Real :: arithmetic_mean

Real :: geometric_mean

Real :: harmonic_mean

! Read in the data

Call read_data

! Calculate the means

Call calc_arithmetic_mean( data, arithmetic_mean )

Call calc_geometric_mean ( data, geometric_mean )

Call calc_harmonic_mean ( data, harmonic_mean )

! Write out the results

Call write_results( arithmetic_mean, geometric_mean, harmonic_mean )

! Free the memory

Call deallocate_data

End Program means

Subprograms

• The sign of a good programmer is well designed, easily understandable

subprograms.

• Fortran has two kinds of subprograms:

• Subroutine, e.g.

Call Random_number( x )

• Function, e.g.

y = Sin( x )

• These are intrinsic subprograms, but you can also define your own subprograms.

Subprogram Types

• There are four types of subprogram

– Intrinsic

– Contained

– Module

– External

• We have met intrinsic subprograms – the ones provided by the language

• In practice you should use Module subprograms most of the time

– But we’ll use contained subprograms as a “stepping stone” to them

• And in Fortran subroutines are much more common than functions

Contained Subprograms

Program hello4

Implicit None

Call greet( 'Ian' ) ! Note write once -

Call greet( 'World' ) ! use many

Contains

Subroutine greet( name )

Character( Len = * ), Intent( In ) :: name

Write( *, * ) 'Hello', name

End Subroutine greet

End Program hello4

$ ./hello4

Hello Ian

Hello World

Functions, Multiple Arguments And Local Variables

Program func_example

Implicit None

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

Write( *, * ) length( 3.0_wp, 4.0_wp )

Contains

Function length( x, y ) Result( r )

Real( wp ) :: r

Real( wp ), Intent( In ) :: x

Real( wp ), Intent( In ) :: y

Real( wp ) :: x_sq, y_sq ! Local Variables

x_sq = x * x

y_sq = y * y

r = Sqrt( x * x + y * y )

End Function length

End Program func_example

$ ./func_example

5.0000000000000000

Multiple Subprograms

Program mindless_optimism

Implicit None

Call greet( 'Ian' )

Call predict_cricket ! Don’t have to have arguments !

Contains

Subroutine greet( name )

Character( Len = * ), Intent( In ) :: name

Write( *, * ) 'Hello', name

End Subroutine greet

Subroutine predict_cricket

Write( *, * ) 'Cricket Result Prediction:'

Write( *, * ) 'England to beat Australia'

End Subroutine predict_cricket

End Program mindless_optimism

$ ./patriotism

Hello Ian

Cricket Result Prediction:

England to beat Australia

Program hello4

Implicit None

Call greet( 'Ian' )

Call greet( 'World' )

Contains

Subroutine greet( name )

Character( Len = * ), Intent( In ) :: name

Write( *, * ) 'Hello', name

End Subroutine greet

End Program hello4

Actual ArgumentsType :: CharacterRank :: 0

Dummy ArgumentType :: CharacterRank :: 0

Argument Association

Real & Dummy Arguments

Program association

Implicit None

Integer :: i

i = 2

Call zero( i )

Write( *, * ) i

Contains

Subroutine zero( a )

Integer, Intent( Out ) :: a

a = 0

End Subroutine zero

End Program association

$ ./association

0

Actual ArgumentsType :: IntegerKind :: DefaultRank :: 0

Dummy ArgumentsType :: IntegerKind :: DefaultRank :: 0

N.B. Dummy arguments must have the same type, kind and rank as the actual argument – “TKR matching”

Argument Association – What Happens

Program argument_mismatch

Implicit None

Integer :: i

Call zero( i )

Contains

Subroutine zero( a )

Real, Intent( Out ) :: a

a = 0

End Subroutine zero

End Program argument_mismatch

$ gfortran match.f90

In file match.f90:4

Call zero( i )

1

Error: Type mismatch in parameter 'a' at (1). Passing INTEGER(4) to REAL(4)

In file match.f90:3

Integer :: i

1

Error (113): Variable 'i' at (1) is used but not set

Actual Argument: Rank 0, Integer, Default Kind

Dummy Argument: Rank 0, Real, Default Kind

Argument Mismatch

Program mismatch2

Implicit None

Write( *, * ) length( 3, 4 )

Contains

Real Function length( x, y )

Real( wp ), Intent( In ) :: x

Real( wp ), Intent( In ) :: y

length = Sqrt( x * x + y * y )

End Function length

End Program mismatch2

Actual Argument: Rank 0, Integer, Default Kind

Dummy Argument: Rank 0, Real, Kind wp

WRONG !

Argument Mismatch

Dummy Arguments

• Dummy argument specification is very similar to normal variables, with a few extras.

• We’ll cover the extras as we go along, the first being Intent

Intent

• Intent specifies what the subprogram will do to the variable. The possible values are:

– Intent( In )

The real argument is initialized and the subprogram will not change the value

– Intent( Out )

Any value the real argument has will be ignored. The subprogram will set the argument.

– Intent( InOut )

The real argument is initialized and the subprogram may change the value

Intent

• It’s easier than it sounds !

– Input only variables Intent( In )

– Output only variables Intent( Out )

– Both Intent( InOut )

• Good style:

– For subroutines avoid Intent( InOut ) except where it really makes sense

– For functions use only Intent( In ) arguments

Program argument_aliasing

Implicit None

Integer :: i

Call set( i, i )

Contains

Subroutine set( a, b )

Integer, Intent( Out ) :: a

Integer, Intent( Out ) :: b

a = 0

b = 1

End Subroutine set

End Program argument_aliasing

For anything but Intent( In )or pointers this is illegal.Avoid! It leads to really nasty bugs

Argument Aliasing

Program host

Implicit None

Integer :: i

i = 7

Call associate

Contains

Subroutine associate

Integer :: j ! But j is local to the

subroutine

Write( *, * ) i

End Subroutine associate

End Program host

$ ./hello4

7

The Subroutine knows the Value of iby Host Association

Host Association

Program scope

Implicit None

Integer :: i

i = 7

Call associate

Contains

Subroutine associate

Integer :: j

j = 8

Write( *, * ) i, j

End Subroutine associate

End Program scope

Scope of Associate

(and Scope by host

association)

Scope of Scope

Scope

Scope

• Any program unit (we’ve seen Program, Subroutine and Function) can only access

entities that are in scope, e.g.

– Variables

– Parameters

– Subprograms

Program scope2

Implicit None

Integer :: i

i = 7

Call associate

Contains

Subroutine associate

Integer :: j

j = 8

Call wrong

End Subroutine associate

Subroutine wrong

Integer :: k

k = -3

Write( *, * ) i, k

Write( *, * ) j

End Subroutine wrong

End Program scope2

Scope of Associate

Scope of Associate2

Scope of Scope2

Legal – wrong is in scope by host association

Legal – i,k are in scope

Illegal – j is NOTin scope

Scope

Scope

• Scope may seem a bit of a pain, but it’s there for protection – you can only access

and change things you are allowed to, this stops all sorts of nasty bugs from some

piece of the program altering something unexpectedly (what if it is not only you

developing the code?)

Local Variable

• Local variables are variables that are in scope for a subprogram and nowhere else.

• You should NOT make ANY assumptions about their initial values

– Uninitialized variables are a very nasty bug

– The NAG compiler is one of the very few that can do a good job at finding them

• But not all of the time – doesn’t work with external libraries, e.g. MPI, MKL

• Intel and gnu can do a fairly half hearted effort

– But you can give them initial values …

• And by default their values are not guaranteed to be preserved from one call to the

next

Program local

Implicit None

Integer :: j

Do j = 1, 3

Call initialized_var

End Do

Contains

Subroutine initialized_var

Integer :: i = 0

i = i + 1

Write( *, * ) i

End Subroutine initialized_var

End Program local

$ ./local

1

2

3

Initialization applies to the FIRST CALL ONLY.Initialization implies the Save attribute

Local Variables - Initialization

The Save Attribute

• The Save attribute means that the value of a local variable will be preserved

between subroutine calls

Integer, Save :: i

• Initialized variables get the Save attribute by default

• Good practice: Avoid local variables with the Save attribute unless you really, really

need them.

Characters and Arrays

• So far we have only looked at passing numeric scalars to subprograms. Characters

and arrays are a little more complicated, but not much …

• For characters you have to consider the length

• For arrays you have to match the rank, extent and bounds

Program character_arguments

Implicit None

Call char_len( 'Ian' )

Call char_len( 'World' )

Contains

Subroutine char_len( string )

Character( Len = * ), Intent( In ) :: string

Write( *, * ) Len( string )

End Subroutine char_len

End Program character_arguments

$ ./character_arguments

3

5

Pick up the length from that of the actual argument

Character Arguments

Program array_arguments

Implicit None

Real, Dimension( 1:2, 1:3 ) :: a

a = 0

Call array_properties( a )

Contains

Subroutine array_properties( x )

Real, Dimension( :, : ), Intent( In ) :: x

Write( *, * ) Size( x, Dim = 1 ), Size( x, Dim = 2 ), &

Size( x )

Write( *, * ) Lbound( x )

Write( *, * ) Ubound( x, Dim = 1 ), Ubound( x, Dim = 2 )

End Subroutine array_properties

End Program array_arguments

$ ./array_arguments

2 3 6

1 1

2 3

Pick up extents fromactual arguments –and ONLY the extents

Array Arguments – Assumed Shape

Program array_arguments

Implicit None

Real, Dimension( 0:1, 1:3 ) :: a

a = 0

Call array_properties( a )

Contains

Subroutine array_properties( x )

Real, Dimension( :, : ), Intent( In ) :: x

Write( *, * ) Size( x, Dim = 1 ), Size( x, Dim = 2 ), &

Size( x )

Write( *, * ) Lbound( x )

Write( *, * ) Ubound( x, Dim = 1 ), Ubound( x, Dim = 2 )

End Subroutine array_properties

End Program array_arguments

$ ./array_arguments

2 3 6

1 1

2 3

Pick up extents fromactual arguments –lower bound is 1 inthe subprogram

Array Arguments – Assumed Shape

Program array_arguments2

Implicit None

Real, Dimension( 0:1, 1:3 ) :: a

a = 0

Call array_properties( a )

Contains

Subroutine array_properties( x )

Real, Dimension( 3:, :4 ), Intent( In ) :: x

Write( *, * ) Size( x, Dim = 1 ), &

Size( x, Dim = 2 ), Size( x )

Write( *, * ) Lbound( x )

Write( *, * ) Ubound( x, Dim = 1 ), Ubound( x, Dim = 2 )

End Subroutine array_properties

End Program array_arguments2

$ ./array_arguments

2 3 6

3 2

4 4

Always keep the same extent but can chose the bounds we need

Array Arguments – Assumed Shape

Array Arguments - A More Realistic Example

Program array_args

Implicit None

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

Real( wp ), Dimension( : ), Allocatable :: a

Real( wp ) :: av

Integer :: i, n

Write( *, * ) 'How many values ?'

Read ( *, * ) n

Allocate( a( 1:n ) ) ! Should really check status

Do i = 1, n

Write( *, * ) 'Please input value ', i

Read ( *, * ) a( i )

End Do

Call average( a, av )

Write( *, * ) 'the average is ', av

Contains

Subroutine average( a, av )

Real( wp ), Dimension( : ), Intent( In ) :: a

Real( wp ), Intent( Out ) :: av

Integer :: i

av = 0.0_wp

Do i = 1, Size( a )

av = av + a( i )

End Do

av = av / Size( a )

End Subroutine average

End Program array_args

>./a.out

How many values ?

3

Please input value 1

0

Please input value 2

1

Please input value 3

2

the average is 1.0000000000000000

The Return Statement

• A subprogram normally exits when it reaches the end.

• You can go back to the calling (sub)program at any point by using the Return

statement

If( error_has_occured ) Then

error = 1 ! Return an error flag

Return

End If

• Good Practice: Avoid Return unless the program logic becomes complicated (

except possibly as the last statement – style issue )

Program return_example

Implicit None

Real, Dimension( : ), Allocatable :: a

Integer :: n

Integer :: error

Read( *, * ) n

Call allocate_array( n, error )

If( error /= 0 ) Then

Write( *, * ) 'Allocation Failed'

End If

Contains

Subroutine allocate_array( n, error )

Integer, Intent( In ) :: n

Integer, Intent( Out ) :: error

Allocate( a( 1:n ), Stat = error )

If( error /= 0 ) Then

Return

End If

End Subroutine allocate_array

End Program return_example

The Return Statement

Summary

• Why subprograms

• Fortran subprogram types

• Contained subprograms

• Actual and dummy arguments

• Argument association

• Intent

• Host association and scope

Further Reading

• Passing unallocated allocatable arrays as actual arguments

– If already allocated you need do nothing special and just do what covered here

– If you want to (re-)allocate them in a subprogram the dummy argument needs to have the

allocatable attribute

– Actually you just do the obvious thing from what you have learnt here …

• Optional and Keyword arguments

• Pure and Elemental subprograms

Lecture 3

Programming Structure 2

Modules

• We saw some of the advantages of subprograms.

– Helping us to organise our programs.

– Allowing us to reuse code

• We might also want to reuse variables.

• And packages these variable with the subprograms that act upon them.

• For this we can use MODULES.

Modules

MODULE pleasantries

IMPLICT NONE

Integer :: age = 49

. . .

CONTAINS

SUBROUTINE greet( name )

CHARACTER( LEN = * ), INTENT( IN ) :: name

WRITE( *, * ) 'Hello ', name

END SUBROUTINE greet

. . .

END MODULE pleasantries

USEing Modules

PROGRAM hello

USE pleasentries ! N.B. BEFORE implicit none

IMPLICT NONE

CALL greet( 'Ian' )

Write(*,*) age

END PROGRAM hello

$ ./hello

Hello Ian

43

Program hello

Use mymodule

Implicit None

Call greet( 'Ian' )

Write(*,*) age

End Program hello

Scope of hello andmymodule by Use

Module mymodule

Implicit None

Integer :: age = 43

Contains

Subroutine greet( name )

Character( Len = * ), Intent( In ) :: name

Write( *, * ) 'Hello ', name

End Subroutine greet

End Module mymodule

mymodule in scope byuse association

Scope ofmymodule

Modules and Scope

The Advantages Of Modules

• Modules allow the breaking up of a large program into multiple files by accessing

scopes exterior to the current (sub)program

• This help

– Comprehensibility

If well written you only need understand one file

– Reuseability

If well written the file may be used in many codes

The Advantages of Modules

• So large programs may be built up from many smaller files, and each of those files

may be used in many programs, and this should also aid in comprehension.

• Well designed modules are the very essence of good programming.

• Another advantage is that the scope may be in a totally separate module and is

restricted to that module – Unless you Use it

Modules

• All of the concepts from contained subprograms pass directly over to USEing

Modules.

• So we know all about

– Dummy and real arguments

– Argument association

– Host association and scope

– Passing scalars, characters and arrays

– Assumed shape arrays

Multiple file compilation

• Good practise is one module per file.

• Compiling modules:

$ nagfor –o prog file1.f90 file2.f90 file3.f90 ...

• If file2.f90 Uses a Module from file1.f90, you MUST compile file1.f90 before file2.f90

• Try: http://www.fortran.com/makemake.perl

PROGRAM fred

USE mod1

…

END PROGRAM fred

File main.f90

MODULE mod1

…

CONTAINS

SUBROUTINE a

USE mod2

…

END SUBROUTINE a

…

END MODULE mod1

File mod1.f90

MODULE mod2

…

CONTAINS

…

END MODULE mod2

File mod2.f90

> nagfor –o prog \

mod2.f90 mod1.f90 main.f90

Note you can Use Modulesin subprograms and at thetop of Modules. MultipleUse statements are alsofine

Order of Compilation

Public And Private In Modules

• We can control access to variables and subprograms in modules.

• Through Public and Private we can ‘fine tune’ Use Association.

• Public variables and subprograms come into scope when a module is used.

• Private variables and subprograms are private to the module.

• By default all are Public.

• Personally I think this is a mistake – it’s good practice to keep what is public to a

minimum

Program host4

Use data4

Implicit None

Write( *, * ) a ! Fine

Write( *, * ) b ! ILLEGAL - b not in scope

End Program host4

Scope of host4 andPUBLIC scope of data4 by Use

Module data4

Implicit None

Real, Public :: a = 1.0

Real, Private :: b = 2.0

End Module data4

We gain Use Association for a but NOT for b

Scope ofdata4

Private Variables

Program host4

Use data4

Implicit None

Write( *, * ) a ! Fine

Call print_b

End Program host4

Scope of host4 andPUBLIC scope of data4 by Use

However b is in scope fordata4

Scope ofdata4

Module data4

Implicit None

Real, Public :: a = 1.0

Public :: print_b

Real, Private :: b = 2.0

Contains

Subroutine print_b

Write( *, * ) b

End Subroutine print_b

End Module data4

Private Variables

Program host5

Use data5

Implicit None

Write( *, * ) a ! ILLEGAL – a not in scope

Write( *, * ) b ! ILLEGAL - b not in scope

End Program host5

Scope of host5 andPUBLIC scope of data5 by Use

Module data5

Implicit None

Real :: a = 1.0

Real :: b = 2.0

Private ! All Private

! unless told

! Otherwise

End Module data5

But NOTHING is public !

Scope ofdata5

Private affectsWHOLE Module

Complete Protection with Private

Protection With Private

• As we have said scope is there to protect you – you can avoid accessing things you

shouldn’t be.

• Further, the more entities there are in the namespace cut down the names you can use in

the local scope – this is known as Namespace Pollution.

• Use private as much as you can.

• Consider using your own prefix, like MPI.

Kind And Modules

• Using MODULE’s we now have a powerful way of designing the precision used in

our code

Module Numbers

Implicit None

Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

End Module Numbers

• If all other MODULE’s include a USE Numbers then we can control the precision of

the whole code via that one MODULE

Program Example

Use numbers ! Specify Precision of whole code

Implicit None

Real( float ) :: total, a, average

Integer :: n, i

Read( *, * ) n

total = 0.0_float

Do i = 1, n

Read( *, * ) a

total = total + a

End Do

average = total / Real( n, Kind( average ) )

Write( *, * ) ’the average is ’, average

End Program Example

KIND Example

External Subprograms

• Subprograms do not have to be contained or in a module.

• Such subprograms are termed external.

• Use of external subprograms in new code should be avoided as you, by default,

lose all the safety features of contained and module subprograms – Argument

mismatch is VERY easy

• However this was the only way to write subprograms before Fortran 90 and a lot of

older programs including much good quality software are only available in this form,

so you should be aware of them.

External Subprograms

Subroutine greet( name )

Implicit None

Character( Len = * ), Intent( In ) :: name

Write( *, * ) 'Hello', name

End Subroutine greet

• Note no program or module or contains in sight

Disadvantages of External Subprograms

• You do not import an interface for any called subprogram

– The compiler will not detect argument mismatch

– You have to declare functions at the calling point

• External Subprograms are always in scope

– Namespace pollution

• By default you can’t use optional arguments, keyword arguments …

– In particular by default you can not use assumed shape arrays

– To get around this you have to pass the array bounds explicitly

• All of this is because you don’t have an interface in scope at the calling site

External Subprograms

Program old_array_arguments

Implicit None

Real, Dimension( 1:2, 1:3 ) :: a

a = 0

Call array_properties( 2, 3, a )

End Program old_array_arguments

Subroutine array_properties( n, m, x )

Integer , Intent( In ) :: n ! Note we pass the

Integer , Intent( In ) :: m ! Array bounds explicitly

Real, Dimension( 1:n, 1:m ), Intent( In ) :: x

Write( *, * ) Size( x, Dim = 1 ), Size( x, Dim = 2 ), Size( x )

Write( *, * ) Lbound( x )

Write( *, * ) Ubound( x, Dim = 1 ), Ubound( x, Dim = 2 )

End Subroutine array_properties

Planning Your Programs

• There are two things to think about:

• What operations the program has to perform

– The functional breakdown

– This gives the list of subprograms we require

– Each subprogram performs one function

• What data the program has to deal with

– The data flow breakdown

– This gives the grouping of subprograms, i.e. the Modules you require

– Each Module acts on one sort of data, i.e. matrix test data, not REAL etc

Summary

• Writing and Using modules

• Use association

• Private and Public variables

• External subprograms and why you should not use them in new code

Further Reading

• Interfaces

• Subprogram and operator overloading

• Derived types – making up your own data types

– If you write any sort of more advanced Fortran you really should learn about derived types

– They work very well with modules

• Use a module to define a given data type and the operations on it

– Thee next stage from this is

• OO features in Fortran

– Came in in F2003 and takes modules and derived onto the next level

– If I had a third day these are the things would be what comprise it

Input and Output

Format Specifier

• We have been using write(*,*) and read(*,*)

• What do the *’s mean?

• The second one refers to a format. It means use free format (it’s up to the compiler).

We can also specify explicit formats

integer :: and

real :: hard, fast

...

write(*,’(f12.4,i5,e20.10)’)hard, and, fast

Format

integer :: and

real :: hard, fast

...

write(*,’(f12.4,i5,e20.10)’)hard, and, fast

• The ’(f12.4,i5,e20.10)’ gives formats for the three numbers included in the write

statement:

• f12.4 - floating point number of width 12 characters with four digits to the right of the

decimal place

• i5 - an integer number of width 5 characters

• e20.10 - an exponential format of width 20 characters with 10 decimal places.

• Note it is simply of type character

Formats

• Formats in general are much more useful for output

– Make it look “pretty”

• In general input is perfectly adequately dealt with by free format

• In general a format for reading just makes life harder

• However there is nothing stopping you, and just occasionally you need one

– Generally a sign of a poorly designed input!

Format

• Format specifiers are strings and can be stored (and edited) as strings

Integer :: hard, and, fast

Character( len = 5 ):: style

…

style = ’(3i5)’ ! Could be built up

! Internal I/O useful, see later

Write( *, style ) hard, and, fast

Format – Repeating And Spacing

• Here we print 3 lots of integers followed by a space

Integer :: hard, and, fast

...

write(*,’(3(i5,1x))’) hard, and, fast

323 1645 12345

Edit Descriptors

Purpose Edit Descriptors

Reading/writing INTEGERs Iw Iw.m

Reading/writing REALs

Decimal form Fw.d

Exponential form Ew.d Ew.dEe

Scientific form ESw.d ESw.dEe

Engineering form ENw.d ENw.dEe

Reading/writing LOGICALs Lw

Reading/writing CHARACTERs A Aw

w: the total number of characters

m: the minimum number of positions to be used – leading zeros

d: the number of digits to the right of the decimal point

e: the number of digits in the exponent part

Minimum Width

• w may be zero - use the minimum width possible to display the number:

Write( *, ’( 4I4 )’ ) 22, -444, 0, 55555

22-444 0**** ! Stars mean can’t show

Write( *, ‘( 4I0 )’ ) 22, -444, 0, 55555

22-444055555

Write( 0, ’( f8.4 )’ ) 12.34567

12.3457

Write( 0, ’( f0.4 )’ ) 12.34567

12.3457

Records, Files and Sequential Access

• A file in Fortran 95 ALWAYS consists of a set of records (“lines”), one of which is an

end-of-file marker.

– In Fortran 2003 there is also non-record based I/O but this is comparatively rarely used

• So far for us each Read/Write deals with one record (“line”) at a time – also note for

the future each “line” can be very long

1 2 3 4 5 EOF6

Integer :: i

Real :: a

Do i = 1, 4

Read ( *, * ) a ! New record

! each time

Write( *, '( f4.1 )' ) a

End Do

4.0 3

6.0 .True.

8. 9 12

10 hello

$ ./read_records < input

4.0

6.0

8.0

10.0

Records, Files and Sequential Access

4.0 3

6.0 .True.

8. 9 12

10 helloInteger :: i

Real, Dimension( 1:4 ) :: a

Do i = 1, 4

Read( *, * ) a( i ) ! New record

! each time

End Do

Write( *, '( 2( 2( f4.1, 1x ), / ) )' ) a

$ ./multi_write < input

4.0 6.0

8.0 10.0

Dealing with Multiple Records

• The / edit descriptor can be used to deal with multiple records in

one write ( or read )

• Input – Remember this?

INTEGER, DIMENSION(1:10) :: x

INTEGER :: n, i

READ(*,*) n

READ(*,*) x

Expects hard return between inputs, at each read.

If reach end of record move onto next one

INTEGER, DIMENSION(1:10) :: x

INTEGER :: n, i

READ(*,*) n ! Hope not > 10

DO i = 1, n

READ(*,*) x(i)

END DO

Multiple Records And Array I/O

Non-Advancing I/O

• What if we don’t want to write (or read) one whole record at once ?

Write( *, ’( ”Hello ” )’, Advance = ’No’ )

Write( *, ’( ”Craig.” )’, Advance = ’No’ )

Write( *, * ) ! Finish Record

$ ./no_advance

Hello Craig.

• Can be nice for prompts

Units and Files

• The first * in write(*,*) refers to the default unit.

• So far we have relied on the default output unit being the screen and the default

input unit being the keyboard.

• We can explicitly write to a different unit by

write(unit,*) …

• Unit is simply a positive integer

– For boring historical reasons I suggest you use values of 10 or greater

• A unit will generally refer to a file.

– But in theory (more often the past) could be e.g. a printer

Files

open(unit = 10, file = ’filename’)

• Writing to unit = 10 will now write to the file called filename.

– Technically this connects file filename to unit 10

– Subsequent I/O operations on unit 10 will now use the file filename

• There are a number of useful additions to the open statement - use them as good

defensive programming measures.

Status

open(unit=10, file=’file’, status=file_stat)

• Where file_stat is of type character and has one of the values ’old’ , ’new’ , ’scratch’,

’replace’ , ’unknown’

• If ’scratch’ you must not supply a name

• Default is status = ’unknown’

• Typically input file will be ’old’, output files will be ’new’.

Action

open(unit=1, file=’file’, status=file_stat, &

action=what)

• Where “what” is of type character and has one of the values ’read’, ’write’ ,

’readwrite’

• Default is action = ’readwrite’

• Typically:

– input files will be ’read’

– output files will be ’write’

• Compare with Intent.

IOSTAT

open(unit=1, file=’file’, status=file_stat, &

action=what, iostat=value)

• value is of type integer.

– positive on error

– zero after success.

– Like the stat in allocate statements.

Position

• open(unit=1, file=’file’, position=pos)

• Where pos is of type characters and is one of ’asis’ , ’rewind’ , ’append’

• Default is position = ’asis’

• Note the default is not defined if the file exists and is not already connected, though

in practice it defaults to rewind.

Unformatted Files

• Files can be unformatted (“binary”) files.

– less disk space

– generally faster

– not necessarily transferable between machines

– not human readable

• STILL RECORD BASED

open(unit=36,file=’file’,form=’unformatted’)

• The associated I/O statements become

write(36) x, y, z

read(36) p

• Note no format as the files are unformatted !

Close

• Opened files should be closed

open(unit = 1, file = ’filename’)

...

...

close(unit = 1)

• We can also use status and iostat with close

• iostat behaves exactly as in open statements

• status can be ’keep’ or ’delete’

• The default for scratch files is ’delete’. The default for all other files is ’keep’

Rewind

Rewind( unit )

• Takes the file back to the start

• Also Backspace – go back one record

• and Endfile – guess !

• Look in a book for further details

INQUIRE(FILE=name, IOSTAT=i_var, …)

INQUIRE(UNIT=io_unit, IOSTAT=i_var, …)

Inquire

• We can also investigate the status of a connection with the INQUIRE function

ACCESS=acc ‘SEQUENTIAL’ ‘DIRECT’ ‘UNDEFINED’

ACTION=act ‘READ’ ‘WRITE’ ‘READWRITE’ ‘UNDEFINED’

DIRECT=dir ‘YES’ ‘NO’ ‘UNKNOWN’

EXIST=ex .TRUE. .FALSE.

FORM=fm ‘FORMATTED’ ‘UNFORMATTED’ ‘UNDEFINED’

FORMATTED=fmt ‘YES’ ‘NO’ ‘UNKNOWN’

NAME=nme returns the file name.

NAMED=nmd .TRUE. .FALSE

NUMBER=num unit_number

OPENED=od .TRUE. .FALSE.

POSITION=poss ‘REWIND’ ‘APPEND’ ‘ASIS’ ‘UNDEFINED’

READ=rd ‘YES’ ‘NO’ ‘UNKNOWN’

READWRITE=rdwr ‘YES’ ‘NO’ ‘UNKNOWN’

SEQUENTIAL=seq ‘YES’ ‘NO’ ‘UNKNOWN’

UNFORMATTED=unf ‘YES’ ‘NO’ ‘UNKNOWN’

WRITE=wr ‘YES’ ‘NO’ ‘UNKNOWN’

Inquire

Internal I/O

• It is also possible to access internal files. Internal files are of type default character.

They are formatted sequential files.

• File connection, file positioning and file inquiry must not be used with internal files.

• If the variable representing the internal file is a scalar the file has one record.

• If it is an array then the file has one record for each element of the array.

• The length of the record is the length of one array element.

Internal I/O

• Typically used to convert machine representations to characters or vice versa e.g.

READ(CHAR_VAR, ’( f6.4, 1x, i4 )’) x, J

WRITE(FMT=*,UNIT=CHAR_VAR)x

Summary

• Use format specifiers to produce neat output

• Free format is usually sufficient for input

• There are lots of edit descriptors!

• All Fortran95 I/O is record based

• OPEN will produce a connection to a file

• Use ACTION, STATUS and IOSTAT as defensive measures

• If you OPEN a file then CLOSE it!

• Use INQUIRE to check the status of a connection

Further Reading

Input/Output

• Direct access files

• Scratch Files

• Stream I/O

More generally about Fortran and programming

• Functions as arguments

• Pointers – not as useful in Fortran as other languages but occasionally useful.

– Allocatable arrays, derived types, OO features and the move_alloc intrinsic cover most occurrences

• Interoperability with C

• IEEE floating point exception handling

• Parallelism via co-arrays

• Tools you can use with Fortran– Revision control, unit testing, documentation generation …

• Common libraries– BLAS, LAPACK, FFTW, PetSc, ScaLAPACK, NAG …

• Talk with other programmers and RSE’s• E.g. at the RSE conference in September http://rse.ac.uk/2017/01/25/rse-conference-2017/

• And practice, practice, practice – you only learn programming by doing it!

Acknowledgments

I would like to thank the Numerical Algorithms Group Ltd. (NAG) for providing much of the material

used in the slides and exercises

Finally

Thank You!

Reuse of this material

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0

International License

http://creativecommons.org/licenses/by-nc-sa/4.0/deed.en_US

This means you are free to copy and redistribute the material and adapt and build on the

material under the following terms: You must give appropriate credit, provide a link to the license and indicate if changes were made. If you adapt or build on the material you must

distribute your work under the same license as the original.

Note that this presentation may contain images owned by others. Please seek their

permission before reusing these images.