module strong_fast_global_mod !$$$ module documentation block ! . . . . ! module: strong_fast_global_mod ! ! abstract: contains all routines for fast strong balance constraint ! ! program history log: ! 2008-04-04 safford - add moddule doc block and missing subroutine doc blocks ! 2012-02-08 kleist - add uvflag in place of uv_hyb_ens ! 2012-11-23 parrish - Replace calls to spanaly_ns and spsynth_ns with inline code. ! Remove subroutines spanaly_ns and spsynth_ns. ! 2013-07-02 parrish - change name of init_strongvars_2 to init_strongvars. ! ! subroutines included: ! init_strongvars -- ! strong_bal_correction_fast_global ! strong_bal_correction_fast_global_ad -- adjoint of strong_bal_correction ! gather_rmstends0 -- get bal diagnostics ! gather_rmstends -- get bal diagnostics ! inmi_coupler_sd2ew0 -- ! inmi_coupler_sd2ew1 -- ! inmi_coupler_sd2ew -- ! inmi_coupler_ew2sd1 -- ! inmi_coupler_ew2sd -- ! inmi_ew_trans -- ! inmi_ew_invtrans_ad -- ! inmi_ew_invtrans -- ! inmi_ew_trans_ad -- ! inmi_coupler_ew2ns0 -- ! inmi_coupler_ew2ns1 -- ! inmi_coupler_ew2ns -- ! inmi_coupler_ns2ew -- ! inmi_nsuvm2zdm -- ! spdz2uv_ns -- compute winds from div and vort for 1 zonal wave number ! spuv2dz_ns -- compute div,vort from winds for one zonal wave number ! ! variable definitions: ! ! attributes: ! language: f90 ! machine: ibm rs/6000 sp !$$$ end documentation block use kinds, only: i_kind,r_kind use gridmod, only: nlat,nlon,lat2,lon2,nsig,sp_a,jstart,istart use gridmod, only: ilat1,jlon1 use constants, only: zero,one,two,rearth use mpimod, only: ierror,mpi_comm_world,mpi_integer4,mpi_rtype,mpi_sum,npe use mod_vtrans, only: speeds,nvmodes_keep,vtrans,vtrans_inv,vtrans_ad,vtrans_inv_ad implicit none ! set default to private private ! set subroutines to public public :: init_strongvars public :: strong_bal_correction_fast_global public :: strong_bal_correction_fast_global_ad public :: gather_rmstends0 public :: gather_rmstends public :: inmi_coupler_sd2ew0 public :: inmi_coupler_sd2ew1 public :: inmi_coupler_sd2ew public :: inmi_coupler_ew2sd1 public :: inmi_coupler_ew2sd public :: inmi_ew_trans public :: inmi_ew_invtrans_ad public :: inmi_ew_invtrans public :: inmi_ew_trans_ad public :: inmi_coupler_ew2ns0 public :: inmi_coupler_ew2ns1 public :: inmi_coupler_ew2ns public :: inmi_coupler_ns2ew public :: inmi_nsuvm2zdm public :: spdz2uv_ns public :: spuv2dz_ns integer(i_kind),allocatable:: mode_list(:,:) ! mode_list(1,j) = lat index for ew strip j ! mode_list(2,j) = vert mode number for ew strip j ! mode_list(3,j) = pe of this lat/vert mode strip integer(i_kind),allocatable:: mmode_list(:,:) ! mmode_list(1,j) = m1 (zonal wave number 1) for ns strip ! mmode_list(2,j) = m2 (zonal wave number 2) for ns strip ! mmode_list(3,j) = vert mode number 1 for ns strip j ! mmode_list(4,j) = vert mode number 2 for ns strip j ! mmode_list(5,j) = pe for ns strip j integer(i_kind) nlatm_0,nlatm_1,m_0,m_1 integer(i_kind) mthis integer(i_kind) nallsend_ew2sd,nallrecv_ew2sd integer(i_kind) nallsend,nallrecv integer(i_kind) nallsend_sd2ew,nallrecv_sd2ew integer(i_kind),allocatable,dimension(:)::mthis0,ndisp,indexglob integer(i_kind),allocatable,dimension(:)::nsend_sd2ew,nrecv_sd2ew integer(i_kind),allocatable,dimension(:)::ndsend_sd2ew,ndrecv_sd2ew integer(i_kind),allocatable,dimension(:)::nsend_ew2sd,nrecv_ew2sd integer(i_kind),allocatable,dimension(:)::ndsend_ew2sd,ndrecv_ew2sd integer(i_kind),allocatable,dimension(:)::nsend,nrecv,ndsend,ndrecv integer(i_kind),allocatable,dimension(:,:)::info_send_sd2ew,info_recv_sd2ew integer(i_kind),allocatable,dimension(:,:)::info_send_ew2sd,info_recv_ew2sd integer(i_kind),allocatable,dimension(:,:)::info_send,info_recv contains subroutine init_strongvars(mype) !$$$ subprogram documentation block ! . . . ! subprogram: init_strongvars ! ! prgrmmr: parrish ! ! abstract: initialize strong fast global initialization ! ! program history log: ! 2008-04-04 safford -- add subprogram doc block ! 2010-03-31 treadon - replace specmod jcap with sp_a structure ! ! input argument list: ! mype - mpi task id ! ! output argument list: ! ! attributes: ! language: f90 ! machine: ibm rs/6000 sp ! !$$$ implicit none integer(i_kind),intent(in ) :: mype allocate(mode_list(3,nlat*nvmodes_keep),mmode_list(5,(sp_a%jcap+1)*nvmodes_keep)) call inmi_coupler_sd2ew0(mype) call inmi_coupler_ew2ns0(mype) call gather_rmstends0 call inmi_coupler_sd2ew1(mype) call inmi_coupler_ew2ns1(mype) call inmi_coupler_ew2sd1(mype) return end subroutine init_strongvars subroutine strong_bal_correction_fast_global(u_t,v_t,t_t,ps_t,mype,psi,chi,t,ps, & bal_diagnostic,fullfield,update,uvflag) !$$$ subprogram documentation block ! . . . . ! subprogram: strong_bal_correction strong balance correction ! prgmmr: parrish org: np23 date: 2006-07-15 ! ! abstract: given input perturbation tendencies of u,v,t,ps from tlm on gaussian grid, ! and input perturbation u,v,t,ps, compute balance adjustment to u,v,t,ps ! which zeroes out input gravity component of perturbation tendencies. ! also output, for later use, input tendencies projected onto gravity modes. ! ! program history log: ! 2006-07-15 parrish ! 2007-04-16 kleist - modified for full field or incremental diagnostics ! 2008-10-08 parrish/derber - modify to output streamfunction and vel. pot. and not update time derivatives ! 2009-11-27 parrish - add uvflag. if uvflag=true, then ! input/output variables psi=u, chi=v. ! 2010-03-31 treadon - replace specmod jcap with sp_a structure ! 2012-02-08 kleist - add uvflag in place of uv_hyb_ens ! 2013-10-26 todling - prevent division by zero when rms's are zero ! ! input argument list: ! u_t - input perturbation u tendency on gaussian grid (subdomains) ! v_t - input perturbation v tendency on gaussian grid (subdomains) ! t_t - input perturbation t tendency on gaussian grid (subdomains) ! ps_t - input perturbation surface pressure tendency on gaussian grid (subdomains) ! mype - current processor ! psi - input perturbation psi on gaussian grid (subdomains) ! chi - input perturbation chi on gaussian grid (subdomains) ! t - input perturbation t on gaussian grid (subdomains) ! ps - input perturbation surface pressure on gaussian grid (subdomains) ! bal_diagnostic - if true, then compute bal diagnostic, a measure of amplitude ! of balanced gravity mode tendencies ! fullfield - if true, full field diagnostics ! if false, incremental ! update - if false, then do not update u,v,t,ps with balance increment ! ! output argument list: ! psi - output balanced perturbation u on gaussian grid (subdomains) ! chi - output balanced perturbation v on gaussian grid (subdomains) ! t - output balanced perturbation t on gaussian grid (subdomains) ! ps - output balanced perturbation surface pressure on gaussian grid (subdomains) ! ! attributes: ! language: f90 ! machine: ibm rs/6000 sp ! !$$$ use mod_strong, only: dinmi,gproj,gproj_diag,gproj_diag_update use constants, only: tiny_r_kind implicit none integer(i_kind) ,intent(in ) :: mype logical ,intent(in ) :: bal_diagnostic,update,fullfield,uvflag real(r_kind),dimension(lat2,lon2,nsig),intent(in ) :: u_t,v_t,t_t real(r_kind),dimension(lat2,lon2) ,intent(in ) :: ps_t real(r_kind),dimension(lat2,lon2,nsig),intent(inout) :: psi,chi,t real(r_kind),dimension(lat2,lon2) ,intent(inout) :: ps real(r_kind),dimension(nvmodes_keep)::rmstend_uf,rmstend_g_uf real(r_kind),dimension(nvmodes_keep)::rmstend_f,rmstend_g_f real(r_kind),dimension(lat2,lon2,nvmodes_keep)::utilde_t,vtilde_t,mtilde_t real(r_kind),dimension(lat2,lon2,nvmodes_keep)::delutilde,delvtilde,delmtilde real(r_kind),dimension(2,0:sp_a%jcap)::divhat,vorthat,mhat,deldivhat,delvorthat,delmhat real(r_kind),allocatable,dimension(:,:)::rmstend_loc_uf,rmstend_g_loc_uf real(r_kind),allocatable,dimension(:,:)::rmstend_loc_f,rmstend_g_loc_f real(r_kind),allocatable,dimension(:,:,:,:)::uvm_ew real(r_kind),allocatable,dimension(:,:,:,:,:)::uvm_ewtrans,uvm_ns,zdm_hat real(r_kind) rmstend_all_uf,rmstend_all_g_uf,rmstend_all_f,rmstend_all_g_f real(r_kind) del2inv,rn,gspeed real(r_kind) diff1,diffi integer(i_kind) i,ipair,kk,mode,n,mmax,m if(.not. (update .or. bal_diagnostic))return mmax=sp_a%jcap ! 1. u,v,t,ps --> utilde,vtilde,mtilde (vertical mode transform) ! (subdomains) (subdomains) call vtrans(u_t,v_t,t_t,ps_t,utilde_t,vtilde_t,mtilde_t) allocate(uvm_ew(nlon,2,3,nlatm_0:nlatm_1),uvm_ewtrans(2,0:sp_a%jcap,2,3,nlatm_0:nlatm_1)) allocate(uvm_ns(3,2,nlat,2,m_0:m_1),zdm_hat(3,2,nlat,2,m_0:m_1)) call inmi_coupler_sd2ew(utilde_t,vtilde_t,mtilde_t,utilde_t,vtilde_t,mtilde_t, & uvm_ew,mype) call inmi_ew_trans(uvm_ew,uvm_ewtrans) call inmi_coupler_ew2ns(uvm_ewtrans,uvm_ns) call inmi_nsuvm2zdm(uvm_ns,zdm_hat) if(bal_diagnostic)then allocate(rmstend_loc_f(2,m_0:m_1)) allocate(rmstend_g_loc_f(2,m_0:m_1)) rmstend_loc_f=zero rmstend_g_loc_f=zero allocate(rmstend_loc_uf(2,m_0:m_1)) allocate(rmstend_g_loc_uf(2,m_0:m_1)) rmstend_g_loc_uf=zero rmstend_loc_uf=zero end if if(update)then !$omp parallel do schedule(dynamic,1) private(kk,ipair,m,mode,gspeed,i,n) & !$omp private(vorthat,divhat,delvorthat,deldivhat,delmhat,mhat,rn,del2inv) do kk=m_0,m_1 do ipair=1,2 m=mmode_list(ipair,kk) mode=mmode_list(ipair+2,kk) gspeed=speeds(abs(mode)) i=0 do n=m,sp_a%jcap i=i+1 vorthat(1,n)=zdm_hat(1,1,i,ipair,kk) vorthat(2,n)=zdm_hat(1,2,i,ipair,kk) divhat( 1,n)=zdm_hat(2,1,i,ipair,kk) divhat( 2,n)=zdm_hat(2,2,i,ipair,kk) mhat( 1,n)=zdm_hat(3,1,i,ipair,kk) mhat( 2,n)=zdm_hat(3,2,i,ipair,kk) end do ! 4. divhat,vorthat,mhat --> deldivhat,delvorthat,delmhat (inmi correction) ! (slabs) (slabs) if(mode > 0) then ! here, delvorthat, etc contain field corrections necessary to zero out gravity component ! of tendencies call dinmi(vorthat(1,m),divhat(1,m),mhat(1,m),delvorthat(1,m),deldivhat(1,m),delmhat(1,m),& m,mmax,gspeed) else ! here, delvorthat, etc contain gravity component of tendencies if(bal_diagnostic) then ! bal_diagnostic and update call gproj_diag_update(vorthat(1,m),divhat(1,m),mhat(1,m),delvorthat(1,m),deldivhat(1,m),delmhat(1,m), & rmstend_loc_uf(ipair,kk),rmstend_g_loc_uf(ipair,kk),rmstend_loc_f(ipair,kk), & rmstend_g_loc_f(ipair,kk),m,mmax,gspeed) else ! update only call gproj(vorthat(1,m),divhat(1,m),mhat(1,m),delvorthat(1,m),deldivhat(1,m),delmhat(1,m), & m,mmax,gspeed) end if end if if(.not. uvflag)then do n=m,sp_a%jcap if(n > 0) then rn=real(n,r_kind) del2inv=-rearth**2/(rn*(rn+one)) else del2inv=zero end if delvorthat(1,n)=delvorthat(1,n)*del2inv delvorthat(2,n)=delvorthat(2,n)*del2inv deldivhat(1,n)=deldivhat(1,n)*del2inv deldivhat(2,n)=deldivhat(2,n)*del2inv end do end if i=0 do n=m,sp_a%jcap i=i+1 zdm_hat(1,1,i,ipair,kk)=delvorthat(1,n) zdm_hat(1,2,i,ipair,kk)=delvorthat(2,n) zdm_hat(2,1,i,ipair,kk)=deldivhat(1,n) zdm_hat(2,2,i,ipair,kk)=deldivhat(2,n) zdm_hat(3,1,i,ipair,kk)=delmhat(1,n) zdm_hat(3,2,i,ipair,kk)=delmhat(2,n) end do end do end do ! 7. delutilde,delvtilde,delmtilde --> psi,chi,t,ps (vertical mode inverse transform) ! (subdomains) (subdomains) ! update u,v,t,ps if(uvflag) then call inmi_nszdm2uvm(uvm_ns,zdm_hat) else call inmi_nspcm_hat2pcm(uvm_ns,zdm_hat) end if call inmi_coupler_ns2ew(uvm_ewtrans,uvm_ns) call inmi_ew_invtrans(uvm_ew,uvm_ewtrans) call inmi_coupler_ew2sd(delutilde,delvtilde,delmtilde,utilde_t,vtilde_t,mtilde_t,uvm_ew,mype) call vtrans_inv(delutilde,delvtilde,delmtilde,psi,chi,t,ps) ! u_t_g=zero;v_t_g=zero;t_t_g=zero;ps_t_g=zero ! call vtrans_inv(utilde_t,vtilde_t,mtilde_t,u_t_g,v_t_g,t_t_g,ps_t_g) else ! bal_diagnostic only no update !$omp parallel do schedule(dynamic,1) private(kk,ipair,m,mode,gspeed,i,n) & !$omp private(vorthat,divhat,mhat) do kk=m_0,m_1 do ipair=1,2 mode=mmode_list(ipair+2,kk) if(mode > 0)cycle m=mmode_list(ipair,kk) gspeed=speeds(abs(mode)) i=0 do n=m,sp_a%jcap i=i+1 vorthat(1,n)=zdm_hat(1,1,i,ipair,kk) vorthat(2,n)=zdm_hat(1,2,i,ipair,kk) divhat( 1,n)=zdm_hat(2,1,i,ipair,kk) divhat( 2,n)=zdm_hat(2,2,i,ipair,kk) mhat( 1,n)=zdm_hat(3,1,i,ipair,kk) mhat( 2,n)=zdm_hat(3,2,i,ipair,kk) end do call gproj_diag(vorthat(1,m),divhat(1,m),mhat(1,m), & rmstend_loc_uf(ipair,kk),rmstend_g_loc_uf(ipair,kk),rmstend_loc_f(ipair,kk), & rmstend_g_loc_f(ipair,kk),m,mmax,gspeed) end do end do end if deallocate(uvm_ew,uvm_ewtrans,uvm_ns,zdm_hat) if(bal_diagnostic) then call gather_rmstends(rmstend_loc_uf, rmstend_uf) call gather_rmstends(rmstend_g_loc_uf,rmstend_g_uf) call gather_rmstends(rmstend_loc_f, rmstend_f) call gather_rmstends(rmstend_g_loc_f, rmstend_g_f) if(mype == 0) then rmstend_all_uf=zero rmstend_all_g_uf=zero if (fullfield) then write(6,*) 'strong_fast_global: full field balance diagnostics -- ' else write(6,*) 'strong_fast_global: incremental balance diagnostics -- ' end if do i=1,nvmodes_keep rmstend_all_uf=rmstend_all_uf+rmstend_uf(i) rmstend_all_g_uf=rmstend_all_g_uf+rmstend_g_uf(i) diffi = rmstend_uf(i)-rmstend_g_uf(i) diff1 = rmstend_uf(1)-rmstend_g_uf(1) if(abs(diffi)