source: LMDZ4/branches/LMDZ4-dev/libf/phylmd/readaerosol_interp.F90 @ 1226

Last change on this file since 1226 was 1216, checked in by jghattas, 15 years ago

Bug-fix dans le calcul de aerosol charge(load) dans la colonne pour
l'interpolation des aerosols.

File size: 19.1 KB
Line 
1! $Id$
2!
3SUBROUTINE readaerosol_interp(id_aero, r_day, first, pplay, paprs, t_seri, mass_out, pi_mass_out)
4!
5! This routine will return the mass concentration at actual day(mass_out) and
6! the pre-industrial values(pi_mass_out) for aerosol corresponding to "id_aero".
7! The mass concentrations for all aerosols are saved in this routine but each
8! call to this routine only treats the aerosol "id_aero".
9!
10! 1) Read in data for the whole year, only at first time step
11! 2) Interpolate to the actual day, only at new day
12! 3) Interpolate to the model vertical grid (target grid), only at new day
13! 4) Test for negative mass values
14
15  USE dimphy, ONLY : klev,klon
16  USE mod_phys_lmdz_para, ONLY : mpi_rank 
17  USE readaerosol_mod
18  USE aero_mod, ONLY : naero_spc, name_aero
19  USE write_field_phy
20
21  IMPLICIT NONE
22
23  INCLUDE "YOMCST.h"
24  INCLUDE "chem.h"     
25  INCLUDE "temps.h"     
26  INCLUDE "clesphys.h"
27  INCLUDE "iniprint.h"
28  INCLUDE "dimensions.h"
29  INCLUDE "comvert.h"
30!
31! Input:
32!****************************************************************************************
33  INTEGER, INTENT(IN)                    :: id_aero! Identity number for the aerosol to treat
34  REAL, INTENT(IN)                       :: r_day  ! Day of integration
35  LOGICAL, INTENT(IN)                    :: first  ! First model timestep
36  REAL, DIMENSION(klon,klev), INTENT(IN) :: pplay  ! pression at model mid-layers
37  REAL, DIMENSION(klon,klev+1),INTENT(IN):: paprs  ! pression between model layers
38  REAL, DIMENSION(klon,klev), INTENT(IN) :: t_seri ! air temperature
39!     
40! Output:     
41!****************************************************************************************
42  REAL, INTENT(OUT) :: mass_out(klon,klev)    ! Mass of aerosol (monthly mean data,from file) [ug AIBCM/m3]
43  REAL, INTENT(OUT) :: pi_mass_out(klon,klev) ! Mass of preindustrial aerosol (monthly mean data,from file) [ug AIBCM/m3]
44!     
45! Local Variables:
46!****************************************************************************************
47  INTEGER                         :: i, k, ierr
48  INTEGER                         :: iday, iyr
49  INTEGER                         :: im, day1, day2, im2
50  INTEGER                         :: pi_klev_src ! Only for testing purpose
51  INTEGER, SAVE                   :: klev_src    ! Number of vertical levles in source field
52!$OMP THREADPRIVATE(klev_src)
53
54  REAL                              :: zrho      ! Air density [kg/m3]
55  REAL                              :: volm      ! Volyme de melange [kg/kg]
56  REAL, DIMENSION(klon)             :: psurf_day, pi_psurf_day
57  REAL, DIMENSION(klon)             :: load_src, pi_load_src  ! Mass load at source grid
58  REAL, DIMENSION(klon)             :: load_tgt, load_tgt_test
59  REAL, DIMENSION(klon,klev)        :: delp ! pressure difference in each model layer
60
61  REAL, ALLOCATABLE, DIMENSION(:,:)            :: pplay_src ! pression mid-layer at source levels
62  REAL, ALLOCATABLE, DIMENSION(:,:)            :: tmp1, tmp2  ! Temporary variables
63  REAL, ALLOCATABLE, DIMENSION(:,:,:,:), SAVE  :: var_year    ! VAR in right dimension for the total year
64  REAL, ALLOCATABLE, DIMENSION(:,:,:,:), SAVE  :: pi_var_year ! pre-industrial VAR, -"-
65!$OMP THREADPRIVATE(var_year,pi_var_year)
66  REAL, ALLOCATABLE, DIMENSION(:,:,:),SAVE     :: var_day     ! VAR interpolated to the actual day and model grid
67  REAL, ALLOCATABLE, DIMENSION(:,:,:),SAVE     :: pi_var_day  ! pre-industrial VAR, -"-
68!$OMP THREADPRIVATE(var_day,pi_var_day)
69  REAL, ALLOCATABLE, DIMENSION(:,:,:), SAVE    :: psurf_year, pi_psurf_year ! surface pressure for the total year
70!$OMP THREADPRIVATE(psurf_year, pi_psurf_year)
71  REAL, ALLOCATABLE, DIMENSION(:,:,:), SAVE    :: load_year, pi_load_year   ! load in the column for the total year
72!$OMP THREADPRIVATE(load_year, pi_load_year)
73
74  REAL, DIMENSION(:,:,:), POINTER   :: pt_tmp      ! Pointer allocated in readaerosol
75  REAL, POINTER, DIMENSION(:), SAVE :: pt_ap, pt_b ! Pointer for describing the vertical levels
76!$OMP THREADPRIVATE(pt_ap, pt_b)
77
78  LOGICAL            :: lnewday      ! Indicates if first time step at a new day
79  LOGICAL,SAVE       :: vert_interp  ! Indicates if vertical interpolation will be done
80  LOGICAL,SAVE       :: debug=.FALSE.! Debugging in this subroutine
81!$OMP THREADPRIVATE(vert_interp, debug)
82
83
84!****************************************************************************************
85! Initialization
86!
87!****************************************************************************************
88
89! Calculation to find if it is a new day
90  iday = INT(r_day)
91  iyr  = iday/360
92  iday = iday-iyr*360         ! day of the actual year
93  iyr  = iyr + annee_ref      ! year of the run   
94  im   = iday/30 +1           ! the actual month
95
96  ! 0.02 is about 0.5/24, namly less than half an hour
97  lnewday = (r_day-FLOAT(iday) < 0.02)
98
99  IF (.NOT. ALLOCATED(var_day)) THEN
100     ALLOCATE( var_day(klon, klev, naero_spc), stat=ierr)
101     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 1',1)
102     ALLOCATE( pi_var_day(klon, klev, naero_spc), stat=ierr)
103     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 2',1)
104
105     ALLOCATE( psurf_year(klon, 12, naero_spc), pi_psurf_year(klon, 12, naero_spc), stat=ierr)
106     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 3',1)
107
108     ALLOCATE( load_year(klon, 12, naero_spc), pi_load_year(klon, 12, naero_spc), stat=ierr)
109     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 4',1)
110
111     lnewday=.TRUE.
112
113     NULLIFY(pt_ap)
114     NULLIFY(pt_b)
115  END IF
116
117!****************************************************************************************
118! 1) Read in data : corresponding to the actual year and preindustrial data.
119!    Only for the first day of the year.
120!
121!****************************************************************************************
122  IF ( (first .OR. iday==1.) .AND. lnewday ) THEN
123     NULLIFY(pt_tmp)
124
125     ! Reading values corresponding to the closest year taking into count the choice of aer_type.
126     ! For aer_type=scenario interpolation between 2 data sets is done in readaerosol.
127     CALL readaerosol(name_aero(id_aero), aer_type, iyr, klev_src, pt_ap, pt_b, pt_tmp, &
128          psurf_year(:,:,id_aero), load_year(:,:,id_aero))
129     IF (.NOT. ALLOCATED(var_year)) THEN
130        ALLOCATE(var_year(klon, klev_src, 12, naero_spc), stat=ierr)
131        IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 5',1)
132     END IF
133     var_year(:,:,:,id_aero) = pt_tmp(:,:,:)
134
135     ! Reading values corresponding to the preindustrial concentrations.
136     CALL readaerosol(name_aero(id_aero), 'preind', iyr, pi_klev_src, pt_ap, pt_b, pt_tmp, &
137          pi_psurf_year(:,:,id_aero), pi_load_year(:,:,id_aero))
138
139     ! klev_src must be the same in both files.
140     ! Also supposing pt_ap and pt_b to be the same in the 2 files without testing.
141     IF (pi_klev_src /= klev_src) THEN
142        WRITE(lunout,*) 'Error! All forcing files for the same aerosol must have the same vertical dimension'
143        WRITE(lunout,*) 'Aerosol : ', name_aero(id_aero)
144        CALL abort_gcm('readaerosol_interp','Differnt vertical axes in aerosol forcing files',1)
145     END IF
146
147     IF (.NOT. ALLOCATED(pi_var_year)) THEN
148        ALLOCATE(pi_var_year(klon, klev_src, 12, naero_spc), stat=ierr)
149        IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 6',1)
150     END IF
151     pi_var_year(:,:,:,id_aero) = pt_tmp(:,:,:)
152   
153     IF (debug) THEN
154        CALL writefield_phy('var_year_jan',var_year(:,:,1,id_aero),klev_src)
155        CALL writefield_phy('var_year_dec',var_year(:,:,12,id_aero),klev_src)
156        CALL writefield_phy('psurf_src',psurf_year(:,:,id_aero),1)
157        CALL writefield_phy('pi_psurf_src',pi_psurf_year(:,:,id_aero),1)
158        CALL writefield_phy('load_year_src',load_year(:,:,id_aero),1)
159        CALL writefield_phy('pi_load_year_src',pi_load_year(:,:,id_aero),1)
160     END IF
161
162     ! Pointer no more useful, deallocate.
163     DEALLOCATE(pt_tmp)
164
165     ! Test if vertical interpolation will be needed.
166     IF (psurf_year(1,1,id_aero)==not_valid .OR. pi_psurf_year(1,1,id_aero)==not_valid ) THEN
167        ! Pressure=not_valid indicates old file format, see module readaerosol
168        vert_interp = .FALSE.
169
170        ! If old file format, both psurf_year and pi_psurf_year must be not_valid
171        IF (  psurf_year(1,1,id_aero) /= pi_psurf_year(1,1,id_aero) ) THEN
172           WRITE(lunout,*) 'Warning! All forcing files for the same aerosol must have the same structure'
173           CALL abort_gcm('readaerosol_interp', 'The aerosol files have not the same format',1)
174        END IF
175       
176        IF (klev /= klev_src) THEN
177           WRITE(lunout,*) 'Old format of aerosol file do not allowed vertical interpolation'
178           CALL abort_gcm('readaerosol_interp', 'Old aerosol file not possible',1)
179        END IF
180
181     ELSE
182        vert_interp = .TRUE.
183     END IF
184
185  END IF  ! IF ( (first .OR. iday==1.) .AND. lnewday ) THEN
186 
187!****************************************************************************************
188! - 2) Interpolate to the actual day.
189! - 3) Interpolate to the model vertical grid.
190!
191!****************************************************************************************
192
193  IF (lnewday) THEN ! only if new day
194!****************************************************************************************
195! 2) Interpolate to the actual day
196!
197!****************************************************************************************
198     ! Find which months and days to use for time interpolation
199     IF (iday < im*30-15) THEN         
200        ! in the first half of the month use month before and actual month
201        im2=im-1
202        day2 = im2*30-15
203        day1 = im2*30+15
204        IF (im2 <= 0) THEN
205           ! the month is january, thus the month before december
206           im2=12
207        END IF
208     ELSE
209        ! the second half of the month
210        im2=im+1
211        IF (im2 > 12) THEN
212           ! the month is december, the following thus january
213           im2=1
214        ENDIF
215        day2 = im*30-15
216        day1 = im*30+15
217     END IF
218     
219     ! Time interpolation, still on vertical source grid
220     ALLOCATE(tmp1(klon,klev_src), tmp2(klon,klev_src),stat=ierr)
221     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 7',1)
222
223     ALLOCATE(pplay_src(klon,klev_src), stat=ierr)
224     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 8',1)
225     
226
227     DO k=1,klev_src
228        DO i=1,klon
229           tmp1(i,k) = &
230                var_year(i,k,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
231                (var_year(i,k,im2,id_aero) - var_year(i,k,im,id_aero))
232           
233           tmp2(i,k) = &
234                pi_var_year(i,k,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
235                (pi_var_year(i,k,im2,id_aero) - pi_var_year(i,k,im,id_aero))
236        END DO
237     END DO
238
239     ! Time interpolation for pressure at surface, still on vertical source grid
240     DO i=1,klon
241        psurf_day(i) = &
242             psurf_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
243             (psurf_year(i,im2,id_aero) - psurf_year(i,im,id_aero))
244       
245        pi_psurf_day(i) = &
246             pi_psurf_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
247             (pi_psurf_year(i,im2,id_aero) - pi_psurf_year(i,im,id_aero))
248     END DO
249
250     ! Time interpolation for the load, still on vertical source grid
251     DO i=1,klon
252        load_src(i) = &
253             load_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
254             (load_year(i,im2,id_aero) - load_year(i,im,id_aero))
255       
256        pi_load_src(i) = &
257             pi_load_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
258             (pi_load_year(i,im2,id_aero) - pi_load_year(i,im,id_aero))
259     END DO
260
261!****************************************************************************************
262! 3) Interpolate to the model vertical grid (target grid)
263!
264!****************************************************************************************
265
266     IF (vert_interp) THEN
267
268        ! - Interpolate variable tmp1 (on source grid) to var_day (on target grid)
269        !********************************************************************************
270        ! a) calculate pression at vertical levels for the source grid using the
271        !    hybrid-sigma coordinates ap and b and the surface pressure, variables from file.
272        DO k = 1, klev_src
273           DO i = 1, klon
274              pplay_src(i,k)= pt_ap(k) + pt_b(k)*psurf_day(i)
275           END DO
276        END DO
277       
278        IF (debug) THEN
279           CALL writefield_phy('psurf_day_src',psurf_day(:),1)
280           CALL writefield_phy('pplay_src',pplay_src(:,:),klev_src)
281           CALL writefield_phy('pplay',pplay(:,:),klev)
282           CALL writefield_phy('day_src',tmp1,klev_src)
283           CALL writefield_phy('pi_day_src',tmp2,klev_src)
284        END IF
285
286        ! b) vertical interpolation on pressure leveles
287        CALL pres2lev(tmp1(:,:), var_day(:,:,id_aero), klev_src, klev, pplay_src, pplay, &
288             1, klon, .FALSE.)
289       
290        IF (debug) CALL writefield_phy('day_tgt',var_day(:,:,id_aero),klev)
291       
292        ! c) adjust to conserve total aerosol mass load in the vertical pillar
293        !    Calculate the load in the actual pillar and compare with the load
294        !    read from aerosol file.
295       
296        ! Find the pressure difference in each model layer
297        DO k = 1, klev
298           DO i = 1, klon
299              delp(i,k) = paprs(i,k) - paprs (i,k+1)
300           END DO
301        END DO
302
303        ! Find the mass load in the actual pillar, on target grid
304        load_tgt(:) = 0.
305        DO k= 1, klev
306           DO i = 1, klon
307              zrho = pplay(i,k)/t_seri(i,k)/RD       ! [kg/m3]
308              volm = var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
309              load_tgt(i) = load_tgt(i) + 1/RG * volm *delp(i,k)
310           END DO
311        END DO
312       
313        ! Adjust, uniform
314        DO k = 1, klev
315           DO i = 1, klon
316              var_day(i,k,id_aero) = var_day(i,k,id_aero)*load_src(i)/load_tgt(i)
317           END DO
318        END DO
319       
320        IF (debug) THEN
321           load_tgt_test(:) = 0.
322           DO k= 1, klev
323              DO i = 1, klon
324                 zrho = pplay(i,k)/t_seri(i,k)/RD       ! [kg/m3]
325                 volm = var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
326                 load_tgt_test(i) = load_tgt_test(i) + 1/RG * volm*delp(i,k)
327              END DO
328           END DO
329           
330           CALL writefield_phy('day_tgt2',var_day(:,:,id_aero),klev)
331           CALL writefield_phy('load_tgt',load_tgt(:),1)
332           CALL writefield_phy('load_tgt_test',load_tgt_test(:),1)
333           CALL writefield_phy('load_src',load_src(:),1)
334        END IF
335
336        ! - Interpolate variable tmp2 (source grid) to pi_var_day (target grid)
337        !********************************************************************************
338        ! a) calculate pression at vertical levels at source grid   
339        DO k = 1, klev_src
340           DO i = 1, klon
341              pplay_src(i,k)= pt_ap(k) + pt_b(k)*pi_psurf_day(i)
342           END DO
343        END DO
344
345        IF (debug) THEN
346           CALL writefield_phy('pi_psurf_day_src',pi_psurf_day(:),1)
347           CALL writefield_phy('pi_pplay_src',pplay_src(:,:),klev_src)
348        END IF
349
350        ! b) vertical interpolation on pressure leveles
351        CALL pres2lev(tmp2(:,:), pi_var_day(:,:,id_aero), klev_src, klev, pplay_src, pplay, &
352             1, klon, .FALSE.)
353
354        IF (debug) CALL writefield_phy('pi_day_tgt',pi_var_day(:,:,id_aero),klev)
355
356        ! c) adjust to conserve total aerosol mass load in the vertical pillar
357        !    Calculate the load in the actual pillar and compare with the load
358        !    read from aerosol file.
359
360        ! Find the load in the actual pillar, on target grid
361        load_tgt(:) = 0.
362        DO k = 1, klev
363           DO i = 1, klon
364              zrho = pplay(i,k)/t_seri(i,k)/RD          ! [kg/m3]
365              volm = pi_var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
366              load_tgt(i) = load_tgt(i) + 1/RG * volm * delp(i,k)
367           END DO
368        END DO
369
370        DO k = 1, klev
371           DO i = 1, klon
372              pi_var_day(i,k,id_aero) = pi_var_day(i,k,id_aero)*pi_load_src(i)/load_tgt(i)
373           END DO
374        END DO
375
376        IF (debug) THEN
377           load_tgt_test(:) = 0.
378           DO k = 1, klev
379              DO i = 1, klon
380                 zrho = pplay(i,k)/t_seri(i,k)/RD          ! [kg/m3]
381                 volm = pi_var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
382                 load_tgt_test(i) = load_tgt_test(i) + 1/RG * volm * delp(i,k)
383              END DO
384           END DO
385           CALL writefield_phy('pi_day_tgt2',pi_var_day(:,:,id_aero),klev)
386           CALL writefield_phy('pi_load_tgt',load_tgt(:),1)
387           CALL writefield_phy('pi_load_tgt_test',load_tgt_test(:),1)
388           CALL writefield_phy('pi_load_src',pi_load_src(:),1)
389        END IF
390
391
392     ELSE   ! No vertical interpolation done
393
394        var_day(:,:,id_aero)    = tmp1(:,:)
395        pi_var_day(:,:,id_aero) = tmp2(:,:)
396
397     END IF ! vert_interp
398
399
400     ! Deallocation
401     DEALLOCATE(tmp1, tmp2, pplay_src, stat=ierr)
402
403!****************************************************************************************
404! 4) Test for negative mass values
405!
406!****************************************************************************************
407     IF (MINVAL(var_day(:,:,id_aero)) < 0.) THEN
408        DO k=1,klev
409           DO i=1,klon
410              ! Test for var_day
411              IF (var_day(i,k,id_aero) < 0.) THEN
412                 IF (iday-day2 < 0.) WRITE(lunout,*) 'iday-day2=',iday-day2
413                 IF (var_year(i,k,im2,id_aero) - var_year(i,k,im,id_aero) < 0.) THEN
414                    WRITE(lunout,*) trim(name_aero(id_aero)),'(i,k,im2)-', &
415                         trim(name_aero(id_aero)),'(i,k,im)=',           &
416                         var_year(i,k,im2,id_aero) - var_year(i,k,im,id_aero)
417                 END IF
418                 
419                 WRITE(lunout,*) 'stop for aerosol : ',name_aero(id_aero)
420                 CALL abort_gcm('readaerosol_interp','Error in interpolation 1',1)
421              END IF
422           END DO
423        END DO
424     END IF
425
426     IF (MINVAL(pi_var_day(:,:,id_aero)) < 0. ) THEN
427        DO k=1, klev
428           DO i=1,klon
429              ! Test for pi_var_day
430              IF (pi_var_day(i,k,id_aero) < 0.) THEN
431                 IF (iday-day2 < 0.) WRITE(lunout,*) 'iday-day2=',iday-day2
432                 IF (pi_var_year(i,k,im2,id_aero) - pi_var_year(i,k,im,id_aero) < 0.) THEN
433                    WRITE(lunout,*) trim(name_aero(id_aero)),'(i,k,im2)-', &
434                         trim(name_aero(id_aero)),'(i,k,im)=',           &
435                         pi_var_year(i,k,im2,id_aero) - pi_var_year(i,k,im,id_aero)
436                 END IF
437                 
438                 WRITE(lunout,*) 'stop for aerosol : ',name_aero(id_aero)
439                 CALL abort_gcm('readaerosol_interp','Error in interpolation 2',1)
440              END IF
441           END DO
442        END DO
443     END IF
444
445  END IF ! lnewday
446
447!****************************************************************************************
448! Copy output from saved variables
449!
450!****************************************************************************************
451
452  mass_out(:,:)    = var_day(:,:,id_aero)
453  pi_mass_out(:,:) = pi_var_day(:,:,id_aero)
454 
455END SUBROUTINE readaerosol_interp
Note: See TracBrowser for help on using the repository browser.