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

Last change on this file since 1237 was 1237, checked in by Laurent Fairhead, 15 years ago

Des modifications sur la lecture des aerosols par Michael
Correction du test sur le jour de lecture des aerosols qui ne marchait
pas avec le nouveau calendrier (a revoir?)
Menage sur quelques prints
SD/MAF

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