COMMON, INCLUDE, BLOCKDATA
the first derivative can be written as:
and the second derivative can be approximated as:
We will also find that it is useful to know the first derivative halfway between two points (say between xi and xi+1.
If you think about it, that is the same approximation to the first derivative that you would get if
you had fit a straight line to the function between xi and xi+1. Such expressions for derivatives
have limited value alone, but are tremendously useful in converting Differential equations to
algebraic equations, that can be solved on a computer.
A COMMON block (see trapezoid.f ) is an old but useful feature in Fortran for letting subprograms communicate information. In its simplest form, blank COMMON, the statement name is followed immediately by a list of variables. If the same statement is repeated in different program units, all will agree on the memory location for any listed variables in the order that they are listed. A change in value of one of the listed variables, will be seen by all program units containing that COMMON statement. For example the following program:
c = a + b
print *, 'c = ', c
will correctly print out a value of three. The main program and two subroutines all agree on the locations for "a", "b", and "c."
One thing should be noticed in this example for those of you who like shortcuts. You might be tempted to replace the common statement in "sub2" with "common c". The result of this replacement would be for the program to print a value of one. As with argument lists, its really order that counts in the variable list for a COMMON block. For this example, the main program, and two subroutines all agree that the first variable name (whatever it may be) listed after the first occurrence of "COMMON" always refers to the same address in memory. The second variable listed after "COMMON" refers to the next address in memory after the space occupied by the first variable, and so on through the last listed variable. Although you can use this order dependency of COMMON to let different subroutines use different names for the same quantity (location), this leads to very unreadable code, and should be avoided. Use identical copies of blank COMMON (or named COMMON), when communicating information.
You may have noticed that I was careful in the last paragraph to refer to the "first occurrence" of COMMON. You are permitted to put multiple blank COMMON statements in a program unit. However, you are not really creating separate COMMON blocks. There can be only one blank COMMON in a program, and multiple COMMON statements just act to extend the length of the single blank COMMON. For example, writing the following two statements:
is exactly equivalent to writing
Having just one COMMON can be fairly constraining, so Fortran also permits named COMMON blocks. The name of the common block immediately follows "COMMON" and is always delimited by "/". Examples of named COMMON are:
The name of the common block is arbitrary and you do not declare its type in a REAL or
INTEGER statement. A COMMON may contain variables of any type, and mixtures of different
types. However, if you mix data types, you must be a little cautious. Most computers want double
precision real variables to begin at even multiples of the double precision word length. If "x1" and
"y1" are 64 bit real numbers, and "i1" is a 32 bit integer in the above example, the even 64 bit
spacing for the real numbers is broken, and trouble can result. Whenever possible segregate
variables into different named COMMONs by type. When not possible (for example blank
COMMON), list all of your REAL variables before listing any INTEGER or CHARACTER
So why do we bother to have both blank and named COMMON? The reason is memory assignment. You should recall that when a program is compiled, space is generally reserved for all variables within the resulting executable file. One exception to this rule that we have already seen is the use of ALLOCATABLE arrays. Space for such arrays is not assigned until the program is running and requests a specific size for the array. This is very important for major scientific and engineering applications where arrays can occupy tens to hundreds of megabytes. However, ALLOCATABLE is a recent (Fortran 90) invention. Originally blank COMMON filled this need. Space for any variable listed in blank COMMON is not assigned until the program starts to execute. This last minute allocation of space, has one important side effect. You can not initialize values for any variable in blank COMMON with a DATA statement. There is no place in the executable file to store the initial value.
In addition to providing more convenient grouping of variables, named COMMON fills the need for COMMON variables that should be initialized with a DATA statement. Unless a special (nonstandard) compiler option is used, memory for named COMMONs is reserved in the executable file. However, a potential for significant confusion exists. With the named COMMON appearing in many subprograms (and perhaps not in the main program at all), where are you going to put the DATA statement? The Fortran standard saves you the decision by not letting you put it in any standard program unit. You must create a special BLOCKDATA subprogram to hold the DATA statements. Here is an example of one such routine, that I've chosen to name DATA1 (name is up to you as are any names chosen for named common blocks).
real dx, dx1,dx2
You can create more than one such subprogram, located anywhere in your program. Usually, BLOCKDATAs are placed immediately after the main program, if the full program is contained in a single file. A BLOCKDATA routine is by its nature non-executable. It generally contains only the BLOCKDATA, END, COMMON, DATA, and type statements, but can also contain EQUIVALENCE, PARAMETER, IMPLICIT, and USE (see below).
I mentioned the value of blank COMMON for storing arrays, but haven't said anything about the interaction of COMMON (both blank and named) with the process of array declaration. Based on your current experience you might guess one approach.
real a(10000), b(10000), c(10), d, e
common a, b
However, you can also set the dimension in the COMMON statements.
real a, b, c, d, e
common a(10000), b(10000)
Either form has the same effect. Given that COMMON establishes a specific memory layout, I prefer the second form, giving the full details of the storage in one location.
One final note on mechanical details of named COMMON. Occasions may arise where the contents of a COMMON are lost. Suppose the main program calls SUBROUTINE A, and SUBROUTINE A calls SUBROUTINE B (but MAIN doesn't call B), and a COMMON named VAL is in A and B but not main. When A returns to MAIN, the Fortran 90 standard doesn't guarantee that the contents of VAL will be preserved for the next call to A. The best way to guarantee the contents of VAL won't disappear is to include a "COMMON/VAL/..." in the main program, even if none of the variables in VAL are used in MAIN. Another way is to use the SAVE statement. Both A and B must include the statement:
Important features of COMMON
While we are on the subject of COMMON blocks, I want to give another example of the value of EQUIVALENCE statements. Often in large programming applications you need to write the contents of all significant system variables including entire common blocks to a disk file for later continuation of your calculation. This is called a restart dump. Why bother? If you get 4 days into a 5 day long computer calculation and the machine crashes, you will suddenly appreciate the value of these restart dumps. Instead of starting the whole thing from scratch, you can pick up the last restart dump to continue with a relatively small loss of time. These dumps are also useful when running a large number of parametric calculations with a common starting point at the end of a long initialization calculation.
The task is simplified with the coding like this:
So what? The example is greatly simplified. In real life it is not unusual to have large numbers of variables (>50) in a given named common. This structure makes the write statements cleaner, and easier to maintain if variables are added to the named common. What happened to the format number in the WRITE? This is an example of an unformatted write. The contents of the listed variables are dumped to the disk file attached to unit 11, in exactly the form they have in memory. Here you would send 8 strings of 32 bits to the disk, containing the bit representation of real numbers. They could be read back from disk with "READ(11) CONTA"
Using COMMON and argument lists is a balancing act. Each argument in an argument list
generally has an associated cost in computer time to pass the argument address to the subprogram,
and long argument lists also carry the burden of making the program more difficult to read.
COMMON blocks simply establish a common agreement on variable locations, that is used
during creation of the executable code. I can use COMMON variables in subroutines with no
additional cost beyond use of local variables (same holds for MODULE variables). The results of
the test program funspeed.f give a little feel for the potential advantage of COMMON. The
unoptimized code shows a significant difference between using an argument list and using a
COMMON to pass information. This difference widens as more variables need to be passed.
However, what is going on with the optimized results? I am passing the same variables in every
pass through the DO loop. The compiler is smart enough to know that it only needs to do a single
load at the beginning of the DO loop to set the addresses used by the subprogram to locate
arguments. Use of argument lists within a DO loop is not always a significant disadvantage.
When in doubt on the proper approach run some timing studies. If no major speed advantage is
obvious, make your decision based on clarity of your program (could dictate either arguments or
COMMON), and on the potential for use of your subprogram in other applications (usually
encourages argument lists).
If you get tired of changing copies of COMMON blocks in many different subroutines, you can
put a single copy of a COMMON block in its own file. The Unix © convention is that the file end
with ".h". The contents of the file can be accessed by the compiler by including an INCLUDE
statement at the appropriate location (see trapz1.f, trapcom.h and trapcom1.h ). Use of
INCLUDE is not restricted to COMMON blocks. It can be used anytime you have a block of
code that appears unaltered in more that one location in the program. However, such applications
to blocks of executable statements lead to highly unreadable programs, and should be avoided.
Discussion of COMMON blocks and the INCLUDE statement has been postponed because you obtained these basic capabilities early in the class from the combination of the MODULE and USE statements. The only capability of COMMON missing in a MODULE is the ability to force data to reside in machine memory in a specific order.
MODULEs have several features not available in COMMON blocks. Unlike COMMON, you can include ALLOCATABLE arrays in MODULES. In doing so you have the ability to allocate an array in one subroutine for use in others (see module.f.) MODULES also make it more convenient to provide internal subprograms to program units than is possible with an INCLUDE statement. A single MODULE permits typing of variables and definition of internal subprograms. The same job would require two INCLUDEs.. When you get to the point of building internal functions, you may want to learn about the PUBLIC and PRIVATE statements to control the flow of information from you module subprograms.
My primary purpose in introducing COMMON blocks has been to prepare you to work with older FORTRAN programs. Unless you have a strong need to control the memory layout of your variables, you should stick with MODULE and USE statements in your own programs.