beginning fortran fortran (77) advanced 29 october 2009 *black text on white background provided for...

45
Beginning Fortran Fortran (77) Advanced 29 October 2009 text on white background provided for easy printing

Upload: raymond-walsh

Post on 13-Dec-2015

237 views

Category:

Documents


0 download

TRANSCRIPT

Beginning Fortran

Fortran (77) Advanced29 October 2009

*Black text on white background provided for easy printing

Example Code

• Write a program to read in five values of temperature in Fahrenheit and convert to degrees Celsius OR Kelvin OR both.

Your Typical Programc234567 PROGRAM MYPROGRAM

STOP END

Program OptionsProgram Options

Declaration of VariablesDeclaration of Variables

MAIN CODEMAIN CODE

Program Start

Options/Variable Declaration

Main Code

Program End

c234567 PROGRAM CONVERTF IMPLICIT NONE PARAMETER NT = 5 REAL F(NT) REAL K(NT) REAL C(NT) LOGICAL DOC LOGICAL DOK INTEGER I DO I = 1, NT READ(*,*) F(I) ENDDO WRITE(*,*) ‘Convert to C?’ READ(*,*) DOC WRITE(*,*) ‘Convert to K?’ READ(*,*) DOK DO I = 1, NT C(I) = (5./9.)*(F(I)-32.) ENDDO IF (DOK .EQV. .TRUE.) THEN DO I = 1, NT K(I) = C(I) + 273.15 ENDDO ENDIF IF ((DOC .EQV. .TRUE.) .AND. (DOK .EQV. .FALSE.)) THEN DO I = 1, NT WRITE(*,*) F(I), ‘F = ‘, C(I), ‘C’ ENDDO ENDIFc IF ((DOC .EQV. .FALSE.) .AND. (DOK .EQV. .TRUE.)) THEN DO I = 1, NT WRITE(*,*) F(I), ‘F = ‘, K(I), ‘K’ ENDDO ENDIFc IF ((DOC .EQV. .TRUE.) .AND. (DOK .EQV. .TRUE.)) THEN DO I = 1, NT WRITE(*,*) F(I), ‘F = ‘, C(I), ‘C ’, K(I), ‘K’ ENDDO ENDIF STOP END

c234567 PROGRAM CONVERTF IMPLICIT NONE PARAMETER NT = 5 REAL F(NT) REAL K(NT) REAL C(NT) LOGICAL DOC LOGICAL DOK INTEGER I DO I = 1, NT READ(*,*) F(I) ENDDO WRITE(*,*) ‘Convert to C?’ READ(*,*) DOC WRITE(*,*) ‘Convert to K?’ READ(*,*) DOK DO I = 1, NT C(I) = (5./9.)*(F(I)-32.) ENDDO IF (DOK .EQV. .TRUE.) THEN DO I = 1, NT K(I) = C(I) + 273.15 ENDDO ENDIF IF ((DOC .EQV. .TRUE.) .AND. (DOK .EQV. .FALSE.)) THEN DO I = 1, NT WRITE(*,*) F(I), ‘F = ‘, C(I), ‘C’ ENDDO ENDIFc IF ((DOC .EQV. .FALSE.) .AND. (DOK .EQV. .TRUE.)) THEN DO I = 1, NT WRITE(*,*) F(I), ‘F = ‘, K(I), ‘K’ ENDDO ENDIFc IF ((DOC .EQV. .TRUE.) .AND. (DOK .EQV. .TRUE.)) THEN DO I = 1, NT WRITE(*,*) F(I), ‘F = ‘, C(I), ‘C ’, K(I), ‘K’ ENDDO ENDIF STOP END

This program is not particularly useful:-What if we want to calculate 3 temperatures? Or 30?-Open source code, change NT, recompile, re-run …

-We are primarily restricted because of the necessity of declaring the value of NT: it is a parameter that has to be set in the code before anything else is done.

Subroutines

• Mini-programs that are run inside of a larger program (or subroutine):

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutines

• Subroutine is called, with variables a, b, and c passed to it. Those same variables, at their current values, now exist in subroutine.

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutine(a,b,c)

INTEGER a, b, c

Subroutines

• Subroutine is called, with variables a, b, and c passed to it. Those same variables, at their current values, now exist in subroutine.

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutine(a,b,c)

INTEGER a, b, c

Subroutines

• Additional variables can be declared within the subroutine. These exist only in the subroutine, and will be destroyed when the routine is done.

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutine(a,b,c)

INTEGER a, b, cINTEGER d, e, f

Subroutines

• Lines of code manipulating variables are processed in the subroutine, possibly changing the values of a, b, and c.

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutine(a,b,c)

INTEGER a, b, cINTEGER d, e, fCodeCodeCode

Subroutines

• At RETURN, code returns to main program after subroutine was called. Variables a, b, and c now have NEW values depending on subroutine.

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutine(a,b,c)

INTEGER a, b, cINTEGER d, e, fCodeCodeCodeRETURNEND

Subroutines

• Main program continues on after the subroutine call with new values for a, b, and c.

Main Program

CodeCodeCodeCALL SUBROUTINE(a,b,c)CodeCodeSTOPEND

INTEGER a, b, c

Subroutine(a,b,c)

INTEGER a, b, cINTEGER d, e, fCodeCodeCodeRETURNEND

Subroutines

• When calling a subroutine, the main program is basically saying:

“Given these variables at their current values, do some stuff and then give me my variables back. Don’t worry; I’ll wait.”

Subroutines

• When calling a subroutine, the main program is basically saying:

“Given these variables at their current values, do some stuff and then give me my variables back. Don’t worry; I’ll wait.”

CALL <subroutine name>(arg1,arg2,arg3,…)

“input arguments”

Input Arguments

• Any variables that the main program wants the subroutine to make use of have to be passed to the subroutine as input arguments.

• These appear as a list of the names of the variables in parentheses after the name of the subroutine being called.

CALL AVERAGE(X1,X2,AVG)

Input Arguments

• Any variables that the main program wants the subroutine to make use of have to be passed to the subroutine as input arguments.

• These appear as a list of the names of the variables in parentheses after the name of the subroutine being called.

CALL AVERAGE(X1,X2,AVG)

Subroutine AVERAGE takes in three variables: two numbers (X1 and X2) and a variable that will represent the average of them (AVG).

Input Arguments

• In the subroutine, these variables are re-declared so that they now exist simultaneously in the main program and in the subroutine:

C234567 SUBROUTINE AVERAGE(X1,X2,AVG) IMPLICIT NONE REAL X1 REAL X2 REAL AVG

Input Arguments

• In the subroutine, these variables are re-declared so that they now exist simultaneously in the main program and in the subroutine:

C234567 SUBROUTINE AVERAGE(X1,X2,AVG) IMPLICIT NONE REAL X1 REAL X2 REAL AVG NOTE: These variables must be

declared as the same type as they are declared in the main program.

Input Arguments

• Now we can write code in the subroutine to compute AVG from X1 and X2:

C234567 SUBROUTINE AVERAGE(X1,X2,AVG) IMPLICIT NONE REAL X1 REAL X2 REAL AVGc AVG = (X1 + X2)/2. RETURN END

Input Arguments

• Any of the input arguments that were changed in the subroutine will now have new values in the main program.

X1 = 3.0X2 = 8.0AVG = -9999.0CALL AVERAGE(X1,X2,AVG)WRITE(*,*) AVG

AVG = (X1 + X2)/2.RETURNEND

Main Program AVERAGE(X1,X2,AVG)

Input Arguments

• Any of the input arguments that were changed in the subroutine will now have new values in the main program.

X1 = 3.0X2 = 8.0AVG = -9999.0CALL AVERAGE(X1,X2,AVG)WRITE(*,*) AVG

AVG = (X1 + X2)/2.RETURNEND

Main Program AVERAGE(X1,X2,AVG)

AVG is sent to subroutine with value of -9999.0

Input Arguments

• Any of the input arguments that were changed in the subroutine will now have new values in the main program.

X1 = 3.0X2 = 8.0AVG = -9999.0CALL AVERAGE(X1,X2,AVG)WRITE(*,*) AVG

AVG = (X1 + X2)/2.RETURNEND

Main Program AVERAGE(X1,X2,AVG)

Subroutine changes value of AVG to 5.5

Input Arguments

• Any of the input arguments that were changed in the subroutine will now have new values in the main program.

X1 = 3.0X2 = 8.0AVG = -9999.0CALL AVERAGE(X1,X2,AVG)WRITE(*,*) AVG

AVG = (X1 + X2)/2.RETURNEND

Main Program AVERAGE(X1,X2,AVG)

At RETURN, we return to the main program, where AVG now has a value of 5.5

Passing Arrays

• You can also pass arrays to a subroutine:– Pass the array dimensions as INTEGERs first, then

pass the array itself

PROGRAM MAINPARAMETER NX = 360PARAMETER NY = 181REAL TEMPS(NX,NY)CALL ZILCH(NX,NY,TEMPS)STOPEND

SUBROUTINE ZILCH(NX,NY,VAR)INTEGER NXINTEGER NYREAL VAR(NX,NY)INTEGER IINTEGER JDO J = 1, NY DO I = 1, NX VAR(I,J) = 0. ENDDOENDDORETURNEND

Passing Arrays

• Notice how the same variable can have different names in the main program and the subroutine.

PROGRAM MAINPARAMETER NX = 360PARAMETER NY = 181REAL TEMPS(NX,NY)CALL ZILCH(NX,NY,TEMPS)STOPEND

SUBROUTINE ZILCH(NX,NY,VAR)INTEGER NXINTEGER NYREAL VAR(NX,NY)INTEGER IINTEGER JDO J = 1, NY DO I = 1, NX VAR(I,J) = 0. ENDDOENDDORETURNEND

Passing ArraysSUBROUTINE ZILCH(NX,NY,VAR)INTEGER NXINTEGER NYREAL VAR(NX,NY)INTEGER IINTEGER JDO J = 1, NY DO I = 1, NX VAR(I,J) = 0. ENDDOENDDORETURNEND

Notice something interesting here:-We took in values from the main program for NX and NY, then created a variable VAR based on those dimensions.-We can do this, because input arguments are special

Rules of Subroutines

• Subroutines are basically small programs built inside of a larger program

• Input arguments are handed down to the subroutine from its parent program – the subroutine is constructed with a priori knowledge of these variables and their present value

• “Given a, b, and c, do something and then give me a, b, and c back.”

Rules of Subroutines

• Since the subroutine is built with the input arguments already known, we can make an array inside of the subroutine based on variables passed into it.

PROGRAM MAININTEGER NXINTEGER NYREAD(*,*) NX, NYCALL MAKEARRAY(NX,NY)STOPEND

SUBROUTINE MAKEARRAY(NX,NY)INTEGER NXINTEGER NYREAL VAR(NX,NY)…RETURNEND

Rules of Subroutines

• Since the subroutine is built with the input arguments already known, we can make an array inside of the subroutine based on variables passed into it.

PROGRAM MAININTEGER NXINTEGER NYREAD(*,*) NX, NYCALL MAKEARRAY(NX,NY)STOPEND

SUBROUTINE MAKEARRAY(NX,NY)INTEGER NXINTEGER NYREAL VAR(NX,NY)…RETURNEND

NX, NY read from user into MAIN NX, NY handed to MAKEARRAY to make VAR

Rules of Subroutines

• This is something we couldn’t do before – CONVERTF was not particularly useful because we couldn’t ask the user for the dimensions of array “F” and then make an array, we had to use a parameter.

• However, we can ask for the dimensions of the array and create an array inside of a subroutine with those dimensions, because for the subroutine, that variable is passed in as a priori knowledge.

CONVERTF

VARIABLE DECLARATION:PARAMETER NX = 5

<Declare Variables based on NX>

VARIABLE DECLARATION:PARAMETER NX = 5

<Declare Variables based on NX>

MAIN CODE:<Read in F, DOC, DOK>

<Compute C, K><Output F, K, C>

STOPEND

MAIN CODE:<Read in F, DOC, DOK>

<Compute C, K><Output F, K, C>

STOPEND

CONVERTF2

VARIABLE DECLARATION:INTEGER NX

VARIABLE DECLARATION:INTEGER NX

MAIN CODE:<Read in NX>CALL SUB(NX)

STOPEND

MAIN CODE:<Read in NX>CALL SUB(NX)

STOPEND

SUB(NX)VARIABLE

DECLARATION:INTEGER NX

<Declare Vars. Based on NX>

VARIABLE DECLARATION:

INTEGER NX<Declare Vars. Based

on NX>

MAIN CODE:<Read in F, DOC, DOK>

<Compute C, K><Output F, K, C>

RETURNEND

MAIN CODE:<Read in F, DOC, DOK>

<Compute C, K><Output F, K, C>

RETURNEND

Using Subroutines

• You can write subroutines in two different ways:– You can write the subroutine directly within the

parent program– You can write the subroutine in a separate *.f file

and compile it along with the parent program

Using Subroutines

STOP

END

SUBROUTINE MYSUBROUTINE(X1,X2,X3,…)

IMPLICIT NONE

REAL X1

REAL X2

Compiling With Subroutines

• Compile external subroutines separately using the following syntax:

• pgf77 –c <filename>.f <options>• Then compile the parent program with the

subroutine *.o files attached:

pgf77 <sub1.o> <sub2.o> … -o <exec. name> <source file>.f <options>

Proper Coding Technique

• There are some simple rules to follow to make sure that your code is readable and is robust – you can do a lot with it without having to write new source code.

Write in CAPITAL LETTERS

• This isn’t required, but writing code in capital letters and comments in lower-case makes it easier to distinguish the two from each other.

Use Subroutines Often

• If you find yourself having to code the same thing in over and over in your program, it is better to block that code off into a subroutine and call the subroutine every time you need to perform that function.

Proper Subroutine Usage

Main ProgramMain Program

Driver SubroutineDriver Subroutine

Sub 1Sub 1

Sub 4Sub 4

Sub 2Sub 2

Sub 3Sub 3

Proper Subroutine Usage

Main ProgramMain Program

Driver SubroutineDriver Subroutine

Sub 1Sub 1

Sub 4Sub 4

Sub 2Sub 2

Sub 3Sub 3

Main Program essentially just reads in necessary information to begin program (array sizes, etc). Passes all of that information to the Driver Subroutine.

Proper Subroutine Usage

Main ProgramMain Program

Driver SubroutineDriver Subroutine

Sub 1Sub 1

Sub 4Sub 4

Sub 2Sub 2

Sub 3Sub 3

Most of the main functions of the program are completed in the Driver Subroutine, where variables are declared based on information passed in from the Main Program.

Proper Subroutine Usage

Main ProgramMain Program

Driver SubroutineDriver Subroutine

Sub 1Sub 1

Sub 4Sub 4

Sub 2Sub 2

Sub 3Sub 3

Individual functions that need to be completed (some multiple times) are written in different subroutines, which are called from the Driver Subroutine.

Proper Subroutine Usage

Main ProgramMain Program

Driver SubroutineDriver Subroutine

Sub 1Sub 1

Sub 4Sub 4

Sub 2Sub 2

Sub 3Sub 3

You will find that most, if not all, professional code is written in this format.

Make Compilation Clear

• Programs can have complicated compilations, especially when you start attaching multiple subroutines with different options.

• If the compilation can be completed on a single line, put a comment in the code somewhere near the top containing the compilation line.

• If it’s more complex than that, make a script that compiles the program for you.

Use Source Directories

• Rather than keeping your source code, your subroutines, and your compiled programs all in the same directory, create a ‘source’ subdirectory where you keep your source code.

• This will prevent you from accidentally deleting, replacing, or otherwise ruining the code you’ve worked on.

Don’t Re-Invent The Wheel

• If you write your subroutines in separate files, you’ll find yourself using them in multiple programs – there’s no need to rewrite it.

• Use professional subroutine packages where possible – e.g. spherepack.