Next: , Previous: Storage Management, Up: Implementation

30.8 Standards (Rules) for Writing CONGEN Code

The following set of rules is designed to help keep CONGEN readable and modifiable.

  1. All routines should have similar organization.

    Each Fortran subroutine should have the following structure:

                    SUBROUTINE DOTHIS(ARG1,ARG2,....
              C     A comment which describes the purpose of this subroutine.
              C     This comment is essential because it provides the only
              C     documentation for nearly all subroutines in CONGEN. The
              C     program, AUTODOC, can be used to get this comment from all
              C     subroutines.

    The separation of the code from the declarations by a blank comment aids in reading the code. It becomes obvious where executed code begins.

    Each C procedure should be written like this:

              dothis(type par1, type par2,...)
              *   A comment which describes the purpose of the routine. This
              *   comment must come here so that automatic documentation can
              *   be implemented (a program similar to AUTODOC is planned.)
                  local declarations
  2. Prototypes for all the C functions should be provided through the use of mkproto, see Mkproto. See the makefile for CONGEN for details of the mechanism. Note that not all files can be processed correctly, such as functions which are declared with structures or types that are machine dependent. All such functions should be placed in the file, noproto.c.
  3. All source files must have a copyright notice at the top. See any source file for the appropriate text.
  4. All C source files must include config.h and wrappers_c.h in that order. It is a good idea to use an existing source file to provide the copyright and includes to get started.
  5. All FLECS source files must include config.h and wrappers_f.h.
  6. All code should be written clearly. Since the code must be largely self-documenting, clarity should not be sacrificed for insignificant gains in efficiency. The use of C and the FLECS preprocessor is encouraged as it graphically illustrates the flow of control and allows for internal procedure calls. Variable names should be chosen with care so as to illustrate their purpose. Avoid using one or two letter variable names in any COMMON blocks. Comments should be used where the function of code is not obvious.
  7. All usages of integers, floats, doubles in C code must use the F77_INTEGER, F77_REAL, and F77_DOUBLE macros defined in config.h. Boolean variables should use the BOOLEAN macro, and Fortran logical variables defined in Fortran should use the F77_LOGICAL macro. The F77_INTEGER macro should declare to a long int. If not, you must review calls to the different scanf and printf functions to ensure correct typing.
  8. Be careful to distinguish between Fortran 77 logical variables and C integers being used to hold Boolean variables. The testing conditions are machine dependent. Use the macros provided in macros.h for Fortran logicals.
  9. Be careful that the type of any numeric constant match correctly with its usage across the various platforms that CONGEN is implemented on. For example, there may be problems with using a real constant in an intrinsic function call with multiple variables in Fortran, eg. SIGN(1.0,P). If P is DOUBLE_DECL, you will have a problem because DOUBLE_DECL can map to either REAL or DOUBLE PRECISION depending on the machine. In such cases, it is better to use a variable or parameter to store the constant.
  10. All usages of DOUBLE PRECISION variables in Fortran must be declared using the DOUBLE_DECL macro. This allows CONGEN to switch double precision variables to single precision on 64-bit computers.
  11. Any variable in Fortran code that holds a pointer to be used by the C code must be declared using the POINTER_DECL macro. On 64 bit architectures, this macro will expand to 64 bit integers. The equivalent type in C is given by the F77_POINTER macro.
  12. Any subroutine defined in C which can be called from FLECS code must have its prototype entered into the source file wrap_cdef.proto. Likewise, any subroutine defined in FLECS which can be called from C must have its prototype entered into the source file wrap_fdef.proto.
  13. Whenever Fortran common blocks are accessed within C, you must use the predefined macro for the common block name. The macro is the upper case name for the common block. Header files (suffix .h) are defined for all common blocks used in C code. For example, if you want to refer to the X coordinate array in C, use COORD.x.
  14. There are number of rules associated with input and output:
    1. All input commands should be free field. The command processor should check that the entire command is consumed.
    2. Short outputs, messages, warnings, and error should be sent to unit 6 for output.
    3. All inputs should be echoed to unit 6. All values read by the command should also be output to unit 6.
    4. All warning and fatal messages should state what subroutine generated it, so that one find the location in the source code where the problem arose.
    5. All data structures output with unformatted I/O statements must have a HDR, ICNTRL, and TITLE in the first two records. See any existing binary output subroutines for the exact format.
    6. Unformatted I/O file formats should remain upward compatible. Use an ICNTRL array element to indicate which version of CONGEN wrote the file. Such upward compatibility must be maintained only across production versions of CONGEN. In other words, a file format for the developmental version may be freely changed until a new version is generated, at which point all future versions must be able to read it.
    7. All I/O must be done through Fortran I/O. C I/O is not to be used. See the procedures in the source code file, CUTIL.C, for useful analogs of C I/O functions to make this rule easy to follow.
  15. All error conditions must terminate with a CALL DIE. The subroutine, DIE, provides a traceback or core dump so the program statements causing the error can be seen.
  16. Large or variable storage requirements for Fortran code must be met on the stack or heap. In C, cgalloc and cgfree should be used for all variable storage needs.
  17. Array overflows must always be checked for when arrays are being written. This is especially important when the array being constructed might be dynamically allocated. Error checking in general should be as complete as feasible.
  18. The code should use a minimum of non-standard Fortran or C features. All non-standard features must be conditionally compiled so that any CONGEN programmer is informed that the code is special.
  19. In order to make subroutines callable from different contexts, parameter passing should be done through the subroutine call rather than through COMMON blocks.
  20. All common blocks which are shared between multiple subprograms are to be placed in files and #include'd into the program. The common blocks should have comments describing each variable in the common block so that new users will know what's there. No directory should be specified for the #include'd files, so that the -I option to the C preprocessor can be used to select the directory at will. If a common block is to be shared between C and Fortran code, use the existing code in the *.h files to implement the needed name equivalence.
  21. Avoid the use of static memory for initialization purposes. As more sections of CONGEN are implemented on parallel computers, making the subroutines reentrant is essential. Also, avoid the use of EQUIVALENCE and DATA statements in Fortran, since all storage referenced by these statements is allocated statically on the Iris.
  22. When using scanf functions in C, use only long int's or doubles for your I/O, and then convert to your type. This avoids the need to control for machine dependent variations in data lengths.