Difference between revisions of "Guide for good coding"

From Planets
Jump to: navigation, search
(How to create a new module/subroutine)
(How to create a new module/subroutine)
Line 21: Line 21:
  
 
<syntaxhighlight lang="Fortran" line>
 
<syntaxhighlight lang="Fortran" line>
      MODULE aquarium_mod
+
    MODULE aquarium_mod
  
      IMPLICIT NONE
+
    IMPLICIT NONE
  
      INTEGER :: water    ! Define what is the variable, the dimension, units (°) etc...
+
    INTEGER :: water    ! Define what is the variable, the dimension, units (°) etc...
      REAL,SAVE,ALLOCATABLE,DIMENSION(:) :: kre1      ! Another comment  
+
    REAL,SAVE,ALLOCATABLE,DIMENSION(:) :: kre1      ! Another comment  
  
      CONTAINS
+
    CONTAINS
  
 
       SUBROUTINE aquarium(kre, grass, other_things
 
       SUBROUTINE aquarium(kre, grass, other_things
Line 47: Line 47:
 
!=======================================================================
 
!=======================================================================
 
        
 
        
      IMPLICIT NONE
+
      IMPLICIT NONE
  
 
!-----------------------------------------------------------------------
 
!-----------------------------------------------------------------------
!
+
!=======================================================================
 
!    Declarations :
 
!    Declarations :
!   --------------
+
!=======================================================================
 
!
 
!
 
!    Input/Output
 
!    Input/Output
 
!    ------------
 
!    ------------
 +
      REAL, INTENT(IN)    ::  something(ngrid,nlayer) ! 2D tabular used as an input only  (W/m^2)
 +
      REAL, INTENT(OUT)    ::  kre(ngrid)              ! 1D tabular output by the subroutine 
 +
      REAL, INTENT(INOUT)  ::  grass(ngrid,nlayer)    ! Variable that is modified by the subroutine
 +
                                                      ! it is an input and output
 +
      LOGICAL, INTENT(IN)  ::  really_anything        ! Boolean variable 
  
      REAL, INTENT(IN)    ::  something(ngrid,nlayer) ! 2D tabular used as an input only  (W/m^2)
+
!    Local saved variables
      REAL, INTENT(OUT)  ::  kre(ngrid)              ! 1D tabular output by the subroutine 
+
!    ---------------------
      REAL, INTENT(INOUT) ::  grass(ngrid,nlayer)    ! Variable that is modified by the subroutine
+
       INTEGER, PARAMETER :: nb_kre = 4               ! Number of kre
                                                      ! it is an input and output
 
      LOGICAL,INTENT(IN)  ::  really_anything        ! Boolean variable 
 
 
 
!    Local saved variables :
 
!    -----------------
 
       INTEGER, PARAMETER :: nb_kre = 6               ! Number of kre
 
 
       INTEGER, SAVE      :: rock                      ! Another variable
 
       INTEGER, SAVE      :: rock                      ! Another variable
       LOGICAL,SAVE :: firstcall=.true.               ! Another variable
+
       LOGICAL, SAVE     :: firstcall=.true.         ! Another variable
  
!    Local variables :
+
!    Local variables
!    -----------------
+
!    ---------------
       REAL tabular(ngrid)                             ! Local var
+
       REAL   tabular(ngrid)                         ! Local var
 
       INTEGER i                                      ! Loop var
 
       INTEGER i                                      ! Loop var
  
!   Beginning of the code :
+
!=======================================================================
!   -----------------
+
Beginning of the code
 +
!=======================================================================
  
 
       IF (firstcall) THEN
 
       IF (firstcall) THEN
 +
        ! initialize rock
 +
        rock = 2
 
         ! identify where are the kre
 
         ! identify where are the kre
 
         DO i=1,nb_kre
 
         DO i=1,nb_kre
 
           kre(i)=i
 
           kre(i)=i
           write(*,*) "the Kre ", i, "is behind the rock"
+
           if (kre(i).gt.rock) then
 +
            write(*,*) "the Kre ", i, "is behind the rock"
 +
          else if (mod(kre(i),2).eq.0) then
 +
            grass(:,nlayer-1)=grass(:,nlayer-1)-grass(:,nlayer) ! every two kre are eating grass in a very complex way
 +
          endif !(kre(i).gt.rock)
 +
 
 
         ENDDO !end of the loop nb_kre
 
         ENDDO !end of the loop nb_kre
       ENDIF   !end firstcall
+
       ENDIF !end firstcall
  
 
       END SUBROUTINE aquarium
 
       END SUBROUTINE aquarium
Line 113: Line 120:
 
       END SUBROUTINE end_aquarium
 
       END SUBROUTINE end_aquarium
 
        
 
        
      END MODULE aquarium_mod
+
    END MODULE aquarium_mod
  
 
</syntaxhighlight>
 
</syntaxhighlight>

Revision as of 11:55, 5 January 2023

How to create a new module/subroutine

Subroutines should be integrated inside a module. A good writing habit is to add the line "IMPLICIT NONE", in the beginning of the module and subroutine.

First you can define all the variable that belongs to the module and could be used at another place. A good thing is also to create a subroutine that allocate and initialise module variables. If the variable is only modified inside the module it should be taged as protected. If the variable belongs only to the module it can be specified to be private.

You can now start the definition of the subroutine. Start by variable and function from other module if necessary. Comment the purpose of the subroutine directly. Declare the variables, first the one pass in arguments. Use the intent to specify the status of the variable inside the subroutine. Continue with the local and saved variables. Then you can define local variables. Remember to comment all of them, you can specify the dimension if the variable is an allocatable variable as well as the units and everything that seems appropriate.

You can finally write the code.

  1     MODULE aquarium_mod
  2 
  3     IMPLICIT NONE
  4 
  5     INTEGER :: water     ! Define what is the variable, the dimension, units (°) etc...
  6     REAL,SAVE,ALLOCATABLE,DIMENSION(:) :: kre1      ! Another comment 
  7 
  8     CONTAINS
  9 
 10       SUBROUTINE aquarium(kre, grass, other_things
 11      &                    really_anything)
 12                                                          
 13       use another_module_mod, only: fct, variable
 14       
 15 !=======================================================================
 16 !   subject:
 17 !   --------
 18 !   What is the subroutine doing
 19 !
 20 !   author: Someone smart 
 21 !   ------
 22 !   update: Someone smarter, march 2012:
 23 !         - I change something here
 24 !   
 25 !=======================================================================
 26       
 27       IMPLICIT NONE
 28 
 29 !-----------------------------------------------------------------------
 30 !=======================================================================
 31 !    Declarations :
 32 !=======================================================================
 33 !
 34 !    Input/Output
 35 !    ------------
 36       REAL, INTENT(IN)     ::  something(ngrid,nlayer) ! 2D tabular used as an input only  (W/m^2)
 37       REAL, INTENT(OUT)    ::  kre(ngrid)              ! 1D tabular output by the subroutine  
 38       REAL, INTENT(INOUT)  ::  grass(ngrid,nlayer)     ! Variable that is modified by the subroutine
 39                                                        ! it is an input and output
 40       LOGICAL, INTENT(IN)  ::  really_anything         ! Boolean variable  
 41 
 42 !    Local saved variables
 43 !    ---------------------
 44       INTEGER, PARAMETER :: nb_kre = 4                ! Number of kre
 45       INTEGER, SAVE      :: rock                      ! Another variable
 46       LOGICAL, SAVE      :: firstcall=.true.          ! Another variable
 47 
 48 !    Local variables
 49 !    ---------------
 50       REAL    tabular(ngrid)                          ! Local var
 51       INTEGER i                                       ! Loop var
 52 
 53 !=======================================================================
 54 !   Beginning of the code
 55 !=======================================================================
 56 
 57       IF (firstcall) THEN
 58         ! initialize rock
 59         rock = 2
 60         ! identify where are the kre
 61         DO i=1,nb_kre
 62           kre(i)=i
 63           if (kre(i).gt.rock) then
 64             write(*,*) "the Kre ", i, "is behind the rock"
 65           else if (mod(kre(i),2).eq.0) then
 66             grass(:,nlayer-1)=grass(:,nlayer-1)-grass(:,nlayer) ! every two kre are eating grass in a very complex way
 67           endif !(kre(i).gt.rock)
 68 
 69         ENDDO !end of the loop nb_kre
 70       ENDIF !end firstcall
 71 
 72       END SUBROUTINE aquarium
 73 
 74 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 75 
 76       SUBROUTINE ini_aquarium(ngrid)
 77 !=======================================================================
 78 !   Initialise module's variable
 79 !=======================================================================
 80       IMPLICIT NONE
 81       INTEGER, INTENT(IN) :: ngrid
 82 
 83       allocate(kre1(ngrid+1))
 84 
 85       END SUBROUTINE ini_aquarium
 86 
 87 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 88 
 89       SUBROUTINE end_aquarium
 90 !=======================================================================
 91 !   Deallocate module's variable
 92 !=======================================================================
 93 
 94       IMPLICIT NONE
 95 
 96       IF (allocated(kre1)) deallocate(kre1)
 97 
 98       END SUBROUTINE end_aquarium
 99       
100     END MODULE aquarium_mod

How to pass variable to subroutine (by argument or by module)

Define when we should use argument and when to use modules

Naming variables convention

What is the naming convention. In vdifc_mod for exemple.

Loop index convention

Index name for loops through:

  • physical grid : ig (max ngrid)
  • vertical levels : l (max nlayer)
  • tracer : iq (max nq)
  • subslopes : islope (max nslope)

iaer=1,naerkind

Efficient loop coding

The more outside loop should correcpond to the last index of an array.

Example:

      DO l=1,nlayer
        DO ig=1,ngrid
          array(ig,l)=l*ig
        ENDDO
      ENDDO

How to use the Intent

Argument of a function can come in 3 different way: IN, OUT, INOUT.

How to comment code

  • In english
  • As much as possible
  • Variable definition : explain what it is, the dimension, the units etc...
  • Subroutine : Explain what it does, who wrote it, who modify it and why if it is a big change
  • Loops : if the enddo is far away you can comment to which index it correspond to.
  • Chapter your code : you can add section to your code to make it clearer.

General guide

  • Create .F90 instead of .F
  • Delete unused argument in a function call if you see one
  • Delete unused variables
  • Choose meaningful names of variables
  • Don't hesitate to comment at much as possible, a code is never too commented
  • Delete unused commented code lines