source: trunk/LMDZ.GENERIC/libf/phystd/optcv.F90 @ 2633

Last change on this file since 2633 was 2582, checked in by emillour, 4 years ago

Generic GCM:
Fixed bug in tpindex (for low temperatures, between first and second
reference temperatures, temperature was wrongly set to tref(1)).
The input temperature was also allowed to be modified by the routine,
which is probably not a good idea and no longer the case.
Took this opportunity to turn tpindex into a module.
GM+EM

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