Difference between revisions of "Guide for good coding"
Romain.vande (talk | contribs) (→Loop index convention) |
Romain.vande (talk | contribs) |
||
Line 133: | Line 133: | ||
Un peu plus pour le PEM peut-être | Un peu plus pour le PEM peut-être | ||
+ | |||
+ | == When to create subroutines instead of line of code == | ||
+ | |||
+ | Quand est ce qu'on décide que ca vaut le coup de faire une routine spécifique : ajout des tendance pdq dans physiq_mod | ||
== How to pass variable to subroutine (by argument or by module) == | == How to pass variable to subroutine (by argument or by module) == |
Revision as of 10:16, 13 January 2023
Contents
- 1 How to create a new module/subroutine
- 2 Naming subroutines convention
- 3 When to create subroutines instead of line of code
- 4 How to pass variable to subroutine (by argument or by module)
- 5 Naming variables convention
- 6 Loop index convention
- 7 Efficient loop coding
- 8 How to use the INTENT
- 9 How to comment code
- 10 General guide
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 writing of the subroutine.
- Start by importing 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, protected :: 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 ENDIF !end firstcall
61
62 ! identify where are the kre
63 DO i=1,nb_kre
64 kre(i)=i
65 if (kre(i).gt.rock) then
66 write(*,*) "the Kre ", i, "is behind the rock"
67 else if (mod(kre(i),2).eq.0) then
68 grass(:,nlayer-1)=grass(:,nlayer-1)-grass(:,nlayer) ! every two kre are eating grass in a very complex way
69 endif !(kre(i).gt.rock)
70 ENDDO !end of the loop nb_kre
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
Naming subroutines convention
Un peu plus pour le PEM peut-être
When to create subroutines instead of line of code
Quand est ce qu'on décide que ca vaut le coup de faire une routine spécifique : ajout des tendance pdq dans physiq_mod
How to pass variable to subroutine (by argument or by module)
Define when we should use argument and when to use modules
Proposition :
- if the variable is not going to change throughout the run (between two calls of the subroutine) => module variable
- else => subroutine argument
Naming variables convention
What is the naming convention. In vdifc_mod for example.
Loop index convention
Index name for loops over:
- physical grid : ig (max ngrid)
- vertical levels : l (max nlayer)
- tracer : iq (max nq)
- subslopes : islope (max nslope)
- aerosol : iaer (max naerkind)
- longitude :
- latitude :
Efficient loop coding
The more outside loop should correspond 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 as much as possible, a code is never too commented
- Delete unused commented code lines