A Modular Program


Even though the simple program structure works well for my simple example, it is counter-productive for longer programs, leading to lack of clarity and slowing code maintenance and modification. Each well defined task in a program should be placed in its own program unit. Here we will execute the tasks in program units call subroutines. The main program simply acts as an outline or driver, triggering execution of the program units that accomplish the tasks. Whatever the contents, you should learn that all Fortran program units share a common structure. As you learn the statements of Fortran keep a picture in your mind of where they fit within this structure.

Remember that before reaching this step you have produced a written description of the of the problem. This design document lists:

I usually do this at a keyboard so that I can easily copy this information into program comments.

Refering to your design document, you must decide what information will be required by each unit of the program, and how it will be shared between the program units to accomplish the overall goal of the program. The first thing you should learn about communication between program units is that simply giving a variable in one unit the same name as a variable in another program unit will not result in communication of the value of that variable between units. Both Intel and MicroSoft may have employees named John Smith, but they are probably not the same person with the same knowledge. A variable named "a" in SUBROUTINE "input" will not refer to the same location in the computer memory as a variable with the same name in SUBROUTINE "add", unless you take special action in your program to insure that these separate program units recognize "a" as the same location in memory.

The simplest way to share information in Fortran 90 is through the MODULE program unit. The first statement in this unit begins with word "module" and is followed by an arbitrary, but unique name for the MODULE (you can define and use as many MODULEs as you want). The MODULE must end with and END (or END MODULE) statement. In between you include type statements for all variables that you want to share. The program units that need these shared variables access them with the USE statement. Simply include a line immediately after the start of your program unit (after the PROGRAM, SUBROUTINE, MODULE, FUNCTION or BLOCKDATA statement) statement beginning with "use" and followed by the name of the module that you want to use. If you inadvertently do something like place the IMPLICIT NONE statement before the USE statements, the program won't compile.

Using the above program unit, the program to read two numbers, add them, and print the result could be written as below.

      module global
      implicit none
      real a,b,s
c    a - one of the numbers to be added
c    b - the other number to be added
c    s  - the sum of a and b
      end module global
c
      program add2
c
 
      implicit none
c
c   use subroutine input to get the values for a and b
c
      call input
c
c    find the sum of and b 
c
      call add
c
c     use the subroutine output to send the results to the screen
c
      call output
      stop
      end
c
      subroutine add
      use global
      implicit none
c
c   Add two numbers and store the sum in "s"
c
      s = a + b
      return
      end
c
      subroutine input 
      use global
      implicit none
      print *, ' This program adds 2 real numbers'
      print *, ' Type them in now separated by a comma or space'
c
c   Now read the numbers that are typed by the user
c   this Fortran read will wait until the numbers are typed
c
      read *, a,b
      return
      end
c
      subroutine output
      use global
      implicit none
c
c   Print out the results with a description
c
      print *,  ' The sum of ', a,' and ' , b
      print *, ' is ' , s
      return
      end

Note that one program unit immediately follows the END statement of a previous unit. Also note that the SUBROUTINEs are not necessarily entered in the same order that they are called. Order of program units in your program file is not particularly important to the compiler. However, when using a single file for your program, one good practice is to start with your MODULEs, follow with the main program, and then provide other program units (SUBROUTINEs and FUNCTIONs) in the alphabetical order of their names. Later, we will learn that you don't have to limit yourself to a single disk file for your program. It is very common to put each program unit in its own file, and to let the compiler combine the contents of all files into a single executable program.

This business of using program units really isn't very complicated. I recommend that once you decide how your are going to split up the tasks and shared data in your program, you start by simply typing a framework of your program consisting of the program unit statements (MODULE, PROGRAM, SUBROUTINE, ...) and associated END statements. Then fill in the statements that assign data types and do the work.

As an example of this approach consider an exercise specified to add 3 numbers. Your program must ask the user for 3 numbers, read them as REAL numbers, add them together, and print out the result. For practice with modules you are to communicate the 3 input numbers to the addition subprogram with one MODULE, and the result to the output subprogram with a second MODULE.

I would first develop the framework for the program with the following coding.

      module invalues
      end module 
      module result
      end module 
      program add3
      end
      subroutine add
      end
      subroutine input 
      end
      subroutine output
      end

Next I would add IMPLICIT NONE statements to program units containing executable statements. I could also add them to the MODULEs, but they don't have any advantage in this instance. At the same time I check to see which program units need access to which shared variables. I add type statements for these variables in the MODULEs and add the appropriate USE statements to the program units using these modules. I don't use any modules in the main program, because it doesn't directly use any of the variables. I use "invalues" in the subroutine "output", because it will also reflect the input values. I could have passed this over if "input" had taken care of this print to the screen. All of this can be done fairly quickly with the help of text editor copy and past commands (in vi "yy" and "p").

      module invalues
      real a,b,c
      end module 
      module result
      real s
      end module 
      program add3
      implicit none
      end
      subroutine add
      use invalues
      use result
      implicit none
      end
      subroutine input 
      use invalues
      implicit none
      end
      subroutine output
      use invalues
      use result
      implicit none
      end

Now it's time to do the real work. I fill in the executable statements in my main program and each SUBROUTINE.

      module invalues
      real a,b,c
      end module 
      module result
      real s
      end module 
      program add3
      implicit none
      call input
      call add
      call output
      stop
      end
      subroutine add
      use invalues
      use result
      implicit none
      s = a + b + c
      return
      end
      subroutine input 
      use invalues
      implicit none
      print *, ' This program adds 3 real numbers'
      print *, ' Type them in now separated by a comma or space'
      read *, a,b,c
      return
      end
      subroutine output
      use invalues
      use result
      implicit none
      print *,  ' The sum of ', a, ', ',b , ' and ' , c
      print *, ' is ' , s
      return
      end

Finally I add comments (generally with cut and paste from my design document), so that I can figure out what I was trying to do when I try to modify the program in six months, or at the very least add comments so that I can pass the programming course. The comments provide definitions of all significant variables, list the purpose of the program and all subprograms, identify the programmer and modification history, and describe key blocks of code.

      module invalues
      real a,b,c
c    a - one of the numbers to be added
c    b - the second number to be added
c    c  - the third number to be added
      end module 
c
      module result
      real s
c    s - the result of the calculation
      end module 
c
      program add3
c
c   Program to add 3 numbers
c   John Mahaffy 11/2/96
c
       implicit none
c
c   use subroutine input to get the values for a, b, and c
c
      call input
c
c    find the sum of and b 
c
      call add
c
c     use the subroutine output to send the results to the screen
c
      call output
      stop
      end
c
      subroutine add
c
c   Perform addition of 3 numbers
c   John Mahaffy 11/2/96
c
      use invalues
      use result
      implicit none
c
c   Add three numbers and store the sum in "s"
c
      s = a + b + c
      return
      end
c
      subroutine input 
c
c   Obtain user input
c   John Mahaffy 11/2/96
c
      use invalues
      implicit none
c
c   Prompt for and read three numbers for addition
c   this Fortran read will wait until the numbers are typed
c
      print *, ' This program adds 3 real numbers'
      print *, ' Type them in now separated by a comma or space'
      read *, a,b,c
      return
      end
c
      subroutine output
      use invalues
      use result
      implicit none
c
c   Print out the results with a description
c   John Mahaffy 11/2/96
c
      print *,  ' The sum of ', a, ', ',b , ' and ' , c
      print *, ' is ' , s
      return
      end

In a program of normal complexity, the solution procedure is often complex enough to justify splitting it into several subprograms corresponding to the stages of the solution. Frequently this results in a multi-layered program with one or more solution subprograms references other subprograms to handle low level steps of the solution. When the program is a complex application, the input and output steps are also broken into multiple subprograms. For these large programs this division facilitates a project employing multiple programmers.


Take a look at past questions on Modules and Subprograms


Back to Lecture 5 / Home


Authored by John Mahaffy and Jason Wehr Maintained by John Mahaffy : jhm@cac.psu.edu