It is recommended that all CCSM components follow a coding convention. The goal is to create code with a consistent look and feel so that it is easier to read and maintain. To date, no conventions have been specified which apply across all CCSM components. Conventions have been defined for the atmospheric model and are included below.
This section defines a set of specifications, rules, and recommendations for the coding of the Community Atmospheric Model (CAM). The purpose is to provide a framework that enables users to easily understand or modify the code, or to port it to new computational environments. In addition, it is hoped that adherence to these guidelines will facilitate the exchange and incorporation of new packages and parameterizations into the model. Other works which influenced the development of this standard are "Report on Column Physics Standards" (http://nsipp.gsfc.nasa.gov/infra/) and "European Standards For Writing and Documenting Exchangeable Fortran 90 Code" (http://nsipp.gsfc.nasa.gov/infra/eurorules.html).
integer :: i,j,k ! Spatial indices
real(r8), dimension(plond,plev), intent(in) :: &
array1, &! array1 is blah blah blah
array2 ! array2 is blah blah blah
Note that the f90 standard defines a limit of 39 continuation lines.
Code lines which are continuation lines of assignment statements must begin to the right of the column of the assignment operator. Similarly, continuation lines of subroutine calls and dummy argument lists of subroutine declarations must have the arguments aligned to the right of the "(" character. Examples of each of these constructs are:
a = b + c*d + ... + &
h*g + e*f
call sub76 (x, y, z, w, a, &
b, c, d, e)
subroutine sub76 (x, y, z, w, a, &
b, c, d, e)
call linemsbc (u3(i1,1,1,j,n3m1), v3(i1,1,1,j,n3m1), t3(i1,1,1,j,n3m1), &
q3(i1,1,1,j,n3m1), qfcst(i1,1,m,j), xxx)
subroutine linemsbc (u, v, t, &
q, qfcst, xxx)
!
! Describe what is going on
!
Key features of this style are 1) it starts with a "!" in column 1; 2) The text starts in column 3; and 3) the text is offset above and below by a blank comment line. The blank comments could just as well be completely blank lines (i.e. no "!") if the developer prefers.
Use of the operators <, >, <=, >=, ==, /= is recommended instead of their deprecated counterparts .lt., .gt., .le., .ge., .eq., and .ne. The motivation is readability.
The second condition in which it is desirable to put multiple routines in a single file is when they are "CONTAIN"ed in a module for the purpose of providing an implicit interface block. This type of construct is strongly encouraged, as it allows the compiler to perform argument consistency checking across routine boundaries. An example is:
file 1:
subroutine driver
use mod1
real :: x, y
...
call sub1(x,y)
call sub2(y)
return
end subroutine
file 2:
module mod1
private
real :: var, var2
public sub1, sub2
contains
subroutine sub1(a,b)
...
return
end subroutine
subroutine sub2(a)
...
return
end subroutine
end module
The number, type, and dimensionality of the arguments passed to sub1 and sub2 are automatically checked by the compiler.
The final reason to store multiple routines and their data in a single module is that the scope of the data defined in the module can be limited to only the routines which are also in the module. This is accomplished with the "private" clause.
If none of the above conditions hold, it is not acceptable to simply glue together a bunch of functions or subroutines in a single file.
Note that by implication multiple modules are not allowed in a single file.
The use of common blocks is deprecated in Fortran 90 and their continued use in the CCM is strongly discouraged. Modules are a better way to declare static data. Among the advantages of modules is the ability to freely mix data of various types, and to limit access to contained variables through use of the ONLY and PRIVATE clauses.
!BUGS: !SEE ALSO: !SYSTEM ROUTINES: !FILES USED: !REMARKS: !TO DO: !CALLING SEQUENCE: !CALLED FROM: !LOCAL VARIABLES:
These keywords may be used at the developer's discretion.
Prologue for Functions and Subroutines
If the function or subroutine is included in a module, the keyword !IROUTINE should be used instead of !ROUTINE.
!-----------------------------------------------------------------------
! BOP
!
! !ROUTINE: <Function name> (!IROUTINE if the function is in a module)
!
! !INTERFACE:
function <name> (<arguments>)
! !USES:
use <module>
! !RETURN VALUE:
implicit none
<type> :: <name> ! <Return value description>
! !PARAMETERS:
<type, intent> :: <parameter> ! <Parameter description>
! !DESCRIPTION:
! <Describe the function of the routine and algorithm(s) used in
! the routine. Include any applicable external references.>
!
! !REVISION HISTORY:
! YY.MM.DD <Name> <Description of activity>
!
! EOP
!-----------------------------------------------------------------------
! $Id: code_conv_cam.tex,v 1.3 2001/06/19 21:44:14 kauff Exp $
! $Author: kauff $
!-----------------------------------------------------------------------
Prologue for a Module
!-----------------------------------------------------------------------
! BOP
!
! !MODULE: <Module name>
!
! !USES:
use <module>
! !PUBLIC TYPES:
implicit none
[save]
<type declaration>
! !PUBLIC MEMBER FUNCTIONS:
! <function> ! Description
!
! !PUBLIC DATA MEMBERS:
<type> :: <variable> ! Variable description
! !DESCRIPTION:
! <Describe the function of the module.>
!
! !REVISION HISTORY:
! YY.MM.DD <Name> <Description of activity>
!
! EOP
!-----------------------------------------------------------------------
! $Id: code_conv_cam.tex,v 1.3 2001/06/19 21:44:14 kauff Exp $
! $Author: kauff $
!-----------------------------------------------------------------------
Prologue for a Header File
!-----------------------------------------------------------------------
! BOP
!
! !INCLUDE: <Header file name>
!
! !DEFINED PARAMETERS:
<type> :: <parameter> ! Parameter description
! !DESCRIPTION:
! <Describe the contents of the header file.>
!
! !REVISION HISTORY:
! YY.MM.DD <Name> <Description of activity>
!
! EOP
!-----------------------------------------------------------------------
! $Id: code_conv_cam.tex,v 1.3 2001/06/19 21:44:14 kauff Exp $
! $Author: kauff $
!-----------------------------------------------------------------------
subroutine sub1 (x, y, z)
implicit none
real(r8), intent(in) :: x
real(r8), intent(out) :: y
real(r8), intent(inout) :: z
y = x
z = z + x
return
end
The term "package" in the following rules refers to a routine or group of routines which takes a well-defined set of input and produces a well-defined set of output. A package can be large, such as a dynamics package, which computes large scale advection for a single timestep. It can also be relatively small, such as a parameterization to compute the effects of gravity wave drag.
When exceptions to the above rule apply, (i.e. routines are required by a package which are not f90 intrinsics or part of the package itself) the required routines which violate the rule must be specified within the package.
subroutine sub
logical first/.true./
if (first) then
first = .false.
<set time-invariant values>
end if
integer, parameter :: r8 = selected_real_kind(12)
integer, parameter :: i8 = selected_int_kind(13)
Thus, any variable declared real(r8) will be of sufficient size to maintain 12 decimal digits in their mantissa. Likewise, integer variables declared integer(i8) will be able to represent an integer of at least 13 decimal digits. Note that the names r8 and i8 defined above are meant to reflect the size in bytes of variables which are subsequently defined with that "kind" value.
real(r8) :: arr(1)
where "arr" is an input argument into which the user wishes to index beyond 1. Use of the (*) construct in array dimensioning to circumvent this problem is forbidden because it effectively disables array bounds checking.
The preferable mechanism for dynamic memory allocation is automatic arrays, as opposed to ALLOCATABLE or POINTER arrays for which memory must be explicitly allocated and deallocated. An example of an automatic array is:
subroutine sub(n)
real :: a(n)
...
return
end
The same routine using an allocatable array would look like:
subroutine sub(n)
real, allocatable :: a(:)
allocate(a(n))
...
deallocate(a)
return
end
Hard-coded numbers should never be passed through argument lists. One good reason for this rule is that a compiler flag, which defines a default precision for constants, cannot be guaranteed. Fortran 90 allows specification of the precision of constants through the "_" compile-time operator (e.g. 3.14_r8 or 365_i8). So if you insist on passing a constant through an argument list, you must also include a precision specification. If this is not done, a called routine which declares the resulting dummy argument as, say, real(r8) or 8 bytes, will produce erroneous results if the default floating point precision is 4 byte reals.