!wrf:MODEL_LAYER:DYNAMICS ! #if (RWORDSIZE == 4) # define VPOWX vspowx # define VPOW vspow #else # define VPOWX vpowx # define VPOW vpow #endif MODULE module_big_step_utilities_em USE module_domain, ONLY : domain USE module_model_constants USE module_state_description USE module_configure, ONLY : grid_config_rec_type USE module_wrf_error CONTAINS !------------------------------------------------------------------------------- SUBROUTINE calc_mu_uv ( config_flags, & mu, mub, muu, muv, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type ) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime , jms:jme ) , INTENT( OUT) :: muu, muv REAL, DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mu, mub ! local stuff INTEGER :: i, j, itf, jtf, im, jm ! ! ! calc_mu_uv calculates the full column dry-air mass at the staggered ! horizontal velocity points (u,v) and places the results in muu and muv. ! This routine uses the reference state (mub) and perturbation state (mu) ! ! itf=ite jtf=MIN(jte,jde-1) IF ( ( its .NE. ids ) .AND. ( ite .NE. ide ) ) THEN DO j=jts,jtf DO i=its,itf muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO ELSE IF ( ( its .EQ. ids ) .AND. ( ite .NE. ide ) ) THEN DO j=jts,jtf DO i=its+1,itf muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO i=its im = its if(config_flags%periodic_x) im = its-1 DO j=jts,jtf ! muu(i,j) = mu(i,j) +mub(i,j) ! fix for periodic b.c., 13 march 2004, wcs muu(i,j) = 0.5*(mu(i,j)+mu(im,j)+mub(i,j)+mub(im,j)) ENDDO ELSE IF ( ( its .NE. ids ) .AND. ( ite .EQ. ide ) ) THEN DO j=jts,jtf DO i=its,itf-1 muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO i=ite im = ite-1 if(config_flags%periodic_x) im = ite DO j=jts,jtf ! muu(i,j) = mu(i-1,j) +mub(i-1,j) ! fix for periodic b.c., 13 march 2004, wcs muu(i,j) = 0.5*(mu(i-1,j)+mu(im,j)+mub(i-1,j)+mub(im,j)) ENDDO ELSE IF ( ( its .EQ. ids ) .AND. ( ite .EQ. ide ) ) THEN DO j=jts,jtf DO i=its+1,itf-1 muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO i=its im = its if(config_flags%periodic_x) im = its-1 DO j=jts,jtf ! muu(i,j) = mu(i,j) +mub(i,j) ! fix for periodic b.c., 13 march 2004, wcs muu(i,j) = 0.5*(mu(i,j)+mu(im,j)+mub(i,j)+mub(im,j)) ENDDO i=ite im = ite-1 if(config_flags%periodic_x) im = ite DO j=jts,jtf ! muu(i,j) = mu(i-1,j) +mub(i-1,j) ! fix for periodic b.c., 13 march 2004, wcs muu(i,j) = 0.5*(mu(i-1,j)+mu(im,j)+mub(i-1,j)+mub(im,j)) ENDDO END IF itf=MIN(ite,ide-1) jtf=jte IF ( ( jts .NE. jds ) .AND. ( jte .NE. jde ) ) THEN DO j=jts,jtf DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO ELSE IF ( ( jts .EQ. jds ) .AND. ( jte .NE. jde ) ) THEN DO j=jts+1,jtf DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO j=jts jm = jts if(config_flags%periodic_y) jm = jts-1 DO i=its,itf ! muv(i,j) = mu(i,j) +mub(i,j) ! fix for periodic b.c., 13 march 2004, wcs muv(i,j) = 0.5*(mu(i,j)+mu(i,jm)+mub(i,j)+mub(i,jm)) ENDDO ELSE IF ( ( jts .NE. jds ) .AND. ( jte .EQ. jde ) ) THEN DO j=jts,jtf-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO j=jte jm = jte-1 if(config_flags%periodic_y) jm = jte DO i=its,itf muv(i,j) = mu(i,j-1) +mub(i,j-1) ! fix for periodic b.c., 13 march 2004, wcs muv(i,j) = 0.5*(mu(i,j-1)+mu(i,jm)+mub(i,j-1)+mub(i,jm)) ENDDO ELSE IF ( ( jts .EQ. jds ) .AND. ( jte .EQ. jde ) ) THEN DO j=jts+1,jtf-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO j=jts jm = jts if(config_flags%periodic_y) jm = jts-1 DO i=its,itf ! muv(i,j) = mu(i,j) +mub(i,j) ! fix for periodic b.c., 13 march 2004, wcs muv(i,j) = 0.5*(mu(i,j)+mu(i,jm)+mub(i,j)+mub(i,jm)) ENDDO j=jte jm = jte-1 if(config_flags%periodic_y) jm = jte DO i=its,itf ! muv(i,j) = mu(i,j-1) +mub(i,j-1) ! fix for periodic b.c., 13 march 2004, wcs muv(i,j) = 0.5*(mu(i,j-1)+mu(i,jm)+mub(i,j-1)+mub(i,jm)) ENDDO END IF END SUBROUTINE calc_mu_uv !------------------------------------------------------------------------------- SUBROUTINE calc_mu_uv_1 ( config_flags, & mu, muu, muv, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type ) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime , jms:jme ) , INTENT( OUT) :: muu, muv REAL, DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mu ! local stuff INTEGER :: i, j, itf, jtf, im, jm ! ! ! calc_mu_uv calculates the full column dry-air mass at the staggered ! horizontal velocity points (u,v) and places the results in muu and muv. ! This routine uses the full state (mu) ! ! itf=ite jtf=MIN(jte,jde-1) IF ( ( its .NE. ids ) .AND. ( ite .NE. ide ) ) THEN DO j=jts,jtf DO i=its,itf muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)) ENDDO ENDDO ELSE IF ( ( its .EQ. ids ) .AND. ( ite .NE. ide ) ) THEN DO j=jts,jtf DO i=its+1,itf muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)) ENDDO ENDDO i=its im = its if(config_flags%periodic_x) im = its-1 DO j=jts,jtf muu(i,j) = 0.5*(mu(i,j)+mu(im,j)) ENDDO ELSE IF ( ( its .NE. ids ) .AND. ( ite .EQ. ide ) ) THEN DO j=jts,jtf DO i=its,itf-1 muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)) ENDDO ENDDO i=ite im = ite-1 if(config_flags%periodic_x) im = ite DO j=jts,jtf muu(i,j) = 0.5*(mu(i-1,j)+mu(im,j)) ENDDO ELSE IF ( ( its .EQ. ids ) .AND. ( ite .EQ. ide ) ) THEN DO j=jts,jtf DO i=its+1,itf-1 muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)) ENDDO ENDDO i=its im = its if(config_flags%periodic_x) im = its-1 DO j=jts,jtf muu(i,j) = 0.5*(mu(i,j)+mu(im,j)) ENDDO i=ite im = ite-1 if(config_flags%periodic_x) im = ite DO j=jts,jtf muu(i,j) = 0.5*(mu(i-1,j)+mu(im,j)) ENDDO END IF itf=MIN(ite,ide-1) jtf=jte IF ( ( jts .NE. jds ) .AND. ( jte .NE. jde ) ) THEN DO j=jts,jtf DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)) ENDDO ENDDO ELSE IF ( ( jts .EQ. jds ) .AND. ( jte .NE. jde ) ) THEN DO j=jts+1,jtf DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)) ENDDO ENDDO j=jts jm = jts if(config_flags%periodic_y) jm = jts-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,jm)) ENDDO ELSE IF ( ( jts .NE. jds ) .AND. ( jte .EQ. jde ) ) THEN DO j=jts,jtf-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)) ENDDO ENDDO j=jte jm = jte-1 if(config_flags%periodic_y) jm = jte DO i=its,itf muv(i,j) = 0.5*(mu(i,j-1)+mu(i,jm)) ENDDO ELSE IF ( ( jts .EQ. jds ) .AND. ( jte .EQ. jde ) ) THEN DO j=jts+1,jtf-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)) ENDDO ENDDO j=jts jm = jts if(config_flags%periodic_y) jm = jts-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,jm)) ENDDO j=jte jm = jte-1 if(config_flags%periodic_y) jm = jte DO i=its,itf muv(i,j) = 0.5*(mu(i,j-1)+mu(i,jm)) ENDDO END IF END SUBROUTINE calc_mu_uv_1 !------------------------------------------------------------------------------- ! Map scale factor comments for this routine: ! Locally not changed, but sent the correct map scale factors ! from module_em (msfuy, msfvx, msfty) SUBROUTINE couple_momentum ( muu, ru, u, msfu, & muv, rv, v, msfv, msfv_inv, & mut, rw, w, msft, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT( OUT) :: ru, rv, rw REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: muu, muv, mut REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfu, msfv, msft, msfv_inv REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: u, v, w ! Local data INTEGER :: i, j, k, itf, jtf, ktf ! ! ! couple_momentum couples the velocities to the full column mass and ! the map factors. ! ! ktf=MIN(kte,kde-1) itf=ite jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf ru(i,k,j)=u(i,k,j)*muu(i,j)/msfu(i,j) ENDDO ENDDO ENDDO itf=MIN(ite,ide-1) jtf=jte DO j=jts,jtf DO k=kts,ktf DO i=its,itf rv(i,k,j)=v(i,k,j)*muv(i,j)*msfv_inv(i,j) ! rv(i,k,j)=v(i,k,j)*muv(i,j)/msfv(i,j) ENDDO ENDDO ENDDO itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,kte DO i=its,itf rw(i,k,j)=w(i,k,j)*mut(i,j)/msft(i,j) ENDDO ENDDO ENDDO END SUBROUTINE couple_momentum !------------------------------------------------------------------- SUBROUTINE calc_mu_staggered ( mu, mub, muu, muv, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime , jms:jme ) , INTENT( OUT) :: muu, muv REAL, DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mu, mub ! local stuff INTEGER :: i, j, itf, jtf ! ! ! calc_mu_staggered calculates the full dry air mass at the staggered ! velocity points (u,v). ! ! itf=ite jtf=MIN(jte,jde-1) IF ( ( its .NE. ids ) .AND. ( ite .NE. ide ) ) THEN DO j=jts,jtf DO i=its,itf muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO ELSE IF ( ( its .EQ. ids ) .AND. ( ite .NE. ide ) ) THEN DO j=jts,jtf DO i=its+1,itf muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO i=its DO j=jts,jtf muu(i,j) = mu(i,j) +mub(i,j) ENDDO ELSE IF ( ( its .NE. ids ) .AND. ( ite .EQ. ide ) ) THEN DO j=jts,jtf DO i=its,itf-1 muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO i=ite DO j=jts,jtf muu(i,j) = mu(i-1,j) +mub(i-1,j) ENDDO ELSE IF ( ( its .EQ. ids ) .AND. ( ite .EQ. ide ) ) THEN DO j=jts,jtf DO i=its+1,itf-1 muu(i,j) = 0.5*(mu(i,j)+mu(i-1,j)+mub(i,j)+mub(i-1,j)) ENDDO ENDDO i=its DO j=jts,jtf muu(i,j) = mu(i,j) +mub(i,j) ENDDO i=ite DO j=jts,jtf muu(i,j) = mu(i-1,j) +mub(i-1,j) ENDDO END IF itf=MIN(ite,ide-1) jtf=jte IF ( ( jts .NE. jds ) .AND. ( jte .NE. jde ) ) THEN DO j=jts,jtf DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO ELSE IF ( ( jts .EQ. jds ) .AND. ( jte .NE. jde ) ) THEN DO j=jts+1,jtf DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO j=jts DO i=its,itf muv(i,j) = mu(i,j) +mub(i,j) ENDDO ELSE IF ( ( jts .NE. jds ) .AND. ( jte .EQ. jde ) ) THEN DO j=jts,jtf-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO j=jte DO i=its,itf muv(i,j) = mu(i,j-1) +mub(i,j-1) ENDDO ELSE IF ( ( jts .EQ. jds ) .AND. ( jte .EQ. jde ) ) THEN DO j=jts+1,jtf-1 DO i=its,itf muv(i,j) = 0.5*(mu(i,j)+mu(i,j-1)+mub(i,j)+mub(i,j-1)) ENDDO ENDDO j=jts DO i=its,itf muv(i,j) = mu(i,j) +mub(i,j) ENDDO j=jte DO i=its,itf muv(i,j) = mu(i,j-1) +mub(i,j-1) ENDDO END IF END SUBROUTINE calc_mu_staggered !------------------------------------------------------------------------------- SUBROUTINE couple ( mu, mub, rfield, field, name, & msf, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte CHARACTER(LEN=1) , INTENT(IN ) :: name REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT( OUT) :: rfield REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mu, mub, msf REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: field ! Local data INTEGER :: i, j, k, itf, jtf, ktf REAL , DIMENSION(ims:ime,jms:jme) :: muu , muv ! ! ! subroutine couple couples the input variable with the dry-air ! column mass (mu). ! ! ktf=MIN(kte,kde-1) IF (name .EQ. 'u')THEN CALL calc_mu_staggered ( mu, mub, muu, muv, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) itf=ite jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf rfield(i,k,j)=field(i,k,j)*muu(i,j)/msf(i,j) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'v')THEN CALL calc_mu_staggered ( mu, mub, muu, muv, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) itf=ite itf=MIN(ite,ide-1) jtf=jte DO j=jts,jtf DO k=kts,ktf DO i=its,itf rfield(i,k,j)=field(i,k,j)*muv(i,j)/msf(i,j) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'w')THEN itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,kte DO i=its,itf rfield(i,k,j)=field(i,k,j)*(mu(i,j)+mub(i,j))/msf(i,j) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'h')THEN itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,kte DO i=its,itf rfield(i,k,j)=field(i,k,j)*(mu(i,j)+mub(i,j)) ENDDO ENDDO ENDDO ELSE itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf rfield(i,k,j)=field(i,k,j)*(mu(i,j)+mub(i,j)) ENDDO ENDDO ENDDO ENDIF END SUBROUTINE couple !------------------------------------------------------------------------------- SUBROUTINE calc_ww_cp ( u, v, mup, mub, ww, & rdx, rdy, msftx, msfty, & msfux, msfuy, msfvx, msfvx_inv, & msfvy, dnw, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: u, v REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mup, mub, & msftx, msfty, & msfux, msfuy, & msfvx, msfvy, & msfvx_inv REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: dnw REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(OUT ) :: ww REAL , INTENT(IN ) :: rdx, rdy ! Local data INTEGER :: i, j, k, itf, jtf, ktf REAL , DIMENSION( its:ite ) :: dmdt REAL , DIMENSION( its:ite, kts:kte ) :: divv REAL , DIMENSION( its:ite+1, jts:jte+1 ) :: muu, muv ! ! ! calc_ww calculates omega using the velocities (u,v) and the dry-air ! column mass (mup+mub). ! The algorithm integrates the continuity equation through the column ! followed by a diagnosis of omega. ! ! ! ! ! calc_ww_cp calculates omega using the velocities (u,v) and the ! column mass mu. ! ! jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) itf=MIN(ite,ide-1) ! mu coupled with the appropriate map factor DO j=jts,jtf DO i=its,min(ite+1,ide) ! u is always coupled with my muu(i,j) = 0.5*(mup(i,j)+mub(i,j)+mup(i-1,j)+mub(i-1,j))/msfuy(i,j) ENDDO ENDDO DO j=jts,min(jte+1,jde) DO i=its,itf ! v is always coupled with mx ! muv(i,j) = 0.5*(mup(i,j)+mub(i,j)+mup(i,j-1)+mub(i,j-1))/msfvx(i,j) muv(i,j) = 0.5*(mup(i,j)+mub(i,j)+mup(i,j-1)+mub(i,j-1))*msfvx_inv(i,j) ENDDO ENDDO DO j=jts,jtf DO i=its,ite dmdt(i) = 0. ww(i,1,j) = 0. ww(i,kte,j) = 0. ENDDO ! Comments on the modifications for map scale factors ! ADT eqn 47 / my (putting rho -> 'mu') is: ! (1/my) partial d mu/dt = -mx partial d/dx(mu u/my) ! -mx partial d/dy(mu v/mx) ! -partial d/dz(mu w/my) ! ! Using nu instead of z the last term becomes: ! -partial d/dnu(mu (dnu/dt)/my) ! ! Integrating with respect to nu over ALL levels, with dnu/dt=0 at top ! and bottom, the last term becomes = 0 ! ! Integral|bot->top[(1/my) partial d mu/dt]dnu = ! Integral|bot->top[-mx partial d/dx(mu u/my) ! -mx partial d/dy(mu v/mx)]dnu ! ! muu='mu'[on u]/my, muv='mu'[on v]/mx ! (1/my) partial d mu/dt is independent of nu ! => LHS = Integral|bot->top[con]dnu = conservation*(-1) = -dmdt ! ! => dmdt = mx*Integral|bot->top[partial d/dx(mu u/my) + ! partial d/dy(mu v/mx)]dnu ! => dmdt = sum_bot->top[divv] ! where ! divv=mx*[partial d/dx(mu u/my) + partial d/dy(mu v/mx)]*delta nu DO k=kts,ktf DO i=its,itf divv(i,k) = msftx(i,j)*dnw(k)*( rdx*(muu(i+1,j)*u(i+1,k,j)-muu(i,j)*u(i,k,j)) & +rdy*(muv(i,j+1)*v(i,k,j+1)-muv(i,j)*v(i,k,j)) ) ! dmdt(i) = dmdt(i) + dnw(k)* ( rdx*(ru(i+1,k,j)-ru(i,k,j)) & ! +rdy*(rv(i,k,j+1)-rv(i,k,j)) ) dmdt(i) = dmdt(i) + divv(i,k) ENDDO ENDDO ! Further map scale factor notes: ! Now integrate from bottom to top, level by level: ! mu dnu/dt/my [k+1] = mu dnu/dt/my [k] + [-(1/my) partial d mu/dt ! -mx partial d/dx(mu u/my) ! -mx partial d/dy(mu v/mx)]*dnu[k->k+1] ! ww [k+1] = ww [k] -(1/my) partial d mu/dt * dnu[k->k+1] - divv[k] ! = ww [k] -dmdt * dnw[k] - divv[k] DO k=2,ktf DO i=its,itf ! ww(i,k,j)=ww(i,k-1,j) & ! - dnw(k-1)* ( dmdt(i) & ! +rdx*(ru(i+1,k-1,j)-ru(i,k-1,j)) & ! +rdy*(rv(i,k-1,j+1)-rv(i,k-1,j)) ) ww(i,k,j)=ww(i,k-1,j) - dnw(k-1)*dmdt(i) - divv(i,k-1) ENDDO ENDDO ENDDO END SUBROUTINE calc_ww_cp !------------------------------------------------------------------------------- SUBROUTINE calc_cq ( moist, cqu, cqv, cqw, n_moist, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte INTEGER , INTENT(IN ) :: n_moist REAL, DIMENSION( ims:ime, kms:kme , jms:jme , n_moist ), INTENT(IN ) :: moist REAL, DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT( OUT) :: cqu, cqv, cqw ! Local stuff REAL :: qtot INTEGER :: i, j, k, itf, jtf, ktf, ispe ! ! ! calc_cq calculates moist coefficients for the momentum equations. ! ! itf=ite jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) IF( n_moist >= PARAM_FIRST_SCALAR ) THEN DO j=jts,jtf DO k=kts,ktf DO i=its,itf qtot = 0. !DEC$ loop count(3) DO ispe=PARAM_FIRST_SCALAR,n_moist qtot = qtot + moist(i,k,j,ispe) + moist(i-1,k,j,ispe) ENDDO ! qtot = 0.5*( moist(i ,k,j,1)+moist(i ,k,j,2)+moist(i ,k,j,3)+ & ! & moist(i-1,k,j,1)+moist(i-1,k,j,2)+moist(i-1,k,j,3) ) ! cqu(i,k,j) = 1./(1.+qtot) cqu(i,k,j) = 1./(1.+0.5*qtot) ENDDO ENDDO ENDDO itf=MIN(ite,ide-1) jtf=jte DO j=jts,jtf DO k=kts,ktf DO i=its,itf qtot = 0. !DEC$ loop count(3) DO ispe=PARAM_FIRST_SCALAR,n_moist qtot = qtot + moist(i,k,j,ispe) + moist(i,k,j-1,ispe) ENDDO ! qtot = 0.5*( moist(i,k,j ,1)+moist(i,k,j ,2)+moist(i,k,j ,3)+ & ! & moist(i,k,j-1,1)+moist(i,k,j-1,2)+moist(i,k,j-1,3) ) ! cqv(i,k,j) = 1./(1.+qtot) cqv(i,k,j) = 1./(1.+0.5*qtot) ENDDO ENDDO ENDDO itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts+1,ktf DO i=its,itf qtot = 0. !DEC$ loop count(3) DO ispe=PARAM_FIRST_SCALAR,n_moist qtot = qtot + moist(i,k,j,ispe) + moist(i,k-1,j,ispe) ENDDO ! qtot = 0.5*( moist(i,k ,j,1)+moist(i,k ,j,2)+moist(i,k-1,j,3)+ & ! & moist(i,k-1,j,1)+moist(i,k-1,j,2)+moist(i,k ,j,3) ) ! cqw(i,k,j) = qtot cqw(i,k,j) = 0.5*qtot ENDDO ENDDO ENDDO ELSE DO j=jts,jtf DO k=kts,ktf DO i=its,itf cqu(i,k,j) = 1. ENDDO ENDDO ENDDO itf=MIN(ite,ide-1) jtf=jte DO j=jts,jtf DO k=kts,ktf DO i=its,itf cqv(i,k,j) = 1. ENDDO ENDDO ENDDO itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts+1,ktf DO i=its,itf cqw(i,k,j) = 0. ENDDO ENDDO ENDDO END IF END SUBROUTINE calc_cq !---------------------------------------------------------------------- SUBROUTINE calc_alt ( alt, al, alb, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime , kms:kme , jms:jme ), INTENT(IN ) :: alb, al REAL, DIMENSION( ims:ime , kms:kme , jms:jme ), INTENT( OUT) :: alt ! Local stuff INTEGER :: i, j, k, itf, jtf, ktf ! ! ! calc_alt computes the full inverse density ! ! itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf alt(i,k,j) = al(i,k,j)+alb(i,k,j) ENDDO ENDDO ENDDO END SUBROUTINE calc_alt !---------------------------------------------------------------------- SUBROUTINE calc_p_rho_phi ( moist, n_moist, & al, alb, mu, muts, ph, p, pb, & t, p0, t0, znu, dnw, rdnw, & rdn, non_hydrostatic, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data LOGICAL , INTENT(IN ) :: non_hydrostatic INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte INTEGER , INTENT(IN ) :: n_moist REAL, DIMENSION( ims:ime , kms:kme , jms:jme ), INTENT(IN ) :: alb, & pb, & t REAL, DIMENSION( ims:ime , kms:kme , jms:jme, n_moist ), INTENT(IN ) :: moist REAL, DIMENSION( ims:ime , kms:kme , jms:jme ), INTENT( OUT) :: al, p REAL, DIMENSION( ims:ime , kms:kme , jms:jme ), INTENT(INOUT) :: ph REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: mu, muts REAL, DIMENSION( kms:kme ), INTENT(IN ) :: znu, dnw, rdnw, rdn REAL, INTENT(IN ) :: t0, p0 ! Local stuff INTEGER :: i, j, k, itf, jtf, ktf, ispe REAL :: qvf, qtot, qf1, qf2 REAL, DIMENSION( its:ite) :: temp,cpovcv_v ! ! ! For the nonhydrostatic option, calc_p_rho_phi calculates the ! diagnostic quantities pressure and (inverse) density from the ! prognostic variables using the equation of state. ! ! For the hydrostatic option, calc_p_rho_phi calculates the ! diagnostic quantities (inverse) density and geopotential from the ! prognostic variables using the equation of state and the hydrostatic ! equation. ! ! itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) #ifndef INTELMKL cpovcv_v = cpovcv #endif IF (non_hydrostatic) THEN IF (n_moist >= PARAM_FIRST_SCALAR ) THEN DO j=jts,jtf DO k=kts,ktf DO i=its,itf qvf = 1.+rvovrd*moist(i,k,j,P_QV) al(i,k,j)=-1./muts(i,j)*(alb(i,k,j)*mu(i,j) & +rdnw(k)*(ph(i,k+1,j)-ph(i,k,j))) temp(i)=(r_d*(t0+t(i,k,j))*qvf)/ & (p0*(al(i,k,j)+alb(i,k,j))) ENDDO #ifdef INTELMKL CALL VPOWX ( itf-its+1, temp(its), cpovcv, p(its,k,j) ) #else ! use vector version from libmassv or from compat lib in frame/libmassv.F CALL VPOW ( p(its,k,j), temp(its), cpovcv_v(its), itf-its+1 ) #endif DO i=its,itf p(i,k,j)= p(i,k,j)*p0-pb(i,k,j) ENDDO ENDDO ENDDO ELSE DO j=jts,jtf DO k=kts,ktf DO i=its,itf al(i,k,j)=-1./muts(i,j)*(alb(i,k,j)*mu(i,j) & +rdnw(k)*(ph(i,k+1,j)-ph(i,k,j))) p(i,k,j)=p0*( (r_d*(t0+t(i,k,j)))/ & (p0*(al(i,k,j)+alb(i,k,j))) )**cpovcv & -pb(i,k,j) ENDDO ENDDO ENDDO END IF ELSE ! hydrostatic pressure, al, and ph1 calc; WCS, 5 sept 2001 IF (n_moist >= PARAM_FIRST_SCALAR ) THEN DO j=jts,jtf k=ktf ! top layer DO i=its,itf qtot = 0. DO ispe=PARAM_FIRST_SCALAR,n_moist qtot = qtot + moist(i,k,j,ispe) ENDDO qf2 = 1./(1.+qtot) qf1 = qtot*qf2 p(i,k,j) = - 0.5*(mu(i,j)+qf1*muts(i,j))/rdnw(k)/qf2 qvf = 1.+rvovrd*moist(i,k,j,P_QV) al(i,k,j) = (r_d/p1000mb)*(t(i,k,j)+t0)*qvf* & (((p(i,k,j)+pb(i,k,j))/p1000mb)**cvpm) - alb(i,k,j) ENDDO DO k=ktf-1,kts,-1 ! remaining layers, integrate down DO i=its,itf qtot = 0. DO ispe=PARAM_FIRST_SCALAR,n_moist qtot = qtot + 0.5*( moist(i,k ,j,ispe) + moist(i,k+1,j,ispe) ) ENDDO qf2 = 1./(1.+qtot) qf1 = qtot*qf2 p(i,k,j) = p(i,k+1,j) - (mu(i,j) + qf1*muts(i,j))/qf2/rdn(k+1) qvf = 1.+rvovrd*moist(i,k,j,P_QV) al(i,k,j) = (r_d/p1000mb)*(t(i,k,j)+t0)*qvf* & (((p(i,k,j)+pb(i,k,j))/p1000mb)**cvpm) - alb(i,k,j) ENDDO ENDDO DO k=2,ktf+1 ! integrate hydrostatic equation for geopotential DO i=its,itf ! ph(i,k,j) = ph(i,k-1,j) - (1./rdnw(k-1))*( & ! (muts(i,j)+mu(i,j))*al(i,k-1,j)+ & ! mu(i,j)*alb(i,k-1,j) ) ph(i,k,j) = ph(i,k-1,j) - (dnw(k-1))*( & (muts(i,j))*al(i,k-1,j)+ & mu(i,j)*alb(i,k-1,j) ) ENDDO ENDDO ENDDO ELSE DO j=jts,jtf k=ktf ! top layer DO i=its,itf qtot = 0. qf2 = 1./(1.+qtot) qf1 = qtot*qf2 p(i,k,j) = - 0.5*(mu(i,j)+qf1*muts(i,j))/rdnw(k)/qf2 qvf = 1. al(i,k,j) = (r_d/p1000mb)*(t(i,k,j)+t0)*qvf* & (((p(i,k,j)+pb(i,k,j))/p1000mb)**cvpm) - alb(i,k,j) ENDDO DO k=ktf-1,kts,-1 ! remaining layers, integrate down DO i=its,itf qtot = 0. qf2 = 1./(1.+qtot) qf1 = qtot*qf2 p(i,k,j) = p(i,k+1,j) - (mu(i,j) + qf1*muts(i,j))/qf2/rdn(k+1) qvf = 1. al(i,k,j) = (r_d/p1000mb)*(t(i,k,j)+t0)*qvf* & (((p(i,k,j)+pb(i,k,j))/p1000mb)**cvpm) - alb(i,k,j) ENDDO ENDDO DO k=2,ktf+1 ! integrate hydrostatic equation for geopotential DO i=its,itf ! ph(i,k,j) = ph(i,k-1,j) - (1./rdnw(k-1))*( & ! (muts(i,j)+mu(i,j))*al(i,k-1,j)+ & ! mu(i,j)*alb(i,k-1,j) ) ph(i,k,j) = ph(i,k-1,j) - (dnw(k-1))*( & (muts(i,j))*al(i,k-1,j)+ & mu(i,j)*alb(i,k-1,j) ) ENDDO ENDDO ENDDO END IF END IF END SUBROUTINE calc_p_rho_phi !---------------------------------------------------------------------- SUBROUTINE calc_php ( php, ph, phb, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: phb, ph REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT( OUT) :: php ! Local stuff INTEGER :: i, j, k, itf, jtf, ktf ! ! ! calc_php calculates the full geopotential from the reference state ! geopotential and the perturbation geopotential (phb_ph). ! ! itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf php(i,k,j) = 0.5*(phb(i,k,j)+phb(i,k+1,j)+ph(i,k,j)+ph(i,k+1,j)) ENDDO ENDDO ENDDO END SUBROUTINE calc_php !------------------------------------------------------------------------------- SUBROUTINE diagnose_w( ph_tend, ph_new, ph_old, w, mu, dt, & u, v, ht, & cf1, cf2, cf3, rdx, rdy, & msftx, msfty, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: ph_tend, & ph_new, & ph_old, & u, & v REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT( OUT) :: w REAL, DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: mu, ht, msftx, msfty REAL, INTENT(IN ) :: dt, cf1, cf2, cf3, rdx, rdy INTEGER :: i, j, k, itf, jtf itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ! ! ! diagnose_w diagnoses the vertical velocity from the geopoential equation. ! Used with the hydrostatic option. ! ! DO j = jts, jtf ! lower b.c. on w ! Notes on map scale factors: ! Chain rule: if Z=Z(X,Y) [true at the surface] then ! dZ/dt = dZ/dX * dX/dt + dZ/dY * dY/dt, U=dX/dt, V=dY/dt ! Using capitals to denote actual values ! In mapped values, u=U, v=V, z=Z, 1/dX=mx/dx, 1/dY=my/dy ! => w = dz/dt = mx u dz/dx + my v dz/dy ! [where dz/dx is just the surface height change between x ! gridpoints, and dz/dy is the change between y gridpoints] ! [NB: cf1, cf2 and cf3 do vertical weighting of u or v values ! nearest the surface] ! Previously msft multiplied by rdy and rdx terms. ! Now msfty multiplies rdy term, and msftx multiplies msftx term DO i = its, itf w(i,1,j)= msfty(i,j)*.5*rdy*( & (ht(i,j+1)-ht(i,j )) & *(cf1*v(i,1,j+1)+cf2*v(i,2,j+1)+cf3*v(i,3,j+1)) & +(ht(i,j )-ht(i,j-1)) & *(cf1*v(i,1,j )+cf2*v(i,2,j )+cf3*v(i,3,j )) ) & +msftx(i,j)*.5*rdx*( & (ht(i+1,j)-ht(i,j )) & *(cf1*u(i+1,1,j)+cf2*u(i+1,2,j)+cf3*u(i+1,3,j)) & +(ht(i,j )-ht(i-1,j)) & *(cf1*u(i ,1,j)+cf2*u(i ,2,j)+cf3*u(i ,3,j)) ) ENDDO ! use geopotential equation to diagnose w ! Further notes on map scale factors ! If ph_tend contains: -mx partial d/dx(mu rho u/my) ! -mx partial d/dy(phi mu v/mx) ! -partial d/dz(phi mu w/my) ! then phi eqn is: partial d/dt(mu phi/my) = ph_tend + mu g w/my ! => w = [my/(mu*g)]*[partial d/dt(mu phi/my) - ph_tend] DO k = 2, kte DO i = its, itf w(i,k,j) = msfty(i,j)*( (ph_new(i,k,j)-ph_old(i,k,j))/dt & - ph_tend(i,k,j)/mu(i,j) )/g ENDDO ENDDO ENDDO END SUBROUTINE diagnose_w !------------------------------------------------------------------------------- SUBROUTINE rhs_ph( ph_tend, u, v, ww, & ph, ph_old, phb, w, & mut, muu, muv, & fnm, fnp, & rdnw, cfn, cfn1, rdx, rdy, & msfux, msfuy, msfvx, & msfvx_inv, msfvy, & msftx, msfty, & non_hydrostatic, & config_flags, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: & u, & v, & ww, & ph, & ph_old, & phb, & w REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(INOUT) :: ph_tend REAL, DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: muu, muv, mut, & msfux, msfuy, & msfvx, msfvy, & msftx, msfty, & msfvx_inv REAL, DIMENSION( kms:kme ), INTENT(IN ) :: rdnw, fnm, fnp REAL, INTENT(IN ) :: cfn, cfn1, rdx, rdy LOGICAL, INTENT(IN ) :: non_hydrostatic ! Local stuff INTEGER :: i, j, k, itf, jtf, ktf, kz, i_start, j_start REAL :: ur, ul, ub, vr, vl, vb REAL, DIMENSION(its:ite,kts:kte) :: wdwn INTEGER :: advective_order LOGICAL :: specified ! ! ! rhs_ph calculates the large-timestep tendency terms for the geopotential ! equation. These terms include the advection and "gw". The geopotential ! equation is cast in advective form, so we don't use the flux form advection ! algorithms here. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. advective_order = config_flags%h_sca_adv_order ! advective_order = 2 ! original configuration (pre Oct 2001) itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) ! Notes on map scale factors (WCS, 2 march 2008) ! phi equation is: mu/my d/dt(phi) = -(1/my) mx mu u d/dx(phi) ! -(1/my) my mu v d/dy(phi) ! - omega d/d_eta(phi) ! +mu g w/my ! ! A little further explanation... ! The tendency term we are computing here is for mu/my d/dt(phi). It is advective form ! but it is multiplied be mu/my. It will be decoupled from (mu/my) when the implicit w-phi ! solution is computed in subourine advance_w. The formulation dates from the early ! days of the mass coordinate model when we were testing both a flux and an advective formulation ! for the geopotential equation and different forms of the vertical momentum equation and the ! vertically implicit solver. ! advective form for the geopotential equation DO j = jts, jtf DO k = 2, kte DO i = its, itf wdwn(i,k) = .5*(ww(i,k,j)+ww(i,k-1,j))*rdnw(k-1) & *(ph(i,k,j)-ph(i,k-1,j)+phb(i,k,j)-phb(i,k-1,j)) ENDDO ENDDO ! RHS term 3 is: - omega partial d/dnu(phi) DO k = 2, kte-1 DO i = its, itf ph_tend(i,k,j) = ph_tend(i,k,j) & - (fnm(k)*wdwn(i,k+1)+fnp(k)*wdwn(i,k)) ENDDO ENDDO ENDDO IF (non_hydrostatic) THEN ! add in "gw" term. DO j = jts, jtf ! in hydrostatic mode, "gw" will be diagnosed ! after the timestep to give us "w" DO i = its, itf ph_tend(i,kde,j) = 0. ENDDO DO k = 2, kte DO i = its, itf ! phi equation RHS term 4 ph_tend(i,k,j) = ph_tend(i,k,j) + mut(i,j)*g*w(i,k,j)/msfty(i,j) ENDDO ENDDO ENDDO END IF ! Notes on map scale factors: ! RHS terms 1 and 2 are: -(1/my) mx u mu partial d/dx(phi) ! -(1/my) my v mu partial d/dy(phi) IF (advective_order <= 2) THEN ! y (v) advection i_start = its j_start = jts itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) IF ( (config_flags%open_ys) .and. jts == jds ) j_start = jts+1 IF ( (config_flags%open_ye) .and. jte == jde ) jtf = jtf-1 DO j = j_start, jtf DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdy/msfty(i,j))* & ( muv(i,j+1)*(v(i,k,j+1)+v(i,k-1,j+1))*msfvy(i,j+1)* & (phb(i,k,j+1)-phb(i,k,j )+ph(i,k,j+1)-ph(i,k,j )) & +muv(i,j )*(v(i,k,j )+v(i,k-1,j ))*msfvy(i,j )* & (phb(i,k,j )-phb(i,k,j-1)+ph(i,k,j )-ph(i,k,j-1)) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdy/msfty(i,j))* & ( muv(i,j+1)*(cfn*v(i,k-1,j+1)+cfn1*v(i,k-2,j+1))*msfvy(i,j+1)* & (phb(i,k,j+1)-phb(i,k,j )+ph(i,k,j+1)-ph(i,k,j )) & +muv(i,j )*(cfn*v(i,k-1,j )+cfn1*v(i,k-2,j ))*msfvy(i,j )* & (phb(i,k,j )-phb(i,k,j-1)+ph(i,k,j )-ph(i,k,j-1)) ) ENDDO ENDDO ! x (u) advection i_start = its j_start = jts itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) IF ( (config_flags%open_xs) .and. its == ids ) i_start = its+1 IF ( (config_flags%open_xe) .and. ite == ide ) itf = itf-1 DO j = j_start, jtf DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdx/msfty(i,j))* & ( muu(i+1,j)*(u(i+1,k,j)+u(i+1,k-1,j))*msfux(i+1,j)* & (phb(i+1,k,j)-phb(i ,k,j)+ph(i+1,k,j)-ph(i ,k,j)) & +muu(i ,j)*(u(i ,k,j)+u(i ,k-1,j))*msfux(i ,j)* & (phb(i ,k,j)-phb(i-1,k,j)+ph(i ,k,j)-ph(i-1,k,j)) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdx/msfty(i,j))* & ( muu(i+1,j)*(cfn*u(i+1,k-1,j)+cfn1*u(i+1,k-2,j))*msfux(i+1,j)* & (phb(i+1,k,j)-phb(i ,k,j)+ph(i+1,k,j)-ph(i ,k,j)) & +muu(i ,j)*(cfn*u(i ,k-1,j)+cfn1*u(i ,k-2,j))*msfux( i,j)* & (phb(i ,k,j)-phb(i-1,k,j)+ph(i ,k,j)-ph(i-1,k,j)) ) ENDDO ENDDO ELSE IF (advective_order <= 4) THEN ! y (v) advection i_start = its j_start = jts itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) IF ( (config_flags%open_ys) .and. jts == jds ) j_start = jts+1 IF ( (config_flags%open_ye) .and. jte == jde ) jtf = jtf-1 DO j = j_start, jtf DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdy/msfty(i,j))*( & ( muv(i,j+1)*(v(i,k,j+1)+v(i,k-1,j+1))*msfvy(i,j+1) & +muv(i,j )*(v(i,k,j )+v(i,k-1,j ))*msfvy(i,j ))* (1./12.)*( & 8.*(ph(i,k,j+1)-ph(i,k,j-1)) & -(ph(i,k,j+2)-ph(i,k,j-2)) & +8.*(phb(i,k,j+1)-phb(i,k,j-1)) & -(phb(i,k,j+2)-phb(i,k,j-2)) ) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdy/msfty(i,j))*( & ( muv(i,j+1)*(cfn*v(i,k-1,j+1)+cfn1*v(i,k-2,j+1))*msfvy(i,j+1) & +muv(i,j )*(cfn*v(i,k-1,j )+cfn1*v(i,k-2,j ))*msfvy(i,j ))* (1./12.)*( & 8.*(ph(i,k,j+1)-ph(i,k,j-1)) & -(ph(i,k,j+2)-ph(i,k,j-2)) & +8.*(phb(i,k,j+1)-phb(i,k,j-1)) & -(phb(i,k,j+2)-phb(i,k,j-2)) ) ) ENDDO ENDDO ! x (u) advection i_start = its j_start = jts itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) IF ( (config_flags%open_xs) .and. its == ids ) i_start = its+1 IF ( (config_flags%open_xe) .and. ite == ide ) itf = itf-1 DO j = j_start, jtf DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdx/msfty(i,j))*( & ( muu(i+1,j)*(u(i+1,k,j)+u(i+1,k-1,j))*msfux(i+1,j) & +muu(i,j )*(u(i ,k,j)+u(i ,k-1,j))*msfux(i ,j) )* (1./12.)*( & 8.*(ph(i+1,k,j)-ph(i-1,k,j)) & -(ph(i+2,k,j)-ph(i-2,k,j)) & +8.*(phb(i+1,k,j)-phb(i-1,k,j)) & -(phb(i+2,k,j)-phb(i-2,k,j)) ) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdx/msfty(i,j))*( & ( muu(i+1,j)*(cfn*u(i+1,k-1,j)+cfn1*u(i+1,k-2,j))*msfux(i+1,j) & +muu(i,j )*(cfn*u(i ,k-1,j)+cfn1*u(i ,k-2,j))*msfux(i ,j) )* (1./12.)*( & 8.*(ph(i+1,k,j)-ph(i-1,k,j)) & -(ph(i+2,k,j)-ph(i-2,k,j)) & +8.*(phb(i+1,k,j)-phb(i-1,k,j)) & -(phb(i+2,k,j)-phb(i-2,k,j)) ) ) ENDDO ENDDO ELSE IF (advective_order <= 6) THEN ! y (v) advection i_start = its j_start = jts itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ! IF ( (config_flags%open_ys) .and. jts == jds ) j_start = jts+1 ! IF ( (config_flags%open_ye) .and. jte == jde ) jtf = jtf-1 IF (config_flags%open_ys .or. specified ) j_start = max(jts,jds+2) IF (config_flags%open_ye .or. specified ) jtf = min(jtf,jde-3) DO j = j_start, jtf DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdy/msfty(i,j))* ( & ( muv(i,j+1)*(v(i,k,j+1)+v(i,k-1,j+1))*msfvy(i,j+1) & +muv(i,j )*(v(i,k,j )+v(i,k-1,j ))*msfvy(i,j ) )* (1./60.)*( & 45.*(ph(i,k,j+1)-ph(i,k,j-1)) & -9.*(ph(i,k,j+2)-ph(i,k,j-2)) & +(ph(i,k,j+3)-ph(i,k,j-3)) & +45.*(phb(i,k,j+1)-phb(i,k,j-1)) & -9.*(phb(i,k,j+2)-phb(i,k,j-2)) & +(phb(i,k,j+3)-phb(i,k,j-3)) ) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdy/msfty(i,j))* ( & ( muv(i,j+1)*(cfn*v(i,k-1,j+1)+cfn1*v(i,k-2,j+1))*msfvy(i,j+1) & +muv(i,j )*(cfn*v(i,k-1,j )+cfn1*v(i,k-2,j ))*msfvy(i,j ) )* (1./60.)*( & 45.*(ph(i,k,j+1)-ph(i,k,j-1)) & -9.*(ph(i,k,j+2)-ph(i,k,j-2)) & +(ph(i,k,j+3)-ph(i,k,j-3)) & +45.*(phb(i,k,j+1)-phb(i,k,j-1)) & -9.*(phb(i,k,j+2)-phb(i,k,j-2)) & +(phb(i,k,j+3)-phb(i,k,j-3)) ) ) ENDDO ENDDO ! pick up near boundary rows using 4th order stencil ! (open bc copy only goes out to jds-1 and jde, hence 4rth is ok but 6th is too big) IF ( (config_flags%open_ys) .and. jts <= jds+1 ) THEN j = jds+1 DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdy/msfty(i,j))* ( & ( muv(i,j+1)*(v(i,k,j+1)+v(i,k-1,j+1))*msfvy(i,j+1) & +muv(i,j )*(v(i,k,j )+v(i,k-1,j ))*msfvy(i,j ) )* (1./12.)*( & 8.*(ph(i,k,j+1)-ph(i,k,j-1)) & -(ph(i,k,j+2)-ph(i,k,j-2)) & +8.*(phb(i,k,j+1)-phb(i,k,j-1)) & -(phb(i,k,j+2)-phb(i,k,j-2)) ) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdy/msfty(i,j))* ( & ( muv(i,j+1)*(cfn*v(i,k-1,j+1)+cfn1*v(i,k-2,j+1))*msfvy(i,j+1) & +muv(i,j )*(cfn*v(i,k-1,j )+cfn1*v(i,k-2,j ))*msfvy(i,j) )* (1./12.)*( & 8.*(ph(i,k,j+1)-ph(i,k,j-1)) & -(ph(i,k,j+2)-ph(i,k,j-2)) & +8.*(phb(i,k,j+1)-phb(i,k,j-1)) & -(phb(i,k,j+2)-phb(i,k,j-2)) ) ) ENDDO END IF IF ( (config_flags%open_ye) .and. jte >= jde-2 ) THEN j = jde-2 DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdy/msfty(i,j))* ( & ( muv(i,j+1)*(v(i,k,j+1)+v(i,k-1,j+1))*msfvy(i,j+1) & +muv(i,j )*(v(i,k,j )+v(i,k-1,j ))*msfvy(i,j) )* (1./12.)*( & 8.*(ph(i,k,j+1)-ph(i,k,j-1)) & -(ph(i,k,j+2)-ph(i,k,j-2)) & +8.*(phb(i,k,j+1)-phb(i,k,j-1)) & -(phb(i,k,j+2)-phb(i,k,j-2)) ) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdy/msfty(i,j))* ( & ( muv(i,j+1)*(cfn*v(i,k-1,j+1)+cfn1*v(i,k-2,j+1))*msfvy(i,j+1) & +muv(i,j )*(cfn*v(i,k-1,j )+cfn1*v(i,k-2,j ))*msfvy(i,j) )* (1./12.)*( & 8.*(ph(i,k,j+1)-ph(i,k,j-1)) & -(ph(i,k,j+2)-ph(i,k,j-2)) & +8.*(phb(i,k,j+1)-phb(i,k,j-1)) & -(phb(i,k,j+2)-phb(i,k,j-2)) ) ) ENDDO END IF ! x (u) advection i_start = its j_start = jts itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) IF (config_flags%open_xs .or. specified ) i_start = max(its,ids+2) IF (config_flags%open_xe .or. specified ) itf = min(itf,ide-3) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) itf=MIN(ite,ide-1) DO j = j_start, jtf DO k = 2, kte-1 DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdx/msfty(i,j))*( & ( muu(i+1,j)*(u(i+1,k,j)+u(i+1,k-1,j))*msfux(i+1,j) & +muu(i,j )*(u(i,k,j )+u(i,k-1,j ))*msfux(i,j) )* (1./60.)*( & 45.*(ph(i+1,k,j)-ph(i-1,k,j)) & -9.*(ph(i+2,k,j)-ph(i-2,k,j)) & +(ph(i+3,k,j)-ph(i-3,k,j)) & +45.*(phb(i+1,k,j)-phb(i-1,k,j)) & -9.*(phb(i+2,k,j)-phb(i-2,k,j)) & +(phb(i+3,k,j)-phb(i-3,k,j)) ) ) ENDDO ENDDO k = kte DO i = i_start, itf ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdx/msfty(i,j))*( & ( muu(i+1,j)*(cfn*u(i+1,k-1,j)+cfn1*u(i+1,k-2,j))*msfux(i+1,j) & +muu(i,j )*(cfn*u(i ,k-1,j)+cfn1*u(i,k-2,j))*msfux(i,j) )* (1./60.)*( & 45.*(ph(i+1,k,j)-ph(i-1,k,j)) & -9.*(ph(i+2,k,j)-ph(i-2,k,j)) & +(ph(i+3,k,j)-ph(i-3,k,j)) & +45.*(phb(i+1,k,j)-phb(i-1,k,j)) & -9.*(phb(i+2,k,j)-phb(i-2,k,j)) & +(phb(i+3,k,j)-phb(i-3,k,j)) ) ) ENDDO ENDDO IF ( (config_flags%open_xs) .and. its <= ids+1 ) THEN i = ids + 1 DO j = j_start, jtf DO k = 2, kte-1 ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdx/msfty(i,j))*( & ( muu(i+1,j)*(u(i+1,k,j)+u(i+1,k-1,j))*msfux(i+1,j) & +muu(i,j )*(u(i,k,j )+u(i,k-1,j ))*msfux(i,j) )* (1./12.)*( & 8.*(ph(i+1,k,j)-ph(i-1,k,j)) & -(ph(i+2,k,j)-ph(i-2,k,j)) & +8.*(phb(i+1,k,j)-phb(i-1,k,j)) & -(phb(i+2,k,j)-phb(i-2,k,j)) ) ) ENDDO k = kte ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdx/msfty(i,j))*( & ( muu(i+1,j)*(cfn*u(i+1,k-1,j)+cfn1*u(i+1,k-2,j))*msfux(i+1,j) & +muu(i,j )*(cfn*u(i ,k-1,j)+cfn1*u(i,k-2,j))*msfux(i,j) )* (1./12.)*( & 8.*(ph(i+1,k,j)-ph(i-1,k,j)) & -(ph(i+2,k,j)-ph(i-2,k,j)) & +8.*(phb(i+1,k,j)-phb(i-1,k,j)) & -(phb(i+2,k,j)-phb(i-2,k,j)) ) ) ENDDO END IF IF ( (config_flags%open_xe) .and. ite >= ide-2 ) THEN i = ide-2 DO j = j_start, jtf DO k = 2, kte-1 ph_tend(i,k,j)=ph_tend(i,k,j) - (0.25*rdx/msfty(i,j))*( & ( muu(i+1,j)*(u(i+1,k,j)+u(i+1,k-1,j))*msfux(i+1,j) & +muu(i,j )*(u(i,k,j )+u(i,k-1,j ))*msfux(i,j) )* (1./12.)*( & 8.*(ph(i+1,k,j)-ph(i-1,k,j)) & -(ph(i+2,k,j)-ph(i-2,k,j)) & +8.*(phb(i+1,k,j)-phb(i-1,k,j)) & -(phb(i+2,k,j)-phb(i-2,k,j)) ) ) ENDDO k = kte ph_tend(i,k,j)=ph_tend(i,k,j) - (0.5*rdx/msfty(i,j))*( & ( muu(i+1,j)*(cfn*u(i+1,k-1,j)+cfn1*u(i+1,k-2,j))*msfux(i+1,j) & +muu(i,j )*(cfn*u(i ,k-1,j)+cfn1*u(i,k-2,j))*msfux(i,j) )* (1./12.)*( & 8.*(ph(i+1,k,j)-ph(i-1,k,j)) & -(ph(i+2,k,j)-ph(i-2,k,j)) & +8.*(phb(i+1,k,j)-phb(i-1,k,j)) & -(phb(i+2,k,j)-phb(i-2,k,j)) ) ) ENDDO END IF END IF ! lateral open boundary conditions, ! start with north and south (y) boundaries i_start = its itf=MIN(ite,ide-1) ! south IF ( (config_flags%open_ys) .and. jts == jds ) THEN j=jts DO k=2,kde kz = min(k,kde-1) DO i = its,itf vb =.5*( fnm(kz)*(v(i,kz ,j+1)+v(i,kz ,j )) & +fnp(kz)*(v(i,kz-1,j+1)+v(i,kz-1,j )) ) vl=amin1(vb,0.) ph_tend(i,k,j)=ph_tend(i,k,j)-rdy*mut(i,j)*( & +vl*(ph_old(i,k,j+1)-ph_old(i,k,j))) ENDDO ENDDO END IF ! north IF ( (config_flags%open_ye) .and. jte == jde ) THEN j=jte-1 DO k=2,kde kz = min(k,kde-1) DO i = its,itf vb=.5*( fnm(kz)*(v(i,kz ,j+1)+v(i,kz ,j)) & +fnp(kz)*(v(i,kz-1,j+1)+v(i,kz-1,j)) ) vr=amax1(vb,0.) ph_tend(i,k,j)=ph_tend(i,k,j)-rdy*mut(i,j)*( & +vr*(ph_old(i,k,j)-ph_old(i,k,j-1))) ENDDO ENDDO END IF ! now the east and west (y) boundaries j_start = its jtf=MIN(jte,jde-1) ! west IF ( (config_flags%open_xs) .and. its == ids ) THEN i=its DO j = jts,jtf DO k=2,kde-1 kz = k ub =.5*( fnm(kz)*(u(i+1,kz ,j)+u(i ,kz ,j)) & +fnp(kz)*(u(i+1,kz-1,j)+u(i ,kz-1,j)) ) ul=amin1(ub,0.) ph_tend(i,k,j)=ph_tend(i,k,j)-(msftx(i,j)/msfty(i,j))*rdx*mut(i,j)*( & +ul*(ph_old(i+1,k,j)-ph_old(i,k,j))) ENDDO k = kde kz = k ub =.5*( fnm(kz)*(u(i+1,kz ,j)+u(i ,kz ,j)) & +fnp(kz)*(u(i+1,kz-1,j)+u(i ,kz-1,j)) ) ul=amin1(ub,0.) ph_tend(i,k,j)=ph_tend(i,k,j)-(msftx(i,j)/msfty(i,j))*rdx*mut(i,j)*( & +ul*(ph_old(i+1,k,j)-ph_old(i,k,j))) ENDDO END IF ! east IF ( (config_flags%open_xe) .and. ite == ide ) THEN i = ite-1 DO j = jts,jtf DO k=2,kde-1 kz = k ub=.5*( fnm(kz)*(u(i+1,kz ,j)+u(i,kz ,j)) & +fnp(kz)*(u(i+1,kz-1,j)+u(i,kz-1,j)) ) ur=amax1(ub,0.) ph_tend(i,k,j)=ph_tend(i,k,j)-(msftx(i,j)/msfty(i,j))*rdx*mut(i,j)*( & +ur*(ph_old(i,k,j)-ph_old(i-1,k,j))) ENDDO k = kde kz = k-1 ub=.5*( fnm(kz)*(u(i+1,kz ,j)+u(i,kz ,j)) & +fnp(kz)*(u(i+1,kz-1,j)+u(i,kz-1,j)) ) ur=amax1(ub,0.) ph_tend(i,k,j)=ph_tend(i,k,j)-(msftx(i,j)/msfty(i,j))*rdx*mut(i,j)*( & +ur*(ph_old(i,k,j)-ph_old(i-1,k,j))) ENDDO END IF END SUBROUTINE rhs_ph !------------------------------------------------------------------------------- SUBROUTINE horizontal_pressure_gradient( ru_tend,rv_tend, & ph,alt,p,pb,al,php,cqu,cqv, & muu,muv,mu,fnm,fnp,rdnw, & cf1,cf2,cf3,rdx,rdy,msfux,msfuy,& msfvx,msfvy,msftx,msfty, & config_flags, non_hydrostatic, & top_lid, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags LOGICAL, INTENT (IN ) :: non_hydrostatic, top_lid INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: & ph, & alt, & al, & p, & pb, & php, & cqu, & cqv REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(INOUT) :: & ru_tend, & rv_tend REAL, DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: muu, muv, mu, & msfux, msfuy, & msfvx, msfvy, & msftx, msfty REAL, DIMENSION( kms:kme ), INTENT(IN ) :: rdnw, fnm, fnp REAL, INTENT(IN ) :: rdx, rdy, cf1, cf2, cf3 INTEGER :: i,j,k, itf, jtf, ktf, i_start, j_start REAL, DIMENSION( ims:ime, kms:kme ) :: dpn REAL :: dpx, dpy LOGICAL :: specified ! ! ! horizontal_pressure_gradient calculates the ! horizontal pressure gradient terms for the large-timestep tendency ! in the horizontal momentum equations (u,v). ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ! Notes on map scale factors: ! Calculates the pressure gradient terms in ADT eqns 44 and 45 ! With upper rho -> 'mu', these are: ! Eqn 30: -mu*(mx/my)*(1/rho)*partial dp/dx ! Eqn 31: -mu*(my/mx)*(1/rho)*partial dp/dy ! ! As we are on nu, rather than height, surfaces: ! ! mu dp/dx = mu alpha partial dp'/dx + (nu mu partial dmubar/dx) alpha' ! + mu partial dphi'/dx + (partial dphi/dx)*(partial dp'/dnu - mu') ! ! mu dp/dy = mu alpha partial dp'/dy + (nu mu partial dmubar/dy) alpha' ! + mu partial dphi'/dy + (partial dphi/dy)*(partial dp'/dnu - mu') ! start with the north-south (y) pressure gradient itf=MIN(ite,ide-1) jtf=jte ktf=MIN(kte,kde-1) i_start = its j_start = jts IF ( (config_flags%open_ys .or. specified .or. & config_flags%nested .or. config_flags%polar ) .and. jts == jds ) j_start = jts+1 IF ( (config_flags%open_ye .or. specified .or. & config_flags%nested .or. config_flags%polar ) .and. jte == jde ) jtf = jtf-1 DO j = j_start, jtf IF ( non_hydrostatic ) THEN k=1 DO i = i_start, itf dpn(i,k) = .5*( cf1*(p(i,k ,j-1)+p(i,k ,j)) & +cf2*(p(i,k+1,j-1)+p(i,k+1,j)) & +cf3*(p(i,k+2,j-1)+p(i,k+2,j)) ) dpn(i,kde) = 0. ENDDO IF (top_lid) THEN DO i = i_start, itf dpn(i,kde) = .5*( cf1*(p(i,kde-1,j-1)+p(i,kde-1,j)) & +cf2*(p(i,kde-2,j-1)+p(i,kde-2,j)) & +cf3*(p(i,kde-3,j-1)+p(i,kde-3,j)) ) ENDDO ENDIF DO k=2,ktf DO i = i_start, itf dpn(i,k) = .5*( fnm(k)*(p(i,k ,j-1)+p(i,k ,j)) & +fnp(k)*(p(i,k-1,j-1)+p(i,k-1,j)) ) END DO END DO ! ADT eqn 45: -mu*(my/mx)*(1/rho)*partial dp/dy ! [alt, al are 1/rho terms; muv, mu are NOT coupled] DO K=1,ktf DO i = i_start, itf ! Here are mu dp/dy terms 1-3 dpy = (msfvy(i,j)/msfvx(i,j))*.5*rdy*muv(i,j)*( & (ph (i,k+1,j)-ph (i,k+1,j-1) + ph(i,k,j)-ph(i,k,j-1)) & +(alt(i,k ,j)+alt(i,k ,j-1))*(p (i,k,j)-p (i,k,j-1)) & +(al (i,k ,j)+al (i,k ,j-1))*(pb(i,k,j)-pb(i,k,j-1)) ) ! Here is mu dp/dy term 4 dpy = dpy + (msfvy(i,j)/msfvx(i,j))*rdy*(php(i,k,j)-php(i,k,j-1))* & (rdnw(k)*(dpn(i,k+1)-dpn(i,k))-.5*(mu(i,j-1)+mu(i,j))) rv_tend(i,k,j) = rv_tend(i,k,j)-cqv(i,k,j)*dpy END DO END DO ELSE ! ADT eqn 45: -mu*(my/mx)*(1/rho)*partial dp/dy ! [alt, al are 1/rho terms; muv, mu are NOT coupled] DO K=1,ktf DO i = i_start, itf ! Here are mu dp/dy terms 1-3; term 4 not needed if hydrostatic dpy = (msfvy(i,j)/msfvx(i,j))*.5*rdy*muv(i,j)*( & (ph (i,k+1,j)-ph (i,k+1,j-1) + ph(i,k,j)-ph(i,k,j-1)) & +(alt(i,k ,j)+alt(i,k ,j-1))*(p (i,k,j)-p (i,k,j-1)) & +(al (i,k ,j)+al (i,k ,j-1))*(pb(i,k,j)-pb(i,k,j-1)) ) rv_tend(i,k,j) = rv_tend(i,k,j)-cqv(i,k,j)*dpy END DO END DO END IF ENDDO ! now the east-west (x) pressure gradient itf=ite jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) i_start = its j_start = jts IF ( (config_flags%open_xs .or. specified .or. & config_flags%nested ) .and. its == ids ) i_start = its+1 IF ( (config_flags%open_xe .or. specified .or. & config_flags%nested ) .and. ite == ide ) itf = itf-1 IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) itf=ite DO j = j_start, jtf IF ( non_hydrostatic ) THEN k=1 DO i = i_start, itf dpn(i,k) = .5*( cf1*(p(i-1,k ,j)+p(i,k ,j)) & +cf2*(p(i-1,k+1,j)+p(i,k+1,j)) & +cf3*(p(i-1,k+2,j)+p(i,k+2,j)) ) dpn(i,kde) = 0. ENDDO IF (top_lid) THEN DO i = i_start, itf dpn(i,kde) = .5*( cf1*(p(i-1,kde-1,j)+p(i,kde-1,j)) & +cf2*(p(i-1,kde-2,j)+p(i,kde-2,j)) & +cf3*(p(i-1,kde-3,j)+p(i,kde-3,j)) ) ENDDO ENDIF DO k=2,ktf DO i = i_start, itf dpn(i,k) = .5*( fnm(k)*(p(i-1,k ,j)+p(i,k ,j)) & +fnp(k)*(p(i-1,k-1,j)+p(i,k-1,j)) ) END DO END DO ! ADT eqn 44: -mu*(mx/my)*(1/rho)*partial dp/dx ! [alt, al are 1/rho terms; muu, mu are NOT coupled] DO K=1,ktf DO i = i_start, itf ! Here are mu dp/dy terms 1-3 dpx = (msfux(i,j)/msfuy(i,j))*.5*rdx*muu(i,j)*( & (ph (i,k+1,j)-ph (i-1,k+1,j) + ph(i,k,j)-ph(i-1,k,j)) & +(alt(i,k ,j)+alt(i-1,k ,j))*(p (i,k,j)-p (i-1,k,j)) & +(al (i,k ,j)+al (i-1,k ,j))*(pb(i,k,j)-pb(i-1,k,j)) ) ! Here is mu dp/dy term 4 dpx = dpx + (msfux(i,j)/msfuy(i,j))*rdx*(php(i,k,j)-php(i-1,k,j))* & (rdnw(k)*(dpn(i,k+1)-dpn(i,k))-.5*(mu(i-1,j)+mu(i,j))) ru_tend(i,k,j) = ru_tend(i,k,j)-cqu(i,k,j)*dpx END DO END DO ELSE ! ADT eqn 44: -mu*(mx/my)*(1/rho)*partial dp/dx ! [alt, al are 1/rho terms; muu, mu are NOT coupled] DO K=1,ktf DO i = i_start, itf ! Here are mu dp/dy terms 1-3; term 4 not needed if hydrostatic dpx = (msfux(i,j)/msfuy(i,j))*.5*rdx*muu(i,j)*( & (ph (i,k+1,j)-ph (i-1,k+1,j) + ph(i,k,j)-ph(i-1,k,j)) & +(alt(i,k ,j)+alt(i-1,k ,j))*(p (i,k,j)-p (i-1,k,j)) & +(al (i,k ,j)+al (i-1,k ,j))*(pb(i,k,j)-pb(i-1,k,j)) ) ru_tend(i,k,j) = ru_tend(i,k,j)-cqu(i,k,j)*dpx END DO END DO END IF ENDDO END SUBROUTINE horizontal_pressure_gradient !------------------------------------------------------------------------------- SUBROUTINE pg_buoy_w( rw_tend, p, cqw, mu, mub, & rdnw, rdn, g, msftx, msfty, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: p REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(INOUT) :: cqw REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(INOUT) :: rw_tend REAL, DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: mub, mu, msftx, msfty REAL, DIMENSION( kms:kme ), INTENT(IN ) :: rdnw, rdn REAL, INTENT(IN ) :: g INTEGER :: itf, jtf, i, j, k REAL :: cq1, cq2 ! ! ! pg_buoy_w calculates the ! vertical pressure gradient and buoyancy terms for the large-timestep ! tendency in the vertical momentum equation. ! ! ! BUOYANCY AND PRESSURE GRADIENT TERM IN W EQUATION AT TIME T ! Map scale factor notes ! ADT eqn 46 RHS terms 6 and 7 (where 7 is "-rho g") ! Dividing by my, and using mu and nu (see Klemp et al. eqns 32, 40) ! term 6: +(g/my) partial dp'/dnu ! term 7: -(g/my) mu' ! ! For moisture-free atmosphere, cq1=1, cq2=0 ! => (1./msft(i,j)) * g * [rdn(k)*{p(i,k,j)-p(i,k-1,j)}-mu(i,j)] itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j = jts,jtf k=kde DO i=its,itf cq1 = 1./(1.+cqw(i,k-1,j)) cq2 = cqw(i,k-1,j)*cq1 rw_tend(i,k,j) = rw_tend(i,k,j)+(1./msfty(i,j))*g*( & cq1*2.*rdnw(k-1)*( -p(i,k-1,j)) & -mu(i,j)-cq2*mub(i,j) ) END DO DO k = 2, kde-1 DO i = its,itf cq1 = 1./(1.+cqw(i,k,j)) cq2 = cqw(i,k,j)*cq1 cqw(i,k,j) = cq1 rw_tend(i,k,j) = rw_tend(i,k,j)+(1./msfty(i,j))*g*( & cq1*rdn(k)*(p(i,k,j)-p(i,k-1,j)) & -mu(i,j)-cq2*mub(i,j) ) END DO ENDDO ENDDO END SUBROUTINE pg_buoy_w !------------------------------------------------------------------------------- SUBROUTINE w_damp( rw_tend, max_vert_cfl,max_horiz_cfl, & u, v, ww, w, mut, rdnw, & rdx, rdy, msfux, msfuy, & msfvx, msfvy, dt, & config_flags, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) USE module_llxy IMPLICIT NONE ! Input data TYPE(grid_config_rec_type ) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: u, v, ww, w REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(INOUT) :: rw_tend REAL, INTENT(OUT) :: max_vert_cfl REAL, INTENT(OUT) :: max_horiz_cfl REAL :: horiz_cfl REAL, DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: mut REAL, DIMENSION( kms:kme ), INTENT(IN ) :: rdnw REAL, INTENT(IN) :: dt REAL, INTENT(IN) :: rdx, rdy REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, msfuy REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfvx, msfvy REAL :: vert_cfl, cf_n, cf_d, maxdub, maxdeta INTEGER :: itf, jtf, i, j, k, maxi, maxj, maxk INTEGER :: some CHARACTER*512 :: temp CHARACTER (LEN=256) :: time_str CHARACTER (LEN=256) :: grid_str integer :: total REAL :: msfuxt , msfxffl ! ! ! w_damp computes a damping term for the vertical velocity when the ! vertical Courant number is too large. This was found to be preferable to ! decreasing the timestep or increasing the diffusion in real-data applications ! that produced potentially-unstable large vertical velocities because of ! unphysically large heating rates coming from the cumulus parameterization ! schemes run at moderately high resolutions (dx ~ O(10) km). ! ! Additionally, w_damp returns the maximum cfl values due to vertical motion and ! horizontal motion. These values are returned via the max_vert_cfl and ! max_horiz_cfl variables. (Added by T. Hutchinson, WSI, 3/5/2007) ! ! itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) some = 0 max_vert_cfl = 0. max_horiz_cfl = 0. total = 0 IF(config_flags%map_proj == PROJ_CASSINI ) then msfxffl = 1.0/COS(config_flags%fft_filter_lat*degrad) END IF IF ( config_flags%w_damping == 1 ) THEN DO j = jts,jtf DO k = 2, kde-1 DO i = its,itf #if 1 IF(config_flags%map_proj == PROJ_CASSINI ) then msfuxt = MIN(msfux(i,j), msfxffl) ELSE msfuxt = msfux(i,j) END IF vert_cfl = abs(ww(i,k,j)/mut(i,j)*rdnw(k)*dt) IF ( vert_cfl > max_vert_cfl ) THEN max_vert_cfl = vert_cfl ; maxi = i ; maxj = j ; maxk = k maxdub = w(i,k,j) ; maxdeta = -1./rdnw(k) ENDIF horiz_cfl = max( abs(u(i,k,j) * rdx * msfuxt * dt), & abs(v(i,k,j) * rdy * msfvy(i,j) * dt) ) if (horiz_cfl > max_horiz_cfl) then max_horiz_cfl = horiz_cfl endif if(vert_cfl .gt. w_beta)then #else ! restructure to get rid of divide ! ! This had been used for efficiency, but with the addition of returning the cfl values, ! the old version (above) was reinstated. (T. Hutchinson, 3/5/2007) ! cf_n = abs(ww(i,k,j)*rdnw(k)*dt) cf_d = abs(mut(i,j)) if(cf_n .gt. cf_d*w_beta )then #endif WRITE(temp,*)i,j,k,' vert_cfl,w,d(eta)=',vert_cfl,w(i,k,j),-1./rdnw(k) CALL wrf_debug ( 100 , TRIM(temp) ) if ( vert_cfl > 2. ) some = some + 1 rw_tend(i,k,j) = rw_tend(i,k,j)-sign(1.,w(i,k,j))*w_alpha*(vert_cfl-w_beta)*mut(i,j) endif END DO ENDDO ENDDO ELSE ! just print DO j = jts,jtf DO k = 2, kde-1 DO i = its,itf #if 1 IF(config_flags%map_proj == PROJ_CASSINI ) then msfuxt = MIN(msfux(i,j), msfxffl) ELSE msfuxt = msfux(i,j) END IF vert_cfl = abs(ww(i,k,j)/mut(i,j)*rdnw(k)*dt) IF ( vert_cfl > max_vert_cfl ) THEN max_vert_cfl = vert_cfl ; maxi = i ; maxj = j ; maxk = k maxdub = w(i,k,j) ; maxdeta = -1./rdnw(k) ENDIF horiz_cfl = max( abs(u(i,k,j) * rdx * msfuxt * dt), & abs(v(i,k,j) * rdy * msfvy(i,j) * dt) ) if (horiz_cfl > max_horiz_cfl) then max_horiz_cfl = horiz_cfl endif if(vert_cfl .gt. w_beta)then #else ! restructure to get rid of divide ! ! This had been used for efficiency, but with the addition of returning the cfl values, ! the old version (above) was reinstated. (T. Hutchinson, 3/5/2007) ! cf_n = abs(ww(i,k,j)*rdnw(k)*dt) cf_d = abs(mut(i,j)) if(cf_n .gt. cf_d*w_beta )then #endif WRITE(temp,*)i,j,k,' vert_cfl,w,d(eta)=',vert_cfl,w(i,k,j),-1./rdnw(k) CALL wrf_debug ( 100 , TRIM(temp) ) if ( vert_cfl > 2. ) some = some + 1 endif END DO ENDDO ENDDO ENDIF IF ( some .GT. 0 ) THEN CALL get_current_time_string( time_str ) CALL get_current_grid_name( grid_str ) WRITE(wrf_err_message,*)some, & ' points exceeded cfl=2 in domain '//TRIM(grid_str)//' at time '//TRIM(time_str)//' hours' CALL wrf_debug ( 0 , TRIM(wrf_err_message) ) WRITE(wrf_err_message,*)'MAX AT i,j,k: ',maxi,maxj,maxk,' vert_cfl,w,d(eta)=',max_vert_cfl, & maxdub,maxdeta CALL wrf_debug ( 0 , TRIM(wrf_err_message) ) ENDIF END SUBROUTINE w_damp !------------------------------------------------------------------------------- SUBROUTINE horizontal_diffusion ( name, field, tendency, mu, & config_flags, & msfux, msfuy, msfvx, msfvx_inv, & msfvy, msftx, msfty, & khdif, xkmhd, rdx, rdy, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte CHARACTER(LEN=1) , INTENT(IN ) :: name REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: field, xkmhd REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mu REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, & msfuy, & msfvx, & msfvx_inv, & msfvy, & msftx, & msfty REAL , INTENT(IN ) :: rdx, & rdy, & khdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end REAL :: mrdx, mkrdxm, mkrdxp, & mrdy, mkrdym, mkrdyp LOGICAL :: specified ! ! ! horizontal_diffusion computes the horizontal diffusion tendency ! on model horizontal coordinate surfaces. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) IF (name .EQ. 'u') THEN i_start = its i_end = ite j_start = jts j_end = MIN(jte,jde-1) IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified ) i_end = MIN(ide-1,ite) IF ( config_flags%open_ys .or. specified ) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified ) j_end = MIN(jde-2,jte) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = ite DO j = j_start, j_end DO k=kts,ktf DO i = i_start, i_end ! The interior is grad: (m_x*d/dx), the exterior is div: (m_x*m_y*d/dx(/m_y)) ! setting up different averagings of m^2 partial d/dX and m^2 partial d/dY mkrdxm=(msftx(i-1,j)/msfty(i-1,j))*mu(i-1,j)*xkmhd(i-1,k,j)*rdx mkrdxp=(msftx(i,j)/msfty(i,j))*mu(i,j)*xkmhd(i,k,j)*rdx mrdx=msfux(i,j)*msfuy(i,j)*rdx mkrdym=( (msfuy(i,j)+msfuy(i,j-1))/(msfux(i,j)+msfux(i,j-1)) )* & 0.25*(mu(i,j)+mu(i,j-1)+mu(i-1,j-1)+mu(i-1,j))* & 0.25*(xkmhd(i,k,j)+xkmhd(i,k,j-1)+xkmhd(i-1,k,j-1)+xkmhd(i-1,k,j))*rdy mkrdyp=( (msfuy(i,j)+msfuy(i,j+1))/(msfux(i,j)+msfux(i,j+1)) )* & 0.25*(mu(i,j)+mu(i,j+1)+mu(i-1,j+1)+mu(i-1,j))* & 0.25*(xkmhd(i,k,j)+xkmhd(i,k,j+1)+xkmhd(i-1,k,j+1)+xkmhd(i-1,k,j))*rdy ! need to do four-corners (t) for diffusion coefficient as there are ! no values at u,v points ! msfuy - has to be y as part of d/dY ! has to be u as we're at a u point mrdy=msfux(i,j)*msfuy(i,j)*rdy ! correctly averaged version of rho~ * m^2 * ! [partial d/dX(partial du^/dX) + partial d/dY(partial du^/dY)] tendency(i,k,j)=tendency(i,k,j)+( & mrdx*(mkrdxp*(field(i+1,k,j)-field(i ,k,j)) & -mkrdxm*(field(i ,k,j)-field(i-1,k,j))) & +mrdy*(mkrdyp*(field(i,k,j+1)-field(i,k,j )) & -mkrdym*(field(i,k,j )-field(i,k,j-1)))) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'v')THEN i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = jte IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified ) i_end = MIN(ide-2,ite) IF ( config_flags%open_ys .or. specified ) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified ) j_end = MIN(jde-1,jte) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = MIN(ite,ide-1) IF ( config_flags%polar ) j_start = MAX(jds+1,jts) IF ( config_flags%polar ) j_end = MIN(jde-1,jte) DO j = j_start, j_end DO k=kts,ktf DO i = i_start, i_end mkrdxm=( (msfvx(i,j)+msfvx(i-1,j))/(msfvy(i,j)+msfvy(i-1,j)) )* & 0.25*(mu(i,j)+mu(i,j-1)+mu(i-1,j-1)+mu(i-1,j))* & 0.25*(xkmhd(i,k,j)+xkmhd(i,k,j-1)+xkmhd(i-1,k,j-1)+xkmhd(i-1,k,j))*rdx mkrdxp=( (msfvx(i,j)+msfvx(i+1,j))/(msfvy(i,j)+msfvy(i+1,j)) )* & 0.25*(mu(i,j)+mu(i,j-1)+mu(i+1,j-1)+mu(i+1,j))* & 0.25*(xkmhd(i,k,j)+xkmhd(i,k,j-1)+xkmhd(i+1,k,j-1)+xkmhd(i+1,k,j))*rdx mrdx=msfvx(i,j)*msfvy(i,j)*rdx mkrdym=(msfty(i,j-1)/msftx(i,j-1))*xkmhd(i,k,j-1)*rdy mkrdyp=(msfty(i,j)/msftx(i,j))*xkmhd(i,k,j)*rdy mrdy=msfvx(i,j)*msfvy(i,j)*rdy tendency(i,k,j)=tendency(i,k,j)+( & mrdx*(mkrdxp*(field(i+1,k,j)-field(i ,k,j)) & -mkrdxm*(field(i ,k,j)-field(i-1,k,j))) & +mrdy*(mkrdyp*(field(i,k,j+1)-field(i,k,j )) & -mkrdym*(field(i,k,j )-field(i,k,j-1)))) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'w')THEN i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified ) i_end = MIN(ide-2,ite) IF ( config_flags%open_ys .or. specified ) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified ) j_end = MIN(jde-2,jte) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = MIN(ite,ide-1) DO j = j_start, j_end DO k=kts+1,ktf DO i = i_start, i_end mkrdxm=(msfux(i,j)/msfuy(i,j))* & 0.25*(mu(i,j)+mu(i-1,j)+mu(i,j)+mu(i-1,j))* & 0.25*(xkmhd(i,k,j)+xkmhd(i-1,k,j)+xkmhd(i,k-1,j)+xkmhd(i-1,k-1,j))*rdx mkrdxp=(msfux(i+1,j)/msfuy(i+1,j))* & 0.25*(mu(i+1,j)+mu(i,j)+mu(i+1,j)+mu(i,j))* & 0.25*(xkmhd(i+1,k,j)+xkmhd(i,k,j)+xkmhd(i+1,k-1,j)+xkmhd(i,k-1,j))*rdx mrdx=msftx(i,j)*msfty(i,j)*rdx ! mkrdym=(msfvy(i,j)/msfvx(i,j))* & mkrdym=(msfvy(i,j)*msfvx_inv(i,j))* & 0.25*(mu(i,j)+mu(i,j-1)+mu(i,j)+mu(i,j-1))* & 0.25*(xkmhd(i,k,j)+xkmhd(i,k,j-1)+xkmhd(i,k-1,j)+xkmhd(i,k-1,j-1))*rdy ! mkrdyp=(msfvy(i,j+1)/msfvx(i,j+1))* & mkrdyp=(msfvy(i,j+1)*msfvx_inv(i,j+1))* & 0.25*(mu(i,j+1)+mu(i,j)+mu(i,j+1)+mu(i,j))* & 0.25*(xkmhd(i,k,j+1)+xkmhd(i,k,j)+xkmhd(i,k-1,j+1)+xkmhd(i,k-1,j))*rdy mrdy=msftx(i,j)*msfty(i,j)*rdy tendency(i,k,j)=tendency(i,k,j)+( & mrdx*(mkrdxp*(field(i+1,k,j)-field(i ,k,j)) & -mkrdxm*(field(i ,k,j)-field(i-1,k,j))) & +mrdy*(mkrdyp*(field(i,k,j+1)-field(i,k,j )) & -mkrdym*(field(i,k,j )-field(i,k,j-1)))) ENDDO ENDDO ENDDO ELSE i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified ) i_end = MIN(ide-2,ite) IF ( config_flags%open_ys .or. specified ) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified ) j_end = MIN(jde-2,jte) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = MIN(ite,ide-1) DO j = j_start, j_end DO k=kts,ktf DO i = i_start, i_end mkrdxm=(msfux(i,j)/msfuy(i,j))*0.5*(xkmhd(i,k,j)+xkmhd(i-1,k,j))*0.5*(mu(i,j)+mu(i-1,j))*rdx mkrdxp=(msfux(i+1,j)/msfuy(i+1,j))*0.5*(xkmhd(i+1,k,j)+xkmhd(i,k,j))*0.5*(mu(i+1,j)+mu(i,j))*rdx mrdx=msftx(i,j)*msfty(i,j)*rdx ! mkrdym=(msfvy(i,j)/msfvx(i,j))*0.5*(xkmhd(i,k,j)+xkmhd(i,k,j-1))*0.5*(mu(i,j)+mu(i,j-1))*rdy mkrdym=(msfvy(i,j)*msfvx_inv(i,j))*0.5*(xkmhd(i,k,j)+xkmhd(i,k,j-1))*0.5*(mu(i,j)+mu(i,j-1))*rdy ! mkrdyp=(msfvy(i,j+1)/msfvx(i,j+1))*0.5*(xkmhd(i,k,j+1)+xkmhd(i,k,j))*0.5*(mu(i,j+1)+mu(i,j))*rdy mkrdyp=(msfvy(i,j+1)*msfvx_inv(i,j+1))*0.5*(xkmhd(i,k,j+1)+xkmhd(i,k,j))*0.5*(mu(i,j+1)+mu(i,j))*rdy mrdy=msftx(i,j)*msfty(i,j)*rdy tendency(i,k,j)=tendency(i,k,j)+( & mrdx*(mkrdxp*(field(i+1,k,j)-field(i ,k,j)) & -mkrdxm*(field(i ,k,j)-field(i-1,k,j))) & +mrdy*(mkrdyp*(field(i,k,j+1)-field(i,k,j )) & -mkrdym*(field(i,k,j )-field(i,k,j-1)))) ENDDO ENDDO ENDDO ENDIF END SUBROUTINE horizontal_diffusion !----------------------------------------------------------------------------------------- SUBROUTINE horizontal_diffusion_3dmp ( name, field, tendency, mu, & config_flags, base_3d, & msfux, msfuy, msfvx, msfvx_inv, & msfvy, msftx, msfty, & khdif, xkmhd, rdx, rdy, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte CHARACTER(LEN=1) , INTENT(IN ) :: name REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: field, & xkmhd, & base_3d REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mu REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, & msfuy, & msfvx, & msfvx_inv, & msfvy, & msftx, & msfty REAL , INTENT(IN ) :: rdx, & rdy, & khdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end REAL :: mrdx, mkrdxm, mkrdxp, & mrdy, mkrdym, mkrdyp LOGICAL :: specified ! ! ! horizontal_diffusion_3dmp computes the horizontal diffusion tendency ! on model horizontal coordinate surfaces. This routine computes diffusion ! a perturbation scalar (field-base_3d). ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified ) i_end = MIN(ide-2,ite) IF ( config_flags%open_ys .or. specified ) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified ) j_end = MIN(jde-2,jte) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = MIN(ite,ide-1) DO j = j_start, j_end DO k=kts,ktf DO i = i_start, i_end mkrdxm=(msfux(i,j)/msfuy(i,j))*0.5*(xkmhd(i,k,j)+xkmhd(i-1,k,j))*0.5*(mu(i,j)+mu(i-1,j))*rdx mkrdxp=(msfux(i+1,j)/msfuy(i+1,j))*0.5*(xkmhd(i+1,k,j)+xkmhd(i,k,j))*0.5*(mu(i+1,j)+mu(i,j))*rdx mrdx=msftx(i,j)*msfty(i,j)*rdx ! mkrdym=(msfvy(i,j)/msfvx(i,j))*0.5*(xkmhd(i,k,j)+xkmhd(i,k,j-1))*0.5*(mu(i,j)+mu(i,j-1))*rdy ! mkrdyp=(msfvy(i,j+1)/msfvx(i,j+1))*0.5*(xkmhd(i,k,j+1)+xkmhd(i,k,j))*0.5*(mu(i,j+1)+mu(i,j))*rdy mkrdym=(msfvy(i,j)*msfvx_inv(i,j))*0.5*(xkmhd(i,k,j)+xkmhd(i,k,j-1))*0.5*(mu(i,j)+mu(i,j-1))*rdy mkrdyp=(msfvy(i,j+1)*msfvx_inv(i,j+1))*0.5*(xkmhd(i,k,j+1)+xkmhd(i,k,j))*0.5*(mu(i,j+1)+mu(i,j))*rdy mrdy=msftx(i,j)*msfty(i,j)*rdy tendency(i,k,j)=tendency(i,k,j)+( & mrdx*( mkrdxp*( field(i+1,k,j) -field(i ,k,j) & -base_3d(i+1,k,j)+base_3d(i ,k,j) ) & -mkrdxm*( field(i ,k,j) -field(i-1,k,j) & -base_3d(i ,k,j)+base_3d(i-1,k,j) ) ) & +mrdy*( mkrdyp*( field(i,k,j+1) -field(i,k,j ) & -base_3d(i,k,j+1)+base_3d(i,k,j ) ) & -mkrdym*( field(i,k,j ) -field(i,k,j-1) & -base_3d(i,k,j )+base_3d(i,k,j-1) ) ) & ) ENDDO ENDDO ENDDO END SUBROUTINE horizontal_diffusion_3dmp !----------------------------------------------------------------------------------------- SUBROUTINE vertical_diffusion ( name, field, tendency, & config_flags, & alt, mut, rdn, rdnw, kvdif, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte CHARACTER(LEN=1) , INTENT(IN ) :: name REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: field, & alt REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mut REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: rdn, rdnw REAL , INTENT(IN ) :: kvdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end REAL , DIMENSION(its:ite, jts:jte) :: vfluxm, vfluxp, zz REAL , DIMENSION(its:ite, 0:kte+1) :: vflux REAL :: rdz LOGICAL :: specified ! ! ! vertical_diffusion ! computes vertical diffusion tendency. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) IF (name .EQ. 'w')THEN i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) j_loop_w : DO j = j_start, j_end DO k=kts,ktf-1 DO i = i_start, i_end vflux(i,k)= (kvdif/alt(i,k,j))*rdnw(k)*(field(i,k+1,j)-field(i,k,j)) ENDDO ENDDO DO i = i_start, i_end vflux(i,ktf)=0. ENDDO DO k=kts+1,ktf DO i = i_start, i_end tendency(i,k,j)=tendency(i,k,j) & +rdn(k)*g*g/mut(i,j)/(0.5*(alt(i,k,j)+alt(i,k-1,j))) & *(vflux(i,k)-vflux(i,k-1)) ENDDO ENDDO ENDDO j_loop_w ELSE IF(name .EQ. 'm')THEN i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) j_loop_s : DO j = j_start, j_end DO k=kts,ktf-1 DO i = i_start, i_end vflux(i,k)=kvdif*rdn(k+1)/(0.5*(alt(i,k,j)+alt(i,k+1,j))) & *(field(i,k+1,j)-field(i,k,j)) ENDDO ENDDO DO i = i_start, i_end vflux(i,0)=vflux(i,1) ENDDO DO i = i_start, i_end vflux(i,ktf)=0. ENDDO DO k=kts,ktf DO i = i_start, i_end tendency(i,k,j)=tendency(i,k,j)+g*g/mut(i,j)/alt(i,k,j) & *rdnw(k)*(vflux(i,k)-vflux(i,k-1)) ENDDO ENDDO ENDDO j_loop_s ENDIF END SUBROUTINE vertical_diffusion !------------------------------------------------------------------------------- SUBROUTINE vertical_diffusion_mp ( field, tendency, config_flags, & base, & alt, mut, rdn, rdnw, kvdif, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: field, & alt REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mut REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: rdn, & rdnw, & base REAL , INTENT(IN ) :: kvdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end REAL , DIMENSION(its:ite, 0:kte+1) :: vflux REAL :: rdz LOGICAL :: specified ! ! ! vertical_diffusion_mp ! computes vertical diffusion tendency of a perturbation variable ! (field-base). Note that base as a 1D (k) field. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) j_loop_s : DO j = j_start, j_end DO k=kts,ktf-1 DO i = i_start, i_end vflux(i,k)=kvdif*rdn(k+1)/(0.5*(alt(i,k,j)+alt(i,k+1,j))) & *(field(i,k+1,j)-field(i,k,j)-base(k+1)+base(k)) ENDDO ENDDO DO i = i_start, i_end vflux(i,0)=vflux(i,1) ENDDO DO i = i_start, i_end vflux(i,ktf)=0. ENDDO DO k=kts,ktf DO i = i_start, i_end tendency(i,k,j)=tendency(i,k,j)+g*g/mut(i,j)/alt(i,k,j) & *rdnw(k)*(vflux(i,k)-vflux(i,k-1)) ENDDO ENDDO ENDDO j_loop_s END SUBROUTINE vertical_diffusion_mp !------------------------------------------------------------------------------- SUBROUTINE vertical_diffusion_3dmp ( field, tendency, config_flags, & base_3d, & alt, mut, rdn, rdnw, kvdif, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: field, & alt, & base_3d REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mut REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: rdn, & rdnw REAL , INTENT(IN ) :: kvdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end REAL , DIMENSION(its:ite, 0:kte+1) :: vflux REAL :: rdz LOGICAL :: specified ! ! ! vertical_diffusion_3dmp ! computes vertical diffusion tendency of a perturbation variable ! (field-base_3d). ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) j_loop_s : DO j = j_start, j_end DO k=kts,ktf-1 DO i = i_start, i_end vflux(i,k)=kvdif*rdn(k+1)/(0.5*(alt(i,k,j)+alt(i,k+1,j))) & *( field(i,k+1,j) -field(i,k,j) & -base_3d(i,k+1,j)+base_3d(i,k,j) ) ENDDO ENDDO DO i = i_start, i_end vflux(i,0)=vflux(i,1) ENDDO DO i = i_start, i_end vflux(i,ktf)=0. ENDDO DO k=kts,ktf DO i = i_start, i_end tendency(i,k,j)=tendency(i,k,j)+g*g/mut(i,j)/alt(i,k,j) & *rdnw(k)*(vflux(i,k)-vflux(i,k-1)) ENDDO ENDDO ENDDO j_loop_s END SUBROUTINE vertical_diffusion_3dmp !------------------------------------------------------------------------------- SUBROUTINE vertical_diffusion_u ( field, tendency, & config_flags, u_base, & alt, muu, rdn, rdnw, kvdif, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: field, & alt REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: muu REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: rdn, rdnw, u_base REAL , INTENT(IN ) :: kvdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end REAL , DIMENSION(its:ite, 0:kte+1) :: vflux REAL :: rdz, zz LOGICAL :: specified ! ! ! vertical_diffusion_u computes vertical diffusion tendency for ! the u momentum equation. This routine assumes a constant eddy ! viscosity kvdif. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) i_start = its i_end = ite j_start = jts j_end = MIN(jte,jde-1) IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified ) i_end = MIN(ide-1,ite) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = ite j_loop_u : DO j = j_start, j_end DO k=kts,ktf-1 DO i = i_start, i_end vflux(i,k)=kvdif*rdn(k+1)/(0.25*( alt(i ,k ,j) & +alt(i-1,k ,j) & +alt(i ,k+1,j) & +alt(i-1,k+1,j) ) ) & *(field(i,k+1,j)-field(i,k,j) & -u_base(k+1) +u_base(k) ) ENDDO ENDDO DO i = i_start, i_end vflux(i,0)=vflux(i,1) ENDDO DO i = i_start, i_end vflux(i,ktf)=0. ENDDO DO k=kts,ktf-1 DO i = i_start, i_end tendency(i,k,j)=tendency(i,k,j)+ & g*g*rdnw(k)/muu(i,j)/(0.5*(alt(i-1,k,j)+alt(i,k,j)))* & (vflux(i,k)-vflux(i,k-1)) ENDDO ENDDO ENDDO j_loop_u END SUBROUTINE vertical_diffusion_u !------------------------------------------------------------------------------- SUBROUTINE vertical_diffusion_v ( field, tendency, & config_flags, v_base, & alt, muv, rdn, rdnw, kvdif, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: field, & alt REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: rdn, rdnw, v_base REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: muv REAL , INTENT(IN ) :: kvdif ! Local data INTEGER :: i, j, k, itf, jtf, ktf, jm1 INTEGER :: i_start, i_end, j_start, j_end REAL , DIMENSION(its:ite, 0:kte+1) :: vflux REAL :: rdz, zz LOGICAL :: specified ! ! ! vertical_diffusion_v computes vertical diffusion tendency for ! the v momentum equation. This routine assumes a constant eddy ! viscosity kvdif. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) i_start = its i_end = MIN(ite,ide-1) j_start = jts j_end = MIN(jte,jde-1) IF ( config_flags%open_ys .or. specified ) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified ) j_end = MIN(jde-1,jte) j_loop_v : DO j = j_start, j_end ! jm1 = max(j-1,1) jm1 = j-1 DO k=kts,ktf-1 DO i = i_start, i_end vflux(i,k)=kvdif*rdn(k+1)/(0.25*( alt(i,k ,j ) & +alt(i,k ,jm1) & +alt(i,k+1,j ) & +alt(i,k+1,jm1) ) ) & *(field(i,k+1,j)-field(i,k,j) & -v_base(k+1) +v_base(k) ) ENDDO ENDDO DO i = i_start, i_end vflux(i,0)=vflux(i,1) ENDDO DO i = i_start, i_end vflux(i,ktf)=0. ENDDO DO k=kts,ktf-1 DO i = i_start, i_end tendency(i,k,j)=tendency(i,k,j)+ & g*g*rdnw(k)/muv(i,j)/(0.5*(alt(i,k,jm1)+alt(i,k,j)))* & (vflux(i,k)-vflux(i,k-1)) ENDDO ENDDO ENDDO j_loop_v END SUBROUTINE vertical_diffusion_v !*************** end new mass coordinate routines !------------------------------------------------------------------------------- SUBROUTINE calculate_full ( rfield, rfieldb, rfieldp, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: rfieldb, & rfieldp REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(OUT ) :: rfield ! Local indices. INTEGER :: i, j, k, itf, jtf, ktf ! ! ! calculate_full ! calculates full 3D field from pertubation and base field. ! ! itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf rfield(i,k,j)=rfieldb(i,k,j)+rfieldp(i,k,j) ENDDO ENDDO ENDDO END SUBROUTINE calculate_full !------------------------------------------------------------------------------ SUBROUTINE coriolis ( ru, rv, rw, ru_tend, rv_tend, rw_tend, & config_flags, & msftx, msfty, msfux, msfuy, & msfvx, msfvy, & f, e, sina, cosa, fzm, fzp, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: ru_tend, & rv_tend, & rw_tend REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: ru, & rv, & rw REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, & msfuy, & msfvx, & msfvy, & msftx, & msfty REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: f, & e, & sina, & cosa REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, & fzp ! Local indices. INTEGER :: i, j , k, ktf INTEGER :: i_start, i_end, j_start, j_end LOGICAL :: specified ! ! ! coriolis calculates the large timestep tendency terms in the ! u, v, and w momentum equations arise from the coriolis force. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) ! coriolis for u-momentum equation ! Notes on map scale factor ! cosa, sina are related to rotating the coordinate frame if desired ! generally sina=0, cosa=1 ! ADT eqn 44, RHS terms 6 and 7: -2 mu w omega cos(lat)/my ! + 2 mu v omega sin(lat)/my ! Define f=2 omega sin(lat), e=2 omega cos(lat) ! => terms are: -e mu w / my + f mu v / my ! rv = mu v / mx ; rw = mu w / my ! => terms are: -e rw + f rv *mx / my i_start = its i_end = ite IF ( config_flags%open_xs .or. specified .or. & config_flags%nested) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified .or. & config_flags%nested) i_end = MIN(ide-1,ite) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = ite DO j = jts, MIN(jte,jde-1) DO k=kts,ktf DO i = i_start, i_end ru_tend(i,k,j)=ru_tend(i,k,j) + (msfux(i,j)/msfuy(i,j))*0.5*(f(i,j)+f(i-1,j)) & *0.25*(rv(i-1,k,j+1)+rv(i,k,j+1)+rv(i-1,k,j)+rv(i,k,j)) & - 0.5*(e(i,j)+e(i-1,j))*0.5*(cosa(i,j)+cosa(i-1,j)) & *0.25*(rw(i-1,k+1,j)+rw(i-1,k,j)+rw(i,k+1,j)+rw(i,k,j)) ENDDO ENDDO IF ( (config_flags%open_xs) .and. (its == ids) ) THEN DO k=kts,ktf ru_tend(its,k,j)=ru_tend(its,k,j) + (msfux(its,j)/msfuy(its,j))*0.5*(f(its,j)+f(its,j)) & *0.25*(rv(its,k,j+1)+rv(its,k,j+1)+rv(its,k,j)+rv(its,k,j)) & - 0.5*(e(its,j)+e(its,j))*0.5*(cosa(its,j)+cosa(its,j)) & *0.25*(rw(its,k+1,j)+rw(its,k,j)+rw(its,k+1,j)+rw(its,k,j)) ENDDO ENDIF IF ( (config_flags%open_xe) .and. (ite == ide) ) THEN DO k=kts,ktf ru_tend(ite,k,j)=ru_tend(ite,k,j) + (msfux(ite,j)/msfuy(ite,j))*0.5*(f(ite-1,j)+f(ite-1,j)) & *0.25*(rv(ite-1,k,j+1)+rv(ite-1,k,j+1)+rv(ite-1,k,j)+rv(ite-1,k,j)) & - 0.5*(e(ite-1,j)+e(ite-1,j))*0.5*(cosa(ite-1,j)+cosa(ite-1,j)) & *0.25*(rw(ite-1,k+1,j)+rw(ite-1,k,j)+rw(ite-1,k+1,j)+rw(ite-1,k,j)) ENDDO ENDIF ENDDO ! coriolis term for v-momentum equation ! Notes on map scale factors ! ADT eqn 45, RHS terms 6 and 6b [0 for sina=0]: -2 mu u omega sin(lat)/mx + ? ! Define f=2 omega sin(lat), e=2 omega cos(lat) ! => terms are: -f mu u / mx ! ru = mu u / my ; rw = mu w / my ! => terms are: -f ru *my / mx + ? j_start = jts j_end = jte IF ( config_flags%open_ys .or. specified .or. & config_flags%nested .or. config_flags%polar) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified .or. & config_flags%nested .or. config_flags%polar) j_end = MIN(jde-1,jte) IF ( (config_flags%open_ys) .and. (jts == jds) ) THEN DO k=kts,ktf DO i=its,MIN(ide-1,ite) rv_tend(i,k,jts)=rv_tend(i,k,jts) - (msfvy(i,jts)/msfvx(i,jts))*0.5*(f(i,jts)+f(i,jts)) & *0.25*(ru(i,k,jts)+ru(i+1,k,jts)+ru(i,k,jts)+ru(i+1,k,jts)) & + (msfvy(i,jts)/msfvx(i,jts))*0.5*(e(i,jts)+e(i,jts))*0.5*(sina(i,jts)+sina(i,jts)) & *0.25*(rw(i,k+1,jts)+rw(i,k,jts)+rw(i,k+1,jts)+rw(i,k,jts)) ENDDO ENDDO ENDIF DO j=j_start, j_end DO k=kts,ktf DO i=its,MIN(ide-1,ite) rv_tend(i,k,j)=rv_tend(i,k,j) - (msfvy(i,j)/msfvx(i,j))*0.5*(f(i,j)+f(i,j-1)) & *0.25*(ru(i,k,j)+ru(i+1,k,j)+ru(i,k,j-1)+ru(i+1,k,j-1)) & + (msfvy(i,j)/msfvx(i,j))*0.5*(e(i,j)+e(i,j-1))*0.5*(sina(i,j)+sina(i,j-1)) & *0.25*(rw(i,k+1,j-1)+rw(i,k,j-1)+rw(i,k+1,j)+rw(i,k,j)) ENDDO ENDDO ENDDO IF ( (config_flags%open_ye) .and. (jte == jde) ) THEN DO k=kts,ktf DO i=its,MIN(ide-1,ite) rv_tend(i,k,jte)=rv_tend(i,k,jte) - (msfvy(i,jte)/msfvx(i,jte))*0.5*(f(i,jte-1)+f(i,jte-1)) & *0.25*(ru(i,k,jte-1)+ru(i+1,k,jte-1)+ru(i,k,jte-1)+ru(i+1,k,jte-1)) & + (msfvy(i,jte)/msfvx(i,jte))*0.5*(e(i,jte-1)+e(i,jte-1))*0.5*(sina(i,jte-1)+sina(i,jte-1)) & *0.25*(rw(i,k+1,jte-1)+rw(i,k,jte-1)+rw(i,k+1,jte-1)+rw(i,k,jte-1)) ENDDO ENDDO ENDIF ! coriolis term for w-mometum ! Notes on map scale factors ! ADT eqn 46/my, RHS terms 5 and 5b [0 for sina=0]: 2 mu u omega cos(lat)/my +? ! Define e=2 omega cos(lat) ! => terms are: e mu u / my + ??? ! ru = mu u / my ; ru = mu v / mx ! => terms are: e ru + ??? DO j=jts,MIN(jte, jde-1) DO k=kts+1,ktf DO i=its,MIN(ite, ide-1) rw_tend(i,k,j)=rw_tend(i,k,j) + e(i,j)* & (cosa(i,j)*0.5*(fzm(k)*(ru(i,k,j)+ru(i+1,k,j)) & +fzp(k)*(ru(i,k-1,j)+ru(i+1,k-1,j))) & -(msftx(i,j)/msfty(i,j))* & sina(i,j)*0.5*(fzm(k)*(rv(i,k,j)+rv(i,k,j+1)) & +fzp(k)*(rv(i,k-1,j)+rv(i,k-1,j+1)))) ENDDO ENDDO ENDDO END SUBROUTINE coriolis !------------------------------------------------------------------------------ SUBROUTINE perturbation_coriolis ( ru_in, rv_in, rw, ru_tend, rv_tend, rw_tend, & config_flags, & u_base, v_base, z_base, & muu, muv, phb, ph, & msftx, msfty, msfux, msfuy, msfvx, msfvy, & f, e, sina, cosa, fzm, fzp, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: ru_tend, & rv_tend, & rw_tend REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: ru_in, & rv_in, & rw, & ph, & phb REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, & msfuy, & msfvx, & msfvy, & msftx, & msfty REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: f, & e, & sina, & cosa REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: muu, & muv REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, & fzp REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: u_base, & v_base, & z_base ! Local storage REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) :: ru, & rv REAL :: z_at_u, z_at_v, wkp1, wk, wkm1 ! Local indices. INTEGER :: i, j , k, ktf INTEGER :: i_start, i_end, j_start, j_end LOGICAL :: specified ! ! ! perturbation_coriolis calculates the large timestep tendency terms in the ! u, v, and w momentum equations arise from the coriolis force. This version ! subtracts off the horizontal velocities from the initial sounding when ! computing the forcing terms, hence "perturbation" coriolis. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. ktf=MIN(kte,kde-1) ! coriolis for u-momentum equation i_start = its i_end = ite IF ( config_flags%open_xs .or. specified .or. & config_flags%nested) i_start = MAX(ids+1,its) IF ( config_flags%open_xe .or. specified .or. & config_flags%nested) i_end = MIN(ide-1,ite) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = ite ! compute perturbation mu*v for use in u momentum equation DO j = jts, MIN(jte,jde-1)+1 DO k=kts+1,ktf-1 DO i = i_start-1, i_end z_at_v = 0.25*( phb(i,k,j )+phb(i,k+1,j ) & +phb(i,k,j-1)+phb(i,k+1,j-1) & +ph(i,k,j )+ph(i,k+1,j ) & +ph(i,k,j-1)+ph(i,k+1,j-1))/g wkp1 = min(1.,max(0.,z_at_v-z_base(k))/(z_base(k+1)-z_base(k))) wkm1 = min(1.,max(0.,z_base(k)-z_at_v)/(z_base(k)-z_base(k-1))) wk = 1.-wkp1-wkm1 rv(i,k,j) = rv_in(i,k,j) - muv(i,j)*( & wkm1*v_base(k-1) & +wk *v_base(k ) & +wkp1*v_base(k+1) ) ENDDO ENDDO ENDDO ! pick up top and bottom v DO j = jts, MIN(jte,jde-1)+1 DO i = i_start-1, i_end k = kts z_at_v = 0.25*( phb(i,k,j )+phb(i,k+1,j ) & +phb(i,k,j-1)+phb(i,k+1,j-1) & +ph(i,k,j )+ph(i,k+1,j ) & +ph(i,k,j-1)+ph(i,k+1,j-1))/g wkp1 = min(1.,max(0.,z_at_v-z_base(k))/(z_base(k+1)-z_base(k))) wk = 1.-wkp1 rv(i,k,j) = rv_in(i,k,j) - muv(i,j)*( & +wk *v_base(k ) & +wkp1*v_base(k+1) ) k = ktf z_at_v = 0.25*( phb(i,k,j )+phb(i,k+1,j ) & +phb(i,k,j-1)+phb(i,k+1,j-1) & +ph(i,k,j )+ph(i,k+1,j ) & +ph(i,k,j-1)+ph(i,k+1,j-1))/g wkm1 = min(1.,max(0.,z_base(k)-z_at_v)/(z_base(k)-z_base(k-1))) wk = 1.-wkm1 rv(i,k,j) = rv_in(i,k,j) - muv(i,j)*( & wkm1*v_base(k-1) & +wk *v_base(k ) ) ENDDO ENDDO ! compute coriolis forcing for u ! Map scale factors: see comments above for Coriolis DO j = jts, MIN(jte,jde-1) DO k=kts,ktf DO i = i_start, i_end ru_tend(i,k,j)=ru_tend(i,k,j) + (msfux(i,j)/msfuy(i,j))*0.5*(f(i,j)+f(i-1,j)) & *0.25*(rv(i-1,k,j+1)+rv(i,k,j+1)+rv(i-1,k,j)+rv(i,k,j)) & - 0.5*(e(i,j)+e(i-1,j))*0.5*(cosa(i,j)+cosa(i-1,j)) & *0.25*(rw(i-1,k+1,j)+rw(i-1,k,j)+rw(i,k+1,j)+rw(i,k,j)) ENDDO ENDDO IF ( (config_flags%open_xs) .and. (its == ids) ) THEN DO k=kts,ktf ru_tend(its,k,j)=ru_tend(its,k,j) + (msfux(its,j)/msfuy(its,j))*0.5*(f(its,j)+f(its,j)) & *0.25*(rv(its,k,j+1)+rv(its,k,j+1)+rv(its,k,j)+rv(its,k,j)) & - 0.5*(e(its,j)+e(its,j))*0.5*(cosa(its,j)+cosa(its,j)) & *0.25*(rw(its,k+1,j)+rw(its,k,j)+rw(its,k+1,j)+rw(its,k,j)) ENDDO ENDIF IF ( (config_flags%open_xe) .and. (ite == ide) ) THEN DO k=kts,ktf ru_tend(ite,k,j)=ru_tend(ite,k,j) + (msfux(ite,j)/msfuy(ite,j))*0.5*(f(ite-1,j)+f(ite-1,j)) & *0.25*(rv(ite-1,k,j+1)+rv(ite-1,k,j+1)+rv(ite-1,k,j)+rv(ite-1,k,j)) & - 0.5*(e(ite-1,j)+e(ite-1,j))*0.5*(cosa(ite-1,j)+cosa(ite-1,j)) & *0.25*(rw(ite-1,k+1,j)+rw(ite-1,k,j)+rw(ite-1,k+1,j)+rw(ite-1,k,j)) ENDDO ENDIF ENDDO ! coriolis term for v-momentum equation ! Map scale factors: see comments above for Coriolis j_start = jts j_end = jte IF ( config_flags%open_ys .or. specified .or. & config_flags%nested .or. config_flags%polar) j_start = MAX(jds+1,jts) IF ( config_flags%open_ye .or. specified .or. & config_flags%nested .or. config_flags%polar) j_end = MIN(jde-1,jte) ! compute perturbation mu*u for use in v momentum equation DO j = j_start-1,j_end DO k=kts+1,ktf-1 DO i = its, MIN(ite,ide-1)+1 z_at_u = 0.25*( phb(i ,k,j)+phb(i ,k+1,j) & +phb(i-1,k,j)+phb(i-1,k+1,j) & +ph(i ,k,j)+ph(i ,k+1,j) & +ph(i-1,k,j)+ph(i-1,k+1,j))/g wkp1 = min(1.,max(0.,z_at_u-z_base(k))/(z_base(k+1)-z_base(k))) wkm1 = min(1.,max(0.,z_base(k)-z_at_u)/(z_base(k)-z_base(k-1))) wk = 1.-wkp1-wkm1 ru(i,k,j) = ru_in(i,k,j) - muu(i,j)*( & wkm1*u_base(k-1) & +wk *u_base(k ) & +wkp1*u_base(k+1) ) ENDDO ENDDO ENDDO ! pick up top and bottom u DO j = j_start-1,j_end DO i = its, MIN(ite,ide-1)+1 k = kts z_at_u = 0.25*( phb(i ,k,j)+phb(i ,k+1,j) & +phb(i-1,k,j)+phb(i-1,k+1,j) & +ph(i ,k,j)+ph(i ,k+1,j) & +ph(i-1,k,j)+ph(i-1,k+1,j))/g wkp1 = min(1.,max(0.,z_at_u-z_base(k))/(z_base(k+1)-z_base(k))) wk = 1.-wkp1 ru(i,k,j) = ru_in(i,k,j) - muu(i,j)*( & +wk *u_base(k ) & +wkp1*u_base(k+1) ) k = ktf z_at_u = 0.25*( phb(i ,k,j)+phb(i ,k+1,j) & +phb(i-1,k,j)+phb(i-1,k+1,j) & +ph(i ,k,j)+ph(i ,k+1,j) & +ph(i-1,k,j)+ph(i-1,k+1,j))/g wkm1 = min(1.,max(0.,z_base(k)-z_at_u)/(z_base(k)-z_base(k-1))) wk = 1.-wkm1 ru(i,k,j) = ru_in(i,k,j) - muu(i,j)*( & wkm1*u_base(k-1) & +wk *u_base(k ) ) ENDDO ENDDO ! compute coriolis forcing for v momentum equation ! Map scale factors: see comments above for Coriolis IF ( (config_flags%open_ys) .and. (jts == jds) ) THEN DO k=kts,ktf DO i=its,MIN(ide-1,ite) rv_tend(i,k,jts)=rv_tend(i,k,jts) - (msfvy(i,jts)/msfvx(i,jts))*0.5*(f(i,jts)+f(i,jts)) & *0.25*(ru(i,k,jts)+ru(i+1,k,jts)+ru(i,k,jts)+ru(i+1,k,jts)) & + (msfvy(i,jts)/msfvx(i,jts))*0.5*(e(i,jts)+e(i,jts))*0.5*(sina(i,jts)+sina(i,jts)) & *0.25*(rw(i,k+1,jts)+rw(i,k,jts)+rw(i,k+1,jts)+rw(i,k,jts)) ENDDO ENDDO ENDIF DO j=j_start, j_end DO k=kts,ktf DO i=its,MIN(ide-1,ite) rv_tend(i,k,j)=rv_tend(i,k,j) - (msfvy(i,j)/msfvx(i,j))*0.5*(f(i,j)+f(i,j-1)) & *0.25*(ru(i,k,j)+ru(i+1,k,j)+ru(i,k,j-1)+ru(i+1,k,j-1)) & + (msfvy(i,j)/msfvx(i,j))*0.5*(e(i,j)+e(i,j-1))*0.5*(sina(i,j)+sina(i,j-1)) & *0.25*(rw(i,k+1,j-1)+rw(i,k,j-1)+rw(i,k+1,j)+rw(i,k,j)) ENDDO ENDDO ENDDO IF ( (config_flags%open_ye) .and. (jte == jde) ) THEN DO k=kts,ktf DO i=its,MIN(ide-1,ite) rv_tend(i,k,jte)=rv_tend(i,k,jte) - (msfvy(i,jte)/msfvx(i,jte))*0.5*(f(i,jte-1)+f(i,jte-1)) & *0.25*(ru(i,k,jte-1)+ru(i+1,k,jte-1)+ru(i,k,jte-1)+ru(i+1,k,jte-1)) & + (msfvy(i,jte)/msfvx(i,jte))*0.5*(e(i,jte-1)+e(i,jte-1))*0.5*(sina(i,jte-1)+sina(i,jte-1)) & *0.25*(rw(i,k+1,jte-1)+rw(i,k,jte-1)+rw(i,k+1,jte-1)+rw(i,k,jte-1)) ENDDO ENDDO ENDIF ! coriolis term for w-mometum ! Map scale factors: see comments above for Coriolis DO j=jts,MIN(jte, jde-1) DO k=kts+1,ktf DO i=its,MIN(ite, ide-1) rw_tend(i,k,j)=rw_tend(i,k,j) + e(i,j)* & (cosa(i,j)*0.5*(fzm(k)*(ru(i,k,j)+ru(i+1,k,j)) & +fzp(k)*(ru(i,k-1,j)+ru(i+1,k-1,j))) & -(msftx(i,j)/msfty(i,j))*sina(i,j)*0.5*(fzm(k)*(rv(i,k,j)+rv(i,k,j+1)) & +fzp(k)*(rv(i,k-1,j)+rv(i,k-1,j+1)))) ENDDO ENDDO ENDDO END SUBROUTINE perturbation_coriolis !------------------------------------------------------------------------------ SUBROUTINE curvature ( ru, rv, rw, u, v, w, ru_tend, rv_tend, rw_tend, & config_flags, & msfux, msfuy, msfvx, msfvy, msftx, msfty, & xlat, fzm, fzp, rdx, rdy, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(INOUT) :: ru_tend, & rv_tend, & rw_tend REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: ru, & rv, & rw, & u, & v, & w REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, & msfuy, & msfvx, & msfvy, & msftx, & msfty, & xlat REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, & fzp REAL , INTENT(IN ) :: rdx, & rdy ! Local data ! INTEGER :: i, j, k, itf, jtf, ktf, kp1, im, ip, jm, jp INTEGER :: i, j, k, itf, jtf, ktf INTEGER :: i_start, i_end, j_start, j_end ! INTEGER :: irmin, irmax, jrmin, jrmax REAL , DIMENSION( its-1:ite , kts:kte, jts-1:jte ) :: vxgm LOGICAL :: specified ! ! ! curvature calculates the large timestep tendency terms in the ! u, v, and w momentum equations arise from the curvature terms. ! ! specified = .false. if(config_flags%specified .or. config_flags%nested) specified = .true. itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ktf=MIN(kte,kde-1) ! irmin = ims ! irmax = ime ! jrmin = jms ! jrmax = jme ! IF ( config_flags%open_xs ) irmin = ids ! IF ( config_flags%open_xe ) irmax = ide-1 ! IF ( config_flags%open_ys ) jrmin = jds ! IF ( config_flags%open_ye ) jrmax = jde-1 ! Define v cross grad m at scalar points - vxgm(i,j) i_start = its-1 i_end = ite j_start = jts-1 j_end = jte IF ( ( config_flags%open_xs .or. specified .or. & config_flags%nested) .and. (its == ids) ) i_start = its IF ( ( config_flags%open_xe .or. specified .or. & config_flags%nested) .and. (ite == ide) ) i_end = ite-1 IF ( ( config_flags%open_ys .or. specified .or. & config_flags%nested .or. config_flags%polar) .and. (jts == jds) ) j_start = jts IF ( ( config_flags%open_ye .or. specified .or. & config_flags%nested .or. config_flags%polar) .and. (jte == jde) ) j_end = jte-1 IF ( config_flags%periodic_x ) i_start = its-1 IF ( config_flags%periodic_x ) i_end = ite DO j=j_start, j_end DO k=kts,ktf DO i=i_start, i_end ! Map scale factor notes: ! msf...y is constant everywhere for cylindrical map projection ! msf...x varies with y only ! But we know that this is not = 0 for cylindrical, ! therefore use msfvX in 1st line ! which => by symmetry use msfuY in 2nd line - ??? vxgm(i,k,j)=0.5*(u(i,k,j)+u(i+1,k,j))*(msfvx(i,j+1)-msfvx(i,j))*rdy - & 0.5*(v(i,k,j)+v(i,k,j+1))*(msfuy(i+1,j)-msfuy(i,j))*rdx ENDDO ENDDO ENDDO ! Pick up the boundary rows for open (radiation) lateral b.c. ! Rather crude at present, we are assuming there is no ! variation in this term at the boundary. IF ( ( config_flags%open_xs .or. (specified .AND. .NOT. config_flags%periodic_x) .or. & config_flags%nested) .and. (its == ids) ) THEN DO j = jts, jte-1 DO k = kts, ktf vxgm(its-1,k,j) = vxgm(its,k,j) ENDDO ENDDO ENDIF IF ( ( config_flags%open_xe .or. (specified .AND. .NOT. config_flags%periodic_x) .or. & config_flags%nested) .and. (ite == ide) ) THEN DO j = jts, jte-1 DO k = kts, ktf vxgm(ite,k,j) = vxgm(ite-1,k,j) ENDDO ENDDO ENDIF ! Polar boundary condition: ! The following change is needed in case one tries using the vxgm route with ! polar B.C.'s in the future, but not needed if 'tan' used IF ( ( config_flags%open_ys .or. specified .or. & config_flags%nested .or. config_flags%polar) .and. (jts == jds) ) THEN DO k = kts, ktf DO i = its-1, ite vxgm(i,k,jts-1) = vxgm(i,k,jts) ENDDO ENDDO ENDIF ! Polar boundary condition: ! The following change is needed in case one tries using the vxgm route with ! polar B.C.'s in the future, but not needed if 'tan' used IF ( ( config_flags%open_ye .or. specified .or. & config_flags%nested .or. config_flags%polar) .and. (jte == jde) ) THEN DO k = kts, ktf DO i = its-1, ite vxgm(i,k,jte) = vxgm(i,k,jte-1) ENDDO ENDDO ENDIF ! curvature term for u momentum eqn. ! Map scale factor notes: ! ADT eqn 44, RHS terms 4 and 5, in cylindrical: mu u v tan(lat)/(a my) ! - mu u w /(a my) ! ru = mu u / my ; rw = mu w / my ; rv = mu v / mx ! => terms are: ! (mx/my)*u rv tan(lat) / a - u rw / a = (u/a)*[(mx/my) rv tan(lat) - rw] ! ru v tan(lat) / a - u rw / a ! xlat defined with end points half grid space from pole, ! hence are on u latitude points i_start = its IF ( config_flags%open_xs .or. specified .or. & config_flags%nested) i_start = MAX ( ids+1 , its ) IF ( config_flags%open_xe .or. specified .or. & config_flags%nested) i_end = MIN ( ide-1 , ite ) IF ( config_flags%periodic_x ) i_start = its IF ( config_flags%periodic_x ) i_end = ite ! Polar boundary condition IF ((config_flags%map_proj == 6) .OR. (config_flags%polar)) THEN DO j=jts,MIN(jde-1,jte) DO k=kts,ktf DO i=i_start,i_end ru_tend(i,k,j)=ru_tend(i,k,j) + u(i,k,j)*reradius* ( & (msfux(i,j)/msfuy(i,j))*0.25*(rv(i-1,k,j+1)+rv(i,k,j+1)+ & rv(i-1,k,j)+rv(i,k,j))*tan(xlat(i,j)*degrad) & - 0.25*(rw(i-1,k+1,j)+rw(i-1,k,j)+rw(i,k+1,j)+rw(i,k,j)) ) ENDDO ENDDO ENDDO ELSE ! normal code DO j=jts,MIN(jde-1,jte) DO k=kts,ktf DO i=i_start,i_end ru_tend(i,k,j)=ru_tend(i,k,j) + 0.5*(vxgm(i,k,j)+vxgm(i-1,k,j)) & *0.25*(rv(i-1,k,j+1)+rv(i,k,j+1)+rv(i-1,k,j)+rv(i,k,j)) & - u(i,k,j)*reradius & *0.25*(rw(i-1,k+1,j)+rw(i-1,k,j)+rw(i,k+1,j)+rw(i,k,j)) ENDDO ENDDO ENDDO END IF ! curvature term for v momentum eqn. ! Map scale factor notes ! ADT eqn 45, RHS terms 4 and 5, in cylindrical: mu u*u tan(lat)/(a mx) ! - mu v w /(a mx) ! ru = mu u / my ; rw = mu w / my ; rv = mu v / mx ! terms are: ! (my/mx)*u ru tan(lat) / a - (my/mx)*v rw / a ! = [my/(mx*a)]*[u ru tan(lat) - v rw] ! (1/a)*[(my/mx)*u ru tan(lat) - w rv] ! xlat defined with end points half grid space from pole, hence are on ! u latitude points => av here ! ! in original wrf, there was a sign error for the rw contribution j_start = jts IF ( config_flags%open_ys .or. specified .or. & config_flags%nested .or. config_flags%polar) j_start = MAX ( jds+1 , jts ) IF ( config_flags%open_ye .or. specified .or. & config_flags%nested .or. config_flags%polar) j_end = MIN ( jde-1 , jte ) IF ((config_flags%map_proj == 6) .OR. (config_flags%polar)) THEN DO j=j_start,j_end DO k=kts,ktf DO i=its,MIN(ite,ide-1) rv_tend(i,k,j)=rv_tend(i,k,j) - (msfvy(i,j)/msfvx(i,j))*reradius* ( & 0.25*(u(i,k,j)+u(i+1,k,j)+u(i,k,j-1)+u(i+1,k,j-1))* & tan((xlat(i,j)+xlat(i,j-1))*0.5*degrad)* & 0.25*(ru(i,k,j)+ru(i+1,k,j)+ru(i,k,j-1)+ru(i+1,k,j-1)) & - v(i,k,j)*0.25*(rw(i,k+1,j-1)+rw(i,k,j-1)+ & rw(i,k+1,j)+rw(i,k,j)) ) ENDDO ENDDO ENDDO ELSE ! normal code DO j=j_start,j_end DO k=kts,ktf DO i=its,MIN(ite,ide-1) rv_tend(i,k,j)=rv_tend(i,k,j) - 0.5*(vxgm(i,k,j)+vxgm(i,k,j-1)) & *0.25*(ru(i,k,j)+ru(i+1,k,j)+ru(i,k,j-1)+ru(i+1,k,j-1)) & - (msfvy(i,j)/msfvx(i,j))*v(i,k,j)*reradius & *0.25*(rw(i,k+1,j-1)+rw(i,k,j-1)+rw(i,k+1,j)+rw(i,k,j)) ENDDO ENDDO ENDDO END IF ! curvature term for vertical momentum eqn. ! Notes on map scale factors: ! ADT eqn 46, RHS term 4: [mu/(a my)]*[u*u + v*v] ! ru = mu u / my ; rw = mu w / my ; rv = mu v / mx ! terms are: u ru / a + (mx/my)v rv / a DO j=jts,MIN(jte,jde-1) DO k=MAX(2,kts),ktf DO i=its,MIN(ite,ide-1) rw_tend(i,k,j)=rw_tend(i,k,j) + reradius* & (0.5*(fzm(k)*(ru(i,k,j)+ru(i+1,k,j))+fzp(k)*(ru(i,k-1,j)+ru(i+1,k-1,j))) & *0.5*(fzm(k)*( u(i,k,j) +u(i+1,k,j))+fzp(k)*( u(i,k-1,j) +u(i+1,k-1,j))) & +(msftx(i,j)/msfty(i,j))*0.5*(fzm(k)*(rv(i,k,j)+rv(i,k,j+1))+fzp(k)*(rv(i,k-1,j)+rv(i,k-1,j+1))) & *0.5*(fzm(k)*( v(i,k,j) +v(i,k,j+1))+fzp(k)*( v(i,k-1,j) +v(i,k-1,j+1)))) ENDDO ENDDO ENDDO END SUBROUTINE curvature !------------------------------------------------------------------------------ SUBROUTINE decouple ( rr, rfield, field, name, config_flags, & fzm, fzp, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data TYPE(grid_config_rec_type) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte CHARACTER(LEN=1) , INTENT(IN ) :: name REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: rfield REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: rr REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(OUT ) :: field REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, fzp ! Local data INTEGER :: i, j, k, itf, jtf, ktf ! ! ! decouple decouples a variable from the column dry-air mass. ! ! ktf=MIN(kte,kde-1) IF (name .EQ. 'u')THEN itf=ite jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts,ktf DO i=its,itf field(i,k,j)=rfield(i,k,j)/(0.5*(rr(i,k,j)+rr(i-1,k,j))) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'v')THEN itf=MIN(ite,ide-1) jtf=jte DO j=jts,jtf DO k=kts,ktf DO i=its,itf field(i,k,j)=rfield(i,k,j)/(0.5*(rr(i,k,j)+rr(i,k,j-1))) ENDDO ENDDO ENDDO ELSE IF (name .EQ. 'w')THEN itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) DO j=jts,jtf DO k=kts+1,ktf DO i=its,itf field(i,k,j)=rfield(i,k,j)/(fzm(k)*rr(i,k,j)+fzp(k)*rr(i,k-1,j)) ENDDO ENDDO ENDDO DO j=jts,jtf DO i=its,itf field(i,kte,j) = 0. ENDDO ENDDO ELSE itf=MIN(ite,ide-1) jtf=MIN(jte,jde-1) ! For theta we will decouple tb and tp and add them to give t afterwards DO j=jts,jtf DO k=kts,ktf DO i=its,itf field(i,k,j)=rfield(i,k,j)/rr(i,k,j) ENDDO ENDDO ENDDO ENDIF END SUBROUTINE decouple !------------------------------------------------------------------------------- SUBROUTINE zero_tend ( tendency, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency ! Local data INTEGER :: i, j, k, itf, jtf, ktf ! ! ! zero_tend sets the input tendency array to zero. ! ! DO j = jts, jte DO k = kts, kte DO i = its, ite tendency(i,k,j) = 0. ENDDO ENDDO ENDDO END SUBROUTINE zero_tend !------------------------------------------------------------------------------- ! Sets the an array on the polar v point(s) to zero SUBROUTINE zero_pole ( field, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: field ! Local data INTEGER :: i, k IF (jts == jds) THEN DO k = kts, kte DO i = its-1, ite+1 field(i,k,jts) = 0. END DO END DO END IF IF (jte == jde) THEN DO k = kts, kte DO i = its-1, ite+1 field(i,k,jte) = 0. END DO END DO END IF END SUBROUTINE zero_pole !------------------------------------------------------------------------------- ! Sets the an array on the polar v point(s) SUBROUTINE pole_point_bc ( field, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: field ! Local data INTEGER :: i, k IF (jts == jds) THEN DO k = kts, kte DO i = its, ite ! field(i,k,jts) = 2*field(i,k,jts+1) - field(i,k,jts+2) field(i,k,jts) = field(i,k,jts+1) END DO END DO END IF IF (jte == jde) THEN DO k = kts, kte DO i = its, ite ! field(i,k,jte) = 2*field(i,k,jte-1) - field(i,k,jte-2) field(i,k,jte) = field(i,k,jte-1) END DO END DO END IF END SUBROUTINE pole_point_bc !====================================================================== ! physics prep routines !====================================================================== SUBROUTINE phy_prep ( config_flags, & ! input mu, muu, muv, u, v, w, p, pb, alt, ph, & ! input phb, t, tsk, moist, n_moist, & ! input mu_3d, rho, th_phy, p_phy , pi_phy , & ! output u_phy, v_phy, w_phy, p8w, t_phy, t8w, & ! output z, z_at_w, dz8w, & ! output fzm, fzp, & ! params RTHRATEN, & RTHBLTEN, RUBLTEN, RVBLTEN, & RQVBLTEN, RQCBLTEN, RQIBLTEN, & RTHCUTEN, RQVCUTEN, RQCCUTEN, & RQRCUTEN, RQICUTEN, RQSCUTEN, & RTHFTEN, RQVFTEN, & RUNDGDTEN, RVNDGDTEN, RTHNDGDTEN, & RQVNDGDTEN, RMUNDGDTEN, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) !---------------------------------------------------------------------- IMPLICIT NONE !---------------------------------------------------------------------- TYPE(grid_config_rec_type) , INTENT(IN ) :: config_flags INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte INTEGER , INTENT(IN ) :: n_moist REAL, DIMENSION( ims:ime, kms:kme , jms:jme , n_moist ), INTENT(IN) :: moist REAL , DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: TSK, mu, muu, muv REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT( OUT) :: u_phy, & v_phy, & w_phy, & pi_phy, & p_phy, & p8w, & t_phy, & th_phy, & t8w, & mu_3d, & rho, & z, & dz8w, & z_at_w REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , & INTENT(IN ) :: pb, & p, & u, & v, & w, & alt, & ph, & phb, & t REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, & fzp REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: RTHRATEN REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: RTHCUTEN, & RQVCUTEN, & RQCCUTEN, & RQRCUTEN, & RQICUTEN, & RQSCUTEN REAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , & INTENT(INOUT) :: RUBLTEN, & RVBLTEN, & RTHBLTEN, & RQVBLTEN, & RQCBLTEN, & RQIBLTEN REAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , & INTENT(INOUT) :: RTHFTEN, & RQVFTEN REAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , & INTENT(INOUT) :: RUNDGDTEN, & RVNDGDTEN, & RTHNDGDTEN, & RQVNDGDTEN, & RMUNDGDTEN INTEGER :: i_start, i_end, j_start, j_end, k_start, k_end, i_startu, j_startv INTEGER :: i, j, k REAL :: w1, w2, z0, z1, z2 !----------------------------------------------------------------------- ! ! ! phys_prep calculates a number of diagnostic quantities needed by ! the physics routines. It also decouples the physics tendencies from ! the column dry-air mass (the physics routines expect to see/update the ! uncoupled tendencies). ! ! ! set up loop bounds for this grid's boundary conditions i_start = its i_end = min( ite,ide-1 ) j_start = jts j_end = min( jte,jde-1 ) k_start = kts k_end = min( kte, kde-1 ) ! compute thermodynamics and velocities at pressure points do j = j_start,j_end do k = k_start, k_end do i = i_start, i_end th_phy(i,k,j) = t(i,k,j) + t0 p_phy(i,k,j) = p(i,k,j) + pb(i,k,j) pi_phy(i,k,j) = (p_phy(i,k,j)/p1000mb)**rcp !! TAKE INTO ACCOUNT cp=f(T) on Venus IF (planet.eq. "venus" ) THEN t_phy(i,k,j)= (th_phy(i,k,j)**nu - nu*(TT00**nu)*log((p1000mb/p_phy(i,k,j))**rcp))**(1/nu) ELSE t_phy(i,k,j) = th_phy(i,k,j)*pi_phy(i,k,j) ENDIF rho(i,k,j) = 1./alt(i,k,j)*(1.+moist(i,k,j,P_QV)) mu_3d(i,k,j) = mu(i,j) u_phy(i,k,j) = 0.5*(u(i,k,j)+u(i+1,k,j)) v_phy(i,k,j) = 0.5*(v(i,k,j)+v(i,k,j+1)) enddo enddo enddo ! compute z at w points do j = j_start,j_end do k = k_start, kte do i = i_start, i_end z_at_w(i,k,j) = (phb(i,k,j)+ph(i,k,j))/g enddo enddo enddo do j = j_start,j_end do k = k_start, kte-1 do i = i_start, i_end dz8w(i,k,j) = z_at_w(i,k+1,j)-z_at_w(i,k,j) enddo enddo enddo do j = j_start,j_end do i = i_start, i_end dz8w(i,kte,j) = 0. enddo enddo ! compute z at p points (average of z at w points) do j = j_start,j_end do k = k_start, k_end do i = i_start, i_end z(i,k,j) = 0.5*(z_at_w(i,k,j) + z_at_w(i,k+1,j) ) !!!! MARS MARS ajout aymeric (ainsi que les arguments de cette routine) w_phy(i,k,j) = 0.5*(w(i,k,j) + w(i,k+1,j) ) enddo enddo enddo ! interp t and p at w points do j = j_start,j_end do k = 2, k_end do i = i_start, i_end p8w(i,k,j) = fzm(k)*p_phy(i,k,j)+fzp(k)*p_phy(i,k-1,j) t8w(i,k,j) = fzm(k)*t_phy(i,k,j)+fzp(k)*t_phy(i,k-1,j) enddo enddo enddo ! extrapolate p and t to surface and top. ! we'll use an extrapolation in z for now do j = j_start,j_end do i = i_start, i_end ! bottom z0 = z_at_w(i,1,j) z1 = z(i,1,j) z2 = z(i,2,j) w1 = (z0 - z2)/(z1 - z2) w2 = 1. - w1 p8w(i,1,j) = w1*p_phy(i,1,j)+w2*p_phy(i,2,j) t8w(i,1,j) = w1*t_phy(i,1,j)+w2*t_phy(i,2,j) ! top z0 = z_at_w(i,kte,j) z1 = z(i,k_end,j) z2 = z(i,k_end-1,j) w1 = (z0 - z2)/(z1 - z2) w2 = 1. - w1 ! p8w(i,kde,j) = w1*p_phy(i,kde-1,j)+w2*p_phy(i,kde-2,j) !!! bug fix extrapolate ln(p) so p is positive definite p8w(i,kde,j) = exp(w1*log(p_phy(i,kde-1,j))+w2*log(p_phy(i,kde-2,j))) t8w(i,kde,j) = w1*t_phy(i,kde-1,j)+w2*t_phy(i,kde-2,j) enddo enddo ! decouple all physics tendencies IF (config_flags%ra_lw_physics .gt. 0 .or. config_flags%ra_sw_physics .gt. 0) THEN DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RTHRATEN(I,K,J)=RTHRATEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF (config_flags%cu_physics .gt. 0) THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RTHCUTEN(I,K,J)=RTHCUTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO IF (P_QV .ge. PARAM_FIRST_SCALAR)THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RQVCUTEN(I,K,J)=RQVCUTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF (P_QC .ge. PARAM_FIRST_SCALAR)THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RQCCUTEN(I,K,J)=RQCCUTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF (P_QR .ge. PARAM_FIRST_SCALAR)THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RQRCUTEN(I,K,J)=RQRCUTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF (P_QI .ge. PARAM_FIRST_SCALAR)THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RQICUTEN(I,K,J)=RQICUTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF(P_QS .ge. PARAM_FIRST_SCALAR)THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RQSCUTEN(I,K,J)=RQSCUTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF ENDIF !!MARS MARS ! IF (config_flags%bl_pbl_physics .gt. 0) THEN IF ( (config_flags%bl_pbl_physics .gt. 0) & .OR. (config_flags%modif_wrf) ) THEN !****MARS DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RUBLTEN(I,K,J) =RUBLTEN(I,K,J)/mu(I,J) RVBLTEN(I,K,J) =RVBLTEN(I,K,J)/mu(I,J) RTHBLTEN(I,K,J)=RTHBLTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO IF (P_QV .ge. PARAM_FIRST_SCALAR) THEN DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RQVBLTEN(I,K,J)=RQVBLTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF (P_QC .ge. PARAM_FIRST_SCALAR) THEN DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RQCBLTEN(I,K,J)=RQCBLTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF IF (P_QI .ge. PARAM_FIRST_SCALAR) THEN DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RQIBLTEN(I,K,J)=RQIBLTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF ENDIF ! decouple advective forcing required by Grell-Devenyi scheme if(( config_flags%cu_physics == GDSCHEME ) .OR. & ( config_flags%cu_physics == G3SCHEME )) then DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RTHFTEN(I,K,J)=RTHFTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO IF (P_QV .ge. PARAM_FIRST_SCALAR)THEN DO J=j_start,j_end DO I=i_start,i_end DO K=k_start,k_end RQVFTEN(I,K,J)=RQVFTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF END IF ! fdda ! note fdda u and v tendencies are staggered, also only interior points have muu/muv, ! so only decouple those IF (config_flags%grid_fdda .gt. 0) THEN i_startu=MAX(its,ids+1) j_startv=MAX(jts,jds+1) DO J=j_start,j_end DO K=k_start,k_end DO I=i_startu,i_end RUNDGDTEN(I,K,J) =RUNDGDTEN(I,K,J)/muu(I,J) ENDDO ENDDO ENDDO DO J=j_startv,j_end DO K=k_start,k_end DO I=i_start,i_end RVNDGDTEN(I,K,J) =RVNDGDTEN(I,K,J)/muv(I,J) ENDDO ENDDO ENDDO DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RTHNDGDTEN(I,K,J)=RTHNDGDTEN(I,K,J)/mu(I,J) ! RMUNDGDTEN(I,J) - no coupling ENDDO ENDDO ENDDO IF (P_QV .ge. PARAM_FIRST_SCALAR) THEN DO J=j_start,j_end DO K=k_start,k_end DO I=i_start,i_end RQVNDGDTEN(I,K,J)=RQVNDGDTEN(I,K,J)/mu(I,J) ENDDO ENDDO ENDDO ENDIF ENDIF END SUBROUTINE phy_prep !------------------------------------------------------------ SUBROUTINE moist_physics_prep_em( t_new, t_old, t0, rho, al, alb, & p, p8w, p0, pb, ph, phb, & th_phy, pii, pf, & z, z_at_w, dz8w, & dt,h_diabatic, & config_flags,fzm, fzp, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! Here we construct full fields ! needed by the microphysics TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER, INTENT(IN ) :: ids,ide, jds,jde, kds,kde INTEGER, INTENT(IN ) :: ims,ime, jms,jme, kms,kme INTEGER, INTENT(IN ) :: its,ite, jts,jte, kts,kte REAL, INTENT(IN ) :: dt REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(IN ) :: al, & alb, & p, & pb, & ph, & phb REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, & fzp REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT( OUT) :: rho, & th_phy, & pii, & pf, & z, & z_at_w, & dz8w, & p8w REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: h_diabatic REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: t_new, & t_old REAL, INTENT(IN ) :: t0, p0 REAL :: z0,z1,z2,w1,w2 INTEGER :: i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: i, j, k !-------------------------------------------------------------------- ! ! ! moist_phys_prep_em calculates a number of diagnostic quantities needed by ! the microphysics routines. ! ! ! set up loop bounds for this grid's boundary conditions i_start = its i_end = min( ite,ide-1 ) j_start = jts j_end = min( jte,jde-1 ) k_start = kts k_end = min( kte, kde-1 ) DO j = j_start, j_end DO k = k_start, kte DO i = i_start, i_end z_at_w(i,k,j) = (ph(i,k,j)+phb(i,k,j))/g ENDDO ENDDO ENDDO do j = j_start,j_end do k = k_start, kte-1 do i = i_start, i_end dz8w(i,k,j) = z_at_w(i,k+1,j)-z_at_w(i,k,j) enddo enddo enddo do j = j_start,j_end do i = i_start, i_end dz8w(i,kte,j) = 0. enddo enddo ! compute full pii, rho, and z at the new time-level ! (needed for physics). ! convert perturbation theta to full theta (th_phy) ! use h_diabatic to temporarily save pre-microphysics full theta DO j = j_start, j_end DO k = k_start, k_end DO i = i_start, i_end #ifdef REVERT t_new(i,k,j) = t_new(i,k,j)-h_diabatic(i,k,j)*dt #endif th_phy(i,k,j) = t_new(i,k,j) + t0 h_diabatic(i,k,j) = th_phy(i,k,j) rho(i,k,j) = 1./(al(i,k,j)+alb(i,k,j)) pii(i,k,j) = ((p(i,k,j)+pb(i,k,j))/p0)**rcp z(i,k,j) = 0.5*(z_at_w(i,k,j) +z_at_w(i,k+1,j) ) pf(i,k,j) = p(i,k,j)+pb(i,k,j) ENDDO ENDDO ENDDO ! interp t and p at w points do j = j_start,j_end do k = 2, k_end do i = i_start, i_end p8w(i,k,j) = fzm(k)*pf(i,k,j)+fzp(k)*pf(i,k-1,j) enddo enddo enddo ! extrapolate p and t to surface and top. ! we'll use an extrapolation in z for now do j = j_start,j_end do i = i_start, i_end ! bottom z0 = z_at_w(i,1,j) z1 = z(i,1,j) z2 = z(i,2,j) w1 = (z0 - z2)/(z1 - z2) w2 = 1. - w1 p8w(i,1,j) = w1*pf(i,1,j)+w2*pf(i,2,j) ! top z0 = z_at_w(i,kte,j) z1 = z(i,k_end,j) z2 = z(i,k_end-1,j) w1 = (z0 - z2)/(z1 - z2) w2 = 1. - w1 ! p8w(i,kde,j) = w1*pf(i,kde-1,j)+w2*pf(i,kde-2,j) p8w(i,kde,j) = exp(w1*log(pf(i,kde-1,j))+w2*log(pf(i,kde-2,j))) enddo enddo END SUBROUTINE moist_physics_prep_em !------------------------------------------------------------------------------ SUBROUTINE moist_physics_finish_em( t_new, t_old, t0, mut, & th_phy, h_diabatic, dt, & config_flags, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! Here we construct full fields ! needed by the microphysics TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags INTEGER, INTENT(IN ) :: ids,ide, jds,jde, kds,kde INTEGER, INTENT(IN ) :: ims,ime, jms,jme, kms,kme INTEGER, INTENT(IN ) :: its,ite, jts,jte, kts,kte REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: t_new, & t_old, & th_phy, & h_diabatic REAL, DIMENSION( ims:ime , jms:jme ), INTENT(INOUT) :: mut REAL, INTENT(IN ) :: t0, dt INTEGER :: i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: i, j, k !-------------------------------------------------------------------- ! ! ! moist_phys_finish_em resets theta to its perturbation value and ! computes and stores the microphysics diabatic heating term. ! ! ! set up loop bounds for this grid's boundary conditions i_start = its i_end = min( ite,ide-1 ) j_start = jts j_end = min( jte,jde-1 ) k_start = kts k_end = min( kte, kde-1 ) ! add microphysics theta diff to perturbation theta, set h_diabatic IF ( config_flags%no_mp_heating .eq. 0 ) THEN DO j = j_start, j_end DO k = k_start, k_end DO i = i_start, i_end t_new(i,k,j) = t_new(i,k,j) + (th_phy(i,k,j)-h_diabatic(i,k,j)) h_diabatic(i,k,j) = (th_phy(i,k,j)-h_diabatic(i,k,j))/dt ENDDO ENDDO ENDDO ELSE DO j = j_start, j_end DO k = k_start, k_end DO i = i_start, i_end ! t_new(i,k,j) = t_new(i,k,j) h_diabatic(i,k,j) = 0. ENDDO ENDDO ENDDO ENDIF END SUBROUTINE moist_physics_finish_em !---------------------------------------------------------------- SUBROUTINE init_module_big_step END SUBROUTINE init_module_big_step SUBROUTINE set_tend ( field, field_adv_tend, msf, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! Input data INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(OUT) :: field REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN) :: field_adv_tend REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN) :: msf ! Local data INTEGER :: i, j, k, itf, jtf, ktf ! ! ! set_tend copies the advective tendency array into the tendency array. ! ! jtf = MIN(jte,jde-1) ktf = MIN(kte,kde-1) itf = MIN(ite,ide-1) DO j = jts, jtf DO k = kts, ktf DO i = its, itf field(i,k,j) = field_adv_tend(i,k,j)*msf(i,j) ENDDO ENDDO ENDDO END SUBROUTINE set_tend !------------------------------------------------------------------------------ SUBROUTINE rk_rayleigh_damp( ru_tendf, rv_tendf, & rw_tendf, t_tendf, & u, v, w, t, t_init, & mut, muu, muv, ph, phb, & u_base, v_base, t_base, z_base, & dampcoef, zdamp, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) ! History: Apr 2005 Modifications by George Bryan, NCAR: ! - Generalized the code in a way that allows for ! simulations with steep terrain. ! ! Jul 2004 Modifications by George Bryan, NCAR: ! - Modified the code to use u_base, v_base, and t_base ! arrays for the background state. Removed the hard-wired ! base-state values. ! - Modified the code to use dampcoef, zdamp, and damp_opt, ! i.e., the upper-level damper variables in namelist.input. ! Removed the hard-wired variables in the older version. ! This damper is used when damp_opt = 2. ! - Modified the code to account for the movement of the ! model surfaces with time. The code now obtains a base- ! state value by interpolation using the "_base" arrays. ! Nov 2003 Bug fix by Jason Knievel, NCAR ! Aug 2003 Meridional dimension, some comments, and ! changes in layout of the code added by ! Jason Knievel, NCAR ! Jul 2003 Original code by Bill Skamarock, NCAR ! Purpose: This routine applies Rayleigh damping to a layer at top ! of the model domain. !----------------------------------------------------------------------- ! Begin declarations. IMPLICIT NONE INTEGER, INTENT( IN ) & :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte REAL, DIMENSION( ims:ime, kms:kme, jms:jme ), INTENT( INOUT ) & :: ru_tendf, rv_tendf, rw_tendf, t_tendf REAL, DIMENSION( ims:ime, kms:kme, jms:jme ), INTENT( IN ) & :: u, v, w, t, t_init, ph, phb REAL, DIMENSION( ims:ime, jms:jme ), INTENT( IN ) & :: mut, muu, muv REAL, DIMENSION( kms:kme ) , INTENT(IN ) & :: u_base, v_base, t_base, z_base REAL, INTENT(IN ) & :: dampcoef, zdamp ! Local variables. INTEGER & :: i_start, i_end, j_start, j_end, k_start, k_end, i, j, k, ktf, k1, k2 REAL & :: pii, dcoef, z, ztop REAL :: wkp1, wk, wkm1 REAL, DIMENSION( kms:kme ) :: z00, u00, v00, t00 ! End declarations. !----------------------------------------------------------------------- pii = 2.0 * asin(1.0) ktf = MIN( kte, kde-1 ) !----------------------------------------------------------------------- ! Adjust u to base state. DO j = jts, MIN( jte, jde-1 ) DO i = its, MIN( ite, ide ) ! Get height at top of model ztop = 0.5*( phb(i ,kde,j)+phb(i-1,kde,j) & +ph(i ,kde,j)+ph(i-1,kde,j) )/g ! Find bottom of damping layer k1 = ktf z = ztop DO WHILE( z >= (ztop-zdamp) ) z = 0.25*( phb(i ,k1,j)+phb(i ,k1+1,j) & +phb(i-1,k1,j)+phb(i-1,k1+1,j) & +ph(i ,k1,j)+ph(i ,k1+1,j) & +ph(i-1,k1,j)+ph(i-1,k1+1,j))/g z00(k1) = z k1 = k1 - 1 ENDDO k1 = k1 + 2 ! Get reference state at model levels DO k = k1, ktf k2 = ktf DO WHILE( z_base(k2) .gt. z00(k) ) k2 = k2 - 1 ENDDO if(k2+1.gt.ktf)then u00(k) = u_base(k2) + ( u_base(k2) - u_base(k2-1) ) & * ( z00(k) - z_base(k2) ) & / ( z_base(k2) - z_base(k2-1) ) else u00(k) = u_base(k2) + ( u_base(k2+1) - u_base(k2) ) & * ( z00(k) - z_base(k2) ) & / ( z_base(k2+1) - z_base(k2) ) endif ENDDO ! Apply the Rayleigh damper DO k = k1, ktf dcoef = 1.0 - MIN( 1.0, ( ztop - z00(k) ) / zdamp ) dcoef = (SIN( 0.5 * pii * dcoef ) )**2 ru_tendf(i,k,j) = ru_tendf(i,k,j) - & muu(i,j) * ( dcoef * dampcoef ) * & ( u(i,k,j) - u00(k) ) END DO END DO END DO ! End adjustment of u. !----------------------------------------------------------------------- !----------------------------------------------------------------------- ! Adjust v to base state. DO j = jts, MIN( jte, jde ) DO i = its, MIN( ite, ide-1 ) ! Get height at top of model ztop = 0.5*( phb(i,kde,j )+phb(i,kde,j-1) & +ph(i,kde,j )+ph(i,kde,j-1) )/g ! Find bottom of damping layer k1 = ktf z = ztop DO WHILE( z >= (ztop-zdamp) ) z = 0.25*( phb(i,k1,j )+phb(i,k1+1,j ) & +phb(i,k1,j-1)+phb(i,k1+1,j-1) & +ph(i,k1,j )+ph(i,k1+1,j ) & +ph(i,k1,j-1)+ph(i,k1+1,j-1))/g z00(k1) = z k1 = k1 - 1 ENDDO k1 = k1 + 2 ! Get reference state at model levels DO k = k1, ktf k2 = ktf DO WHILE( z_base(k2) .gt. z00(k) ) k2 = k2 - 1 ENDDO if(k2+1.gt.ktf)then v00(k) = v_base(k2) + ( v_base(k2) - v_base(k2-1) ) & * ( z00(k) - z_base(k2) ) & / ( z_base(k2) - z_base(k2-1) ) else v00(k) = v_base(k2) + ( v_base(k2+1) - v_base(k2) ) & * ( z00(k) - z_base(k2) ) & / ( z_base(k2+1) - z_base(k2) ) endif ENDDO ! Apply the Rayleigh damper DO k = k1, ktf dcoef = 1.0 - MIN( 1.0, ( ztop - z00(k) ) / zdamp ) dcoef = (SIN( 0.5 * pii * dcoef ) )**2 rv_tendf(i,k,j) = rv_tendf(i,k,j) - & muv(i,j) * ( dcoef * dampcoef ) * & ( v(i,k,j) - v00(k) ) END DO END DO END DO ! End adjustment of v. !----------------------------------------------------------------------- !----------------------------------------------------------------------- ! Adjust w to base state. DO j = jts, MIN( jte, jde-1 ) DO i = its, MIN( ite, ide-1 ) ztop = ( phb(i,kde,j) + ph(i,kde,j) ) / g DO k = kts, MIN( kte, kde ) z = ( phb(i,k,j) + ph(i,k,j) ) / g IF ( z >= (ztop-zdamp) ) THEN dcoef = 1.0 - MIN( 1.0, ( ztop - z ) / zdamp ) dcoef = ( SIN( 0.5 * pii * dcoef ) )**2 rw_tendf(i,k,j) = rw_tendf(i,k,j) - & mut(i,j) * ( dcoef * dampcoef ) * w(i,k,j) END IF END DO END DO END DO ! End adjustment of w. !----------------------------------------------------------------------- !----------------------------------------------------------------------- ! Adjust potential temperature to base state. DO j = jts, MIN( jte, jde-1 ) DO i = its, MIN( ite, ide-1 ) ! Get height at top of model ztop = ( phb(i,kde,j) + ph(i,kde,j) ) / g ! Find bottom of damping layer k1 = ktf z = ztop DO WHILE( z >= (ztop-zdamp) ) z = 0.5 * ( phb(i,k1,j) + phb(i,k1+1,j) + & ph(i,k1,j) + ph(i,k1+1,j) ) / g z00(k1) = z k1 = k1 - 1 ENDDO k1 = k1 + 2 ! Get reference state at model levels DO k = k1, ktf k2 = ktf DO WHILE( z_base(k2) .gt. z00(k) ) k2 = k2 - 1 ENDDO if(k2+1.gt.ktf)then t00(k) = t_base(k2) + ( t_base(k2) - t_base(k2-1) ) & * ( z00(k) - z_base(k2) ) & / ( z_base(k2) - z_base(k2-1) ) else t00(k) = t_base(k2) + ( t_base(k2+1) - t_base(k2) ) & * ( z00(k) - z_base(k2) ) & / ( z_base(k2+1) - z_base(k2) ) endif ENDDO ! Apply the Rayleigh damper DO k = k1, ktf dcoef = 1.0 - MIN( 1.0, ( ztop - z00(k) ) / zdamp ) dcoef = (SIN( 0.5 * pii * dcoef ) )**2 t_tendf(i,k,j) = t_tendf(i,k,j) - & mut(i,j) * ( dcoef * dampcoef ) * & ( t(i,k,j) - t00(k) ) END DO END DO END DO ! End adjustment of potential temperature. !----------------------------------------------------------------------- END SUBROUTINE rk_rayleigh_damp !============================================================================== !============================================================================== SUBROUTINE sixth_order_diffusion( name, field, tendency, mu, dt, & config_flags, & diff_6th_opt, diff_6th_factor, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) ! History: 14 Nov 2006 Name of variable changed by Jason Knievel ! 07 Jun 2006 Revised and generalized by Jason Knievel ! 25 Apr 2005 Original code by Jason Knievel, NCAR ! Purpose: Apply 6th-order, monotonic (flux-limited), numerical ! diffusion to 3-d velocity and to scalars. ! References: Ming Xue (MWR Aug 2000) ! Durran ("Numerical Methods for Wave Equations..." 1999) ! George Bryan (personal communication) !------------------------------------------------------------------------------ ! Begin: Declarations. IMPLICIT NONE INTEGER, INTENT(IN) & :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte TYPE(grid_config_rec_type), INTENT(IN) & :: config_flags REAL, DIMENSION( ims:ime, kms:kme, jms:jme ), INTENT(INOUT) & :: tendency REAL, DIMENSION( ims:ime, kms:kme, jms:jme ), INTENT(IN) & :: field REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN) & :: mu REAL, INTENT(IN) & :: dt REAL, INTENT(IN) & :: diff_6th_factor INTEGER, INTENT(IN) & :: diff_6th_opt CHARACTER(LEN=1) , INTENT(IN) & :: name INTEGER & :: i, j, k, & i_start, i_end, & j_start, j_end, & k_start, k_end, & ktf REAL & :: dflux_x_p0, dflux_y_p0, & dflux_x_p1, dflux_y_p1, & tendency_x, tendency_y, & mu_avg_p0, mu_avg_p1, & diff_6th_coef LOGICAL & :: specified ! End: Declarations. !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! Begin: Translate the diffusion factor into a diffusion coefficient. See ! Durran's text, section 2.4.3, then adjust for sixth-order diffusion (not ! fourth) and for diffusion in two dimensions (not one). For reference, a ! factor of 1.0 would mean complete diffusion of a 2dx wave in one time step, ! although application of the flux limiter reduces somewhat the effects of ! diffusion for a given coefficient. diff_6th_coef = diff_6th_factor * 0.015625 / ( 2.0 * dt ) ! End: Translate diffusion factor. !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! Begin: Assign limits of spatial loops depending on variable to be diffused. ! The halo regions are already filled with values by the time this subroutine ! is called, which allows the stencil to extend beyond the domains' edges. ktf = MIN( kte, kde-1 ) IF ( name .EQ. 'u' ) THEN i_start = its i_end = ite j_start = jts j_end = MIN(jde-1,jte) k_start = kts k_end = ktf ELSE IF ( name .EQ. 'v' ) THEN i_start = its i_end = MIN(ide-1,ite) j_start = jts j_end = jte k_start = kts k_end = ktf ELSE IF ( name .EQ. 'w' ) THEN i_start = its i_end = MIN(ide-1,ite) j_start = jts j_end = MIN(jde-1,jte) k_start = kts+1 k_end = ktf ELSE i_start = its i_end = MIN(ide-1,ite) j_start = jts j_end = MIN(jde-1,jte) k_start = kts k_end = ktf ENDIF ! End: Assignment of limits of spatial loops. !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! Begin: Loop across spatial dimensions. DO j = j_start, j_end DO k = k_start, k_end DO i = i_start, i_end !------------------------------------------------------------------------------ ! Begin: Diffusion in x (i index). ! Calculate the diffusive flux in x direction (from Xue's eq. 3). dflux_x_p0 = ( 10.0 * ( field(i, k,j) - field(i-1,k,j) ) & - 5.0 * ( field(i+1,k,j) - field(i-2,k,j) ) & + ( field(i+2,k,j) - field(i-3,k,j) ) ) dflux_x_p1 = ( 10.0 * ( field(i+1,k,j) - field(i ,k,j) ) & - 5.0 * ( field(i+2,k,j) - field(i-1,k,j) ) & + ( field(i+3,k,j) - field(i-2,k,j) ) ) ! If requested in the namelist (diff_6th_opt=2), prohibit up-gradient diffusion ! (variation on Xue's eq. 10). IF ( diff_6th_opt .EQ. 2 ) THEN IF ( dflux_x_p0 * ( field(i ,k,j)-field(i-1,k,j) ) .LE. 0.0 ) THEN dflux_x_p0 = 0.0 END IF IF ( dflux_x_p1 * ( field(i+1,k,j)-field(i ,k,j) ) .LE. 0.0 ) THEN dflux_x_p1 = 0.0 END IF END IF ! Apply 6th-order diffusion in x direction. IF ( name .EQ. 'u' ) THEN mu_avg_p0 = mu(i-1,j) mu_avg_p1 = mu(i ,j) ELSE IF ( name .EQ. 'v' ) THEN mu_avg_p0 = 0.25 * ( & mu(i-1,j-1) + & mu(i ,j-1) + & mu(i-1,j ) + & mu(i ,j ) ) mu_avg_p1 = 0.25 * ( & mu(i ,j-1) + & mu(i+1,j-1) + & mu(i ,j ) + & mu(i+1,j ) ) ELSE mu_avg_p0 = 0.5 * ( & mu(i-1,j) + & mu(i ,j) ) mu_avg_p1 = 0.5 * ( & mu(i ,j) + & mu(i+1,j) ) END IF tendency_x = diff_6th_coef * & ( ( mu_avg_p1 * dflux_x_p1 ) - ( mu_avg_p0 * dflux_x_p0 ) ) ! End: Diffusion in x. !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! Begin: Diffusion in y (j index). ! Calculate the diffusive flux in y direction (from Xue's eq. 3). dflux_y_p0 = ( 10.0 * ( field(i,k,j ) - field(i,k,j-1) ) & - 5.0 * ( field(i,k,j+1) - field(i,k,j-2) ) & + ( field(i,k,j+2) - field(i,k,j-3) ) ) dflux_y_p1 = ( 10.0 * ( field(i,k,j+1) - field(i,k,j ) ) & - 5.0 * ( field(i,k,j+2) - field(i,k,j-1) ) & + ( field(i,k,j+3) - field(i,k,j-2) ) ) ! If requested in the namelist (diff_6th_opt=2), prohibit up-gradient diffusion ! (variation on Xue's eq. 10). IF ( diff_6th_opt .EQ. 2 ) THEN IF ( dflux_y_p0 * ( field(i,k,j )-field(i,k,j-1) ) .LE. 0.0 ) THEN dflux_y_p0 = 0.0 END IF IF ( dflux_y_p1 * ( field(i,k,j+1)-field(i,k,j ) ) .LE. 0.0 ) THEN dflux_y_p1 = 0.0 END IF END IF ! Apply 6th-order diffusion in y direction. IF ( name .EQ. 'u' ) THEN mu_avg_p0 = 0.25 * ( & mu(i-1,j-1) + & mu(i ,j-1) + & mu(i-1,j ) + & mu(i ,j ) ) mu_avg_p1 = 0.25 * ( & mu(i-1,j ) + & mu(i ,j ) + & mu(i-1,j+1) + & mu(i ,j+1) ) ELSE IF ( name .EQ. 'v' ) THEN mu_avg_p0 = mu(i,j-1) mu_avg_p1 = mu(i,j ) ELSE mu_avg_p0 = 0.5 * ( & mu(i,j-1) + & mu(i,j ) ) mu_avg_p1 = 0.5 * ( & mu(i,j ) + & mu(i,j+1) ) END IF tendency_y = diff_6th_coef * & ( ( mu_avg_p1 * dflux_y_p1 ) - ( mu_avg_p0 * dflux_y_p0 ) ) ! End: Diffusion in y. !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ ! Begin: Combine diffusion in x and y. tendency(i,k,j) = tendency(i,k,j) + tendency_x + tendency_y ! End: Combine diffusion in x and y. !------------------------------------------------------------------------------ ENDDO ENDDO ENDDO ! End: Loop across spatial dimensions. !------------------------------------------------------------------------------ END SUBROUTINE sixth_order_diffusion !============================================================================== !============================================================================== END MODULE module_big_step_utilities_em