OGIP Memo OGIP/92-012
OGIP Fortran Programming Standard
Koji Mukai
Code 668,
NASA/GSFC,
Greenbelt,
MD 20771
Version 1.0 (first release): 1992 Nov 19
SUMMARY
This memo contains various standards and recommendations regarding
OGIP Fortran programs. One standard is the extensions to Fortran 77 that
can be used, considering the features of existing compilers and
the Fortran 90 standards. Another is the prolog comments that explain
what the subroutine is, how to use it etc. This is followed by a general
recommendations on programming style.
Despite the considerable software development that has been going on at OGIP, many of which are distributed to the community, we have not had a group-wide policy on programming practices. Recently, we have had discussions on how rigidly we should conform to the ANSI Fortran 77 standard, the results of which are presented in § 2. In § 3, the major differences between two major brand of computers are discussed. We also deal with wider issues of programming style, possibilities within Fortran 77 that are not good, areas where the language standard is not specific enough, etc. etc.
In cases where OGIP has made a commitment to provide a set of software to be released to the community, the programmers1 involved must ensure that the software products are portable. This must be done by conforming to the generally recognized standard and isolating any system-dependent operations into a small set of subroutines; these topics are covered in § 2 and § 3, respectively. All portable software must conform to the ANSI Fortran 77 except for OGIP-approved extensions, and follow the rules marked with a ``¶'' in § 5.
It is possible to relax the portability requirement if we limit the machine types to, e.g., UNIX workstations and VAXes. In this example, IBM mainframes, PCs and Crays (among others) are excluded, but this will probably not impact many OGIP users. For this reason, there are two sets of OGIP-approved extensions; one for general portability, the other for a more restricted portability. Which portability criterion should apply to a given piece of code is a policy matter; even though this document does make suggestions, those should not be taken to be the final decisions.
Fortran 90 is the new international standard of the language, containing many advanced features. All the widely used extensions of the current standard are in the new standard. It is backward compatible although certain features of the language are marked ``obsolescent''; these may be deleted in the next standard after Fortran 90, an added incentive for programmers not to use them (only those features widely regarded as bad are in this list).
Fortran 90 includes:
Obsolescent features are:
There are already some Fortran 90 ``compilers,'' which translates Fortran 90 codes to Fortran 77 or C; these are adequate for prototyping and testing purposes (in the case of NAG Fortran 90 compiler, benchmark tests suggest noticeable (25-50%) slowness compared with the same algorithm compiled with a native compiler). DEC has declared they are developing a Fortran 90 compiler, although they would not say when it might be available. A general availability of Fortran 90 compilers probably is a few years off. Nevertheless, we should keep Fortran 90 standard in mind and switch to it as soon as it becomes widely available.
In the mean time, those obsolescent features should not be used in OGIP programs.
On other issues, such as making the software foolproof, easy to use and easy to maintain, we will not enforce rigorous rules; such rules tend to be definite for the sake of definiteness and often annoys the independent-minded, well-disciplined programmers. Therefore all the rules in § 5 that are not marked with a ``¶'' should be taken as advice; there is no harm in establishing your own personal style as long as you understand the reason why these rules exist.
The explanations for the rules in § 5, as well as § 3, are put in this document so that you can make intelligent decisions regarding your programming style.
VMS Fortran has the /STANDARD option; Sun F77 has the -ansi option. Both are used to turn off all the compiler-specific extensions to ANSI Standard Fortran 77. This options, as well as utilities such as SPAG can be used to check how closely your code conforms to the Fortran 77 standard.
In OGIP Fortran programs to be released to the community for use on a wide variety of machines, only the ANSI standard Fortran 77 and the extensions given below are allowed. The FITSIO package already conforms to this strict standard; this level of strict conformance may be required of general-purpose subroutine packages.
The following extensions are features common to VMS Fortran, Sun Fortran, MIPS Fortran and ``f2c2.''
ASTRO-D software, for example, may require only this level of portability.
The following commonly-used extensions to ANSI standard Fortran 77 will not be allowed in any portable OGIP programs.
In addition to the difference among Fortran compilers, features of the operating systems and command languages play a major role in determining which program is portable and which is not. This section summarizes the major differences between VAX/VMS/DCL and Sun/UNIX/c-shell that Fortran programmers should be aware of.
The following is an example of prolog comments in a style recommended by Allyn Tennant and Ian George. The comments are sandwitched between *+ and *-, which allows automatic extraction of prolog comments.
*+SX_FITLIN SUBROUTINE SX_FITLIN(X,Y,SIGMAY,NPTS,MODE,A,SIGMAA,B,SIGMAB,R) INTEGER NPTS, MODE REAL X(NPTS), Y(NPTS), SIGMAY(NPTS) REAL A, SIGMAA, B, SIGMAB, R C C Description: C Fits straight line Y = A + B*X by least squares. C C Arguments: C NPTS (i) : No. of data pts in X,Y,SIGMAY, must be >2. C X(NPTS) (i) : Array of independent variables C Y(NPTS) (i) : Array of dependent variables C SIGMAY(NPTS) (i) : Array of Std Errors on Y (only used if MODE=1) C MODE (i) : Data weighting mode..... C -1 for WEIGHT = 1/ABS(Y) i.e. Poission errors C 0 for WEIGHT = 0.0 i.e. all points same weight. C 1 for WEIGHT = 1/SIGMAY**2 i.e. user-supplied errors. C A (io): Intercept on X=0 line C SIGMAA (o): Std error in A assuming Gaussian error distribution. C B (o): Slope of line C SIGMAB (o): Std error in B assuming Gaussian error distribution. C R (o): Correlation coeff between X and Y C C Origin: C Algorithm LINFIT by Bevington, but adapted to ... blah, C .... blah blah C Authors/Modification History: C Ian M George (1989 April 28), original version C Allyn F Tennant (1992 Aug 01), minor bugs corrected C Nick White (1992 Sept 03), MODE=-1 added to handle ... blah blah C blah blah blah C Allyn Tennant (1992 Sep 14), improved comments. *- Version 2.3.2
Here are the set of rules, with brief explanations. Those with ``¶'' will be strictly enforced for software to be released to the community.
Do Not Use Unapproved Extension to Fortran 77 ¶ 1
Use the ANSI standard plus OGIP extensions (§ 2) only, if you are mandated to provide a portable software tool to the community.
Do Not Use Obsolescent Features ¶ 2
Although these features will remain in Fortran 90, it is wise to avoid them. They are marked obsolescent for good reasons.
Use indenting to show structure ¶ 3
No explanation necessary.
Do not overuse STOP, RETURN and ENTRY 4
The idea behind this recommendation is to make it easy to see where the execution of programs and subroutine starts and ends. The first two are usually unnecessary since END statements have the desired effect (NB. HP Fortran requires RETURN, which is a violation of the standard).
Avoid GO TO 5
It is often possible to use DO loops and block IFs instead of GO TOs; this usually helps in making the program structure clear. However, in standard Fortran 77, a total avoidance of GO TOs can actually result in a poorly structured code so this rule should not be taken to extremes.
Use the computed GO TO sparingly 6
Computed GO TO can be a reasonable substitute for a ``case'' construct, where value of a single variable (e.g., command number in a command-driven program) determines what is to be executed next. However, there is an alternative (by using IF blocks) within the current language; Fortran 90 will provide an explicit SELECT CASE construct with all the features you would want in such a construct.
User input must not be case-sensitive ¶ 7
Only exception to this rule is the file names on case-sensitive systems.
Validate inputs ¶ 8
Users must be allowed to make mistakes without crashing the program. Reading with err=<label> is always a good idea; in addition, case-by-case validation (e.g., if the program requires a positive number, check for it) should be performed before using the input data.
Do not overprint with ``+'' 9
This does not always work; if it is desirable to overprint, wrap it up in a device-dependent subroutine.
Be device-independent 10
Avoid device (e.g., terminal) dependent code (e.g., VT100 escape sequences) as much as possible, or isolate it in a subroutine.
Declare every variable ¶ 11
Do not use DIMENSION for arrays.
Define sizes parametrically 12
Use the parameter statements so that you only have to change it to change the array size.
Use CHARACTER∗(∗) 13
Dummy argument should in general avoid a hard-wired length for generality.
Use standard data types 14
Fortran standard recognizes INTEGER, REAL, DOUBLE PRECISION, CHARACTER and LOGICAL. Type declaration of the form REAL*n is often recognized but non-standard, and should be avoided as much as possible, although there are situation where INTEGER*2 is essential. BYTE is also highly non-standard.
Don't access uninitialized variables 15
Usually uninitialized numerical variables are 0, but this is not guaranteed.
Save everything you have to 16
Local variables within a subroutine usually retain the values at the end of the previous call. This practice is not guaranteed, however, unless there is a SAVE statement.
Logical and Integer are different 17
Thus, do not treat an integer as logical or vice versa.
Don't use EQUIVALENCE 18
Using EQUIVALENCE to ``convert'' among different file types is a useful trick; however, note this often makes the code machine-dependent. Using EQUIVALENCE on anything in a common block, or using EQUIVALENCE to extend an array, are both extremely dangerous.
Use distinctive names 19
We actually recommend to break the Fortran 77 restriction of 6-characters for subroutines and functions, for a package of subroutines to be used widely for different application programs. This is to minimize the danger of clashing subroutine names among different packages (e.g., a new version of PGPLOT may have a new subroutine with the name you have used for your subroutine). The British STARLINK recommends the following standard form: < pcg > _ < s/f-name > , where < pcg > is a 3-character package name and < s/f-name > is a 5-character subroutine (function) name. This is an excellent suggestion and we propose to adopt this as an OGIP standard.
Data type must not change across a CALL 20
Changing data type across a call is very machine-dependent. It should be done only with extreme care.
FUNCTIONs must not have side effects 21
Make it into a subroutine, if there are more than one output variables.
Subroutines should report errors using a flag 22
This will result in a code more flexible than if the subroutine printed out error messages or stops the program.
NOTE: Should we have an OGIP standard for error handling? Sounds like a good idea, but how?
Use distinct names 23
See the rule on subroutine/function names above.
Minimize use of COMMON 24
Overuse can result in a code that is hard to read. A subroutine package should collect all its internal common blocks in a include file. Passing arguments from the host program to a general-purpose subroutine library using a common block is discouraged.
Follow the standard order 25
Each common blocks should contain doubles, single precision reals and integers (and if non-portable, integer*2s, bytes/characters) in that order. On many machines, this minimizes the operations when extracting individual variables out of the common block.
Use statement labels only on Format and Continue 26
Actual number crunching should be separated from decisions and loops; also, different loops and decisions should have their own end-points. By the same token, avoid nesting multiple DO loops with the same label.
Clean up garbage 27
Unused statement labels, declared but unused variables and unused format statements all make the code less readable.
Use XANLIB 28
XANLIB contains a set of subroutines that perform system dependent tasks. OGIP programmers should use these whenever possible to avoid re-inventing the wheel.
Don't use literal I/O unit numbers 29
Hardwired unit numbers make it hard to avoid conflict.
Be aware of floating-point limitations 30
There are many ways in which floating number arithmetic can trip up a programmer.
Thus, do not compare real numbers for equality; use brackets to specify the best order of execution; use multiplication rather than recursive addition, if that is possible.
Do not use mixed mode arithmetic 31
Converting from a real to an integer, for example, should be done explicitly; these are major events in terms of computing speed, and should be treated as such.
Prolog comments¶ 32
Explain what the module does, what input and output variables are, list author(s), dates and history, as specified in § 4.
Begin modules properly 33
Comments preceding the first statement of a module (PROGRAM, SUBROUTINE, FUNCTION or BLOCK DATA), or those following the END statements, are discouraged to minimize confusion.
Explain variables 34
Particularly if the variable names are cryptic, which often is the case when the programmer is strictly obeying the 6-letter variable name rule.
Make comments stand out from code 35
Use blank lines and spaces, and use other visual aids.
Write meaningful comments 36
This is a warning against trivial comments (I=I+1; ``increment counter''). Explain why you are doing this, rather than what you are doing.
Avoid clever but obscure code 37
At least comment why it's clever, preferably with a reference.
Use VMS compatible file names ¶ 38
In cases where program has to know the file name (scratch file, help file), the file name should be a legitimate one on VMS, even if the program is written on a UNIX machine.
Do not overuse INCLUDE 39
INCLUDE statements, by their very nature, cannot avoid involvement with the operating system dependent nature of file names. Using INCLUDE on files in the same directory as the code is relatively harmless; INCLUDE across directory boundaries are necessarily system-dependent and should be minimized.
Do not rely on compiler switches 40
Compiler switches usually enable you to extend Fortran standard; it is hard to enforce the use of the necessary switches.
I thank several OGIP members and Allyn Tennant for their comments on an earlier version of this document. I also relied heavily on U.K. Starlink document by P. T. Wallace.
1This includes, but not limited to professional programmers, who are likely to have known all the things in this document anyway. This memo is aimed more towards scientists writing software part-time.
2F2c is a public domain software that produces ANSI standard C programs from input Fortran 77 units that may contain certain extensions
3In Fortran 90, there is a keyword
``POSITION'' which can take values ``APPEND,'' ``REWIND''
or ``ASIS.''