HowTo: LMDZ code guidelines
De LMDZPedia
Révision de 18 juillet 2024 à 11:54 par Abarral (discussion | contributions)
/!\ 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: ...
.