Personal tools
You are here: Home cm Wiki Fortran Style Guide
Views
Fortran Style Guide copied.

Fortran Style Guide

last edited 3 years ago by karl

Introduction

The purpose of this document is to outline the programming style all CMISS programmers should adopt when adding to/extending or otherwise altering Fortran code in CMISS.

Subroutines and Functions

The following is a sample subroutine (blank lines are to be included as well)

      SUBROUTINE SAMPLE(integer variable names in alphabetic order,
real variable names in alphabetic order,
complex variable names in alphabetic order,
character variable names in alphabetic order,
logical variable names in alphabetic order,
ERROR,*)

C#### Subroutine: SAMPLE
C### Description:
C### Provides an example for programmers to copy when creating new
C### subroutines. A description of the function of the subroutine
C### should be here.
C**** Created by <name> YYYY-MM-DD

IMPLICIT NONE
CHARACTER*(*) ROUTINENAME
PARAMETER(ROUTINENAME='SAMPLE')
INCLUDE 'cmiss$reference:aaaa00.cmn'
! Parameter List
INTEGER integer variables in parameter list in alphabetic order
REAL*8 real*8 variables in parameter list in alphabetic order
COMPLEX complex variables in parameter list in alphabetic order
CHARACTER character variables in parameter list in alphabetic order
LOGICAL logical variables in parameter list in alphabetic order
CHARACTER ERROR*(*)
! Local variables
INTEGER local integer variables in alphabetic order
REAL*8 local real*8 variables in alphabetic order
COMPLEX local complex variables in alphabetic order
CHARACTER local character variables in alphabetic order
LOGICAL local logical variables in alphabetic order
! Functions
INTEGER integer functions in alphabetic order
REAL*8 real*8 functions in alphabetic order
CHARACTER character functions in alphabetic order
LOGICAL logical functions in alphabetic order

CALL ENTERS(ROUTINENAME,*9999)

C Main body of code. NOTE: Variables that are not used should not be
C passed or declared as local.

IF(error condition) THEN
CALL FLAG_ERROR(0,'error condition not satisfied')
GOTO 9999
ENDIF

C More main body of code. There should be no tabs in the code.
C If you are not using emacs then you may need to customize your editor
C to prevent it indenting with tabs.

CALL EXITS(ROUTINENAME)
RETURN
9999 CALL ERRORIN(ROUTINENAME)
CALL EXITS(ROUTINENAME)
RETURN 1
END

Functions have a similar form with no ENTERS or EXITS calls:

      REAL*8 FUNCTION TEST(integer, real*8, complex, character, logical)

C#### Function: CALC_NUM_SITE
C### Type: REAL*8
C### Description:
C### Returns the length of a piece of string.

IMPLICIT NONE
Variable declarations as for subroutines

code
TEST=RP-DF

RETURN
END

Note: All routines should have a 1 line description at the top of the module. e.g.

C###  Routine: TEST (fn) solves NP-complete problems in linear time
C### Routine: SAMPLE solves NP-complete problems in constant time

The routines in modules should be separated into groups of block data units, then functions, then subroutines, sorted alphabetically within each group.

Commenting Styles

C***  For any comment that should stand out

C??? For any queries

C!!! For caution remarks.
C!!! e.g. suspected bugs, temporary additions, quick hacks (!)

C PJH 2002-05-29: For major alterations, code deletions

IF(INLINE_COMMENT) THEN ! Inline comments
ENDIF

C For all other comments

These last two styles are flexible. In general, use '!' for non-intrusive comments and 'C' for more visual comments.

When major new variables are introduced the commenting style described in documentation comment format should be used.

All IF statements using codes or flags should be commented. e.g.

      IF(KTYP26.EQ.1) THEN ! Optimising wrt to material parameters
C Statements...
ENDIF

DO loop format

Use lower case for loop variables. e.g.
      DO ng=1,NGT(nb)
A(ng)=B(ng)
ENDDO !ng

Indicate close of loops with a comment (as above).

DO loop counters should be INTEGER and not REAL or DOUBLE PRECISION variables.

IF statement format

      IF(...) THEN
ELSE IF(...) THEN
ENDIF !...

Indicate close of conditionals with a comment (as above).

General

  • All output should be less than 90 columns.
  • All indentation is by 2 spaces, not tabs. If you are using nedit as an editor you will need to edit the preferences so that it does not use tabs for indentation.
  • All code lies within 72 columns, and all comments where possible.
  • To indicate continuation of the previous line, use `&' as the character in the 6th column. The code on continued lines should be indented by 2 spaces more than the code on the first line of the statement.
  • All real constants should be explicitly stated as double precision. Use a small letter `d'. e.g. 0.0d0 not 0. or 0.0
  • All numerical constants or tolerances generally used should be in symbolic form and defined in a common block, initialized in a block data unit. e.g.
          A=2.0d0*PI
    IF(DABS(SUM).LT.ZERO_TOL) SUM=0.0d0
  • String literals should not span lines. If a long string is required use the concatenation operator to join strings across lines. e.g.
          LONG_STRING='If this string was one literal, spread across two '//
    & 'lines, it would be unclear how many spaces were in the middle.'
    IF(DABS(SUM).LT.ZERO_TOL) SUM=0.0d0
  • Multiple local variables should be like nn1,nn2 not n1n,n2n.
  • Initialization of common block variables must NOT be done using DATA statements in procedures or functions; use a block data unit.
  • When declaring an array, the dimensions should not be split across more than one line.

CM CMGUI Link Code

In order to keep the link between CM and CMGUI up to date, it is necessary to include ``house-keeping'' code inside CM. Currently, this is only implemented for nodes, although in the future it can be expected to be extended to include elements, basis functions, etc. When creating or destroying nodes, it is necessary to call either NODE_CREATE or NODE_DESTROY. These subroutines take only the node number (i.e. np) of the particular node.
      CALL NODE_CREATE(np,ERROR,*9999)
or
      CALL NODE_DESTROY(np,ERROR,*9999)

Whenever you write (or modify) code that modifies nodes (i.e. nodal values or the actual fields that are stored at the node), then it is necessary to add a call to the subroutine NODE_CHANGE. This takes the node number np to be changed, and whether or not the structure of the node changes. i.e.

      CALL NODE_CHANGE(np,.TRUE.,ERROR,*9999)