User Tools

Site Tools


dev:codingconventions

Coding Conventions

Stick to the standard

  • Code enabled by default should be standard Fortran 2008 [-std=f2008] and C99 [-std=c99]
  • OpenMP code should follow version 3.X of the standard
  • MPI should should follow version 3 of the standard
  • Extended functionality should match POSIX and 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.
    • always use REAL() with KIND parameter, i.e. r = REAL(i, KIND=dp).
    • avoid FLOAT() in favour of REAL(, KIND=dp).
    • 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]. 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

Always prefer built-in (intrinsic) functions instead of hand-coded routines since they usually include extra numerical checks to avoid intermediate under- or overflow while still performing optimally. Examples:

  • NORM2(x) instead of SQRT(x(1)**2 + x(2)**2 + x(3)**2)
  • DOT_PRODUCT(x, x) instead of x(1)**2 + x(2)**2 + x(3)**2
  • DOT_PRODUCT(x, y) instead of x(1)*y(1) + x(2)*y(2) + x(3)*y(3)

For many common operations there exist wrappers in CP2K to prevent usage errors and to allow for central redirections, i.e. avoid to use direct calls to external libraries in CP2K

  • 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 fft_lib.F instead of calling FFT (any library) 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
dev/codingconventions.txt · Last modified: 2020/08/21 10:15 by 127.0.0.1