subroutine prewgt(mype) !$$$ subprogram documentation block ! . . . . ! subprogram: prewgt ! prgmmr: wu org: np22 date: 2000-03-15 ! ! abstract: setup smoothing and grid transform for background error ! ! program history log: ! 2000-03-15 wu ! 2004-02-03 kleist, updated to load background stats according ! to updated mpi distribution on horizontal slabs ! 2004-03-15 derber, kleist, incorporate variances into this routine ! stats from single file, additional clean up ! 2004-05-17 kleist, documentation and clean up ! 2004-08-03 treadon - add only to module use, add intent in/out ! 2004-10-26 wu - include factors hzscl in the range of RF table ! 2004-11-02 treadon - add horizontal resolution error check on berror_stats ! 2004-11-16 treadon - add longitude dimension to variance array dssv ! 2004-11-20 derber - modify to make horizontal table more reproducable and ! move most of table calculations to berror ! 2005-01-22 parrish - split out balance variables to subroutine prebal--this ! to make anisotropic filtering option less confusing ! 2005-02-23 wu - setup background variance for qoption=2 ! 2005-03-28 wu - change loop index (mlat+1 to mlat) over varq ! 2005-04-14 treadon - add corq2 to global berror_stats read ! 2005-04-22 treadon - change berror file to 4-byte reals ! 2005-05-27 kleist - add setup call for new patch interpolation ! 2005-08-16 guo - add gmao surface interface ! 2005-09-28 guo - set nrr=nlat to support the GMAO grid ! 2005-09-28 guo - fixed nrr to nlat-2 to avoid the subscript of ! array rlats being out of the range, and to avoid the ! singularity of rs at rlats(1)=-pi/2. ! 2005-11-16 wgu - set nolp=nr+1+(ny-nlat)/2 to make sure ! nmix+nrmxb=nr in routine smoothrf no matter what ! number nlat is. ! 2005-11-29 derber - unify ozone variance calculation ! 2006-01-10 treadon - replace rdsfull with read_gfssfc_full ! 2006-01-11 kleist - place upper/lower bounds on qoption=2 variance ! 2006-01-31 treadon - invert hzscl ! 2006-02-03 derber - fix up sl array stuff ! 2006-04-12 treadon - remove sigl (not used) ! 2006-04-21 kleist - add capability to perturb background error parameters ! 2006-07-28 derber - use r1000 from constants ! 2006-09-18 derber - change minimum moisture variance ! 2007-05-30 h.liu - use oz stats from berror file ! 2007-07-03 kleist - add option for flow-dependent background error variances ! 2008-04-23 safford - rm unused uses and vars ! 2008-07-30 guo - read stats using m_berror_stats ! 2009-01-12 gayno - rm use of read_gfssfc_full ! 2010-02-25 zhu - mv varq to m_berror_stats ! - make changes for generalizing control variables, ! change interface of berror_read_wgt,use nrf* ! 2010-04-01 treadon - move strip to gridmod ! 2010-04-10 parrish - remove rhgues, no longer needed ! ! input argument list: ! mype - mpi task id ! ! output argument list: ! ! ! attributes: ! language: f90 ! machine: ibm RS/6000 SP ! !$$$ use kinds, only: r_kind,i_kind,r_single use berror, only: dssvs,wtaxs,& bw,wtxrs,inaxs,inxrs,as,nr,ny,nx,mr,ndeg,& nf,vs,be,dssv,norh,bl2,bl,init_rftable,hzscl,& pert_berr,bkgv_flowdep,tsfc_sdv,slw,slw1,slw2 use m_berror_stats,only : berror_read_wgt use mpimod, only: nvar_id,levs_id use mpimod, only: mpi_comm_world,ierror,mpi_rtype use jfunc, only: qoption use control_vectors, only: nrf,nrf2,nrf3,nrf3_sf,nrf3_cw,nrf3_q,& nrf3_vp,nrf3_t,nrf3_oz,nrf2_ps,nrf2_sst,nrf3_loc,nrf2_loc use gridmod, only: istart,jstart,lat2,lon2,rlats,nlat,nlon,nsig,& nnnn1o,lat1,lon1,itotsub,iglobal,ltosi,ltosj,ijn,displs_g,& strip use constants, only: izero,ione,zero,quarter,half,one,two,three,& rearth_equator,pi,r1000 use guess_grids, only: isli2 use smooth_polcarf, only: norsp,setup_smooth_polcas implicit none ! Declare passed variables integer(i_kind),intent(in ) :: mype ! Declare local variables integer(i_kind) n,nrr,iii,jjj,nxg,i2,im,jm,j2,loc integer(i_kind) i,j,k,ii,nn,nbuf,nmix,nxe,nor,ndx,ndy integer(i_kind) nlathh,mm1,nolp,mm,ir,k1 integer(i_kind) ix,jx,mlat integer(i_kind) kd,kt,kq,kc,koz,nf2p integer(i_kind),dimension(0:40):: iblend real(r_kind) wlipi,wlipih,df real(r_kind) samp,y,s2u,x,dxx,df2,pi2 real(r_kind),dimension(ndeg):: rate real(r_kind),dimension(ndeg,ndeg):: turn real(r_kind),dimension(nsig,0:nlat+ione,nrf3):: vz real(r_kind),dimension(0:nlat+ione,nsig,nrf3):: hwll real(r_kind),dimension(lat2,lon2)::temp real(r_kind),dimension(0:nlat+ione,nrf2):: hwllp real(r_kind),dimension(nlat,nlon):: sl,factx real(r_kind),dimension(-nf:nf,-nf:nf) :: fact1,fact2 real(r_kind),dimension(mr:nlat-2_i_kind):: rs real(r_kind),dimension(lat1*lon1)::zsm real(r_kind),dimension(itotsub)::work1 real(r_kind),dimension(ny,nx,3):: scsli real(r_kind),dimension(-nf:nf,-nf:nf,3):: scs12 real(r_single),dimension(nlat,nsig,nrf3):: corz real(r_single),dimension(nlat,nrf2):: corp real(r_single),dimension(nlat,nlon):: corsst real(r_kind),dimension(lon2,nsig):: dsv real(r_single) hsstmin real(r_kind) minhsst real(r_kind),allocatable:: randfct(:) real(r_kind),allocatable,dimension(:,:,:,:):: sli,sli1,sli2 real(r_single),dimension(nlat,nsig,nrf3):: hwllin real(r_single),dimension(nlat,nrf2):: hwllinp real(r_single),dimension(nlat,nlon):: hsst real(r_single),dimension(nsig,nlat,nrf3):: vscalesin real(r_kind),dimension(lat2,lon2,nsig):: sfvar,vpvar,tvar real(r_kind),dimension(lat2,lon2):: psvar ! real(r_kind),parameter:: eight_tenths = 0.8_r_kind ! real(r_kind),parameter:: six = 6.0_r_kind ! real(r_kind),parameter:: r400 = 400.0_r_kind ! real(r_kind),parameter:: r800 = 800.0_r_kind ! real(r_kind),parameter:: r40000 = 40000.0_r_kind ! real(r_kind),parameter:: r25 = one/25.0_r_kind ! Initialize local variables pi2=two*pi ndy=(nlat-ny)/2 nxe=nlon/8 nor=norh*2 mm1=mype+ione nlathh=nlat/4 nf2p=2*nf+ione ! Setup blending mm=4_i_kind call blend(mm,iblend) nolp=nr+ione+(ny-nlat)/2 ! nbuf=nolp/4 nbuf=izero nmix=nolp-nbuf*2 dxx=one/(nmix+ione) bl2=zero k=izero do i=1,nmix k=k+ione x=i*dxx y=zero y=iblend(mm) do j=mm-ione,0,-1 y=x*y+iblend(j) enddo y=y*x**(mm+ione) bl2(k)=one-y enddo do k=1,nmix bl2(k)=sqrt(bl2(k)) end do nmix=(nx-nlon) dxx=one/(nmix+ione) ndx=(nx-nlon) bl=zero k=ndx-nmix do i=1,nmix k=k+ione x=i*dxx y=zero y=iblend(mm) do j=mm-ione,0,-1 y=x*y+iblend(j) enddo y=y*x**(mm+ione) bl(k)=one-y enddo do k=1,nmix bl(k)=sqrt(bl(k)) end do ! Setup sea-land mask sl=zero if(bw /= zero)then do j=1,lon1*lat1 zsm(j)=zero end do do j=1,lon2 do i=1,lat2 temp(i,j)=float(isli2(i,j)) end do end do call strip(temp,zsm,ione) call mpi_allgatherv(zsm,ijn(mm1),mpi_rtype,& work1,ijn,displs_g,mpi_rtype,& mpi_comm_world,ierror) do k=1,iglobal i=ltosi(k) ; j=ltosj(k) sl(i,j)=work1(k) end do do j=1,nlon do i=1,nlat if(sl(i,j) > one)sl(i,j)=zero enddo enddo call smoothww(nlat,nlon,sl,half,2_i_kind,ione) do j=1,nlon do i=1,nlat sl(i,j)=min(max(sl(i,j),zero),one) enddo enddo end if ! Get background error statistics from a file ("berror_stats"). call berror_read_wgt(corz,corp,hwllin,hwllinp,vscalesin,corsst,hsst,mype) mlat=nlat ! load the horizontal length scales hwll=zero do j=1,nrf3 do k=1,nsig do i=1,nlat hwll(i,k,j)=hwllin(i,k,j) end do end do end do hwll(:,:,nrf3_oz)=hwll(:,:,nrf3_oz)*three !inflate scale hwll(:,:,nrf3_cw)=hwll(:,:,nrf3_q) !use hwll of q for cw for now ! surface pressure hwllp=zero do j=1,nrf2 do i=1,nlat hwllp(i,j)=hwllinp(i,j) end do end do ! sea surface temperature, convert from km to m ! also calculate a minimum horizontal length scale for ! sst to be used for land skin temp and ice temp hsstmin=1.e10_r_single minhsst=1.e10_r_kind do j=1,nlon do i=1,nlat hsst(i,j)=r1000*hsst(i,j) hsstmin=min(hsstmin,hsst(i,j)) end do end do minhsst=hsstmin ! perturb background error ! Things to perturb: as(1-8), hzscl(1-3) and vs(1) if (pert_berr) then allocate(randfct(12)) call get_randoms(12_i_kind,randfct) do i=1,8 as(i)=as(i)+as(i)*randfct(i) end do do i=1,3 hzscl(i)=hzscl(i)+hzscl(i)*randfct(8_i_kind+i) end do vs=vs+vs*randfct(12) if (mype==izero) then write(6,*) 'PREWGT: REDEFINE AS = ',as write(6,*) 'PREWGT: REDEFINE HZSCL = ',hzscl write(6,*) 'PREWGT: REDEFINE VS = ',vs end if deallocate(randfct) end if ! As used in the code, the horizontal length scale ! parameters are used in an inverted form. Invert ! the parameter values here. do i=1,3 hzscl(i)=one/hzscl(i) end do ! apply scaling (deflate/inflate) to vertical length scales ! note: parameter vs needs to be inverted vs=one/vs ! Initialize full array to zero before loading part of array below vz=zero ! load vertical length scales do j=1,nrf3 do k=1,nsig do i=1,nlat vz(k,i,j)=vs*vscalesin(k,i,j) end do end do end do ! for now use q error for cwm do k=1,nsig do i=1,nlat vz(k,i,nrf3_cw)=vz(k,i,nrf3_q) end do end do call rfdpar1(be,rate,ndeg) call rfdpar2(be,rate,turn,samp,ndeg) ! Load background error variances onto subdomains do k=1,nsig do i=1,lat2 ix=istart(mm1)+i-2_i_kind ix=max(ix,2_i_kind) ix=min(nlat-ione,ix) do j=1,lon2 sfvar(i,j,k)=corz(ix,k,nrf3_sf) vpvar(i,j,k)=corz(ix,k,nrf3_vp) tvar(i,j,k)=corz(ix,k,nrf3_t) end do end do end do do i=1,lat2 ix=istart(mm1)+i-2_i_kind ix=max(ix,2_i_kind) ix=min(nlat-ione,ix) do j=1,lon2 psvar(i,j)=corp(ix,nrf2_ps) end do end do ! Reweight the variances based on flow dependence if flag set if (bkgv_flowdep) call bkgvar_rewgt(sfvar,vpvar,tvar,psvar,mype) ! vertical length scales !!!$omp parallel do schedule(dynamic,1) private(i,n,k,j,jx,ix,loc,dsv) do n=1,nrf3 loc=nrf3_loc(n) do j=1,lat2 jx=istart(mm1)+j-2 jx=max(jx,2) jx=min(nlat-1,jx) call smoothzo(vz(1,jx,n),samp,rate,n,j,dsv) ! load variances onto subdomains if (n==nrf3_sf) then do k=1,nsig do i=1,lon2 dssv(j,i,k,n)=dsv(i,k)*sfvar(j,i,k)*as(loc) ! streamfunction end do end do else if (n==nrf3_vp) then do k=1,nsig do i=1,lon2 dssv(j,i,k,n)=dsv(i,k)*vpvar(j,i,k)*as(loc) ! velocity potential end do end do else if (n==nrf3_t) then do k=1,nsig do i=1,lon2 dssv(j,i,k,n)=dsv(i,k)*tvar(j,i,k)*as(loc) ! temperature end do end do else do k=1,nsig do i=1,lon2 dssv(j,i,k,n)=dsv(i,k)*corz(jx,k,n)*as(loc) end do end do end if enddo end do ! Special case of dssv for qoption=2 if (qoption==2) call compute_qvar3d !!!$omp parallel do schedule(dynamic,1) private(i,n,j,jx,ix,loc) do n=1,nrf2 loc=nrf2_loc(n) if (n==nrf2_ps) then do j=1,lat2 do i=1,lon2 dssvs(j,i,n)=psvar(j,i)*as(loc) ! surface pressure end do end do else if (n==nrf2_sst) then do j=1,lat2 do i=1,lon2 if(isli2(j,i) == ione)then dssvs(j,i,nrf2+1)= tsfc_sdv(1) ! land surface temperature else if(isli2(j,i) == 2_i_kind)then dssvs(j,i,nrf2+2)= tsfc_sdv(2) ! ice surface temperature else jx=istart(mm1)+j-2_i_kind jx=max(jx,2_i_kind) jx=min(nlat-ione,jx) ix=jstart(mm1)+i-2_i_kind if (ix==izero) ix=nlon ix=max(ix,ione) if (ix==nlon+ione) ix=ione ix=min(nlon,ix) dssvs(j,i,n)=corsst(jx,ix)*as(loc) ! sea surface temperature end if end do end do end if end do ! distance of gaussian lat from pole on stereogaphic map ! r=r/(1+z) do ir=mr,ubound(rs,1) ! ubound(rs,1) is nlat-2 to skip S.P. rs(ir)=cos(rlats(nlat-ir))/(one+sin(rlats(nlat-ir))) enddo df=tan(pi2/nlon*half) ! set up polcas call setwts(wtaxs,wtxrs,inaxs,inxrs,rs,df,nor,nxe,nf,mr,nr) ! set up smooth_polcas if desired (norsp > 0) if(norsp>izero) call setup_smooth_polcas ! load arrays which are in correct units, to be used to ! define the scales below do j=1,nlon do i=2,nlat-ione factx(i,j)=one/(one+(one-sl(i,j))*bw) end do factx(1,j)=factx(2,j) factx(nlat,j)=factx(nlat-ione,j) end do wlipi=nlon/pi2 wlipih=nlon/pi2*half*samp*samp do j=1,nx jjj=j-ndx if(jjj<ione)jjj=nlon+jjj if(jjj>nlon)jjj=jjj-nlon do i=1,ny iii=i+ndy scsli(i,j,1)=(rlats(iii+ione)-rlats(iii-ione))*wlipih*cos(rlats(iii))* & factx(iii,jjj)**2 scsli(i,j,2)=(rlats(iii )-rlats(iii-ione))*wlipi*factx(iii,jjj) scsli(i,j,3)=cos(rlats(iii))*factx(iii,jjj) enddo enddo nxg=nxe+norh nrr=ubound(rs,1) ! was nf*3/2 ndx=(nx-nlon)/2 call polcasl(factx,fact1,fact2,ione,nf,mr,nrr,nor,rs,df,nxe,nxg) fact1(0,0)=quarter*(fact1(1,0)+fact1(0,1)+fact1(-1,0)+fact1(0,-1)) fact2(0,0)=quarter*(fact2(1,0)+fact2(0,1)+fact2(-1,0)+fact2(0,-1)) df2=df*df do j=-nf,nf jm=j-ione j2=j*j do i=-nf,nf im=i-ione i2=i*i scs12(i,j,1)=(samp/(one+(i2+j2)*df2))**2*fact1(i,j)**2 scs12(i,j,2)=one/(one+((im*im+i2)*half+j2)*df2)*fact1(i,j) scs12(i,j,3)=one/(one+(i2+(j2+jm*jm)*half)*df2)*fact1(i,j) enddo enddo ! Convert horizontal scales from physical units (m) to grid relative units ! rearth_equator is the equatorial radius from a 1999 IAG report. The ! horizontal scales are defined at the equator, hence the need for the ! equatorial radius. s2u=(two*pi*rearth_equator)/float(nlon) allocate(sli(ny,nx,2,nnnn1o),sli1(-nf:nf,-nf:nf,2,nnnn1o), & sli2(-nf:nf,-nf:nf,2,nnnn1o)) !!!$omp parallel do schedule(dynamic,1) private(k,k1,j,ii,iii,jjj,i,n,nn,factx,fact1,fact2) do k=1,nnnn1o k1=levs_id(k) if (k1==izero) then do j=1,nlon do i=2,nlat-ione factx(i,j)=zero end do end do else n=nvar_id(k) nn=-ione do ii=1,nrf3 if (nrf3_loc(ii)==n) then nn=ii do j=1,nlon do i=2,nlat-ione factx(i,j)=s2u/hwll(i,k1,nn) end do end do exit end if end do if (nn==-ione) then do ii=1,nrf2 if (nrf2_loc(ii)==n .or. n>nrf) then nn=ii if (n>nrf) nn=n-nrf3 if (nn==nrf2_sst) then do j=1,nlon do i=2,nlat-ione factx(i,j)=s2u/hsst(i,j) end do end do else if (nn>nrf2) then do j=1,nlon do i=2,nlat-ione factx(i,j)=two*s2u/minhsst end do end do else do j=1,nlon do i=2,nlat-ione factx(i,j)=s2u/hwllp(i,nn) end do end do end if exit end if end do end if endif ! end if over nvar_id do j=1,nlon factx(1,j)=factx(2,j) factx(nlat,j)=factx(nlat-ione,j) end do call polcasl(factx,fact1,fact2,ione,nf,mr,nrr,nor,rs,df,nxe,nxg) fact1(0,0)=quarter*(fact1(1,0)+fact1(0,1)+fact1(-1,0)+fact1(0,-1)) fact2(0,0)=quarter*(fact2(1,0)+fact2(0,1)+fact2(-1,0)+fact2(0,-1)) ! first sli do j=1,nx jjj=j-ndx if(jjj < ione)jjj=jjj+nlon if(jjj > nlon)jjj=jjj-nlon do i=1,ny iii=i+ndy slw((j-ione)*ny+i,k)=scsli(i,j,1)*factx(iii,jjj)**2 sli(i,j,1,k)=scsli(i,j,2)*factx(iii,jjj) sli(i,j,2,k)=scsli(i,j,3)*factx(iii,jjj) enddo enddo ! now load sli1/sli2 do j=-nf,nf do i=-nf,nf slw2((j+nf)*nf2p+nf+ione+i,k)=scs12(i,j,1)*fact1(i,j)**2 slw1((j+nf)*nf2p+nf+ione+i,k)=scs12(i,j,1)*fact2(i,j)**2 sli2(i,j,1,k)=scs12(i,j,2)*fact1(i,j) sli1(i,j,1,k)=scs12(i,j,2)*fact2(i,j) sli2(i,j,2,k)=scs12(i,j,3)*fact1(i,j) sli1(i,j,2,k)=scs12(i,j,3)*fact2(i,j) enddo enddo end do ! end do over nsig1o/loadling of sli arrays ! Load tables used in recursive filters call init_rftable(mype,rate,nnnn1o,sli,sli1,sli2) deallocate(sli,sli1,sli2) return end subroutine prewgt subroutine blend(n,iblend) !$$$ subprogram documentation block ! . . . . ! subprogram: blend ! prgmmr: purser org: w/nmc22 date:1998 ! ! abstract: put coefficients for n+1,..,2n+1, into iblend(0),.. ! iblend(n) ! ! program history log: ! 2004-05-13 kleist documentation ! 2008-04-23 safford - rm unused uses ! ! input argument list: ! n - number of powers to blend ! ! output argument list: ! iblend - blended coefficients ! ! remarks: put the coefficients for powers n+1,..,2n+1, into iblend(0), ! ..iblend(n),for the "blending polynomial" of continuity- ! degree n in the interval [0,1]. For example, with n=1, the ! blending polynomial has up to 1st derivatives continuous ! with y(0)=0, y(1)=1, y'(0)=y'(1)=0, when y(x)=3x^2-2x^3. ! Hence iblend={3,-2} ! ! attributes: ! language: f90 ! machine: ibm rs/6000 sp ! !$$$ use kinds, only: i_kind use constants, only: izero,ione implicit none ! Declare passed variables integer(i_kind) ,intent(in ) :: n integer(i_kind),dimension(0:n),intent( out) :: iblend ! Declare local parameters integer(i_kind),parameter:: nn=12_i_kind ! Declare local variables integer(i_kind) np,i,j,ib integer(i_kind),dimension(0:nn):: ipascal(0:nn) if(n>nn)stop np=n+ione do i=0,n ipascal(i)=izero enddo ipascal(0)=ione do i=0,n do j=i,1,-1 ipascal(j)=ipascal(j)-ipascal(j-ione) enddo enddo ib=ione do i=1,n ib=(ib*2*(2*i+1))/i enddo do j=0,n iblend(j)=(ib*ipascal(j))/(np+j) enddo return end subroutine blend subroutine get_randoms(count,randnums) !$$$ subprogram documentation block ! . . . . ! subprogram: get_randoms ! prgmmr: kleist org: np22 date: 2006-04-24 ! ! abstract: get random numbers for perturbing background error parms ! ! program history log: ! 2006-04-21 kleist ! 2008-04-23 safford - rm unused uses ! ! input argument list: ! count - number or random numbers to generate ! ! output argument list: ! randnums - array of scaled random numbers ! ! attributes: ! language: f90 ! machine: ibm RS/6000 SP ! !$$$ use kinds, only: r_kind,i_kind use obsmod, only: iadate use berror, only: pert_berr_fct use constants, only: ione, one, two implicit none integer(i_kind) ,intent(in ) :: count real(r_kind),dimension(count),intent( out) :: randnums integer(i_kind),allocatable,dimension(:):: numrnds real(r_kind),dimension(count+ione):: temps real(r_kind):: rseed integer(i_kind) i,ksize call random_seed(size=ksize) allocate(numrnds(ksize)) ! set seed as a function of analysis date rseed = 1e6_r_kind*iadate(1) + 1e4_r_kind*iadate(2) & + 1e2_r_kind*iadate(3) + iadate(4) do i=1,ksize numrnds(i)=rseed end do call random_seed(put=numrnds) deallocate(numrnds) ! this goes from 0-1, but want -1 to 1 call random_number(temps) ! Set range to be +/- factor ! and don't use first random number generated based on date do i=1,count randnums(i) = pert_berr_fct*(one - two*temps(i+ione)) end do return end subroutine get_randoms