⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 settau.f90

📁 CCSM Research Tools: Community Atmosphere Model (CAM)
💻 F90
字号:
#include <misc.h>#include <params.h>subroutine settau(zdt, iter)!----------------------------------------------------------------------- ! ! Purpose: ! Set time invariant hydrostatic matrices, which depend on the reference! temperature and pressure in the semi-implicit time step. Note that! this subroutine is actually called twice, because the effective time! step changes between step 0 and step 1.! ! Method: ! zdt = delta t for next semi-implicit time step.! ! Author: CCM1! !-----------------------------------------------------------------------!! $Id: settau.F90,v 1.6 2001/09/06 21:26:10 erik Exp $! $Author: erik $!!-----------------------------------------------------------------------  use precision  use pmgrid  use pspect  use commap  use physconst, only: cappa, rair, gravit  implicit none#include <comhyb.h>!------------------------------Arguments--------------------------------  real(r8), intent(in) :: zdt      ! time step (or dt/2 at time 0)  integer, intent(in) :: iter      ! Iteration index!---------------------------Local workspace-----------------------------  real(r8) aq(plev,plev)#if ( defined CRAY )  real(r8) work(plev,2)          ! work array for matrix inverter  real(r8) zdtr                  ! used by minv#else  real(r8) rcond,z(plev),det(2),work(plev)  integer ipvt(plev)#endif  real(r8) zcr(plev)             ! gravity wave equivalent depth  real(r8) zci(plev)             ! dummy, used to print phase speeds  real(r8) zdt2                  ! zdt**2  real(r8) factor                ! intermediate workspace  real(r8) zdt0u                 ! vertical diff. of ref. temp (above)  real(r8) zshu                  ! interface "sigma" (above)  real(r8) zr2ds                 ! 1./(2.*hypd(k))  real(r8) zdt0d                 ! vertical diff. of ref. temp (below)  real(r8) zshd                  ! interface "sigma" (below)  real(r8) ztd                   ! temporary accumulator  real(r8) zcn                   ! sq(n)  real(r8) zb(plev,plev)         ! semi-implicit matrix in d equation  integer k,kk,kkk               ! level indices  integer n                      ! n-wavenumber index  integer nneg                   ! number of unstable mean temperatures!-----------------------------------------------------------------------!! Only do useful work if iter = 1!  if (iter /= 1) return  zdt2 = zdt*zdt!! Set mean temperature! NOTE: Making t0 an actual function of height ***DOES NOT WORK***!  do k=1,plev     t0(k) = 300.  end do!! Calculate hydrostatic matrix tau!  zdt0u = 0.  zshu = 0.  do k=1,plev     zr2ds = 1./(2.*hypd(k))     if (k < plev) then        zdt0d = t0(k+1) - t0(k)        zshd = hybi(k+1)     else        zdt0d = 0.        zshd = 0.     end if     factor = ((zdt0u*zshu + zdt0d*zshd) - (zdt0d + zdt0u))*zr2ds     do kk=1,k-1        tau(kk,k) = factor*hypd(kk) + cappa*t0(k)*ecref(kk,k)     end do     factor = (zdt0u*zshu + zdt0d*zshd - zdt0d)*zr2ds     tau(k,k) = factor*hypd(k) + cappa*t0(k)*ecref(k,k)     factor = (zdt0u*zshu + zdt0d*zshd)*zr2ds     do kk=k+1,plev        tau(kk,k) = factor*hypd(kk)     end do     zdt0u = zdt0d     zshu = zshd  end do!! Vector for linear surface pressure term in divergence! Pressure gradient and diagonal term of hydrostatic components!  do k=1,plev     bps(k) = t0(k)     bps(k) = bps(k)*rair  end do  do k=1,plev     do kk=1,plev        ztd = bps(k) * hypd(kk)/hypi(plevp)        do kkk=1,plev           ztd = ztd + href(kkk,k)*tau(kk,kkk)        end do        zb(kk,k) = ztd        aq(kk,k) = ztd     end do  end do!! Compute and print gravity wave equivalent depths and phase speeds!  call qreig(zb      ,plev    ,zcr     )  do k=1,plev     zci(k) = sign(1._r8,zcr(k))*sqrt(abs(zcr(k)))     zcr(k) = zcr(k) / gravit  end do  if (masterproc) then     write(6,910) (t0(k),k=1,plev)     write(6,920) (zci(k),k=1,plev)     write(6,930) (zcr(k),k=1,plev)  end if!! Test for unstable mean temperatures (negative phase speed and eqivalent! depth) for at least one gravity wave.!  nneg = 0  do k=1,plev     if (zcr(k)<=0.) nneg = nneg + 1  end do  if (nneg/=0) then     write(6,*)'---------------------------------------------------'     write(6,*)'SETTAU: UNSTABLE MEAN TEMPERATURE. STOP'     call endrun  end if!! Compute and invert matrix a(n)=(i+sq*b*delt**2)!            do k=1,plev     do kk=1,plev        aq(kk,k) = aq(kk,k)*zdt2        bm1(kk,k,1) = 0.     end do  end do  do n=2,pnmax     zcn = sq(n)     do k=1,plev        do kk=1,plev           zb(kk,k) = zcn*aq(kk,k)           if(kk.eq.k) zb(kk,k) = zb(kk,k) + 1.        end do     end do!! Use CRAY PVP routine to invert matrix, otherwise use linpack routines!  #if ( defined CRAY )     call minv(zb,plev,plev,work,zdtr,1.0e-100,0,1)#else     call dgeco(zb,plev,plev,ipvt,rcond,z)     call dgedi(zb,plev,plev,ipvt,det,work,01)#endif     do k=1,plev        do kk=1,plev           bm1(kk,k,n) = zb(kk,k)        end do     end do  end do910 format(' REFERENCE TEMPERATURES FOR SEMI-IMPLICIT SCHEME = ',  /(1x,12f9.3))920 format(' GRAVITY WAVE PHASE SPEEDS (M/S) FOR MEAN STATE = '    /(1x,12f9.3))930 format(' GRAVITY WAVE EQUIVALENT DEPTHS (M) FOR MEAN STATE = ' /(1x,12f9.3))  returnend subroutine settau!============================================================================================subroutine qreig(a       ,i       ,b       )!----------------------------------------------------------------------- ! ! Purpose: ! Create complex matrix P with real part = A and imaginary part = 0! Find its eigenvalues and return their real parts.! ! Method: ! This routine is of unknown lineage. It is only used to provide the! equivalent depths of the reference atmosphere for a diagnostic print! in SETTAU and has no effect on the model simulation. Therefore it can ! be replaced at any time with a functionally equivalent, but more ! understandable, procedure.  Consequently, the internal commenting has ! not been brought up to CAM standards.                               ! ! Author: ! !-----------------------------------------------------------------------!! $Id: settau.F90,v 1.6 2001/09/06 21:26:10 erik Exp $! $Author: erik $!!-----------------------------------------------------------------------  use precision  use pmgrid  implicit none!------------------------------Arguments--------------------------------  real(r8), intent(in)  :: a(*)      ! Input real part  integer , intent(in)  :: i  real(r8), intent(out) :: b(*)!-----------------------------------------------------------------------!---------------------------Local variables-----------------------------  complex(r8) p(plev*plev)      complex(r8) q(plev*plev)  integer l,ij,ik               ! indicies!-----------------------------------------------------------------------!  l = 0  do ij=1,i     do ik=1,i        l = l + 1        p(l) = cmplx(a(l),0._r8)     end do  end do  call cmphes(p       ,i       ,1       ,i       )  call cmplr(p       ,q       ,i)  do ij=1,i     b(ij) = real(q(ij))  end do  returnend subroutine qreig!============================================================================================subroutine cmphes(ac      ,nac     ,k       ,l       )!----------------------------------------------------------------------- ! ! Purpose: ! Reduce complex matrix (ac) to upper Hessenburg matrix (ac)! ! Method: ! This routine is of unknown lineage. It is only used to provide the! equivalent depths of the reference atmosphere for a diagnostic print! in SETTAU and has no effect on the model simulation. Therefore it can ! be replaced at any time with a functionally equivalent, but more ! understandable, procedure.  Consequently, the internal commenting has ! not been brought up to CCM3 or CAM standards.                               !! Author: ! !-----------------------------------------------------------------------!! $Id: settau.F90,v 1.6 2001/09/06 21:26:10 erik Exp $! $Author: erik $!!-----------------------------------------------------------------------  use precision  implicit none!------------------------------Arguments--------------------------------  integer, intent(in) :: nac                ! Dimension of one side of matrix ac  integer, intent(in) :: k,l                !  complex(r8), intent(inout) :: ac(nac,nac) ! On input, complex matrix to be converted                                            ! On output, upper Hessenburg matrix!-----------------------------------------------------------------------!---------------------------Local variables-----------------------------  complex(r8) x          complex(r8) y           integer la              integer m1              integer i,m,j         ! Indices  integer j1,i1         ! Loop limits!-----------------------------------------------------------------------!  la = l - 1  m1 = k + 1  do m=m1,la     i = m     x = (0.0,0.0)     do j=m,l        if (abs(ac(j,m-1))>abs(x)) then           x = ac(j,m-1)           i = j        end if     end do     if (i/=m) then        j1 = m - 1        do j=j1,nac           y = ac(i,j)           ac(i,j) = ac(m,j)           ac(m,j) = y        end do        do j=1,l           y = ac(j,i)           ac(j,i) = ac(j,m)           ac(j,m) = y        end do     end if     if (x/=(0.0,0.0)) then        i1 = m + 1        do i=i1,l           y = ac(i,m-1)           if (y/=(0.0,0.0)) then              y = y/x              ac(i,m-1) = y              do j=m,nac                 ac(i,j) = ac(i,j) - y*ac(m,j)              end do              do j=1,l                 ac(j,m) = ac(j,m) + y*ac(j,i)              end do           end if        end do     end if  end do  returnend subroutine cmphes!============================================================================================subroutine cmplr(hes     ,w       ,nc)!----------------------------------------------------------------------- ! ! Purpose: ! Compute w, eigenvalues of upper Hessenburg matrix hes! ! Method: ! This routine is of unknown lineage. It is only used to provide the! equivalent depths of the reference atmosphere for a diagnostic print! in SETTAU and has no effect on the model simulation. Therefore it can ! be replaced at any time with a functionally equivalent, but more ! understandable, procedure.  Consequently, the internal commenting has ! not been brought up to CCM3 or CAM standards.                               !! Author: ! !-----------------------------------------------------------------------!! $Id: settau.F90,v 1.6 2001/09/06 21:26:10 erik Exp $! $Author: erik $!!-----------------------------------------------------------------------  use precision  implicit none!------------------------------Arguments--------------------------------  integer    , intent(in) :: nc            ! Dimension of input and output matrices  complex(r8), intent(inout) :: hes(nc,nc) ! Upper hessenberg matrix from comhes  complex(r8), intent(out):: w(nc)         ! Weights!-----------------------------------------------------------------------!---------------------------Local variables-----------------------------  integer itest   integer nfail      ! Limit for number of iterations to convergence  integer ntest   integer n,j,m   integer i          ! Eigenvalue  integer its        ! Iteration counter  integer l   integer l1,m1,n1,i1  real(r8) a   real(r8) sr   real(r8) si   real(r8) tr   real(r8) ti   real(r8) xr   real(r8) yr   real(r8) zr   real(r8) xi   real(r8) yi   real(r8) areal   real(r8) eps  complex(r8) s   complex(r8) t   complex(r8) x   complex(r8) y   complex(r8) z   complex(r8) u  data itest/0/  save a,eps,sr,itest!-----------------------------------------------------------------------!  nfail = 30  if (itest==0) then     a = 15    continue     eps = a     sr = 1 + a     a = a/2.0     if (sr/=1.0) go to 5     itest = 1  end if  if (nc.le.0) then     write(6,*)'CMPLR: Entered with incorrect dimension  '     write(6,*)'NC=',NC     call endrun  end if  ntest = 10  n = nc  t = 0.010 continue  if (n==0) go to 300  its = 020 continue  if (n/=1) then     do l1=2,n        l = n + 2 - l1        if (abs(hes(l,l-1)) <= eps*(abs(hes(l-1,l-1))+abs(hes(l,l)))) go to 50     end do  end if  l = 150 continue  if (l/=n) then     if (its==nfail) then        i = nc - n + 1        write(6,*)'CMPLR: Failed to converge in ',nfail,' iterations'        write(6,*)'Eigenvalue=',i        call endrun     end if     if (its==ntest) then        ntest = ntest + 10        sr = hes(n,n-1)        si = hes(n-1,n-2)        sr = abs(sr)+abs(si)        u = (0.0,-1.0)*hes(n,n-1)        tr = u        u = (0.0,-1.0)*hes(n-1,n-2)        ti = u        tr = abs(tr) + abs(ti)        s = cmplx(sr,tr)     else        s = hes(n,n)        x = hes(n-1,n)*hes(n,n-1)        if (abs(x)/=0.0) then           y = 0.5*(hes(n-1,n-1)-s)           u = y*y + x           z = sqrt(u)           u = conjg(z)*y           areal = u           if (areal<0.0) z = -z           x = x/(y+z)           s = s - x        end if     end if     do i=1,n        hes(i,i) = hes(i,i) - s     end do     t = t + s     its = its + 1     j = l + 1     xr = abs(hes(n-1,n-1))     yr = abs(hes(n,n-1))     zr = abs(hes(n,n))     n1 = n - 1     if ((n1/=1).and.(n1>=j)) then        do m1=j,n1           m = n1 + j - m1           yi = yr           yr = abs(hes(m,m-1))           xi = zr           zr = xr           xr = abs(hes(m-1,m-1))           if (yr.le.eps*zr/yi*(zr+xr+xi)) go to 100        end do     end if     m = l100  continue     m1 = m + 1     do i=m1,n        x = hes(i-1,i-1)        y = hes(i,i-1)        if (abs(x)<abs(y)) then           i1 = i - 1           do j=i1,n              z = hes(i-1,j)              hes(i-1,j) = hes(i,j)              hes(i,j) = z           end do           z = x/y           w(i) = 1.0        else           z = y/x           w(i) = -1.0        end if        hes(i,i-1) = z        do j=i,n           hes(i,j) = hes(i,j) - z*hes(i-1,j)        end do     end do     m1 = m + 1     do j=m1,n        x = hes(j,j-1)        hes(j,j-1) = 0.0        areal = w(j)        if (areal>0.0) then           do i=l,j              z = hes(i,j-1)              hes(i,j-1) = hes(i,j)              hes(i,j) = z           end do        end if        do i=l,j           hes(i,j-1) = hes(i,j-1) + x*hes(i,j)        end do     end do     go to 20  end if  w(n) = hes(n,n) + t  n = n - 1  go to 10300 continue  returnend subroutine cmplr

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -