source: trunk/LMDZ.PLUTO/libf/phypluto/optcv.F90 @ 3917

Last change on this file since 3917 was 3889, checked in by debatzbr, 4 months ago

Pluto PCM: Pass haze production parameters as keys in callphys.def
BBT

  • Property svn:executable set to *
File size: 15.7 KB
Line 
1MODULE optcv_mod
2
3IMPLICIT NONE
4
5CONTAINS
6
7SUBROUTINE OPTCV(DTAUV,TAUV,TAUCUMV,PLEV,  &
8     QXVAER,QSVAER,GVAER,WBARV,COSBV,       &
9     TAURAY,TAUAERO,TMID,PMID,TAUGSURF,QVAR,MUVAR)
10
11  use radinc_h, only: L_NLAYRAD, L_NLEVRAD, L_LEVELS, L_NSPECTV, L_NGAUSS, L_REFVAR, NAERKIND
12  use radcommon_h, only: gasv, tlimit, wrefVAR, Cmk, tgasref, pfgasref,wnov,scalep,indv,glat_ig
13  use gases_h, only: gfrac, ngasmx, igas_H2, igas_H2O, igas_He, igas_N2, &
14                     igas_CH4, igas_N2
15  use comcstfi_mod, only: g, r, mugaz
16  use callkeys_mod, only: kastprof,continuum,graybody,callgasvis,callmufi,Fabs_aers_VI,Fabs_aerf_VI
17  use recombin_corrk_mod, only: corrk_recombin, gasv_recomb
18  use tpindex_mod, only: tpindex
19
20  implicit none
21
22  !==================================================================
23  !
24  !     Purpose
25  !     -------
26  !     Calculates shortwave optical constants at each level.
27  !
28  !     Authors
29  !     -------
30  !     Adapted from the NASA Ames code by R. Wordsworth (2009)
31  !
32  !==================================================================
33  !
34  !     THIS SUBROUTINE SETS THE OPTICAL CONSTANTS IN THE VISUAL
35  !     IT CALCULATES FOR EACH LAYER, FOR EACH SPECTRAL INTERVAL IN THE VISUAL
36  !     LAYER: WBAR, DTAU, COSBAR
37  !     LEVEL: TAU
38  !
39  !     TAUV(L,NW,NG) is the cumulative optical depth at the top of radiation code
40  !     layer L. NW is spectral wavelength interval, ng the Gauss point index.
41  !
42  !     TLEV(L) - Temperature at the layer boundary
43  !     PLEV(L) - Pressure at the layer boundary (i.e. level)
44  !     GASV(NT,NPS,NW,NG) - Visible k-coefficients
45  !
46  !-------------------------------------------------------------------
47
48
49  real*8,intent(out) :: DTAUV(L_NLAYRAD,L_NSPECTV,L_NGAUSS)
50  real*8 DTAUKV(L_LEVELS,L_NSPECTV,L_NGAUSS)
51  real*8,intent(out) :: TAUV(L_NLEVRAD,L_NSPECTV,L_NGAUSS)
52  real*8,intent(out) :: TAUCUMV(L_LEVELS,L_NSPECTV,L_NGAUSS)
53  real*8,intent(in) :: PLEV(L_LEVELS)
54  real*8,intent(in) :: TMID(L_LEVELS), PMID(L_LEVELS)
55  real*8,intent(out) :: COSBV(L_NLAYRAD,L_NSPECTV,L_NGAUSS)
56  real*8,intent(out) :: WBARV(L_NLAYRAD,L_NSPECTV,L_NGAUSS)
57
58  ! for aerosols
59  real*8,intent(in) :: QXVAER(L_LEVELS,L_NSPECTV,NAERKIND)
60  real*8,intent(in) :: QSVAER(L_LEVELS,L_NSPECTV,NAERKIND)
61  real*8,intent(in) :: GVAER(L_LEVELS,L_NSPECTV,NAERKIND)
62  real*8,intent(in) :: TAUAERO(L_LEVELS,NAERKIND)
63
64  ! local arrays (saved for convenience as need be allocated)
65  real*8,save,allocatable :: TAUAEROLK(:,:,:)
66  real*8,save,allocatable :: TAEROS(:,:,:)
67!$OMP THREADPRIVATE(TAUAEROLK,TAEROS)
68
69  integer L, NW, NG, K, LK, IAER
70  integer MT(L_LEVELS), MP(L_LEVELS), NP(L_LEVELS)
71  real*8  ANS, TAUGAS
72  real*8,intent(in) :: TAURAY(L_NSPECTV) ! Rayleigh scattering
73  real*8  TRAY(L_LEVELS,L_NSPECTV) ! Rayleigh scattering
74  real*8  DPR(L_LEVELS), U(L_LEVELS)
75  real*8  LCOEF(4), LKCOEF(L_LEVELS,4)
76
77  real*8,intent(out) :: taugsurf(L_NSPECTV,L_NGAUSS-1)
78  real*8 DCONT,DAERO
79  real*8 DRAYAER
80  double precision wn_cont, p_cont, p_air, T_cont, dtemp, dtempc
81  double precision p_cross
82
83  ! variable species mixing ratio variables
84  real*8,intent(in) :: QVAR(L_LEVELS)
85  real*8,intent(in) :: MUVAR(L_LEVELS)
86  real*8 :: WRATIO(L_LEVELS)
87  real*8  KCOEF(4)
88  integer NVAR(L_LEVELS)
89
90  ! temporary variables to reduce memory access time to gasv
91  real*8 tmpk(2,2)
92  real*8 tmpkvar(2,2,2)
93
94  ! temporary variables for multiple aerosol calculation
95  real*8 atemp(L_NLAYRAD,L_NSPECTV)
96  real*8 btemp(L_NLAYRAD,L_NSPECTV)
97  real*8 ctemp(L_NLAYRAD,L_NSPECTV)
98
99  ! variables for k in units m^-1
100  real*8 dz(L_LEVELS)
101
102  ! Variables for aerosol absorption
103  real*8 Fabs_aer(NAERKIND)
104
105  integer igas, jgas
106
107  integer interm
108
109  logical :: firstcall=.true.
110!$OMP THREADPRIVATE(firstcall)
111
112  if (firstcall) then
113    ! allocate local arrays of size "naerkind" (which are also
114    ! "saved" so that this is done only once in for all even if
115    ! we don't need to store the value from a time step to the next)
116    allocate(TAUAEROLK(L_LEVELS,L_NSPECTV,NAERKIND))
117    allocate(TAEROS(L_LEVELS,L_NSPECTV,NAERKIND))
118    firstcall=.false.
119  endif ! of if (firstcall)
120
121  !! AS: to save time in computing continuum (see bilinearbig)
122  IF (.not.ALLOCATED(indv)) THEN
123      ALLOCATE(indv(L_NSPECTV,ngasmx,ngasmx))
124      indv = -9999 ! this initial value means "to be calculated"
125  ENDIF
126
127  !=======================================================================
128  !     Determine the total gas opacity throughout the column, for each
129  !     spectral interval, NW, and each Gauss point, NG.
130  !     Calculate the continuum opacities, i.e., those that do not depend on
131  !     NG, the Gauss index.
132
133  dtauv(:,:,:)   = 0.0
134  tauv(:,:,:)    = 0.0
135  taucumv(:,:,:) = 0.0
136
137  taugsurf(:,:) = 0.0
138  dpr(:)        = 0.0 ! pressure difference between levels
139  lkcoef(:,:)   = 0.0
140  DTAUKV(:,:,:) = 0.0
141
142  if(callmufi) then
143   Fabs_aer(1) = Fabs_aers_VI
144   Fabs_aer(2) = Fabs_aerf_VI
145  else
146   Fabs_aer(:) = 1.0
147  endif
148
149  do K=2,L_LEVELS
150     DPR(k) = PLEV(K)-PLEV(K-1)
151
152     ! if we have continuum opacities, we need dz
153     if(kastprof)then
154        dz(k) = dpr(k)*(1000.0d0*8.3145d0/muvar(k))*TMID(K)/(g*PMID(K))
155        U(k)  = Cmk*DPR(k)*mugaz/muvar(k)
156     else
157        dz(k) = dpr(k)*R*TMID(K)/(glat_ig*PMID(K))*mugaz/muvar(k)
158        U(k)  = Cmk*DPR(k)*mugaz/muvar(k)     ! only Cmk line in optci.F
159            !JL13 the mugaz/muvar factor takes into account water meanmolecular weight if water is present
160     endif
161
162     call tpindex(PMID(K),TMID(K),QVAR(K),pfgasref,tgasref,WREFVAR, &
163          LCOEF,MT(K),MP(K),NVAR(K),WRATIO(K))
164
165     do LK=1,4
166        LKCOEF(K,LK) = LCOEF(LK)
167     end do
168  end do                    ! levels
169
170  ! Spectral dependance of aerosol absorption
171       !JL18 It seems to be good to have aerosols in the first "radiative layer" of the gcm in the IR
172            !   but visible does not handle very well diffusion in first layer.
173            !   The tauaero and tauray are thus set to 0 (a small value for rayleigh because the code crashes otherwise)
174            !   in the 4 first semilayers in optcv, but not optci.
175            !   This solves random variations of the sw heating at the model top.
176  do iaer=1,naerkind
177     do NW=1,L_NSPECTV
178        TAEROS(1:4,NW,IAER)=0.d0
179        do K=5,L_LEVELS
180           TAEROS(K,NW,IAER) = TAUAERO(K,IAER) * QXVAER(K,NW,IAER)
181           ! Aerosol absorption correction --> impact on opacity.
182           if (callmufi .and. (TAEROS(K,NW,IAER).gt.0.d0)) then
183            TAEROS(K,NW,IAER) = TAEROS(K,NW,IAER) * &
184                                ((QSVAER(K,NW,IAER)/QXVAER(K,NW,IAER)) + Fabs_aer(IAER)*(1.-(QSVAER(K,NW,IAER)/QXVAER(K,NW,IAER))))
185           endif
186        end do ! L_LEVELS
187     end do ! L_NSPECTV
188  end do ! naerkind
189 
190  ! Rayleigh scattering
191  do NW=1,L_NSPECTV
192     TRAY(1:4,NW)   = 1d-30
193     do K=5,L_LEVELS
194        TRAY(K,NW)   = TAURAY(NW) * DPR(K)
195     end do                    ! levels
196  end do
197
198  !     we ignore K=1...
199  do K=2,L_LEVELS
200
201     do NW=1,L_NSPECTV
202
203        DRAYAER = TRAY(K,NW)
204        !     DRAYAER is Tau RAYleigh scattering, plus AERosol opacity
205        do iaer=1,naerkind
206           DRAYAER = DRAYAER + TAEROS(K,NW,IAER)
207        end do
208
209        DCONT = 0.0 ! continuum absorption
210
211        if(continuum.and.(.not.graybody).and.callgasvis)then
212           ! include continua if necessary
213           wn_cont = dble(wnov(nw))
214           T_cont  = dble(TMID(k))
215           do igas=1,ngasmx
216
217              if(gfrac(igas).eq.-1)then ! variable
218                 p_cont  = dble(PMID(k)*scalep*QVAR(k)) ! qvar = mol/mol
219              else
220                 p_cont  = dble(PMID(k)*scalep*gfrac(igas)*(1.-QVAR(k)))
221              endif
222
223              dtemp=0.0
224              if(igas.eq.igas_N2)then
225
226                 interm = indv(nw,igas,igas)
227!                 call interpolateN2N2(wn_cont,T_cont,p_cont,dtemp,.false.,interm)
228                 indv(nw,igas,igas) = interm
229                 ! only goes to 500 cm^-1, so unless we're around a cold brown dwarf, this is irrelevant in the visible
230
231               ! elseif(igas.eq.igas_H2)then !AF24: removed
232
233               elseif(igas.eq.igas_CH4)then
234
235                 ! first do self-induced absorption
236                 interm = indv(nw,igas,igas)
237                 call interpolateCH4CH4(wn_cont,T_cont,p_cont,dtemp,.false.,interm)
238                 indv(nw,igas,igas) = interm
239
240                 ! then cross-interactions with other gases  !AF24: removed
241
242            !   elseif(igas.eq.igas_H2O.and.T_cont.gt.100.0)then  !AF24: removed
243
244              endif
245              DCONT = DCONT + dtemp
246
247           enddo
248
249           DCONT = DCONT*dz(k)
250
251        endif
252
253        do ng=1,L_NGAUSS-1
254
255           ! Now compute TAUGAS
256
257           ! Interpolate between water mixing ratios
258           ! WRATIO = 0.0 if the requested water amount is equal to, or outside the
259           ! the water data range
260
261           if(L_REFVAR.eq.1)then ! added by RW for special no variable case
262
263              ! JVO 2017 : added tmpk because the repeated calls to gasi/v increased dramatically
264              ! the execution time of optci/v -> ~ factor 2 on the whole radiative
265              ! transfer on the tested simulations !
266
267              IF (corrk_recombin) THEN ! Added by JVO
268                tmpk = GASV_RECOMB(MT(K):MT(K)+1,MP(K):MP(K)+1,1,NW,NG) ! contains the mix of recombined species
269              ELSE
270                tmpk = GASV(MT(K):MT(K)+1,MP(K):MP(K)+1,1,NW,NG)
271              ENDIF
272
273              KCOEF(1) = tmpk(1,1) ! KCOEF(1) = GASV(MT(K),MP(K),1,NW,NG)
274              KCOEF(2) = tmpk(1,2) ! KCOEF(2) = GASV(MT(K),MP(K)+1,1,NW,NG)
275              KCOEF(3) = tmpk(2,2) ! KCOEF(3) = GASV(MT(K)+1,MP(K)+1,1,NW,NG)
276              KCOEF(4) = tmpk(2,1) ! KCOEF(4) = GASV(MT(K)+1,MP(K),1,NW,NG)
277
278           else
279
280              IF (corrk_recombin) THEN
281                tmpkvar = GASV_RECOMB(MT(K):MT(K)+1,MP(K):MP(K)+1,NVAR(K):NVAR(K)+1,NW,NG)
282              ELSE
283                tmpkvar = GASV(MT(K):MT(K)+1,MP(K):MP(K)+1,NVAR(K):NVAR(K)+1,NW,NG)
284              ENDIF
285
286              KCOEF(1) = tmpkvar(1,1,1) + WRATIO(K) *  &
287                        ( tmpkvar(1,1,2)-tmpkvar(1,1,1) )
288
289              KCOEF(2) = tmpkvar(1,2,1) + WRATIO(K) *  &
290                        ( tmpkvar(1,2,2)-tmpkvar(1,2,1) )
291
292              KCOEF(3) = tmpkvar(2,2,1) + WRATIO(K) *  &
293                        ( tmpkvar(2,2,2)-tmpkvar(2,2,1) )
294
295              KCOEF(4) = tmpkvar(2,1,1) + WRATIO(K) *  &
296                        ( tmpkvar(2,1,2)-tmpkvar(2,1,1) )
297
298
299           endif
300
301           ! Interpolate the gaseous k-coefficients to the requested T,P values
302
303           ANS = LKCOEF(K,1)*KCOEF(1) + LKCOEF(K,2)*KCOEF(2) +            &
304                LKCOEF(K,3)*KCOEF(3) + LKCOEF(K,4)*KCOEF(4)
305
306           TAUGAS  = U(k)*ANS
307
308           TAUGSURF(NW,NG) = TAUGSURF(NW,NG) + TAUGAS + DCONT
309           DTAUKV(K,nw,ng) = TAUGAS &
310                             + DRAYAER & ! DRAYAER includes all scattering contributions
311                             + DCONT ! For parameterized continuum aborption
312
313        end do
314
315        ! Now fill in the "clear" part of the spectrum (NG = L_NGAUSS),
316        ! which holds continuum opacity only
317
318        NG              = L_NGAUSS
319        DTAUKV(K,nw,ng) = DRAYAER + DCONT ! Scattering + parameterized continuum absorption
320
321     end do
322  end do
323
324
325  !=======================================================================
326  !     Now the full treatment for the layers, where besides the opacity
327  !     we need to calculate the scattering albedo and asymmetry factors
328
329            !JL18 It seems to be good to have aerosols in the first "radiative layer" of the gcm in the IR
330            !   but not in the visible
331            !   The tauaero is thus set to 0 in the 4 first semilayers in optcv, but not optci.
332            !   This solves random variations of the sw heating at the model top.
333  do iaer=1,naerkind
334    DO NW=1,L_NSPECTV
335      TAUAEROLK(1:4,NW,IAER)=0.d0
336      DO K=5,L_LEVELS
337           TAUAEROLK(K,NW,IAER) = TAUAERO(K,IAER) * QSVAER(K,NW,IAER) ! effect of scattering albedo
338      ENDDO
339    ENDDO
340  end do
341
342  DO NW=1,L_NSPECTV
343     DO L=1,L_NLAYRAD-1
344        K = 2*L+1
345             atemp(L,NW) = SUM(GVAER(K,NW,1:naerkind) * TAUAEROLK(K,NW,1:naerkind)) + &
346                      SUM(GVAER(K+1,NW,1:naerkind) * TAUAEROLK(K+1,NW,1:naerkind))
347      ! Aerosol absorption correction --> impact on single scattering albedo.
348      if (callmufi) then
349         if ((TAEROS(K,NW,1).gt.0.d0) .and. TAEROS(K+1,NW,1).gt.0.d0) then
350            btemp(L,NW) = TAUAEROLK(K,NW,1) / &
351                          (QSVAER(K,NW,1)/QXVAER(K,NW,1) + &
352                           Fabs_aer(1)*(1.-QSVAER(K,NW,1)/QXVAER(K,NW,1))) + &
353                          TAUAEROLK(K+1,NW,1) / &
354                          (QSVAER(K+1,NW,1)/QXVAER(K+1,NW,1) + &
355                           Fabs_aer(1)*(1.-QSVAER(K+1,NW,1)/QXVAER(K+1,NW,1)))
356         else
357            btemp(L,NW) = TAUAEROLK(K,NW,1) + TAUAEROLK(K+1,NW,1)
358         endif
359         if ((TAEROS(K,NW,2).gt.0.d0) .and. TAEROS(K+1,NW,2).gt.0.d0) then
360            btemp(L,NW) = btemp(L,NW) + &
361                          (TAUAEROLK(K,NW,2) / &
362                          (QSVAER(K,NW,2)/QXVAER(K,NW,2) + &
363                           Fabs_aer(2)*(1.-QSVAER(K,NW,2)/QXVAER(K,NW,2)))) + &
364                          (TAUAEROLK(K+1,NW,2) / &
365                          (QSVAER(K+1,NW,2)/QXVAER(K+1,NW,2) + &
366                           Fabs_aer(2)*(1.-QSVAER(K+1,NW,2)/QXVAER(K+1,NW,2))))
367         else
368            btemp(L,NW) = btemp(L,NW) + TAUAEROLK(K,NW,2) + TAUAEROLK(K+1,NW,2)
369         endif
370      else
371         btemp(L,NW) = SUM(TAUAEROLK(K,NW,1:naerkind)) + SUM(TAUAEROLK(K+1,NW,1:naerkind))
372      endif ! callmufi
373      ctemp(L,NW) = btemp(L,NW) + 0.9999*(TRAY(K,NW) + TRAY(K+1,NW))  ! JVO 2017 : does this 0.999 is really meaningful ?
374       
375      btemp(L,NW) = btemp(L,NW) + TRAY(K,NW) + TRAY(K+1,NW)
376           COSBV(L,NW,1:L_NGAUSS) = atemp(L,NW)/btemp(L,NW)
377     END DO ! L vertical loop
378
379     ! Last level
380     !-----------
381     L = L_NLAYRAD
382     K = 2*L+1
383     atemp(L,NW) = SUM(GVAER(K,NW,1:naerkind) * TAUAEROLK(K,NW,1:naerkind))
384     ! Aerosol absorption correction --> impact on single scattering albedo.
385     if (callmufi) then
386      if (TAEROS(K,NW,1).gt.0.d0) then
387         btemp(L,NW) = TAUAEROLK(K,NW,1) / &
388                       (QSVAER(K,NW,1)/QXVAER(K,NW,1) + &
389                        Fabs_aer(1)*(1.-QSVAER(K,NW,1)/QXVAER(K,NW,1)))
390      else
391         btemp(L,NW) = TAUAEROLK(K,NW,1)
392      endif
393      if (TAEROS(K,NW,2).gt.0.d0) then
394         btemp(L,NW) = btemp(L,NW) + &
395                       (TAUAEROLK(K,NW,2) / &
396                       (QSVAER(K,NW,2)/QXVAER(K,NW,2) + &
397                        Fabs_aer(2)*(1.-QSVAER(K,NW,2)/QXVAER(K,NW,2))))
398      else
399         btemp(L,NW) = btemp(L,NW) + TAUAEROLK(K,NW,2)
400      endif
401     else
402      btemp(L,NW) = SUM(TAUAEROLK(K,NW,1:naerkind))
403     endif ! callmufi
404     ctemp(L,NW) = btemp(L,NW) + 0.9999*TRAY(K,NW) ! JVO 2017 : does this 0.999 is really meaningful ?
405     
406     btemp(L,NW) = btemp(L,NW) + TRAY(K,NW)
407     COSBV(L,NW,1:L_NGAUSS) = atemp(L,NW)/btemp(L,NW)
408  END DO ! NW spectral loop
409
410  DO NG=1,L_NGAUSS
411    DO NW=1,L_NSPECTV
412     DO L=1,L_NLAYRAD-1
413
414        K              = 2*L+1
415        DTAUV(L,nw,ng) = DTAUKV(K,NW,NG) + DTAUKV(K+1,NW,NG)
416        WBARV(L,nw,ng) = ctemp(L,NW) / DTAUV(L,nw,ng)
417
418      END DO ! L vertical loop
419
420        ! Last level
421
422        L              = L_NLAYRAD
423        K              = 2*L+1
424        DTAUV(L,nw,ng) = DTAUKV(K,NW,NG)
425
426        WBARV(L,NW,NG) = ctemp(L,NW) / DTAUV(L,NW,NG)
427
428     END DO                 ! NW spectral loop
429  END DO                    ! NG Gauss loop
430
431  ! Total extinction optical depths
432  DO NG=1,L_NGAUSS ! full gauss loop
433     DO NW=1,L_NSPECTV
434        TAUV(1,NW,NG)=0.0D0
435        TAUCUMV(1,NW,NG)=0.0D0
436
437        DO K=2,L_LEVELS
438           TAUCUMV(K,NW,NG)=TAUCUMV(K-1,NW,NG)+DTAUKV(K,NW,NG)
439        END DO
440
441        DO L=1,L_NLAYRAD
442           TAUV(L,NW,NG)=TAUCUMV(2*L,NW,NG)
443        END DO
444        TAUV(L,NW,NG)=TAUCUMV(2*L_NLAYRAD+1,NW,NG)
445     END DO
446  END DO ! end full gauss loop
447
448end subroutine optcv
449
450END MODULE optcv_mod
Note: See TracBrowser for help on using the repository browser.