SUBROUTINES, FUNCTIONS

SUBROUTINE

COMMUNICATION

DIMENSIONS

FUNCTION

PROGRAM EXAMPLE

INTERNAL READ AND WRITE

(BACK TO TOPIC INDEX)
Subroutine. A subroutine is like a program, i.e., it is a program unit, but it is called by the overlying program when a specific task needs to be carried out.

Subroutines can call other subroutines.

To call a subroutine from another subroutine or the main program: CALL GETXY (X, NX, Z) The subroutine is of the form: SUBROUTINE GETXY (ARG1, ARG2, ARG3)

various declarations statements

:

:

executable statements

:

RETURN

END

(start)
Communication:
Communications between the main program with subroutines and between subroutines can be carried out in two ways

1) Arguments: The arguments in a subroutine transfer the memory addresses of the variables from the calling statement to the subroutine and vice versa. In Fortran actual variable values are not transferred!! This is known as ‘pass by address’, i.e. subroutines use call by reference, not call by value. The arguments are pointers to addresses that contain the desired value.

2) COMMON statements: COMMON statements assign a variable or variables to a block of shared memory. This memory is accessed by every program or subroutine that contains the COMMON block. COMMON blocks have the form:

COMMON/NAME/VAR1, VAR2, VAR3

where:
NAME is the name of the COMMON block.

VAR1, VAR2, VAR3 are the variables that define the memory that is being shared in the COMMON block.
Example of call by reference:

CALL GETXY (X(3), 2, Z)

The values of X(3), 2, and Z are NOT passed but the addresses in memory for X(3), 2, and Z are passed to the subroutine GETXY. The use of ‘2’ is dangerous in that it may be redefined to some other value associated with that address. All further uses of ‘2’ in the program may then have a strange value.

Call by reference is very useful for many applications. A simple example for filters and moving averages is:

NX=5

DO J=1,10

CALL GETXY (X(J), NX, Z(J))

END DO

The subroutine will look at successive addresses of array X:

J=1 – calling program

X(1), X(2), X(3), X(4), X(5) – subroutine

J = 2 – calling program

X(2), X(3), X(4), X(5), X(6) – subroutine

etc.

(start)
Dimensions:
When transferring arrays into a subroutine, it is a good idea to specify all of the memory requirements for the subroutine in the main program. This is also useful for "work" arrays needed as temporary storage locations in, e.g., a subroutine.

Example:

In the main program, we declare the arrays:

PARAMETER (N=100)

REAL X(N), Z(N)

:

:

NX=N

CALL GETXY (X,NX,Z)

Thus, we can declare in the subroutine:

SUBROUTINE GETXY(ARG1, ARG2, ARG3)

REAL ARG1 (*), ARG3 (*)

INTEGER ARG2

or, we can use the same variable names:

SUBROUTINE GETXY(X,NX,Z)

REAL X(*), Z(*)

INTEGER NX

(start)
Function:
A FUNCTION is similar to a subroutine, except it is called when a specific value needs to be calculated. It then returns the value as the name of the function itself. A function has:

1) one or more arguments just like a subroutine;

2) it itself has a value which is returned to the program unit that calls the function.

Example:

X = X2 (Y (I))

where:

Y (I) is the argument for the function X2.

Example:

REAL FUNCTION X2 (X)

C This function finds the square of X.

REAL X

X2 = X*X

RETURN

END

There are many ‘intrinsic’ Fortran functions. Some of these are:

EXP, SQRT, SIN, ATAN, ALOG, ALOG10,

MIN, MAX AMIN1, AMAX1, MOD, etc.

Functions can have any of the variable types allowed in Fortran, e.g., LOGICAL, REAL, INTEGER, COMPLEX, etc.

Example:

LOGICAL SEARCH

:

:

if (SEARCH (I, J, K)) then

:

END IF
 
 

LOGICAL FUNCTION SEARCH (I, J, K)

INTEGER I, J, K

if (I.EQ.J .AND. J.EQ.K) then

SEARCH = .TRUE.

ELSE

SEARCH = .FALSE.

RETURN

END

PROGRAM MAKEDATA

c pls 9-7-93

c make data records for use in other programs

c each record will contain up to mx real variables

c x(1 ... mx) real vector for data

integer mx

parameter (mx=1000)

real x(mx)

c nx actual number of variables in each record

c nrecs number of records of data to make

integer nx, nrecs

c file name to save data for future use

character*32 fname

c logical unit number for file

integer ifile

c counters

integer jx, jrec

c bytes/real this machine

integer mbytes

parameter (mbytes=4)
 

c get the input parameters from the user:

c filename, data values/record, # of records
 

write(*,*)'enter name of file to store data: '

read(*, '(a32)')fname

write(*,'(a32)')fname

write(* ,'(/)')

write(*,*)'number of data values/record='

read(*,*) nx

write(*,*)nx

write(* ,'(/)')

write(*,*)'number of records to save='

read(*,*) nrecs

write(*,*)nrecs

write(* ,'(/)')
 

c open the file fname as unformatted, direct access

c logical unit number is ifile=12
 

ifile=12

open(ifile,file=fname,form='unformatted',status='unknown',

- access='direct',recl=mbytes*nx)
 

c loop over all nrecs records, jrec=1,...nrecs

c define data, x, as record number, jrec, for jx=1,...nx

c save on file with logical unit number, ifile
 

do jrec=1,nrecs

do jx=1,nx

x(jx)=float(jrec)

enddo

write(ifile,rec=jrec)(x(jx),jx=1,nx)

enddo
 

c close file, quit
 

close(ifile)

stop

end

PROGRAM MAIN

c pls 9-7-93

c read data records and calculate their mean, post for user

c each record will contain up to mx real variables

c x(1 ... mx) real vector for data
 

integer mx

parameter (mx=1000)

real x(mx)
 

c nx actual number of variables in each record

c nrecs number of records of data

integer nx, nrecs

c file name for data to be used

character*32 fname

c logical unit number

integer ifile

c counters

integer jx, jrec

c bytes/real this machine

integer mbytes

parameter (mbytes=4)

c mean value

real xmean
 

c get the input parameters from the user:

c filename, data values/record, # of records
 

write(*,*)'enter name of file to read: '

read(*, '(a32)')fname

write(*,'(a32)')fname

write(* ,'(/)')

write(*,*)'number of data values/record='

read(*,*) nx

write(*,*)nx

write(* ,'(/)')

write(*,*)'number of records to read='

read(*,*) nrecs

write(*,*)nrecs

write(* ,'(/)')
 

c open the file fname as unformatted, direct access

c logical unit=12
 

ifile=12

open(ifile,file=fname,form='unformatted',status='unknown',

- access='direct',recl=mbytes*nx)
 

c loop over all nrecs records

c read data get mean
 

do jrec=1,nrecs

read(ifile,rec=jrec)(x(jx),jx=1,nx)

call mean(x,nx,xmean)

write(*,*)'the mean for record ',jrec,' is',xmean

enddo
 

c close file, quit
 

close(ifile)

stop

end
 
 
 

subroutine mean(x,nx,xmean)

real x(*), xmean

integer nx

c for the vector x of length nx

c get the mean value, xmean

c counter jx

integer jx
 

c initialize xmean as zero

c guard against divide by zero

xmean=0.

if(nx.le.0) return

c sum
 

do jx=1,nx

xmean=xmean+x(jx)

enddo
 

c get mean

xmean=xmean/nx

return

end

(start)
Internal READs and WRITEs:

FORTRAN users can read from and write to character strings in a program. These character strings are known as internal files. In these specialized READs and WRITEs, the Logical Unit Numbers are replaced with character string variables.

Example:

If a user has 20 files in the directory, each named FILE1.DAT, FILE2.DAT, . . . . FILE20.DAT, and he or she wants to open each file to do some processing; the following code below will achieve that result. Note that only one file will be open at a time.

CHARACTER*40 FNAME

CHARACTER*1 CHAR1

CHARACTER*2 CHAR2

INTEGER I

DO I = 1, 20

IF (I.LE.9) THEN

WRIte (char1, 10010) I

fname = ‘file’ // char1// ‘.dat’

else

Write (char2, 10010) i

fname = ‘file’ // char2 // ‘.dat’

endif

open (lun, file = fname, status = ‘old’)

:

(processing)

:

END DO

10010 FORMAT (A)

(start)