HowTo: LMDZ code guidelines

De LMDZPedia
Révision de 18 juillet 2024 à 11:53 par Abarral (discussion | contributions) ((WIP) very rough example)

(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à : navigation, rechercher
 /!\ This page is a WORK IN PROGRESS. Nothing in this page should be considered correct or consensual for now. /!\

Example code

Note: in this example, we added "meta-comments" indicated by !!

Note: of course, there's always exceptions to "Always", but they should systematically documented by a comment, with a proper explanation.


!! File: lmdz_mymodule.f90
!!         ^ all module files should start with their component name, (e.g. "lmdz")
!!                      ^ use ".f90" for all free-form files, unless they contain preprocessor directives (then use ".F90").

!! At the top of the file, we provide a comment to explain what this modules does
! implementation of my_useful_stuff.
! ----------------------------------

!! Unless specified otherwise, all files should contain a single module which encapsulates all their content
MODULE my_module
!!  ^ all Fortran keywords are in CAPS, everything else is in lowercase.
  USE my_other_module, ONLY: function_a, function_b
  !!                     ^ Always specify explicitely which functions you use from a module.

!!^ use indentation (2 spaces) to provide visual clarity

  IMPLICIT NONE; PRIVATE
  !!                ^ Always make your module private, and expose explicitely which functions are public
  !!    ^ Always use IMPLICIT NONE at the module-level
  PUBLIC my_var, my_subroutine

  REAL, PARAMETER :: my_var
  REAL            :: a, b, c, d, e, f
  !!               ^ use "::" even if it's not strictly necessary
  !!       ^ Alignment of "::" is not necessary, but should be attempted whenever it provides readability and is relevant (e.g. there's some link between the aligned variables)
        
CONTAINS
  
 !! Put at least a blank line before/after each function/subroutine
  SUBROUTINE my_subroutine(arg1, arg2, arg3) ! handle event xxxx
  !!                            ^ comments should always be right before, or on the same line as what they're commenting
  !!                            ^ as for modules, all functions should be documented in a comment
    INTEGER, INTENT(IN) :: arg1
    !!          ^ Always provide intent 
    REAL, INTENT(IN)    :: arg2


    INTEGER, INTENT(INOUT) :: arg3
    REAl, INTENT(OUT) :: out1
    !!^ Group together IN, then INOUT, then OUT
    ! ... body of my_subroutine
  END SUBROUTINE my_subroutine

!! ^ always use named blocks for END


END MODULE my_module
!!       ^ always use named blocks for END


Some comments:

  • Limit to the bare minimum the use of preprocessor #ifdef keys. Those decrease lisibility, disable automatic code analysis, and generally make code a pain to manage and read. Ideally, a given preprocessor key should be used only once, or if not possible, in a single module for the entire codebase.
  • Limit the use of <include> headers to the bare minimum. Whenever not possible, wrap those include in a module, and import that module instead. This provides much more flexibility, e.g. when using ONLY: ....