Read Chpt 15, Chpt. 18.8, Finish Hw11 and Start Hw12
COMMON (blank and named), BLOCKDATA, INCLUDE
Numerical integration and differentiation are another set of topics that I've relegated to a Postscript file, because of the number of equations involved in illustrating the processes. You can look at some examples of the Trapezoidal rule for integration in trapezoid.f, trapz1.f, and trapz2.f. trapz1.f needs the files trapcom.h and trapcom1.h to compile properly. You can get all of these files by typing:
cp ~jhm/201/integrate/* .
These examples have been programmed to illustrate two other ways (besides argument lists) to pass information between program units (main program, subroutines, and functions. The first is the COMMON block, and the second the Fortran 90 MODULE structure. Both establish variable names (addresses in memory) that more than one program unit can use.
program test common a,b,c a=1. b=2. call sub1 call sub2 stop end subroutine sub1 common a,b,c c = a + b return end subroutine sub2 common a,b,c print *, 'c = ', c return endwill 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:
common a,b,c common x,y,zis exactly equivalent to writing
common a,b,c,x,y,zHaving 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:
common/realvar/x,y,z common/intvar/ i,j,k common/miscvar/ x1,i1,y1,j1,z1,k1The 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 variables.
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).
blockdata data1 common/dtdata/ dt,dt1,dt2 common/dxdata/ dx,dx1,dx2 real dt,dt1,dt2 real dx, dx1,dx2 data dt,dt1,dt2/.01.001,.0001/,dx,dx1,dx2/.1,.2,.3/ endYou 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 common/other/c,d,eHowever, you can also set the dimension in the COMMON statements.
real a, b, c, d, e common a(10000), b(10000) common/other/c(10),d,e
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:
save /val/Important features of COMMON
The task is simplified with the coding like this:
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. 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).
A MODULE has one major feature 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 convient 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.
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.
Written and Maintained by John Mahaffy : jhm@cac.psu.edu