Fortran Subprograms
Fortran Subprograms
Until now, all of the programs have essentially been single, fairly small programs.
However, as we scale up into larger programs, this methodology will become
more difficult. When developing larger programs, it becomes necessary to break
larger programs up into multiple, smaller more manageable pieces. Then, during
program development, it is possible to focus on each subsection or piece
individually and then combine the results into a final complete program. And, for
very large projects, multiple people may work on different parts of the program
simultaneously. Some of the key advantages of developing a program using
functions and/or subroutines include:
● Structured development of programs
● Reuse of subprograms
● Isolation of subprograms
Fortran subprograms are the mechanism to break a large program into multiple
smaller parts. This allows for a more comprehensive program design.
Subprogram Types
There are two types of Fortran subprograms: functions, and subroutines, each of
which is explained in the following sections.
Program Layout
The functions and subroutines can be defined as either internal or external.
Internal functions and
subroutines are defined within the program statement (i.e., before the “end
program <name>”
statement). The basic layout for both internal and external subprograms are as
follows:
program <name>
<declarations>
<program statements>
contains
<internal functions or subroutines>
end program <name>
<external functions or subroutines>
Where a combination of both or either internal or external routines is allowed.
Arguments
When writing and using Fortran subprograms, it is typically necessary to provide
data to a subprogram and/or to obtain results back from the functions or
subroutines. This information, in the form of variables, is referred to as an
argument or arguments. The argument or arguments in the calling routine are
referred to as actual arguments, and the argument or arguments in the function or
subroutine are referred to as formal arguments. The formal arguments take on the
values that are passed from the calling routine. The only way to transfer values in
to or out of a subroutine is through the arguments. A function typically passes
values in through the arguments with a single return value (via the function
name). All other variables are independent and isolated.
Functions
Intrinsic Functions
As described previously, an intrinsic function is a built-in function that is already
available. Some of
the intrinsic functions already described include sin(), cos(), tan(), real(), int(),
and nint(). A more comprehensive list is contained in Appendix D.
User-Defined Functions
The <type> is one of the Fortran data types: real, integer, logical, character, or
complex. It is possible to place the type declaration on a separate line from the
function statement. The information, in the form of arguments, is passed from the
calling routine to the function. Each of the passed arguments must be declared
and the declaration must include the type and the intent. The arguments in the
calling routine and the function must match and are matched up by position.
Which, given a Fahrenheit temperature, will return the Celsius temperature. The
single input argument, ftemp, is declared to be a real value and “intent(in)”, which
means that the value is expected to be coming into the function and cannot be
changed. The final value is returned to the calling routine by assigning a value to
the function name, fahr_to_celsius, in this example.
Subroutines
The information, in the form of arguments, is passed from the calling routine to
the subroutine. Each of the passed arguments must be declared and the declaration
must include the type and the intent. The arguments in the calling routine and the
subroutine must match and are matched up by position.
For example, given the following simple program to find the sum and average of
three numbers.
program subExample
implicit none
real :: x1=4.0, y1=5.0, z1=6.0, sum1, ave1
real :: x2=4.0, y2=5.0, z2=6.0, sum2, ave2
call sumAve(x1, y1, z1, sum1, ave1)
write (*,'(a,f5.1,3x,a,f5.1)') "Sum=", sum1, &
"Average=", ave1
call sumAve(x2, y2, z2, sum2, ave2)
write (*,'(a,f5.1,3x,a,f5.1)') "Sum=", sum2, &
"Average=", ave2
contains
subroutine sumAve (a, b, c, sm, av)
real, intent(in) :: a, b, c
real, intent(out) :: sm, av
sm = a + b + c
av = sm / 3.0
return
end subroutine sumAve
end program subExample
The arguments in the first call (x1, y1, z1, sum1, and ave1) are matched up to the
arguments in the subroutine (a, b, c, sm, and av) by position. That is, the x1 from
the call is matched with the a in the subroutine. The arguments in the second call
(x2, y2, z2, sum2, and ave2) are again matched up to the arguments in the
subroutine (a, b, c, sm, and av) by position. While the names of the variables do
not need to match, the data types must match. Variables declared in a function or
subroutine are not the same as variables in the calling routine. This is true, even
if they are the same name!