source: trunk/LMDZ.TITAN/libf/phytitan/tracer_h.F90 @ 3497

Last change on this file since 3497 was 3090, checked in by slebonnois, 13 months ago

BdeBatz? : Cleans microphysics and makes few corrections for physics

File size: 11.7 KB
Line 
1! AUTHORS : J. Burgalat (2018), B. de Batz de Trenquelléon (2022)
2!
3! OpenMP directives in this module are inconsistent:
4!   - sizes (nmicro...) are thread private \___ BUT BOTH ARE INITIALIZED IN THE SAME ROUTINE
5!   - indexes array are common             /
6!
7!  Tracers sizes do not need to be private.
8!  In such case, OMP THREADPRIVATE should be removed and initracer2 should be called within an OMP SINGLE statement.
9!
10MODULE tracer_h
11  !! Stores data related to physics tracers.
12  !!
13  !! The module stores public global variables related to the number of tracers
14  !! available in the physics and their kind:
15  !!
16  !! Currently, tracers can be used either for chemistry process (nchimi) or
17  !! microphysics (nmicro).
18  !!
19  !! The subroutine "initracer2" initializes and performs sanity check of
20  !! the tracer definitions given in traceur.def and the required tracers in physics
21  !! (based on the run parameters).
22  !!
23  !! The module provides additional methods:
24  !!
25  !!   - indexOfTracer : search for the index of a tracer in the global table (tracers_h:noms) by name.
26  !!   - nameOfTracer  : get the name of tracer from a given index (of the global table).
27  !!   - dumpTracers   : print the names of all tracers indexes given in argument.
28  !!
29  IMPLICIT NONE
30
31  INTEGER, SAVE :: nqtot_p  = 0 !! Total number of physical tracers
32  INTEGER, SAVE :: nmicro = 0 !! Number of microphysics tracers.
33  INTEGER, SAVE :: nice   = 0 !! Number of microphysics ice tracers (subset of nmicro).
34  INTEGER, SAVE :: nchimi = 0 !! Number of chemical (gaz species) tracers.
35  !$OMP THREADPRIVATE(nqtot_p,nmicro,nice,nchimi)
36
37  INTEGER, DIMENSION(:), ALLOCATABLE, SAVE :: chimi_indx  !! Indexes of all chemical species tracers
38  INTEGER, DIMENSION(:), ALLOCATABLE, SAVE :: micro_indx  !! Indexes of all microphysical tracers
39  INTEGER, DIMENSION(:), ALLOCATABLE, SAVE :: ices_indx   !! Indexes of all ice microphysical tracers
40  INTEGER, DIMENSION(:), ALLOCATABLE, SAVE :: gazs_indx   !! Indexes of all gazs microphysical tracers
41
42  CHARACTER(len=30), DIMENSION(:), ALLOCATABLE, SAVE :: noms      !! name of the tracer
43  REAL, DIMENSION(:), ALLOCATABLE, SAVE              :: mmol      !! mole mass of tracer(g/mol-1)
44  REAL, DIMENSION(:), ALLOCATABLE, SAVE              :: rat_mmol  !! molar mass ratio
45  REAL, DIMENSION(:), ALLOCATABLE, SAVE              :: rho_q     !! tracer densities (kg.m-3)
46  !$OMP THREADPRIVATE(noms,mmol,rat_mmol,rho_q)
47
48
49
50  ! tracer indexes: these are initialized in initracer and should be 0 if the
51  !                 corresponding tracer does not exist
52
53
54  CONTAINS
55
56  SUBROUTINE initracer2(nq,nametrac,talk_to_me)
57    !! Initialize tracer names and attributes.
58    !!
59    !! The method initializes the list of tracer names used in the physics from their
60    !! dynamics counterpart.
61    !!
62    !! In addition, it initializes arrays of indexes for the different sub-processes of the physics:
63    !!
64    !!   - tracers_h:micro_indxs, the array of tracers indexes used for the microphysics.
65    !!   - tracers_h:chimi_indxs, the array of tracers indexes used for the chemistry.
66    !!
67    !! The method also initializes the molar mass array (tracers_h:mmol) for the chemistry and the
68    !! molar mass ratio (tracers_h:rat_mmol).
69    !!
70    !! @note
71    !! Strict checking of chemical species name is performed here if the chemistry is activated
72    !! (see callchim variable). All the values of 'cnames' must be found in the tracers names
73    !! related to chemistry.
74    !! @note
75    !! Tests are more permissive for the microphysics and is only based on the mimimum number of
76    !! tracers expected. Strict name checking is performed in inimufi.
77    USE callkeys_mod
78    USE comcstfi_mod, only: mugaz
79    USE comchem_h, only: nkim, cnames, cmmol
80    IMPLICIT NONE
81
82    INTEGER, INTENT(in)                          :: nq         !! Total number of tracers (fixed at compile time)
83    character(len=30), DIMENSION(nq), INTENT(in) :: nametrac   !! name of the tracer from dynamics (from 'traceurs.def')
84    LOGICAL, INTENT(in), OPTIONAL                :: talk_to_me !! Enable verbose mode.
85
86    LOGICAL                                      :: verb,found
87    CHARACTER(len=30)                            :: str
88
89    INTEGER :: i,j,n
90
91    verb = .true. ; IF (PRESENT(talk_to_me)) verb = talk_to_me
92
93    ! nqtot_p could be used everywhere in the physic :)
94    nqtot_p=nq
95
96    IF (.NOT.ALLOCATED(noms)) ALLOCATE(noms(nq))
97    noms(:)=nametrac(:)
98
99    IF (.NOT.ALLOCATED(rho_q)) ALLOCATE(rho_q(nq)) ! Defined for all tracers, currently initialized to 0.0
100    rho_q(:) = 0.0
101
102    ! Defined for all tracers, (actually) initialized only for chemical tracers
103    IF (.NOT.ALLOCATED(mmol)) ALLOCATE(mmol(nq))
104    IF (.NOT.ALLOCATED(rat_mmol)) ALLOCATE(rat_mmol(nq))
105    mmol(:)  = 0.0
106    rat_mmol(:) = 1.0
107
108    ! Compute number of microphysics tracers:
109    ! By convention they all have the prefix "mu_" (case sensitive !)
110    nmicro = 0
111    IF (callmufi) THEN
112      DO i=1,nq
113        str = noms(i)
114        IF (str(1:3) == "mu_") nmicro = nmicro+1
115      ENDDO
116      ! Checking the expected number of tracers:
117      !   no cloud:  4 ; w cloud :  4 + 2 + (1+)
118      ! Note that we do not make assumptions on the number of chemical species for clouds, this
119      ! will be checked in inimufi.
120      IF (callclouds) THEN
121        IF (nmicro < 7) THEN
122          WRITE(*,'((a),I3,(a))') "initracer2:error: Inconsistent number of microphysical tracers &
123            &(expected at least 7 tracers,",nmicro," given)"
124          CALL abort_physic("initracer2", "inconsistent number of tracers", 42)
125          STOP
126        ENDIF
127      ELSE IF (nmicro < 4) THEN
128          WRITE(*,'((a),I3,(a))') "initracer2:error: Inconsistent number of microphysical tracers &
129            &(expected at least 4 tracers,",nmicro," given)"
130          CALL abort_physic("initracer2", "inconsistent number of tracers", 42)
131      ELSE IF  (nmicro > 4) THEN
132        WRITE(*,'(a)') "initracer2:info: I was expecting only four tracers, you gave me &
133          &more. I'll just pretend nothing happen !"
134      ENDIF
135      ! microphysics indexes share the same values than original tracname.
136      IF (.NOT.ALLOCATED(micro_indx)) ALLOCATE(micro_indx(nmicro))
137      j = 1
138      DO i=1,nq
139        str = noms(i)
140        IF (str(1:3) == "mu_") THEN
141          micro_indx(j) = i
142          j=j+1
143        ENDIF
144      ENDDO
145    ELSE
146      IF (.NOT.ALLOCATED(micro_indx)) ALLOCATE(micro_indx(nmicro))
147    ENDIF
148
149    ! Compute number of chemical species:
150    !   simply assume that all other tracers ARE chemical species
151    nchimi = nqtot_p - nmicro
152
153    ! Titan chemistry requires exactly 44 tracers:
154    ! Test should be in callchim condition
155
156    IF (callchim) THEN
157      IF (nchimi .NE. nkim) THEN
158        WRITE(*,*) "initracer2:error: Inconsistent number of chemical species given (",nkim," expected)"
159        CALL abort_physic("initracer2", "inconsistent number of tracers", 42)
160      ENDIF
161      IF (.NOT.ALLOCATED(chimi_indx)) ALLOCATE(chimi_indx(nchimi))
162      n = 0 ! counter on chimi_indx
163      DO j=1,nkim
164        found = .false.
165        DO i=1,nq
166          IF (TRIM(cnames(j)) == TRIM(noms(i))) THEN
167            n = n + 1
168            chimi_indx(n) = i
169            mmol(i) = cmmol(j)
170            rat_mmol(i) = cmmol(j)/mugaz
171            found = .true.
172            EXIT
173          ENDIF
174        ENDDO
175        IF (.NOT.found) THEN
176          WRITE(*,*) "initracer2:error: "//TRIM(cnames(j))//" is missing from tracers definition file."
177        ENDIF
178      ENDDO
179      IF (n .NE. nkim) THEN
180        WRITE(*,*) "initracer2:error: Inconsistent number of chemical species given (",nkim," expected)"
181        CALL abort_physic("initracer2", "inconsistent number of tracers", 42)
182      ENDIF
183    ELSE
184      IF (.NOT.ALLOCATED(chimi_indx)) ALLOCATE(chimi_indx(0))
185    ENDIF
186    IF (verb) THEN
187      IF (callmufi.OR.callchim) WRITE(*,*) "===== INITRACER2 SPEAKING ====="
188      IF (callmufi) THEN
189         WRITE(*,*) "Found ",nmicro, "microphysical tracers"
190        call dumpTracers(micro_indx)
191        WRITE(*,*) "-------------------------------"
192      ENDIF
193      IF (callchim) THEN
194        WRITE(*,*) "Found ",nchimi, "chemical tracers"
195        call dumpTracers(chimi_indx)
196        WRITE(*,*) "-------------------------------"
197      ENDIF
198    ENDIF
199
200  END SUBROUTINE initracer2
201
202  FUNCTION indexOfTracer(name, sensitivity) RESULT(idx)
203    !! Get the index of a tracer by name.
204    !!
205    !! The function searches in the global tracer table (tracer_h:noms)
206    !! for the given name and returns the first index matching "name".
207    !!
208    !! If no name in the table matches the given one, -1 is returned !
209    !!
210    !! @warning
211    !! initracers must be called before any use of this function.
212    IMPLICIT NONE
213    CHARACTER(len=*), INTENT(in)  :: name         !! Name of the tracer to search.
214    LOGICAL, OPTIONAL, INTENT(in) :: sensitivity  !! Case sensitivity (true by default).
215    INTEGER :: idx                                !! Index of the first tracer matching name or -1 if not found.
216    LOGICAL                  :: zsens
217    INTEGER                  :: j
218    CHARACTER(len=LEN(name)) :: zname
219    zsens = .true. ; IF(PRESENT(sensitivity)) zsens = sensitivity
220    idx = -1
221    IF (.NOT.ALLOCATED(noms)) RETURN
222    IF (zsens) THEN
223      DO j=1,SIZE(noms)
224        IF (TRIM(noms(j)) == TRIM(name)) THEN
225          idx = j ; RETURN
226        ENDIF
227      ENDDO
228    ELSE
229      zname = to_lower(name)
230      DO j=1,SIZE(noms)
231        IF (TRIM(to_lower(noms(j))) == TRIM(zname)) THEN
232          idx = j ; RETURN
233        ENDIF
234      ENDDO
235    ENDIF
236
237    CONTAINS
238
239    FUNCTION to_lower(istr) RESULT(ostr)
240      !! Lower case conversion function.
241      IMPLICIT NONE
242      CHARACTER(len=*), INTENT(in) :: istr
243      CHARACTER(len=LEN(istr)) :: ostr
244      INTEGER :: i, ic
245      ostr = istr
246      DO i = 1, LEN_TRIM(istr)
247        ic = ICHAR(istr(i:i))
248        IF (ic >= 65 .AND. ic < 90) ostr(i:i) = char(ic + 32)
249      ENDDO
250    END FUNCTION to_lower
251  END FUNCTION indexOfTracer
252
253  FUNCTION nameOfTracer(indx) RESULT(name)
254    !! Get the name of a tracer by index.
255    !!
256    !! The function searches in the global tracer table (tracer_h:noms)
257    !! and returns the name of the tracer at given index.
258    !!
259    !! If the index is out of range an empty string is returned.
260    !!
261    !! @warning
262    !! initracers must be called before any use of this function.
263    IMPLICIT NONE
264    INTEGER, INTENT(in) :: indx   !! Index of the tracer name to retrieve.
265    CHARACTER(len=30)   :: name   !! Name of the tracer at given index.
266    name = ''
267    IF (.NOT.ALLOCATED(noms)) RETURN
268    IF (indx <= 0 .OR. indx > SIZE(noms)) RETURN
269    name = noms(indx)
270  END FUNCTION nameOfTracer
271
272  SUBROUTINE dumpTracers(indexes)
273    !! Print the names of the given list of tracers indexes.
274    INTEGER, DIMENSION(:), INTENT(in) :: indexes
275    INTEGER :: i,idx,nt
276    CHARACTER(len=:), ALLOCATABLE :: suffix
277   
278    IF (.NOT.ALLOCATED(noms)) THEN
279      WRITE(*,'(a)') "[tracers_h:dump_tracers] warning: 'noms' is not allocated, tracers_h:initracer2 has not be called yet"
280      RETURN
281    ENDIF
282    nt = size(noms)
283    WRITE(*,"(a)") "local -> global : name"
284    DO i=1,size(indexes)
285      idx = indexes(i)
286      IF (idx < 1 .OR. idx > nt) THEN
287        ! WRITE(*,'((a),I3,(a),I3,(a))') "index out of range (",idx,"/",nt,")"
288        CYCLE
289      ENDIF
290      IF (ANY(chimi_indx == idx)) THEN
291        suffix = ' (chimi)'
292      ELSE IF (ANY(micro_indx == idx)) THEN
293        suffix = ' (micro'
294        IF (ALLOCATED(ices_indx)) THEN
295          IF (ANY(ices_indx == idx)) suffix=suffix//", ice"
296        ENDIF
297        IF (ALLOCATED(gazs_indx)) THEN
298          IF (ANY(gazs_indx == idx)) suffix=suffix//", gaz"
299        ENDIF
300        suffix=suffix//")"
301      ELSE
302        suffix=" ()"
303      ENDIF
304      WRITE(*,'(I5,(a),I6,(a))') i," -> ",idx ," : "//TRIM(noms(idx))//suffix
305    ENDDO
306  END SUBROUTINE dumpTracers
307
308
309END MODULE tracer_h
310
Note: See TracBrowser for help on using the repository browser.