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

Last change on this file since 1264 was 1249, checked in by yann meurdesoif, 15 years ago

Corrections de Bug divers - portage vers Titane (CCRT) -
YM

File size: 20.2 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 .AND. debug )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  ELSE
113     lnewday=.FALSE.
114  ENDIF
115
116  IF(mpi_rank == 0 .AND. debug)then
117     ! 0.02 is about 0.5/24, namly less than half an hour
118     OLDNEWDAY = (r_day-FLOAT(iday) < 0.02)
119     ! Once per day, update aerosol fields
120     lmt_pas = NINT(86400./pdtphys)
121     PRINT*,'r_day-FLOAT(iday) =',r_day-FLOAT(iday)
122     PRINT*,'itap =',itap
123     PRINT*,'pdtphys =',pdtphys
124     PRINT*,'lmt_pas =',lmt_pas
125     PRINT*,'iday =',iday
126     PRINT*,'r_day =',r_day
127     PRINT*,'day_cur =',day_cur
128     PRINT*,'mth_cur =',mth_cur
129     PRINT*,'year_cur =',year_cur
130     PRINT*,'NINT(86400./pdtphys) =',NINT(86400./pdtphys)
131     PRINT*,'MOD(0,1) =',MOD(0,1)
132     PRINT*,'lnewday =',lnewday
133     PRINT*,'OLDNEWDAY =',OLDNEWDAY
134  ENDIF
135
136  IF (.NOT. ALLOCATED(var_day)) THEN
137     ALLOCATE( var_day(klon, klev, naero_spc), stat=ierr)
138     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 1',1)
139     ALLOCATE( pi_var_day(klon, klev, naero_spc), stat=ierr)
140     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 2',1)
141
142     ALLOCATE( psurf_year(klon, 12, naero_spc), pi_psurf_year(klon, 12, naero_spc), stat=ierr)
143     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 3',1)
144
145     ALLOCATE( load_year(klon, 12, naero_spc), pi_load_year(klon, 12, naero_spc), stat=ierr)
146     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 4',1)
147
148     lnewday=.TRUE.
149
150     NULLIFY(pt_ap)
151     NULLIFY(pt_b)
152  END IF
153
154!****************************************************************************************
155! 1) Read in data : corresponding to the actual year and preindustrial data.
156!    Only for the first day of the year.
157!
158!****************************************************************************************
159  IF ( (first .OR. iday==0) .AND. lnewday ) THEN
160     NULLIFY(pt_tmp)
161
162     ! Reading values corresponding to the closest year taking into count the choice of aer_type.
163     ! For aer_type=scenario interpolation between 2 data sets is done in readaerosol.
164     CALL readaerosol(name_aero(id_aero), aer_type, iyr, klev_src, pt_ap, pt_b, pt_tmp, &
165          psurf_year(:,:,id_aero), load_year(:,:,id_aero))
166     IF (.NOT. ALLOCATED(var_year)) THEN
167        ALLOCATE(var_year(klon, klev_src, 12, naero_spc), stat=ierr)
168        IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 5',1)
169     END IF
170     var_year(:,:,:,id_aero) = pt_tmp(:,:,:)
171
172     ! Reading values corresponding to the preindustrial concentrations.
173     CALL readaerosol(name_aero(id_aero), 'preind', iyr, pi_klev_src, pt_ap, pt_b, pt_tmp, &
174          pi_psurf_year(:,:,id_aero), pi_load_year(:,:,id_aero))
175
176     ! klev_src must be the same in both files.
177     ! Also supposing pt_ap and pt_b to be the same in the 2 files without testing.
178     IF (pi_klev_src /= klev_src) THEN
179        WRITE(lunout,*) 'Error! All forcing files for the same aerosol must have the same vertical dimension'
180        WRITE(lunout,*) 'Aerosol : ', name_aero(id_aero)
181        CALL abort_gcm('readaerosol_interp','Differnt vertical axes in aerosol forcing files',1)
182     END IF
183
184     IF (.NOT. ALLOCATED(pi_var_year)) THEN
185        ALLOCATE(pi_var_year(klon, klev_src, 12, naero_spc), stat=ierr)
186        IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 6',1)
187     END IF
188     pi_var_year(:,:,:,id_aero) = pt_tmp(:,:,:)
189   
190     IF (debug) THEN
191        CALL writefield_phy('var_year_jan',var_year(:,:,1,id_aero),klev_src)
192        CALL writefield_phy('var_year_dec',var_year(:,:,12,id_aero),klev_src)
193        CALL writefield_phy('psurf_src',psurf_year(:,:,id_aero),1)
194        CALL writefield_phy('pi_psurf_src',pi_psurf_year(:,:,id_aero),1)
195        CALL writefield_phy('load_year_src',load_year(:,:,id_aero),1)
196        CALL writefield_phy('pi_load_year_src',pi_load_year(:,:,id_aero),1)
197     END IF
198
199     ! Pointer no more useful, deallocate.
200     DEALLOCATE(pt_tmp)
201
202     ! Test if vertical interpolation will be needed.
203     IF (psurf_year(1,1,id_aero)==not_valid .OR. pi_psurf_year(1,1,id_aero)==not_valid ) THEN
204        ! Pressure=not_valid indicates old file format, see module readaerosol
205        vert_interp = .FALSE.
206
207        ! If old file format, both psurf_year and pi_psurf_year must be not_valid
208        IF (  psurf_year(1,1,id_aero) /= pi_psurf_year(1,1,id_aero) ) THEN
209           WRITE(lunout,*) 'Warning! All forcing files for the same aerosol must have the same structure'
210           CALL abort_gcm('readaerosol_interp', 'The aerosol files have not the same format',1)
211        END IF
212       
213        IF (klev /= klev_src) THEN
214           WRITE(lunout,*) 'Old format of aerosol file do not allowed vertical interpolation'
215           CALL abort_gcm('readaerosol_interp', 'Old aerosol file not possible',1)
216        END IF
217
218     ELSE
219        vert_interp = .TRUE.
220     END IF
221
222  END IF  ! IF ( (first .OR. iday==0) .AND. lnewday ) THEN
223 
224!****************************************************************************************
225! - 2) Interpolate to the actual day.
226! - 3) Interpolate to the model vertical grid.
227!
228!****************************************************************************************
229
230  IF (lnewday) THEN ! only if new day
231!****************************************************************************************
232! 2) Interpolate to the actual day
233!
234!****************************************************************************************
235     ! Find which months and days to use for time interpolation
236     IF (iday < im*30-15) THEN
237        ! in the first half of the month use month before and actual month
238        im2=im-1
239        day2 = im2*30-15
240        day1 = im2*30+15
241        IF (im2 <= 0) THEN
242           ! the month is january, thus the month before december
243           im2=12
244        END IF
245     ELSE
246        ! the second half of the month
247        im2=im+1
248        IF (im2 > 12) THEN
249           ! the month is december, the following thus january
250           im2=1
251        ENDIF
252        day2 = im*30-15
253        day1 = im*30+15
254     END IF
255     
256     ! Time interpolation, still on vertical source grid
257     ALLOCATE(tmp1(klon,klev_src), tmp2(klon,klev_src),stat=ierr)
258     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 7',1)
259
260     ALLOCATE(pplay_src(klon,klev_src), stat=ierr)
261     IF (ierr /= 0) CALL abort_gcm('readaerosol_interp', 'pb in allocation 8',1)
262     
263
264     DO k=1,klev_src
265        DO i=1,klon
266           tmp1(i,k) = &
267                var_year(i,k,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
268                (var_year(i,k,im2,id_aero) - var_year(i,k,im,id_aero))
269           
270           tmp2(i,k) = &
271                pi_var_year(i,k,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
272                (pi_var_year(i,k,im2,id_aero) - pi_var_year(i,k,im,id_aero))
273        END DO
274     END DO
275
276     ! Time interpolation for pressure at surface, still on vertical source grid
277     DO i=1,klon
278        psurf_day(i) = &
279             psurf_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
280             (psurf_year(i,im2,id_aero) - psurf_year(i,im,id_aero))
281       
282        pi_psurf_day(i) = &
283             pi_psurf_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
284             (pi_psurf_year(i,im2,id_aero) - pi_psurf_year(i,im,id_aero))
285     END DO
286
287     ! Time interpolation for the load, still on vertical source grid
288     DO i=1,klon
289        load_src(i) = &
290             load_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
291             (load_year(i,im2,id_aero) - load_year(i,im,id_aero))
292       
293        pi_load_src(i) = &
294             pi_load_year(i,im2,id_aero) - FLOAT(iday-day2)/FLOAT(day1-day2) * &
295             (pi_load_year(i,im2,id_aero) - pi_load_year(i,im,id_aero))
296     END DO
297
298!****************************************************************************************
299! 3) Interpolate to the model vertical grid (target grid)
300!
301!****************************************************************************************
302
303     IF (vert_interp) THEN
304
305        ! - Interpolate variable tmp1 (on source grid) to var_day (on target grid)
306        !********************************************************************************
307        ! a) calculate pression at vertical levels for the source grid using the
308        !    hybrid-sigma coordinates ap and b and the surface pressure, variables from file.
309        DO k = 1, klev_src
310           DO i = 1, klon
311              pplay_src(i,k)= pt_ap(k) + pt_b(k)*psurf_day(i)
312           END DO
313        END DO
314       
315        IF (debug) THEN
316           CALL writefield_phy('psurf_day_src',psurf_day(:),1)
317           CALL writefield_phy('pplay_src',pplay_src(:,:),klev_src)
318           CALL writefield_phy('pplay',pplay(:,:),klev)
319           CALL writefield_phy('day_src',tmp1,klev_src)
320           CALL writefield_phy('pi_day_src',tmp2,klev_src)
321        END IF
322
323        ! b) vertical interpolation on pressure leveles
324        CALL pres2lev(tmp1(:,:), var_day(:,:,id_aero), klev_src, klev, pplay_src, pplay, &
325             1, klon, .FALSE.)
326       
327        IF (debug) CALL writefield_phy('day_tgt',var_day(:,:,id_aero),klev)
328       
329        ! c) adjust to conserve total aerosol mass load in the vertical pillar
330        !    Calculate the load in the actual pillar and compare with the load
331        !    read from aerosol file.
332       
333        ! Find the pressure difference in each model layer
334        DO k = 1, klev
335           DO i = 1, klon
336              delp(i,k) = paprs(i,k) - paprs (i,k+1)
337           END DO
338        END DO
339
340        ! Find the mass load in the actual pillar, on target grid
341        load_tgt(:) = 0.
342        DO k= 1, klev
343           DO i = 1, klon
344              zrho = pplay(i,k)/t_seri(i,k)/RD       ! [kg/m3]
345              volm = var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
346              load_tgt(i) = load_tgt(i) + 1/RG * volm *delp(i,k)
347           END DO
348        END DO
349       
350        ! Adjust, uniform
351        DO k = 1, klev
352           DO i = 1, klon
353              var_day(i,k,id_aero) = var_day(i,k,id_aero)*load_src(i)/load_tgt(i)
354           END DO
355        END DO
356       
357        IF (debug) THEN
358           load_tgt_test(:) = 0.
359           DO k= 1, klev
360              DO i = 1, klon
361                 zrho = pplay(i,k)/t_seri(i,k)/RD       ! [kg/m3]
362                 volm = var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
363                 load_tgt_test(i) = load_tgt_test(i) + 1/RG * volm*delp(i,k)
364              END DO
365           END DO
366           
367           CALL writefield_phy('day_tgt2',var_day(:,:,id_aero),klev)
368           CALL writefield_phy('load_tgt',load_tgt(:),1)
369           CALL writefield_phy('load_tgt_test',load_tgt_test(:),1)
370           CALL writefield_phy('load_src',load_src(:),1)
371        END IF
372
373        ! - Interpolate variable tmp2 (source grid) to pi_var_day (target grid)
374        !********************************************************************************
375        ! a) calculate pression at vertical levels at source grid   
376        DO k = 1, klev_src
377           DO i = 1, klon
378              pplay_src(i,k)= pt_ap(k) + pt_b(k)*pi_psurf_day(i)
379           END DO
380        END DO
381
382        IF (debug) THEN
383           CALL writefield_phy('pi_psurf_day_src',pi_psurf_day(:),1)
384           CALL writefield_phy('pi_pplay_src',pplay_src(:,:),klev_src)
385        END IF
386
387        ! b) vertical interpolation on pressure leveles
388        CALL pres2lev(tmp2(:,:), pi_var_day(:,:,id_aero), klev_src, klev, pplay_src, pplay, &
389             1, klon, .FALSE.)
390
391        IF (debug) CALL writefield_phy('pi_day_tgt',pi_var_day(:,:,id_aero),klev)
392
393        ! c) adjust to conserve total aerosol mass load in the vertical pillar
394        !    Calculate the load in the actual pillar and compare with the load
395        !    read from aerosol file.
396
397        ! Find the load in the actual pillar, on target grid
398        load_tgt(:) = 0.
399        DO k = 1, klev
400           DO i = 1, klon
401              zrho = pplay(i,k)/t_seri(i,k)/RD          ! [kg/m3]
402              volm = pi_var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
403              load_tgt(i) = load_tgt(i) + 1/RG * volm * delp(i,k)
404           END DO
405        END DO
406
407        DO k = 1, klev
408           DO i = 1, klon
409              pi_var_day(i,k,id_aero) = pi_var_day(i,k,id_aero)*pi_load_src(i)/load_tgt(i)
410           END DO
411        END DO
412
413        IF (debug) THEN
414           load_tgt_test(:) = 0.
415           DO k = 1, klev
416              DO i = 1, klon
417                 zrho = pplay(i,k)/t_seri(i,k)/RD          ! [kg/m3]
418                 volm = pi_var_day(i,k,id_aero)*1.E-9/zrho ! [kg/kg]
419                 load_tgt_test(i) = load_tgt_test(i) + 1/RG * volm * delp(i,k)
420              END DO
421           END DO
422           CALL writefield_phy('pi_day_tgt2',pi_var_day(:,:,id_aero),klev)
423           CALL writefield_phy('pi_load_tgt',load_tgt(:),1)
424           CALL writefield_phy('pi_load_tgt_test',load_tgt_test(:),1)
425           CALL writefield_phy('pi_load_src',pi_load_src(:),1)
426        END IF
427
428
429     ELSE   ! No vertical interpolation done
430
431        var_day(:,:,id_aero)    = tmp1(:,:)
432        pi_var_day(:,:,id_aero) = tmp2(:,:)
433
434     END IF ! vert_interp
435
436
437     ! Deallocation
438     DEALLOCATE(tmp1, tmp2, pplay_src, stat=ierr)
439
440!****************************************************************************************
441! 4) Test for negative mass values
442!
443!****************************************************************************************
444     IF (MINVAL(var_day(:,:,id_aero)) < 0.) THEN
445        DO k=1,klev
446           DO i=1,klon
447              ! Test for var_day
448              IF (var_day(i,k,id_aero) < 0.) THEN
449                 IF (iday-day2 < 0.) WRITE(lunout,*) 'iday-day2=',iday-day2
450                 IF (var_year(i,k,im2,id_aero) - var_year(i,k,im,id_aero) < 0.) THEN
451                    WRITE(lunout,*) trim(name_aero(id_aero)),'(i,k,im2)-', &
452                         trim(name_aero(id_aero)),'(i,k,im)=',           &
453                         var_year(i,k,im2,id_aero) - var_year(i,k,im,id_aero)
454                 END IF
455                 
456                 WRITE(lunout,*) 'stop for aerosol : ',name_aero(id_aero)
457                 CALL abort_gcm('readaerosol_interp','Error in interpolation 1',1)
458              END IF
459           END DO
460        END DO
461     END IF
462
463     IF (MINVAL(pi_var_day(:,:,id_aero)) < 0. ) THEN
464        DO k=1, klev
465           DO i=1,klon
466              ! Test for pi_var_day
467              IF (pi_var_day(i,k,id_aero) < 0.) THEN
468                 IF (iday-day2 < 0.) WRITE(lunout,*) 'iday-day2=',iday-day2
469                 IF (pi_var_year(i,k,im2,id_aero) - pi_var_year(i,k,im,id_aero) < 0.) THEN
470                    WRITE(lunout,*) trim(name_aero(id_aero)),'(i,k,im2)-', &
471                         trim(name_aero(id_aero)),'(i,k,im)=',           &
472                         pi_var_year(i,k,im2,id_aero) - pi_var_year(i,k,im,id_aero)
473                 END IF
474                 
475                 WRITE(lunout,*) 'stop for aerosol : ',name_aero(id_aero)
476                 CALL abort_gcm('readaerosol_interp','Error in interpolation 2',1)
477              END IF
478           END DO
479        END DO
480     END IF
481
482  END IF ! lnewday
483
484!****************************************************************************************
485! Copy output from saved variables
486!
487!****************************************************************************************
488
489  mass_out(:,:)    = var_day(:,:,id_aero)
490  pi_mass_out(:,:) = pi_var_day(:,:,id_aero)
491 
492END SUBROUTINE readaerosol_interp
Note: See TracBrowser for help on using the repository browser.