User Tools

Site Tools


dev:codingconventions

This is an old revision of the document!


Coding Conventions

Stick to the standard

  • Code enabled by default should be standard Fortran2003 [-std=f2003]
  • Avoid using new OOP aspects, because compilers do not yet support them well enough.
  • OpenMP code should follow the version 3.X of the standard
  • MPI should should follow the version 2.X of the standard
  • Extended functionality should match POSIX / LSB.

Write explicit code

  • Every USE-statement should have an ONLY:-clause, which lists the imported symbols [-Wuse-without-only].
  • Every OMP PARALLEL-region should declare default(none).
  • Every static variable should be marked with the SAVE attribute.
  • Every Fortran module should contain the line IMPLICIT NONE [-fimplicit-none].
  • Every conversion that might change value should be explicit [-Wconversion]. Rationale:
    • INTEGER i=4.9999, i.e. i=INT(4.9999) implies i==4. Use NINT(4.9999) as appropriate.
    • natom*natom, nrow_global*ncol_global overflows INT(KIND=4) for large simulations.
    • the global number of grid points (pw_grid_type%ngpts,ngpts_cut) overflows INT(KIND=4) for large simulations.

Don't use poorly designed language features

  • Do not use the GOTO-statement. See also http://xkcd.com/292/ and 10.1145/362929.362947
  • Do not use left-hand-side (lhs) reallocations of allocatables [-Wrealloc-lhs-all]. Why?
  • Do not use FORALL constructs. Why?
  • Do not use OMP THREADPRIVATE variables.
  • Do not query the STAT from a DEALLOCATE, the Fortran runtime takes care.
  • Do not use RANDOM_NUMBER(), it's not consistent across different compilers.

Fight spaghetti code

There are two measure of defense against spaghetti code:

  1. Decoupling on the module and package level:
    • Every module should depend on as few other modules as possible.
    • Every package should depend on as few other packages as possible.
  2. Information hiding, also known as encapsulation.
    • External libraries should be wrapped within a single module or package.
    • Every module should hide its content by containing the line PRIVATE and only few public symbols.
    • Every package should hide its content by providing only a small public API through a single module.

Use existing infrastructure

For many common operation there exist wrappers in CP2K to prevent usage errors and to allow for central redirections.

  • Use the routines from cp_files.F instead of calling OPEN and CLOSE directly.
  • Use the routines from the full-matrix fm-package instead of calling BLAS or Scalapack directly.
  • Use the routines from message_passing.F instead of calling MPI directly.
  • Use the routines from machine.F to access architecture depended things like e.g. the working directory.
  • Don't use UNIT=* in WRITE or PRINT statements. Instead request a unit from the logger: iw=cp_logger_get_default_unit_nr() and write only if you actually received a unit: IF(iw>0) WRITE (UNIT=iw, ,,,).
  • Use CP2K's error-handling, instead of the STOP statement.

Remove dead code

  • Every line of code has to be compiled and maintained. Hence, unused variables and code poses an unnecessary burden and should be removed [-Wunused-variable -Wunused-but-set-variable -Wunused-dummy-argument].
  • Sometimes it is beneficial to keep debugging code around nevertheless. Such code should be put into a IF(debug_this_module)-block, with a parameter set to .FALSE.. This way the code will stay up-to-date and easily callable.

Format and document code

  • Each files should start with the official CP2K header.
  • Each .F file should contain either a PROGRAM or a single MODULE, whose name matches the filename.
  • Each module and routine should be annotated with Doxygen documentation.
  • Each preprocessor flag should start with two underscores and be documented in the INSTALL-file and added to the cp2k_flags function (cp2k_info.F).
  • The code should be formatted with the prettify-tool by running make -j pretty.

Write tests

Doxygen documentation

  • Every FUNCTION and SUBROUTINE should be preceded by a valid doxygen block.
  • The following keywords are required: \brief, \param (for each parameter), \retval (for functions)
  • The following keywords are optional: \note, \par, \date, \author
  • Please run make doxify to format your doxygen comments, or generate templates where none exist
  • See our doxygen pages for the result

Formatting conventions and auto-formatting (prettify)

Uniform formatting of CP2K source code will be enabled in the near future by a prettify script that is an almost complete auto-formatter for Fortran 90 source code. As a rule of thumb, developers should not worry about the format of their code and just let prettify do its magic by running make -j pretty. The chosen formatting conventions for CP2K are as follows:

  • Sorting and alignment of variable declarations and USE statements, removal of unused list entries.
  • Indentation with a relative width of 3 characters.
  • Line continuations are aligned with the previous opening delimiter (, [ or (/ or with an assignment operator = or =>. If none of the above is present, a default hanging indent of 3 characters is applied.
  • All operators are surrounded by exactly one whitespace character, except for arithmetic operators.
  • Removal of extraneous whitespace and consecutive blank lines.
  • Uppercase notation for all Fortran and OpenMP keywords.

The following formatting decisions are still manual and are never changed by prettify:

  • Positions of line breaks (except for variable declarations and USE statements).
  • No indentation of subsequent DO / IF statements that are aligned with each other.

There may be cases where manual alignment is preferred over the rules stated above. The following options for manual formatting are provided:

  • No automatic realignment of line continuations that are prefixed with an &.
  • No auto-formatting of lines to which a comment starting with !& is attached.
  • No auto-formatting of code blocks enclosed between two comment lines starting with !&< and !&>.

A few examples to illustrate how to deal with cases where auto-formatting produces unsatisfying results:

  • Reduce hanging indent by inserting linebreaks directly after assignment operator and opening delimiter:
! No:
long_result_var_name = long_function_name(arg_1, arg_2, &
                                          arg_3, arg_4, arg_5)+ &
                       foo
! Yes:
long_result_var_name = &
   long_function_name( &
      arg_1, arg_2, &
      arg_3, arg_4, arg_5)+ &
   foo
  • Avoid linebreaks in deeply nested expressions:
! No:
bessj0 = (r1+y*(r2+y*(r3+y*(r4+y* &
                            (r5+y*r6)))))/(s1+y*(s2+y*(s3+y* &
                                                       (s4+y*(s5+y*s6)))))
! Yes:
bessj0 = (r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))))/ &
         (s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))
  • Alignment by explicit bracketing:
! No:
foo = bar+foobar(x1, y1, z1)* &
      foobar(x2, y2, z2)* &
      foobar(x3, y3, z3)
! Yes:
foo = bar+(foobar(x1, y1, z1)* &
           foobar(x2, y2, z2)* &
           foobar(x3, y3, z3))
  • Special vertical alignment may require manual formatting:
! Auto-formatting:
align_me = [-1, 10, 0, &
            0, 1000, 0, &
            0, -1, 1]
! Manual alignment (!& disables whitespace formatting):
align_me = [-1,   10, 0, & !&
             0, 1000, 0, & !&
             0,   -1, 1] !&
! Alternatively:
!&<
align_me = [-1,   10, 0, &
             0, 1000, 0, &
             0,   -1, 1]
!&>
dev/codingconventions.1458133835.txt.gz · Last modified: 2020/08/21 10:14 (external edit)