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