Chapter 11. More Fortran Elements: Functions and Subroutines 11.1 ...
Chapter 11. More Fortran Elements: Functions and Subroutines 11.1 ...
Chapter 11. More Fortran Elements: Functions and Subroutines 11.1 ...
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Chapter</strong> <strong>11.</strong> <strong>More</strong> <strong>Fortran</strong> <strong>Elements</strong>: <strong>Functions</strong> <strong>and</strong> <strong>Subroutines</strong><br />
<strong>11.</strong>1 Overview<br />
In many situations, it is useful to write portable <strong>Fortran</strong> code so that a particular algorithm<br />
may be used in more than one program. It also is helpful when programming a complex problem<br />
to break it up into smaller sections. <strong>Fortran</strong> functions <strong>and</strong> subroutines are small subprograms that<br />
allow for portability <strong>and</strong> division of tasks.<br />
<strong>11.</strong> 2 <strong>Functions</strong><br />
A function in <strong>Fortran</strong> is a subprogram that takes some arguments, performs some<br />
calculations, <strong>and</strong> returns a single result. Intrinsic functions such as SIN(), COS(), ABS(), <strong>and</strong><br />
EXP() are special built-in cases of <strong>Fortran</strong> functions; however, an external function subprogram<br />
may be written to perform any desired computation.<br />
<strong>11.</strong>2.1 Function Subprogram Layout<br />
The layout of an external function subprogram is very similar to any other program layout<br />
in <strong>Fortran</strong>. A function has four main sections as shown in Figure <strong>11.</strong>1: the function type <strong>and</strong> name<br />
with specified arguments, variable declarations, the main body of the subprogram, <strong>and</strong> the end of the<br />
subprogram.<br />
type function name(arg1, arg2, …) start of function<br />
implicit none<br />
variable declarations<br />
real arg1, arg2, x, y<br />
integer i, j, k<br />
.<br />
.<br />
.<br />
calculations are carried<br />
out here<br />
.<br />
.<br />
.<br />
return<br />
end<br />
main body of function subprogram<br />
end of function<br />
Figure <strong>11.</strong>1. Layout of a typical <strong>Fortran</strong> function subprogram.<br />
The FUNCTION statement is placed at the beginning of the function subprogram <strong>and</strong><br />
identifies the function name. The function must be declared as a specific type, INTEGER or<br />
REAL, prior to the function name. The arguments passed to the function from the main program<br />
are enclosed in parentheses after the function name. Any number of arguments may be passed <strong>and</strong><br />
the arguments may correspond to any variable type <strong>and</strong> also may be arrays.<br />
The Variable Declaration section of the subprogram has the same format as it does in a<br />
regular <strong>Fortran</strong> program. Note that the arguments passed to the function from a main program<br />
must be declared in the Variable Declaration section.<br />
67
The Main Body of the subprogram has the same format as in a regular <strong>Fortran</strong> program.<br />
The main computational task of the function is carried out in this section.<br />
The End of the Function is indicated by the statement RETURN, which passes execution<br />
back to the main program, <strong>and</strong> END, which signifies the end of the function subprogram.<br />
<strong>11.</strong>2.2 Using an External Function in a <strong>Fortran</strong> Program<br />
An external function is used in a <strong>Fortran</strong> program in much the same way as an intrinsic<br />
function. When an intrinsic function is used, it is included as part of an assignment statement. For<br />
example, to evaluate the expression x = 3sin( 24t),<br />
an assignment statement including the intrinsic<br />
function SIN() is used, as illustrated below.<br />
X = 3.0*SIN(24.0*T)<br />
€<br />
An external function may be called in a similar fashion as part of an assignment statement. A<br />
typical assignment statement employing an external function is shown below.<br />
Z = FUNCTION(ARG1, ARG2, …)<br />
The function may be passed one or more arguments by the main program. However, the result of<br />
function evaluation is a single numerical value, just as the result of evaluating sin 1.5<br />
numerical value.<br />
In order to use an external function as part of an assignment statement, the name of the<br />
function must be declared in the Variable Declaration section of the main program. The function<br />
may be declared as real or integer depending on the type of result it<br />
€<br />
returns.<br />
68<br />
( ) yields a single<br />
<strong>11.</strong>2.3 Function Subprogram Example<br />
The use of an external function in <strong>Fortran</strong> will be illustrated with the example of numerical<br />
integration. The trapezoidal approximation to the integral of a function is given by the expression<br />
b<br />
∫ f ( x)<br />
dx ≈ h<br />
2 f x [ ( 1)<br />
+ f ( xn ) ] + h∑ f ( xi) . (<strong>11.</strong>1)<br />
a<br />
In Equation (<strong>11.</strong>1), the function has been sampled on the interval a ≤ x ≤ b by n points separated<br />
by step size h. An external function written to implement the trapezoidal approximation to the<br />
integral is given<br />
€<br />
below.<br />
€<br />
n−1<br />
i=2
REAL*8 FUNCTION TRAP(NPTS, H, F)<br />
IMPLICIT NONE<br />
INTEGER NPTS, I<br />
REAL*8 H, F(NPTS)<br />
TRAP = 0.5 * H * ( F(1) + F(NPTS) )<br />
DO 100 I = 2, NPTS–1<br />
TRAP = TRAP + H * F(I)<br />
100 CONTINUE<br />
RETURN<br />
END<br />
The arguments that must be passed to the function from the main program include the<br />
number of integration points, the step size h, <strong>and</strong> the array containing the sampled function. These<br />
variables <strong>and</strong> any others used within the function subprogram must be defined in the variable<br />
declaration statement. The variable names used in the function argument list are dummy variables.<br />
The same names do not have to be used in the main program but their types must match.<br />
The main body of the function subprogram calculates the value of the integral using the<br />
trapezoidal approximation, Equation (<strong>11.</strong>1). At the end of the subprogram, the value of the integral<br />
is stored in the variable TRAP. The RETURN statement then sends the program control back to<br />
the main program.<br />
An example of a <strong>Fortran</strong> program that uses the TRAP function to determine the value of the<br />
integral<br />
e x<br />
1<br />
∫ dx with the trapezoidal approximation is given below. A step size of Δx = 0.01 is<br />
0<br />
employed so that the number of integration points is 101. The main program must define as<br />
REAL*8 the variable TRAP, which corresponds to the value returned by the function subprogram.<br />
€<br />
€<br />
PROGRAM INTEGRATE<br />
IMPLICIT NONE<br />
INTEGER N, I<br />
REAL*8 DELTAX, X, F(101), INTEGRAL, TRAP<br />
DELTAX = 0.01<br />
N = 101<br />
DO 100 I = 1, N<br />
X = DELTAX * (I–1)<br />
F(I) = EXP(X)<br />
100 CONTINUE<br />
INTEGRAL = TRAP(N, DELTAX, F)<br />
WRITE(*,*) 'The value of the integral is ', INTEGRAL<br />
69
STOP<br />
END<br />
In the main program, the variable denoting the number of points is N but in the function the<br />
same variable is defined as NPTS. The variable names do not have to match. The first argument in<br />
the argument list of the function will be stored as the integer variable NPTS in the function no<br />
matter what it is called in the main program. Similarly, in the main program, the step size is called<br />
DELTAX, but in the function the same variable is called H. In both the main program <strong>and</strong> the<br />
function subprogram, the array containing the function to be integrated is called F; however, in<br />
general the two array names do not have to match.<br />
<strong>11.</strong>2.4 Compiling Source Code Containing External <strong>Functions</strong><br />
To compile a <strong>Fortran</strong> program that uses an external function, the source code may be saved<br />
in a single file or in multiple files. If the source code for the main program <strong>and</strong> the external<br />
function is stored in a single file, the source code for the function must be listed after the main<br />
program. The compilation with g77 is then no different than that of a single <strong>Fortran</strong> program:<br />
g77 –o pgm.exe file.f<br />
If the source code of the main program is stored in one file <strong>and</strong> the source code of the external<br />
function is stored in a second file, then the compilation statement must include both files:<br />
g77 –o pgm.exe file1.f file2.f<br />
Here, file1.f <strong>and</strong> file2.f are the two files containing the main program <strong>and</strong> external function source<br />
code, <strong>and</strong> pgm.exe is the single executable program created by compilation. Note that any number<br />
of external functions may be employed in a main program.<br />
<strong>11.</strong>3 <strong>Subroutines</strong><br />
A subroutine in <strong>Fortran</strong> also is a subprogram <strong>and</strong> is similar to an external function. The<br />
difference is that a function may return only one numerical result <strong>and</strong> a subroutine may return<br />
multiple numerical results.<br />
<strong>11.</strong>3.1 Subroutine Layout<br />
The layout of a subroutine is very similar to that of a function. A subroutine has four main<br />
sections as shown in Figure <strong>11.</strong>2: the subroutine name with specified arguments, variable<br />
declarations, the main body of the subroutine, <strong>and</strong> the end of the subroutine.<br />
70
subroutine name(arg1, arg2, …) start of subroutine<br />
implicit none<br />
variable declarations<br />
real arg1, arg2, x, y<br />
integer i, j, k<br />
.<br />
.<br />
.<br />
calculations are carried<br />
out here<br />
.<br />
.<br />
.<br />
return<br />
end<br />
main body of subroutine<br />
end of subroutine<br />
Figure <strong>11.</strong>2. Layout of a typical <strong>Fortran</strong> subroutine.<br />
The SUBROUTINE statement is placed at the beginning of the subroutine <strong>and</strong> identifies<br />
the subroutine name. The arguments passed to <strong>and</strong> from the subroutine are enclosed in parentheses<br />
after the subroutine name. Any number of arguments may be passed back <strong>and</strong> forth <strong>and</strong> the<br />
arguments may correspond to any variable type <strong>and</strong> also may be arrays.<br />
The Variable Declaration section of the subroutine has the same format as it does in a<br />
regular <strong>Fortran</strong> program. Note that the arguments passed between the subroutine <strong>and</strong> the main<br />
program must be declared in the Variable Declaration section.<br />
The Main Body of the subroutine has the same format as in a regular <strong>Fortran</strong> program.<br />
The main computational tasks of the subroutine are carried out in this section.<br />
The End of the Subroutine is indicated by the statement RETURN, which passes<br />
execution back to the main program, <strong>and</strong> END, which signifies the end of the subroutine.<br />
<strong>11.</strong>3.2 Using a Subroutine in a <strong>Fortran</strong> Program<br />
A subroutine is employed in a <strong>Fortran</strong> program in a slightly different way than an external<br />
function. Because the subroutine may pass back to the main program multiple numerical results,<br />
the subroutine is not included as part of an assignment statement. Rather, a CALL statement is<br />
employed. The format of a typical CALL statement is shown below.<br />
CALL NAME(ARG1, ARG2, …)<br />
In the CALL statement, NAME refers to the name of the subroutine. Note that the subroutine name<br />
should not be the same as any other variable name <strong>and</strong> unlike an external function, it should not be<br />
declared as a real or integer variable. This is because a subroutine may pass back to the main<br />
program the values of many variables, both real <strong>and</strong> integer, while a function only returns a single<br />
value.<br />
71
<strong>11.</strong>3.3 Subroutine Example<br />
The use of a subroutine in <strong>Fortran</strong> will be illustrated with the example of the Verlet<br />
algorithm. Recall from <strong>Chapter</strong> 5 <strong>and</strong> Assignment 1 that the velocity Verlet algorithm for<br />
numerically approximating solutions to Newton’s equations of motion is<br />
€<br />
x n+1 = x n + v n Δt + 1<br />
2 a n Δt<br />
( )2 . (<strong>11.</strong>2)<br />
vn+1 = vn + 1<br />
2 an + a ( n+1)Δt<br />
. (<strong>11.</strong>3)<br />
A subroutine written to carry out N steps of the Verlet algorithm for the harmonic oscillator is given<br />
below. The number of points, time step size, harmonic oscillator force constant, mass, <strong>and</strong> initial<br />
position <strong>and</strong> initial velocity<br />
€<br />
are the variables passed to the subroutine. The subroutine returns two<br />
arrays, the position <strong>and</strong> velocity as functions of time.<br />
SUBROUTINE VERLET(N, DT, K, M, X0, V0, X, V)<br />
IMPLICIT NONE<br />
INTEGER N, I<br />
REAL*8 DT, K, M, X0, V0, A1, A2, X(N), V(N)<br />
X(1) = X0<br />
V(1) = V0<br />
DO 100 I = 2, N<br />
A1 = –K*X(I–1)/M<br />
X(I) = X(I–1) + V(I–1)*DT + 0.5*A1*DT**2<br />
A2 = –K*X(I)/M<br />
V(I) = V(I–1) + 0.5*(A1+A2)*DT<br />
100 CONTINUE<br />
RETURN<br />
END<br />
All the variables passed from the main program to the subroutine as well as any others used<br />
within the subroutine must be defined in the variable declaration statement. As was the case for<br />
external function, the variable names used in the subroutine argument list are dummy variables. The<br />
same names do not have to be used in the main program but their types must match.<br />
The main body of the subroutine carries out multiple iterations of the Verlet equations<br />
(<strong>11.</strong>2) <strong>and</strong> (<strong>11.</strong>3). At the end of the subroutine, the array X contains the position as a function of<br />
time <strong>and</strong> the array V contains the velocity as a function of time. These arrays are passed back to the<br />
main program. The RETURN statement then sends the program control back to the main program.<br />
An example of a main program that calls the VERLET subroutine is given below. The<br />
values of the step size, number of time steps, force constant, mass, <strong>and</strong> initial position <strong>and</strong> velocity<br />
are all input from the screen. The main program then calls the VERLET subroutine to advance the<br />
72
position <strong>and</strong> velocity solutions in time. Once the subroutine has completed its calculations, the<br />
results are written to a file by the main program along with the time.<br />
PROGRAM HARMOSC<br />
IMPLICIT NONE<br />
INTEGER NTIME, I<br />
REAL*8 DELTAT, K, M, T, X0, V0, X(5000), V(5000)<br />
OPEN(UNIT=25, FILE='verlet.out', STATUS='unknown')<br />
WRITE(*,*)'Enter force constant:'<br />
READ(*,*) K<br />
WRITE (*,*)'Enter mass:'<br />
READ(*,*) M<br />
WRITE (*,*)'Enter deltat:'<br />
READ(*,*) DELTAT<br />
WRITE (*,*)'Enter no. of time steps:'<br />
READ(*,*) NTIME<br />
WRITE (*,*)'Enter initial position:'<br />
READ(*,*) X0<br />
WRITE (*,*)'Enter initial velocity:'<br />
READ(*,*) V0<br />
CALL VERLET(NTIME, DELTAT, K, M, X0, V0, X, V)<br />
T = 0.<br />
DO 100 I = 1, NTIME<br />
T = T + DELTAT<br />
WRITE(25,*) T, X(I), V(I)<br />
100 CONTINUE<br />
CLOSE(UNIT=25)<br />
STOP<br />
END<br />
In the main program, the variable denoting the number of time steps is NTIME but in the<br />
subroutine the same variable is defined as N. As was the case for external functions, the variable<br />
names do not have to match in the subroutine <strong>and</strong> main program. The first argument in the<br />
argument list of the subroutine will be stored as the integer variable N in the function no matter<br />
what it is called in the main program. Similarly, in the main program, the time step size is called<br />
DELTAT, but in the subroutine the same variable is called DT.<br />
<strong>11.</strong>3.4 Compiling Source Code Containing <strong>Subroutines</strong><br />
To compile a <strong>Fortran</strong> program that uses a subroutine, the source code may be saved in a<br />
single file or in multiple files. If the source code for the main program <strong>and</strong> the subroutine is stored<br />
in a single file, the source code for the subroutine must be listed after the main program. The<br />
compilation with g77 is then no different than that of a single <strong>Fortran</strong> program:<br />
73
g77 –o pgm.exe file.f<br />
If the source code of the main program is stored in one file <strong>and</strong> the source code of the subroutine is<br />
stored in a second file, then the compilation statement must include both files:<br />
g77 –o pgm.exe file1.f file2.f<br />
Here, file1.f <strong>and</strong> file2.f are the two files containing the main program <strong>and</strong> subroutine source code,<br />
<strong>and</strong> pgm.exe is the single executable program created by compilation. Note that any number of<br />
subroutines may be employed in a main program.<br />
74
<strong>Chapter</strong> 11 Review Problems<br />
1. Construct an external function in <strong>Fortran</strong> to convert degrees Fahrenheit to Celsius. The<br />
function is passed the temperature in degrees Fahrenheit <strong>and</strong> returns the temperature in Celsius.<br />
Write a main program to input the temperature in degrees Fahrenheit <strong>and</strong> use the external<br />
function to convert to Celsius. The main program should then write out the temperature in<br />
degrees Fahrenheit <strong>and</strong> Celsius to the screen.<br />
2. Write an external function in <strong>Fortran</strong> to calculate the factorial n!<br />
3. Construct a subroutine to calculate the average <strong>and</strong> st<strong>and</strong>ard deviation of a data set. The<br />
subroutine should be passed the number of data points <strong>and</strong> a one-dimensional array containing<br />
the data.<br />
75