= PALM coding rules = '''Why to follow some standards?'''\\\\ Because everyone has her/his own programming style, sort of a dialect, making it difficult for other developers to understand, extend, debug, or optimize the code. So what do we do? We learn and apply the coding standard to make PALM more easily readable for all current and future developers. Let's all work on that together. We are aware that the PALM core doesn't completely comply with the following rules yet, but we are working on that. \\\\ Formulated rules and specifications are based on the specifications given for the ocean dynamics model [add-new-link-to NEMO]. Other work that influenced the development of this standard are [add-link Community Climate System Model], [add-link Software Developer's Guide], [add-link Report on Column Physics Standards], and [add-link European Standards For Writing and Documenting Exchangeable FORTRAN 90 Code]. \\ = (1) General hints & requirements = == (1.1) Language == * FORTRAN-2003 standard (all FORTRAN compilers can handle this, FORTRAN-2008 standard not yet supported by all compilers) * Use English language only * Use ASCII characters only * Use SI units as physical units * '''NO''' use of tab characters\\(only exception: Makefile) || '''AVOID''' || '''USE INSTEAD''' || || COMMON blocks || ... || == (1.2) Implementing new features to PALM == * module structure (template) * available interfaces in the PALM core \\ = (2) Documenting & commenting = \\ = (3) Naming conventions = == (3.1) Use of lower & upper case letters == * '''Upper case:''' FORTRAN keywords and intrinsic functions or routines, e.g. * SUBROUTINE, MODULE, etc. * INTEGER, REAL, PARAMETER, etc. * DO, ENDDO, IF, ELSE, etc. * READ, WRITE, CALL, etc. * MPI_ALLTOALL (MPI functions), NF90_CREATE (NetCDF functions), etc.\\ * '''Lower case:''' Everything else! \\ = (4) Formatting & sorting = Line length limit: '''80''' characters (soft) | '''120''' characters (hard). The absolute limit for compilers is '''132''' characters! == (4.1) Indentation, spaces & line breaks == '''__General module/subroutine structure''' (see Fig. 1) {{{ #!div style="align:'left'; width: 450px; border: 0px solid; float:right" [[Image(rules_indent_general.png, 450px, right, margin-right=2, margin-top=0, border=0)]]\\ '''Fig. 1''' Indentation example with highlighted whitespaces. Click to enlarge. }}} * '''0 whitespace''' in front of pre-processor directives * '''1 whitespace''' before MODULE, CONTAINS, SUBROUTINE (= first indentation level) * '''+3 whitespaces''' for all following indentation levels \\(only exception: ONLY list in USE statements '''+4 whitespaces''')\\\\ * '''1 whitespace''' between individual strings, and between strings and symbols/numbers * '''1 whitespace''' before and after all operators (+, -, *, =, /)\\(exception: '''0 whitespace''' for ** (exponent operator, e.g. u**2) and operators within expressions for array indices, e.g. u(i+1)) * '''1 whitespace''' after ''','''\\(only exception: '''0 whitespace''' between array dimensions, e.g. (i,j,k)) * '''1 whitespace''' before '''::''' \\(at minimum, see Sect. [#align Alignment]) * '''2 whitespace''' after ''':''' and '''::'''\\\\ * '''1 blank line''' between enclosed/unrelated blocks of instructions, assignments, clauses, statements, etc. * '''2 blank lines''' in front of each SUBROUTINE within a MODULE * place '''&''' character for line continuation at position 80 (minimum), max at position 120\\('''Note:''' FORTRAN-2003 defines a limit of 39 continuation lines) '''__Whitespaces between brackets''' (see Fig. 1) * '''0 whitespace''' between string and '''(''' * '''1 whitespace''' after '''(''' and before ''')'''\\(only exception: '''0 whitespace''' for brackets containing array indices) \\\\\\\\\\\\\\\\\\\\\\\\ '''__Whitespaces in DO loops, IF blocks, CASE structures''' (see Fig. 2) {{{ #!div style="align:'left'; width: 450px; border: 0px solid; float:right" [[Image(rules_indent_loops.png, 450px, right, margin-right=2, margin-top=0, border=0)]]\\ '''Fig. 2''' Indentation & whitespaces in loops. Click to enlarge. }}} * In general: '''1 whitespace''' everywhere and '''3 whitespace''' for each indentation level * But: '''2 whitespace'''\\ * between '''DO''' and '''loop index''' * after '''IF ( )''' --> see {{{CALL}}}, {{{THEN}}} * in front of and after logical operators (e.g. '''.OR.''', see [#operators list of allowed operators]) \\\\\\\\\\ == (4.2) Alignment == (see Fig. 3) {{{ #!div style="align:'left'; width: 450px; border: 0px solid; float:right" [[Image(rules_align.png, 450px, right, margin-right=2, margin-top=0, border=0)]]\\ '''Fig. 3''' Alignment example. Click to enlarge. }}} * Block-wise alignment of continuation line mark '''&''' * Alignment of ONLY lists * At least block-wise alignment for same type/group of declaration statement * Alignment of message_string values * Alignment of expressions between brackets (e.g. in '''IF ( ) THEN''' or in argument list of subroutine calls) * Alignment of related code, e.g. in complex equations or setting of initial values for variables '''(missing in png)''' \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ == (4.3) Alphabetical sorting == * Members in ONLY lists of USE statements (see e.g. Fig. 3) * Parameters in NAMELISTS (see e.g. initialization_parameters NAMELIST in parin.f90) * Declaration types (first CHARACTERs, then INTEGERs, etc., see Fig. 3) * Variables in declaration statements (see Fig. 3) == Commenting & documentation == Documentation consists of putting information both internally and externally of the source code. Comments should give a good idea of what the code does and where to look for any special activity. PALM supports the use of Doxygen, a tool for generating documentation and flow charts from annotated source code. This requires some special formatting, as described below. '''File header section''' * todos, notes, author,.... * Declaration !< Description * see file header * @author etc. * MODULE/SUBROUTINE description !> '''Inside the code''' * Examples.png.. * Avoid superfluous comments, such as\\ {{{a = a + 1 ! Increment a by one}}} * Example for multiple-line declaration comment ! !-- Text starts at same position as indented code to be described '''Outside the code''' You are in the middle of it. We have an extensive online documentation wiki embedded into a [link-to trac] project management system, directly connected to the svn repository, allowing to [browse the PALM code] @ all its former and of course current revision in a web-based environment. Your carefully developed code can only be used, if there is a documentation that tells the PALM user how to use and steer the feature. = (X) Coding = == (X.1) Variable & parameter declarations == * clear structure in declaration part (USE, IMPLICIT NONE, declarations, SAVE, PRIVATE, PUBLIC list_of_public_variables) * for long lists form groups * one declaration line per variable == Naming conventions == Use clear, unambiguous naming in '''lower-case letters''', with individual words separated by underscore. * MODULE/SUBROUTINE: name is constructed (if applicable) as verb followed by object, e.g.\\ {{{land_surface_model}}} or {{{read_restart_data}}} * MODULE/SUBROUTINE files: .f90 --> MODULE ... END MODULE (simplification of Make process) * Functions: names provide information about the value it is expected to return, e.g.\\ {{{solar_zenith_angle( )}}} * Variables & constants: names are readable, memorable and descriptive * LOGICAL (boolean) variables: give names that imply\\ {{{TRUE}}} or {{{FALSE}}} '''PROHIBITED:''' * Names that may clash with the operating system or language intrinsics, e.g.\\ {{{read( )}}} or {{{access( )}}} * One-letter variable names (only allowed for basic flow variables like velocities (u, v, w), humidity (q) or turbulent kinetic energy (e), as well as loop or other counters (e.g. i, j, k)) == Allowed operators == * Use /=, <, <=, ==, >, >=, etc. as relational operators instead of .GE., .LT., etc. * Use .AND., .OR., .NOT. as logical operators == Preprocessor directives == PALM works with the C Pre-Processor (CPP), available on any UNIX platform, and covered my most FORTRAN compilers. Only few pre-processor directives are used in PALM, and activated by the {{{%cpp_options}}} variable in the .palm.config. file. Table or link to other page || '''flag''' || '''description''' || || __parallel || .... || Use this syntax (starting at first character of a line): {{{#if defined(__parallel) some code #endif}}} together with the standard logical operators '''!''' (instead of .NOT.), '''||''' (instead of .OR.), '''&&''' (instead of .AND.), e.g. {{{#if ! defined(__parallel) && (__netcdf)}}} == File header == * Files always start with a doxygen-readable comment line including the FORTRAN file name. * This is followed by the license section. If your code originates from another model, please clarify the license and permissions for this code to enter the PALM model system. It might be necessary in that case to add some more information to this header. * The revisions section will later include short notes of the changes applied to a specific svn revision of this file. The {{{$Id$}}} string is required so that svn knows to automatically generate the respective time stamp for a revision (see existing SOURCE files).\\ --> [link-to How to initialize Id keyword in svn] * mention revision history and link to [How to commit] * Finally, involved authors are included, followed by a description of the purpose and functions of the module. If necessary, TODOs, notes and known bugs can be added. The "!>" indicate doxygen-readable comment lines, the "@" marks doxygen variables. == (X) Code structure == * one module per file (only exception: modules.f90) * clarify program entities, i.e. use {{{SUBROUTINE ... END SUBROUTINE }}}, same holds for INTERFACE, MODULE, PROGRAM ------------------------- == Error messages == * Use message routine (explain parameters here...) * I/O error conditions via IOSTAT (is this fail-safe for different compilers?) == Code optimization == ??? == (X) Final steps == '''Good practice''' * no warning/error message should remain during compile (also try debug options) '''Clean up''' * PRINT/WRITE statements for debugging * Check that all parameters are used