Style conventions in Cloudy
Home Up C94.00 Other versions Revision history The future Acknowledgements Contacts, Mailing list Links Site map, search

 

Home
Up

 

Why a style convention?

A uniform style convention is essential for clarity and simplicity.  This is an essential matter of self-discipline that is at the core of successful development of large codes.  There are a countable infinity of different style conventions, and Cloudy uses exactly one of them.  This is simply the way it is.  Countless studies show the benefits of a following a single style convention throughout a large code.

Changes in the core logic of the code

Changes of the code's logic are documented by comments that have a predictable string giving the date as part of the comment.  This makes it possible to use a pattern searcher such as grep to find out why something changed at a particular time.  The style for a change to the code is

/* >>chng 99 aug 02 upper limit of loop was off by one */
/* for(i=0; i<ncell; ++i ) */
for(i=0; i<)ncell-1); ++i)

The essential ingredients are the string ">>chng" which denotes the start of a line describing the change.  Next comes a space and the last two digits of the year.  Another space is followed by the first three characters of the name of the month ALL in lower case.  After another space comes two digits that give the day of the month, from 01 through 31.  The remainder of the line is a comment that documents the change.  

The old code should be left in place by commenting it out whenever possilbe.  For one-line changes this can be done with /* */ style comments. Larger blocks of code should be commented out with the style

#if 0
#endif

Atomic and molecular data

Codes like Cloudy only exist because of the community of atomic and molecular physicists who make their data public.  Every calculation with Cloudy consumes millions of atomic cross sections and rate coefficients.  It is important that the fundamental atomic data be fully referenced.  

The style used makes it possible to use a pattern searcher like grep to automatically find data sources.   At the point in the code where the data are used, a comment in the form

/* >>refer c2 as Lennon, D.J., Dufton, P.L., Hibbert, A., Kingston, A.E. 1985, ApJ, 294, 200 */

The string ">>refer" identifies this as a reference.  Next comes the ion - CII in this example.  The type of data, one of as, cs, etc, follows.  Finally the actual reference in ApJ format completes the line. These four fields are separated by tabs.  This makes it possible for a perl script to generate a formatted list of atomic data sources.

Variable names

Cloudy is evolving towards a simple formulation of the Hungarian naming convention (Simonyi 1977).  In this convention the first few characters of a variable name indicate the type and function of that variable.  

Variable names and strong typing

In part, the naming convention used in the code today looks back to an under- appreciated advantage in the FORTRAN II and FORTRAN 66 languages - the fully implicit designation of variable types by the first letter of its name.  The naming convention forced by early versions of FORTRAN (integers begin with i-n, real numbers with other characters) is still useful since the type can be determined by a glance at the name.  This is used in the current code.

Integers

Integers begin with the characters i, j, k, l, m, or n.  
Counters begin with n.  Examples include nLevel or nLoop.
Loop indices are generally i, j, or k.  Sometimes they are counters.
Indices within arrays begin with ip.  Examples include ipContinuum or ipCIV1549.

Double or float variables

These begin with letters between a through h, and o through z.  Examples include PumpRate, DestRate, or CollisIoniz.  At this time the naming convention does not distinguish between floats and doubles.  Eventually the code will be totally double precision.  In some cases floating numbers naturally will have names beginning with one of the letters reserved for integers.  In this case a lower case x is used as the first character.  Examples include xJumpDown, xMoleDen.

Characters and strings

Character variables and strings begin with "ch".  Examples are chName or chReadInput.

Logical variables

These begin with "lg".  Examples are lgOK, lgDone.  These are of intrinsic type int.

Structure names

Variables with a common purpose are grouped together into structures.  For instance the electron density variable eden is an element of the structure phycon with the name phycon.eden.  The declaration for a structure occurs within an included file with the same name ending with ".h" - the phycon structure is in phycon.h.  This is where eden is defined since its full name is phycon.eden.

Braces

The format of braces consumes a staggering amount of debate but is important since the format must be followed consistently across the code for it to be instantly legible.  There are three major styles of braces:

Style 1;

if( a>0 )
{
    b = 0.;
}
else
{
    b = 1.;
}

Style 2:

if( a>0 )
    {
        b = 0.;
    }
else
    {
        b = 1.;
    }

Style 3:

if( a>0 ) {
    b = 0.; }
else {
    b = 1.;}

The code uses the first style.  Any one of the three could have been chosen, but the first one was chosen.  We must have the self-restraint to consistently follow this arbitrary choice.

Indention is tabbed out

Tab characters are used to make indention, rather than hard spaces.  There is one extra level of indention per set of braces.  The style is shown as the following

for( i=0; i<9; ++i )
{
(tab)for( i=0; i<9; ++i )
(tab){
(tab)(tab)for( i=0; i<9; ++i )
(tab)(tab){
(tab)(tab)(tab)code
(tab)(tab)}
(tab)}
}

which appears as

for( i=0; i<9; ++i )
{
    for( i=0; i<9; ++i )
    {
        for( i=0; i<9; ++i )
        {
            code
        }
    }
}

Broken code, trial code, new code, and code that needs to be fixed

Three routines are part of the global namespace, and can be called anywhere within the code, to indicate code that needs attention.  These are broken(), to indicate something that is broken, fixit(), to indicate something that needs to be fixed, and TestCode(), to indicate temporary test code.  Each of these sets a flag when it is called, so that the code will produce a comment at the end of the calculation, noting that this code is in place.  The call to the routine should be followed by a comment indicating the reason for the call, as in the following example:

broken();/* electron density solver disabled to trace temperature bug */

so that both the call and the reason for the call can be revealed by doing a string search on all files.

New code should have a call to CodeReview to make sure that the new code is reviewed either by someone else, or by the author several days after it was written.

Hit Counter
Last changed 04/05/03.
Return to the Cloudy Home Page.
Copyright 1978-2003 Gary J. Ferland