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

Last change on this file since 3000 was 2373, checked in by aslmd, 5 years ago

Titan: a couple of calls to abort_gcm remaining in the physics replaced by abort_physic.

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