Met Office logo

Fortran coding standard for FCM

Last updated: 28 November 2006

Met Office
FitzRoy Road, Exeter
Devon, EX1 3PB
United Kingdom

© Crown copyright 2006. All rights reserved.

Questions regarding this document or permissions to quote from it should be directed to the IPR Manager.

Contents

Main contents:

  1. Introduction
  2. Programming Fortran for the FCM build system
  3. Programming Fortran in general
  4. Program templates

1. Introduction

Fortran is the standard programming language at the Met Office for developing scientific and research applications, in particular, for programs running on the supercomputers. This document describes some guidelines that should be followed by developers when writing Fortran code, especially for code in systems hosted by FCM.

2. Programming Fortran for the FCM build system

2.1 General

To get the most out of the FCM build system, you should follow these guidelines when you develop your code:

  1. Each source file should contain one and no more than one top level program unit, (such as a PROGRAM, a standalone SUBROUTINE/FUNCTION or a MODULE). All top level standalone program units in a source tree should be uniquely named. ("Top level" means a standalone program unit that is compilable independently, i.e. this rule does not restrict the naming and placements of sub-programs in a CONTAINS section.) FCM may fail to set up the dependency tree of your source correctly if you do not follow this rule.

    A clash of program unit names happens most often when you have multiple versions of the same program unit in the same source tree. You should design your code to avoid this situation. If it is not possible to do so, you may have to use a pre-processor to ensure that there is only one copy of each program unit in the source tree. Another situation where clashes of program unit names may occur is when you are developing code that is shared between several projects. In this case, you may want to agree with the other projects a naming convention to define a unique namespace for program units in each project. (E.g. some projects at the Met Office have adopted a naming convention such that all shared program units in a project are named with a unique prefix.)

  2. All code should be written using the free source form. (At Fortran 95, the free source form can have a maximum of 132 characters per line, and up to 39 continuations in a Fortran statement.) The fixed source form is obsolete, and is not supported by the interface file generators used by FCM.
  3. An interface should be provided when calling a SUBROUTINE or a FUNCTION. Not only is this considered good practice, it also allows FCM to determine the dependency relationship of your source files. An interface can be provided in these ways:
    Internal sub-program
    Place sub-programs in the CONTAINS section of a standalone program unit. There are two advantages for this approach. Firstly, the sub-programs will get an automatic interface when the container program unit is compiled. Secondly, it should be easier for the compiler to provide optimisation when the sub-programs are internal to the caller. The disadvantage of this approach is that the sub-programs are local to the caller, and so they cannot be called by other program units. Therefore, this approach is only suitable for small sub-programs local to a particular program unit.

    Note: One way to share a sub-program unit between several top level program units is to make use of the Fortran INCLUDE statement. You can write the sub-program unit in a separate file and place it in the CONTAINS section of different program units using INCLUDE statements. The disadvantage of this approach is that when the program is compiled, a copy of the sub-program unit will be embedded within each of the top level program units. This may lead to an increase in size of the executable, and so this approach is still only suitable for small sub-programs local to a small number of program units.

    Example:

    In the file "sub_prog.inc":
    SUBROUTINE sub_prog (some, arg)
    ! Some declarations ...
    ! Some executable statements ...
    END SUBROUTINE sub_prog
    
    In the file "bar.f90":
    SUBROUTINE bar (more, arg)
    ! Some declarations ...
    ! Some executable statements ...
    CALL sub_prog (some, arg)
    ! More executable statements ...
    CONTAINS
      INCLUDE 'sub_prog.inc'
    END SUBROUTINE bar
    
    Module procedures
    Place sub-programs in the CONTAINS section of a MODULE. Again, the sub-programs will have automatic interfaces when the MODULE is compiled. If you give the sub-programs the PUBLIC attribute (which is the default), you will be able to call them from anywhere using the current MODULE. You will also gain all the advantages offered by a MODULE. (E.g. a MODULE will allow you to design your code in a more object-oriented manner.) However, MODULE dependency can have an impact on the efficiency of incremental compilations. For example, if you modify items that are local to the MODULE, it is very difficult for the build system to detect that your change does not affect program units using the MODULE, so the build system will end up compiling the MODULE and all the program units that use it.

    Example:

    In the file "my_mod.f90":
    MODULE my_mod
    ! Some module declarations
    CONTAINS
      SUBROUTINE sub_prog (some, arg)
      ! Some declarations ...
      ! Some executable statements ...
      END SUBROUTINE sub_prog
    END MODULE my_mod
    
    In the file "foo.f90":
    SUBROUTINE foo (some, arg)
    USE my_mod, ONLY: sub_prog
    ! Some declarations ...
    ! Some executable statements ...
    CALL sub_prog (some, arg)
    ! More executable statements ...
    END SUBROUTINE foo
    
    Interface files
    For each source file containing a standalone SUBROUTINE or FUNCTION, FCM generates a file containing the interface of the SUBROUTINE or FUNCTION. By default, the generated file is named after the original source file, but with the file extension replaced by "*.interface". In the specification section of the caller routine, you will then be able to declare the interface using a Fortran INCLUDE statement to include the interface file. This type of INCLUDE statement is detected automatically by FCM, which will use it to set up the dependency tree.

    The advantage of using an interface file is that the caller is now dependent on the interface file, rather than the SUBROUTINE or FUNCTION itself. If you change the SUBROUTINE or FUNCTION without modifying its interface, the build system will not re-compile the caller in incremental build, (but it will be intelligent enough to re-link the executable with the updated object).

    Note: By default, an interface file is named after the original source file. Bearing this in mind, it is worth noting that file names in a Unix/Linux system are case-sensitive, and so the interface file name declared by your INCLUDE statement is also case sensitive. If you use an incorrect case in the INCLUDE statement, the dependency tree will be set up incorrectly and the compilation will fail. Another problem is that if you do not name your file after the program unit, the dependency tree will be wrong. To avoid this problem, it is recommended that all source files are named in lower case after the program units they contain. (Alternatively, you can use the TOOL::INTERFACE option in the FCM build configuration file to allow you to alter the default behaviour so that the interface file is named after the "program" unit in lowercase. We may alter FCM in the future so that this will become the default. In the mean time, it is highly recommended that you use this option and design your new code accordingly.)

    Example:

    In the file "sub_prog.f90":
    SUBROUTINE sub_prog (some, arg)
    ! Some declarations ...
    ! Some executable statements ...
    END SUBROUTINE sub_prog
    
    In the file "egg.f90":
    SUBROUTINE egg (some, arg)
    ! Some declarations ...
    INCLUDE 'sub_prog.interface'
    ! More declarations ...
    ! Some executable statements ...
    CALL sub_prog (some, arg)
    ! More executable statements ...
    END SUBROUTINE egg
    
    Interfaces in a module
    There is also a half-way house approach between the second and the third options. You can have a dedicated MODULE where a large number of INCLUDE interface file statements are placed. Other program units get their interfaces by importing from this MODULE. A major disadvantage of this approach is that the sub-programs with their interfaces declared within this MODULE will not be able to call any other sub-programs declared within the same MODULE, as it will run into a cyclic dependency problem. Another disadvantage is that if an interface changes, the MODULE and all program units depending on the MODULE will have to be re-compiled, even though the change may be unrelated to some or all of these program units. For these reasons, this approach is only good if you have a bundle of sub-programs that have relatively stable interfaces and are very much independent of one another.

    Note: a similar approach can be useful when you have a library of legacy or external code. In this situation, you will simply declare the interfaces for all the library sub-programs in the MODULE. Any programs that call sub-programs within the library can then import their interfaces by using the MODULE.

    Example:

    In the file "my_i_mod.f90":
    MODULE my_i_mod
    ! Some declarations
    INCLUDE 'sub_prog.interface'
    ! More declarations
    END MODULE my_i_mod
    
    In the file "ham.f90":
    SUBROUTINE ham (some, arguments)
    USE my_i_mod, ONLY: sub_prog
    ! Some declarations ...
    ! Some executable statements ...
    CALL sub_prog (some, arguments)
    ! More executable statements ...
    END SUBROUTINE ham
    

    FCM also supports the use of a "! DEPENDS ON" directive for users to specify a dependency from within a source file. This feature is documented in the Further dependency features sub-section of the FCM user guide. However, it is worth noting that this method is only included in FCM to support legacy code. It is not a feature recommended for new code, and its use should be gradually phased out from existing code.

  4. Arguments and local variables should be declared in different statements. It makes your declaration clearer, and it is friendlier to the interface file generator.
    Common practice Better approach
    SUBROUTINE foo (a, b, c)
    
    INTEGER :: a, b, c, i, j, k
    
    ! ...
    
    END SUBROUTINE foo
    
    SUBROUTINE foo (a, b, c)
    
    INTEGER :: a, b, c
    
    INTEGER :: i, j, k
    
    ! ...
    
    END SUBROUTINE foo
    
  5. Use the ONLY clause in a USE <module> statement to declare all imported symbols (i.e. parameters, variables, functions, subroutines, etc). This makes it easier to locate the source of each symbol, and avoids unintentional access to other PUBLIC symbols within the MODULE. It is also friendlier to the compiler and the interface file generator, as they will not have to import modules and symbols that are unnecessary.
  6. In its default settings, FCM recognises the following file extensions as Fortran free format source files:

2.2 Use of C pre-processor with Fortran

We do not recommend the use of C pre-processor with Fortran. However, it is acknowledged that there are some situations when it is necessary to pre-process Fortran code. FCM supports pre-processing in two ways. Pre-processing can be left to the compiler or it can be done in a separate early stage of the build process. A separate pre-process stage can be useful if pre-processing changes any of the following in a program unit:

However, using a separate pre-process stage is not the best way of working, as it adds an overhead to the build process. If your code requires pre-processing, you should try to design it to avoid changes in the above.

In practice, the only reasonable use of C pre-processor with Fortran is for code selection. For example, pre-processing is useful for isolating machine specific libraries or instructions, where it may be appropriate to use inline alternatives for small sections of code. Another example is when multiple versions of the same procedure exist in the source tree and you need to use the pre-processor to select the correct version for your build.

Avoid using the C pre-processor for code inclusion, as you should be able to do the same via the Fortran INCLUDE statement. You should also avoid embedding pre-processor macros within the continuations of a Fortran statement, as it can make your code very confusing.

3. Programming Fortran in general

The guidelines in this section are recommended practices for programming Fortran in general. These are guidelines you should try to adhere to when you are developing new code. If you are modifying existing code, you should adhere to its existing standard and style where possible. If you want to change its standard and style, you should seek prior agreements with the owner and the usual developers of the code. Where possible, you should try to maintain the same layout and style within a source file, and preferably, within all the source code in a particular project.

When reading these guidelines, it is assumed that you already have a good understanding of modern Fortran terminology. It is understood that these guidelines may not cover every aspect of your work. In such cases, you will be a winner if you use a bit of common sense, and always bearing in mind that some other people may have to maintain the code in the future.

Always test your code before releasing it. Do not ignore compiler warnings, as they may point you to potential problems.

3.1 Layout and formatting

The following is a list of recommended practices for layout and formatting when you write code in Fortran.

3.2 Style

The following is a list of recommended styles when you write code in Fortran.

3.3 Fortran features

The following is a list of Fortran features that you should use or avoid.

4. Program templates

The following is a basic template for a SUBROUTINE:

SUBROUTINE <subroutine_name> (<arguments>, ...)

! Description:
!   <Explain the usage of the subroutine and what it does.>
!
! (c) Crown copyright Met Office. All rights reserved.
! For further details please refer to the file COPYRIGHT.txt
! which you should have received as part of this distribution.
! ------------------------------------------------------------------------------

! Modules
<module declarations, each with a list of imported symbols>

IMPLICIT NONE

! Arguments:
<arguments with INTENT (  OUT)>
<arguments with INTENT (INOUT)>
<arguments with INTENT (IN   )>

! Local declarations:
<parameters, derived data types, variables, etc>

! INTERFACE blocks
<INCLUDE interface blocks for external procedures>
<interface blocks for procedure and operator overloading>

!-------------------------------------------------------------------------------

<... subroutine executable statements>

!-------------------------------------------------------------------------------

CONTAINS

  <sub-programs>

END SUBROUTINE <subroutine_name>

Note: