SURFEX v8.1
General documentation of Surfex
ch_emission_fluxn.F90
Go to the documentation of this file.
1 !SFX_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
2 !SFX_LIC This is part of the SURFEX software governed by the CeCILL-C licence
3 !SFX_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
4 !SFX_LIC for details. version 1.
5 ! #########
6  SUBROUTINE ch_emission_flux_n (DTCO, U, CHE, SV, CHU, HPROGRAM,PSIMTIME,PSFSV, PRHOA, PTSTEP, KNBTS_MAX)
7 ! ######################################################################
8 !!
9 !!*** *CH_EMISSION_FLUX_n* -
10 !!
11 !! PURPOSE
12 !! -------
13 !! Return a time-dependent emission flux based on tabulated values
14 !!
15 !!** METHOD
16 !! ------
17 !!
18 !! AUTHOR
19 !! ------
20 !! D. Gazen
21 !!
22 !! MODIFICATIONS
23 !! -------------
24 !! Original 08/02/00
25 !! C. Mari 30/10/00 call to MODD_TYPE_EFUTIL and MODD_CST
26 !! D.Gazen 01/12/03 change emissions handling for surf. externalization
27 !! P.Tulet 01/01/04 change emission conversion factor
28 !! P.Tulet 01/01/05 add dust, orilam
29 !! M.Leriche 2015 suppress ZDEPOT
30 !! M.Moge 01/2016 using READ_SURF_FIELD2D for 2D surfex fields reads
31 !!
32 !! EXTERNAL
33 !! --------
34 !!
35 !!
36 !! IMPLICIT ARGUMENTS
37 !! ------------------
38 !
40 USE modd_surf_atm_n, ONLY : surf_atm_t
42 USE modd_sv_n, ONLY : sv_t
43 USE modd_ch_surf_n, ONLY : ch_surf_t
44 !
46 USE modd_csts, ONLY: ndaysec
47 !
48 USE modi_read_surf_field2d
49 USE modi_init_io_surf_n
50 USE modi_end_io_surf_n
51 USE modi_get_luout
52 !UPG*AERO1
54 USE modi_ch_aer_emission
55 !UPG*AERO1
56 !!
57 !------------------------------------------------------------------------------
58 !
59 !* 0. DECLARATIONS
60 ! -----------------
61 !
62 USE yomhook ,ONLY : lhook, dr_hook
63 USE parkind1 ,ONLY : jprb
64 !
65 USE modi_abor1_sfx
66 !
67 IMPLICIT NONE
68 !
69 !* 0.1 declaration of arguments
70 !
71 TYPE(data_cover_t), INTENT(INOUT) :: DTCO
72 TYPE(surf_atm_t), INTENT(INOUT) :: U
73 TYPE(ch_emis_field_t), INTENT(INOUT) :: CHE
74 TYPE(sv_t), INTENT(INOUT) :: SV
75 TYPE(ch_surf_t), INTENT(INOUT) :: CHU
76 !
77  CHARACTER(LEN=6), INTENT(IN) :: HPROGRAM ! program calling surf. schemes
78 REAL, INTENT(IN) :: PSIMTIME ! time of simulation in sec UTC
79  ! (counting from midnight of
80  ! the current day)
81 REAL,DIMENSION(:,:), INTENT(INOUT) :: PSFSV ! emission flux in ppp*m/s
82 REAL, DIMENSION(:), INTENT(IN) :: PRHOA ! air density (kg/m3)
83 REAL, INTENT(IN) :: PTSTEP ! atmospheric time-step (s)
84 INTEGER, INTENT(IN) :: KNBTS_MAX !max size of TEMISS%NETIMES
85 
86 !
87 !* 0.2 declaration of local variables
88 !
89 INTEGER :: IVERB ! verbosity level
90 INTEGER :: KSIZE1D ! 1D size = X*Y physical domain
91 INTEGER :: JI ! loop control
92 REAL :: ZALPHA ! interpolation weight
93 !
94 INTEGER :: INBTS ! Number of emission times for a species
95 INTEGER :: ITIM1,ITIM2 ! first/last time for interpolation
96 INTEGER :: INDX1,INDX2 ! first/next index for data interpolation
97 INTEGER :: ISIMTIME, ITPERIOD
98  CHARACTER (LEN=16) :: YRECFM ! LFI article name
99 TYPE(pronosvar_t),POINTER :: CURPRONOS !Current pronostic variable
100 !
101 !* 0.3 declaration of saved local variables
102 !
103  CHARACTER(LEN=6), DIMENSION(:), POINTER :: CNAMES
104 REAL,DIMENSION(SIZE(PSFSV,1),KNBTS_MAX) :: ZWORK ! temporary array for reading data
105 REAL,DIMENSION(SIZE(PSFSV,1),SIZE(PSFSV,2)) :: ZEMIS ! interpolated in time emission flux
106 REAL,DIMENSION(SIZE(PSFSV,1)) :: ZFCO ! CO flux
107 INTEGER :: INEQ ! number of chemical var
108  !(=NEQ (chimie gaz) + NSV_AER (chimie aerosol)
109 INTEGER :: IWS ! window size
110 INTEGER :: IRESP ! return code for I/O
111 INTEGER :: ILUOUT ! Outputlisting unit
112 LOGICAL :: LIOINIT ! True if I/O init done
113 INTEGER :: JW
114 INTEGER :: ITIME
115 LOGICAL :: GCO = .false. ! switch if CO emission are available
116 REAL(KIND=JPRB) :: ZHOOK_HANDLE
117 !
118 !------------------------------------------------------------------------------
119 !
120 !* EXECUTABLE STATEMENTS
121 ! ---------------------
122 !
123 IF (lhook) CALL dr_hook('CH_EMISSION_FLUX_N',0,zhook_handle)
124  CALL get_luout(hprogram,iluout)
125 lioinit = .false.
126 iverb = 5
127 ksize1d = SIZE(psfsv,1)
128 ineq = SIZE(psfsv,2)
129 !
130 !------------------------------------------------------------------------------
131 !
132 !* 3. INTERPOLATE SURFACE FLUXES IN TIME IF NEEDED
133 ! ------------------------------------------------
134 !
135 IF (che%XTIME_SIMUL == 0.) THEN
136  che%XTIME_SIMUL = psimtime
137 ELSE
138  che%XTIME_SIMUL = che%XTIME_SIMUL + ptstep
139 END IF
140 
141 IF (iverb >= 5) WRITE(iluout,*) '******** CH_EMISSION_FLUX ********'
142 DO ji=1,SIZE(che%TSEMISS)
143 ! Simulation time (counting from midnight) is saved
144  isimtime = che%XTIME_SIMUL
145 !
146  inbts = SIZE(che%TSEMISS(ji)%NETIMES) !
147  iws = che%TSEMISS(ji)%NWS ! Window Size for I/O
148  indx1 = che%TSEMISS(ji)%NDX ! Current data index
149 !
150  IF (inbts == 1) THEN
151 ! Time Constant Flux
152 ! XFWORK already points on data (see ch_buildemiss.f90)
153  IF (iverb >= 6) THEN
154  WRITE(iluout,*) 'NO interpolation for ',trim(che%TSEMISS(ji)%CNAME)
155  IF (iverb >= 10 ) WRITE(iluout,*) che%TSEMISS(ji)%XFWORK
156  END IF
157  ELSE
158  IF (iverb >= 6) THEN
159  WRITE(iluout,*) 'Interpolation (T =',isimtime,') : ',che%TSEMISS(ji)%CNAME
160  END IF
161  IF (isimtime < che%TSEMISS(ji)%NETIMES(1)) THEN
162 ! Tsim < T(1)=Tmin should not happen but who knows ?
163  che%TSEMISS(ji)%NTX = 1
164  ELSE
165 ! Check for periodicity when ISIMTIME is beyond last emission time
166 ! and probably correct ISIMTIME
167  IF (isimtime > che%TSEMISS(ji)%NETIMES(inbts)) THEN
168 ! Tsim > T(INBTS)=Tmax
169  itperiod = (1+(che%TSEMISS(ji)%NETIMES(inbts)-&
170  che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NPX))/ndaysec)*ndaysec
171  isimtime = modulo(isimtime-che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NPX),itperiod)+&
172  che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NPX)
173  IF (iverb >= 6) THEN
174  WRITE(iluout,*) ' ITPERIOD = ', itperiod
175  WRITE(iluout,*) ' ISIMTIME modifie = ', isimtime
176  END IF
177  IF (che%TSEMISS(ji)%NTX == inbts .AND. isimtime<che%TSEMISS(ji)%NETIMES(inbts)) THEN
178 ! Update time index NTX
179  che%TSEMISS(ji)%NTX = che%TSEMISS(ji)%NPX
180 ! Increment data index NDX : NDX correction will occur later
181 ! to assure 1 <= NDX <= IWS
182  indx1 = indx1 + 1
183  END IF
184  END IF
185 !
186 ! search NTX such that : ETIMES(NTX) < ISIMTIME <= ETIMES(NTX+1)
187 ! and make NDX follow NTX : NDX correction will occur later
188 ! to assure 1 <= NDX <= IWS
189  DO WHILE (che%TSEMISS(ji)%NTX < inbts)
190  IF (isimtime >= che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NTX+1)) THEN
191  che%TSEMISS(ji)%NTX = che%TSEMISS(ji)%NTX + 1
192  indx1 = indx1 + 1
193  indx2 = indx1 + 1
194  ELSE
195  EXIT
196  END IF
197  END DO
198  END IF
199 !
200 ! Check availability of data within memory Window (XEMISDATA(:,1:IWS))
201  IF (indx1 >= iws) THEN
202 !
203 ! Data index reached the memory window limits
204 !
205  IF (che%TSEMISS(ji)%LREAD) THEN
206 !
207 ! File must be read to update XEMISDATA array for this species
208 !
209  IF (.NOT. lioinit) THEN
210 ! Must be done once before reading
211  CALL init_io_surf_n(dtco, u, hprogram,'FULL ','SURF ','READ ')
212  IF (iverb >= 6) WRITE(iluout,*) 'INIT des I/O DONE.'
213  lioinit=.true.
214  END IF
215  yrecfm='E_'//trim(che%TSEMISS(ji)%CNAME)
216  IF (iverb >= 6)&
217  WRITE (iluout,*) 'READ emission :',trim(yrecfm),&
218  ', SIZE(ZWORK)=',SIZE(zwork,1),inbts
219  CALL read_surf_field2d(hprogram,zwork(:,1:inbts),yrecfm)
220 !
221 ! Correction : Replace 999. with 0. value in the Emission FLUX
222  WHERE(zwork(:,1:inbts) == 999.)
223  zwork(:,1:inbts) = 0.
224  END WHERE
225  WHERE(zwork(:,1:inbts) == 1.e20)
226  zwork(:,1:inbts) = 0.
227  END WHERE
228  DO itime=1,inbts
229  zwork(:,itime) = zwork(:,itime)*chu%XCONVERSION(:)
230  END DO
231 !
232 !
233  IF ((che%TSEMISS(ji)%NTX+iws-1) > inbts) THEN
234 !
235 ! ===== Periodic CASE =====
236 !
237  IF (iverb >= 6)&
238  WRITE (iluout,*) 'Periodic CASE : NPX =',che%TSEMISS(ji)%NPX
239  IF (iws < (inbts-che%TSEMISS(ji)%NPX+1)) THEN
240 ! Window size is smaller then number of periodical times
241 !
242 ! example : IWS=5, NPX=2, INBTS=11, NTX=9
243 ! NTX NPX
244 ! | |
245 ! time index : ...9 10 11 # 2 3 4...11 #
246 ! old data index :[1 2 3 4 5]
247 ! new data index : [1 2 3 4 5]
248 ! |
249 ! NDX
250 !
251  che%TSEMISS(ji)%XEMISDATA(:,1:inbts-che%TSEMISS(ji)%NTX+1) = &
252  zwork(:,che%TSEMISS(ji)%NTX:inbts)
253 !
254  IF (iverb >= 6) THEN
255  WRITE(iluout,*) 'Window SIZE smaller than INBTS !'
256  WRITE(iluout,*) 'Window index, Time index'
257  DO jw=1,inbts-che%TSEMISS(ji)%NTX+1
258  WRITE(iluout,*) jw,che%TSEMISS(ji)%NTX+jw-1
259  END DO
260  END IF
261 !
262  che%TSEMISS(ji)%XEMISDATA(:,inbts-che%TSEMISS(ji)%NTX+2:iws) = &
263  zwork(:,che%TSEMISS(ji)%NPX:che%TSEMISS(ji)%NPX+iws-inbts+che%TSEMISS(ji)%NTX-2)
264 !
265  IF (iverb >= 6) THEN
266  DO jw=inbts-che%TSEMISS(ji)%NTX+2,iws
267  WRITE(iluout,*) jw,che%TSEMISS(ji)%NPX+jw-(inbts-che%TSEMISS(ji)%NTX+2)
268  END DO
269  END IF
270  indx1 = 1
271  indx2 = 2
272  ELSE
273 ! Window size may get smaller AND it will be the last reading
274 !
275 ! example : IWS=6, NPX=7, INBTS=11, NTX=9
276 !
277 ! NTX NPX NTX
278 ! | | |
279 ! time index: ...9 10 11 # 7 8 9 10 11 #
280 ! old data index: ...6]
281 ! new data index: [1 2 3 4 5]
282 ! |
283 ! NDX=NTX-NPX+1
284 !
285  iws = inbts-che%TSEMISS(ji)%NPX+1
286  che%TSEMISS(ji)%NWS = iws
287  che%TSEMISS(ji)%XEMISDATA(:,1:iws) = zwork(:,che%TSEMISS(ji)%NPX:inbts)
288  IF (iverb >= 6) THEN
289  WRITE(iluout,*) 'Window SIZE equal or greater than INBTS !'
290  WRITE(iluout,*) 'Window index, Time index'
291  DO jw=1,iws
292  WRITE(iluout,*) jw,che%TSEMISS(ji)%NPX+jw-1
293  END DO
294  END IF
295  indx1 = che%TSEMISS(ji)%NTX-che%TSEMISS(ji)%NPX+1
296  indx2 = mod((indx1+1),iws)
297  che%TSEMISS(ji)%LREAD = .false. ! no more reading
298  END IF
299  ELSE
300 !
301 ! ===== NON periodic (normal) CASE =====
302 !
303 ! example : with IWS=5, the window moves forward
304 ! NTX
305 ! |
306 ! time index : 1 2 3 4 5 6 7 8 9 10 11 ... INBTS #
307 ! old data index :[1 2 3 4 5]
308 ! new data index : [1 2 3 4 5]
309 ! |
310 ! NDX
311 !
312  che%TSEMISS(ji)%XEMISDATA(:,1:iws) = zwork(:,che%TSEMISS(ji)%NTX:che%TSEMISS(ji)%NTX+iws-1)
313  IF (iverb >= 6) THEN
314  WRITE(iluout,*) 'Window index, Time index'
315  DO jw=1,iws
316  WRITE(iluout,*) jw,che%TSEMISS(ji)%NTX+jw-1
317  END DO
318  END IF
319  indx1 = 1
320  indx2 = 2
321  END IF
322  ELSE
323 ! Data is already in memory because window size is sufficient
324 ! to hold INBTS emission times => simply update NDX according to NTX
325 !
326  IF (iws==inbts) THEN
327 !
328 ! 'Window size' = 'Nb emis times' at INIT (ch_init_emission)
329 ! so NDX must be set equal to NTX (the window does not move)
330 ! example :
331 ! NPX NTX
332 ! | |
333 ! time index : 1 2 3 ... INBTS
334 ! data index : [1 2 3 ... INBTS]
335 ! |
336 ! NDX
337 
338  indx1 = che%TSEMISS(ji)%NTX
339  indx2 = indx1+1
340  IF (indx2 > iws) indx2=che%TSEMISS(ji)%NPX
341  ELSE
342 !
343 ! Windows size changed during periodic case
344 ! NDX must be equal to NTX - NPX + 1
345 ! (the window does not move)
346 ! example :
347 ! NTX
348 ! |
349 ! time index : NPX NPX+1 NPX+2 ... INBTS
350 ! data index : [1 2 3 ... IWS]
351 ! |
352 ! NDX
353  indx1 = che%TSEMISS(ji)%NTX-che%TSEMISS(ji)%NPX+1
354  indx2 = mod((indx1+1),iws)
355  END IF
356  END IF
357  ELSE ! (INDX1 < IWS)
358  indx2 = indx1+1
359  END IF
360 !
361 ! Don't forget to update NDX with new value INDX1
362  che%TSEMISS(ji)%NDX = indx1
363 !
364 ! Compute both times for interpolation
365  IF (che%TSEMISS(ji)%NTX < inbts) THEN
366  itim1 = che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NTX)
367  itim2 = che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NTX+1)
368  ELSE
369  itim1 = che%TSEMISS(ji)%NETIMES(inbts)
370  itim2 = che%TSEMISS(ji)%NETIMES(che%TSEMISS(ji)%NPX)+itperiod
371  END IF
372 !
373 ! Interpolate variables in time -> update XFWORK
374 !
375 !
376 ! time : ITIM1...Tsim...ITIM2
377 ! | |
378 ! data index : INDX1 INDX2
379 !
380 !
381  zalpha = (REAL(ISIMTIME) - ITIM1) / (ITIM2-ITIM1)
382  che%TSEMISS(ji)%XFWORK(:) = zalpha*che%TSEMISS(ji)%XEMISDATA(:,indx2) +&
383  (1.-zalpha)*che%TSEMISS(ji)%XEMISDATA(:,indx1)
384  IF (iverb >= 6) THEN
385  WRITE(iluout,*) ' Current time INDEX : ',che%TSEMISS(ji)%NTX
386  WRITE(iluout,*) ' TIME : ',isimtime, ' (',itim1,',',itim2,')'
387  WRITE(iluout,*) ' Window size : ',che%TSEMISS(ji)%NWS
388  WRITE(iluout,*) ' Current data INDEX : ',indx1,indx2
389  IF (iverb >= 10) WRITE(iluout,*) ' FLUX : ',che%TSEMISS(ji)%XFWORK
390  END IF
391  END IF
392 END DO
393 !
394 ! Agregation : flux computation
395 !
396 zemis(:,:) = 0.
397 !
398 ! Point on head of Pronostic variable list
399 ! to cover the entire list.
400 IF (sv%NSV_AEREND > 0) THEN
401 CNAMES=>SV%CSV(SV%NSV_CHSBEG:SV%NSV_AEREND)
402 ELSE
403 CNAMES=>SV%CSV(SV%NSV_CHSBEG:SV%NSV_CHSEND)
404 END IF
405 CURPRONOS=>CHE%TSPRONOSLIST
406 DO WHILE(ASSOCIATED(curpronos))
407  IF (curpronos%NAMINDEX > ineq) THEN
408  WRITE(iluout,*) 'FATAL ERROR in CH_EMISSION_FLUXN : SIZE(ZEMIS,2) =',&
409  ineq,', INDEX bugge =',curpronos%NAMINDEX
410  CALL abor1_sfx('CH_EMISSION_FLUXN: FATAL ERROR')
411  END IF
412 
413  zemis(:,curpronos%NAMINDEX) = 0.
414 !
415 ! Loop on the number of agreg. coeff.
416  DO ji=1,curpronos%NBCOEFF
417 ! Compute agregated flux
418  zemis(:,curpronos%NAMINDEX) = zemis(:,curpronos%NAMINDEX)+&
419  curpronos%XCOEFF(ji)*che%TSEMISS(curpronos%NEFINDEX(ji))%XFWORK(:)
420  END DO
421 
422  IF (iverb >= 6) THEN
423  WRITE(iluout,*) 'Agregation for ',cnames(curpronos%NAMINDEX)
424  IF (iverb >= 10) WRITE(iluout,*) 'ZEMIS = ',zemis(:,curpronos%NAMINDEX)
425  END IF
426  IF ((cnames(curpronos%NAMINDEX) == "CO") .AND. any(zemis(:,curpronos%NAMINDEX).GT.0.)) THEN
427  zfco(:) = zemis(:,curpronos%NAMINDEX)
428  gco = .true.
429  END IF
430 
431  curpronos=>curpronos%NEXT
432 !
433 END DO
434 !
435 IF ((lch_aero_flux).AND.(sv%NSV_AERBEG > 0)) THEN
436  IF (gco) THEN
437  CALL ch_aer_emission(zemis, prhoa, sv%CSV, sv%NSV_CHSBEG, pfco=zfco)
438  ELSE
439  CALL ch_aer_emission(zemis, prhoa, sv%CSV, sv%NSV_CHSBEG)
440  ENDIF
441 END IF
442 !
443 psfsv(:,:) = psfsv(:,:) + zemis(:,:)
444 !
445 IF (lioinit) CALL end_io_surf_n(hprogram)
446 !
447 IF (iverb >= 6) WRITE(iluout,*) '******** END CH_EMISSION_FLUX ********'
448 IF (lhook) CALL dr_hook('CH_EMISSION_FLUX_N',1,zhook_handle)
449 !
450 END SUBROUTINE ch_emission_flux_n
subroutine abor1_sfx(YTEXT)
Definition: abor1_sfx.F90:7
integer, parameter jprb
Definition: parkind1.F90:32
subroutine ch_emission_flux_n(DTCO, U, CHE, SV, CHU, HPROGRAM, PSI
subroutine end_io_surf_n(HPROGRAM)
Definition: end_io_surfn.F90:7
subroutine get_luout(HPROGRAM, KLUOUT)
Definition: get_luout.F90:7
logical lhook
Definition: yomhook.F90:15
subroutine read_surf_field2d(HPROGRAM, PFIELD2D, HFIELDNAME, HCOMMEN
integer, save ndaysec
Definition: modd_csts.F90:84
subroutine init_io_surf_n(DTCO, U, HPROGRAM, HMASK, HSCHEME, HACTION
subroutine ch_aer_emission(PFLUX, PRHODREF, HSV, KSV_CHSBEG, PFCO)