!WRF:MODEL_LAYER:DYNAMICS ! ! SMALL_STEP code for the geometric height coordinate model ! !--------------------------------------------------------------------------- MODULE module_small_step_em USE module_configure USE module_model_constants CONTAINS SUBROUTINE small_step_prep( u_1, u_2, v_1, v_2, w_1, w_2, & t_1, t_2, ph_1, ph_2, & mub, mu_1, mu_2, & muu, muus, muv, muvs, & mut, muts, mudf, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & u_save, v_save, w_save, & t_save, ph_save, mu_save, & ww, ww_save, & c2a, pb, p, alt, & msfux, msfuy, msfvx, & msfvx_inv, & msfvy, msftx, msfty, & rdx, rdy, & rk_step, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! religion first ! declarations for the stuff coming in 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 INTEGER, INTENT(IN ) :: rk_step REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT) :: u_1, & v_1, & w_1, & t_1, & ph_1 REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT( OUT) :: u_save, & v_save, & w_save, & t_save, & ph_save REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT) :: u_2, & v_2, & w_2, & t_2, & ph_2 REAL, DIMENSION(ims:ime, kms:kme, jms:jme), INTENT( OUT) :: c2a, & ww_save REAL, DIMENSION(ims:ime, kms:kme, jms:jme), INTENT(IN ) :: pb, & p, & alt, & ww REAL, DIMENSION(ims:ime, jms:jme) , INTENT(INOUT) :: mu_1,mu_2 REAL, DIMENSION(ims:ime, jms:jme) , INTENT(IN ) :: mub, & muu, & muv, & mut, & msfux,& msfuy,& msfvx,& msfvx_inv,& msfvy,& msftx,& msfty REAL, DIMENSION(ims:ime, jms:jme) , INTENT( OUT) :: muus, & muvs, & muts, & mudf REAL, DIMENSION(ims:ime, jms:jme) , INTENT( OUT) :: mu_save REAL, INTENT(IN) :: rdx,rdy REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f ! local variables INTEGER :: i, j, k INTEGER :: i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: i_endu, j_endv ! ! ! small_step_prep prepares the prognostic variables for the small timestep. ! This includes switching time-levels in the arrays and computing coupled ! perturbation variables for the small timestep ! (i.e. mu*u" = mu(t)*u(t)-mu(*)*u(*); mu*u" is advanced during the small ! timesteps ! ! 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) i_endu = ite j_endv = jte ! if this is the first RK step, reset *_1 to *_2 ! (we are replacing the t-dt fields with the time t fields) IF ((rk_step == 1) ) THEN DO j=j_start, j_end DO i=i_start, i_end MU_1(i,j)=MU_2(i,j) ww_save(i,kde,j) = 0. ww_save(i,1,j) = 0. MUDF(i,j) = 0. ! initialize external mode div damp to zero ENDDO ENDDO DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_endu u_1(i,k,j) = u_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_endv DO k=k_start, k_end DO i=i_start, i_end v_1(i,k,j) = v_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_end t_1(i,k,j) = t_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO k=k_start, min(kde,kte) DO i=i_start, i_end w_1(i,k,j) = w_2(i,k,j) ph_1(i,k,j) = ph_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO i=i_start, i_end MUTS(i,j)=MUB(i,j)+MU_2(i,j) ENDDO DO i=i_start, i_endu MUUS(i,j) = MUU(i,j) ENDDO ENDDO DO j=j_start, j_endv DO i=i_start, i_end MUVS(i,j) = MUV(i,j) ENDDO ENDDO DO j=j_start, j_end DO i=i_start, i_end MU_SAVE(i,j)=MU_2(i,j) MU_2(i,j)=0. ENDDO ENDDO ELSE DO j=j_start, j_end DO i=i_start, i_end MUTS(i,j)=MUB(i,j)+MU_1(i,j) ENDDO DO i=i_start, i_endu MUUS(i,j)=0.5*(MUB(i,j)+MU_1(i,j)+MUB(i-1,j)+MU_1(i-1,j)) ENDDO ENDDO DO j=j_start, j_endv DO i=i_start, i_end MUVS(i,j)=0.5*(MUB(i,j)+MU_1(i,j)+MUB(i,j-1)+MU_1(i,j-1)) ENDDO ENDDO DO j=j_start, j_end DO i=i_start, i_end MU_SAVE(i,j)=MU_2(i,j) MU_2(i,j)=MU_1(i,j)-MU_2(i,j) ENDDO ENDDO END IF ! set up the small timestep variables DO j=j_start, j_end DO i=i_start, i_end ww_save(i,kde,j) = 0. ww_save(i,1,j) = 0. ENDDO ENDDO DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_end c2a(i,k,j) = cpovcv*(pb(i,k,j)+p(i,k,j))/alt(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_endu u_save(i,k,j) = u_2(i,k,j) ! u coupled with my u_2(i,k,j) = ((c1h(k)*muus(i,j)+c2h(k))*u_1(i,k,j)-(c1h(k)*muu(i,j)+c2h(k))*u_2(i,k,j))/msfuy(i,j) ENDDO ENDDO ENDDO DO j=j_start, j_endv DO k=k_start, k_end DO i=i_start, i_end v_save(i,k,j) = v_2(i,k,j) ! v coupled with mx ! v_2(i,k,j) = ((c1h(k)*muvs(i,j)+c2h(k))*v_1(i,k,j)-(c1h(k)*muv(i,j)+c2h(k))*v_2(i,k,j))/msfvx(i,j) v_2(i,k,j) = ((c1h(k)*muvs(i,j)+c2h(k))*v_1(i,k,j)-(c1h(k)*muv(i,j)+c2h(k))*v_2(i,k,j))*msfvx_inv(i,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_end t_save(i,k,j) = t_2(i,k,j) t_2(i,k,j) = (c1h(k)*muts(i,j)+c2h(k))*t_1(i,k,j)-(c1h(k)*mut(i,j)+c2h(k))*t_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end ! DO k=k_start, min(kde,kte) DO k=k_start, kde DO i=i_start, i_end w_save(i,k,j) = w_2(i,k,j) ! w coupled with my w_2(i,k,j) = ((c1f(k)*muts(i,j)+c2f(k))* w_1(i,k,j)-(c1f(k)*mut(i,j)+c2f(k))* w_2(i,k,j))/msfty(i,j) ph_save(i,k,j) = ph_2(i,k,j) ph_2(i,k,j) = ph_1(i,k,j)-ph_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end ! DO k=k_start, min(kde,kte) DO k=k_start, kde DO i=i_start, i_end ww_save(i,k,j) = ww(i,k,j) ENDDO ENDDO ENDDO END SUBROUTINE small_step_prep !------------------------------------------------------------------------- SUBROUTINE small_step_finish( u_2, u_1, v_2, v_1, w_2, w_1, & t_2, t_1, ph_2, ph_1, ww, ww1, & mu_2, mu_1, & mut, muts, muu, muus, muv, muvs, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & u_save, v_save, w_save, & t_save, ph_save, mu_save, & msfux, msfuy, msfvx, msfvy, & msftx, msfty, & h_diabatic, & number_of_small_timesteps,dts, & rk_step, rk_order, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! religion first ! stuff passed in 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 INTEGER, INTENT(IN ) :: number_of_small_timesteps INTEGER, INTENT(IN ) :: rk_step, rk_order REAL, INTENT(IN ) :: dts REAL, DIMENSION(ims:ime, kms:kme, jms:jme), INTENT(IN ) :: u_1, & v_1, & w_1, & t_1, & ww1, & ph_1 REAL, DIMENSION(ims:ime, kms:kme, jms:jme), INTENT(INOUT) :: u_2, & v_2, & w_2, & t_2, & ww, & ph_2 REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(IN ) :: u_save, & v_save, & w_save, & t_save, & ph_save, & h_diabatic REAL, DIMENSION(ims:ime, jms:jme), INTENT(INOUT) :: muus, muvs REAL, DIMENSION(ims:ime, jms:jme), INTENT(INOUT) :: mu_2, mu_1 REAL, DIMENSION(ims:ime, jms:jme), INTENT(INOUT) :: mut, muts, & muu, muv, mu_save REAL, DIMENSION(ims:ime, jms:jme), INTENT(IN ) :: msfux, msfuy, & msfvx, msfvy, & msftx, msfty REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f ! local stuff INTEGER :: i,j,k INTEGER :: i_start, i_end, j_start, j_end, i_endu, j_endv ! ! ! small_step_finish reconstructs the full uncoupled prognostic variables ! from the coupled perturbation variables used in the small timesteps. ! ! i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) i_endu = ite j_endv = jte ! addition of time level t back into variables DO j = j_start, j_endv DO k = kds, kde-1 DO i = i_start, i_end ! v coupled with mx v_2(i,k,j) = (msfvx(i,j)*v_2(i,k,j) + v_save(i,k,j)*(c1h(k)*muv(i,j)+c2h(k)))/(c1h(k)*muvs(i,j)+c2h(k)) ENDDO ENDDO ENDDO DO j = j_start, j_end DO k = kds, kde-1 DO i = i_start, i_endu ! u coupled with my u_2(i,k,j) = (msfuy(i,j)*u_2(i,k,j) + u_save(i,k,j)*(c1h(k)*muu(i,j)+c2h(k)))/(c1h(k)*muus(i,j)+c2h(k)) ENDDO ENDDO ENDDO DO j = j_start, j_end DO k = kds, kde DO i = i_start, i_end ! w coupled with my w_2(i,k,j) = (msfty(i,j)*w_2(i,k,j) + w_save(i,k,j)*(c1f(k)*mut(i,j)+c2f(k)))/(c1f(k)*muts(i,j)+c2f(k)) ph_2(i,k,j) = ph_2(i,k,j) + ph_save(i,k,j) ww(i,k,j) = ww(i,k,j) + ww1(i,k,j) ENDDO ENDDO ENDDO IF ( rk_step < rk_order ) THEN DO j = j_start, j_end DO k = kds, kde-1 DO i = i_start, i_end t_2(i,k,j) = (t_2(i,k,j) + t_save(i,k,j)*(c1h(k)*mut(i,j)+c2h(k)))/(c1h(k)*muts(i,j)+c2h(k)) ENDDO ENDDO ENDDO ELSE DO j = j_start, j_end DO k = kds, kde-1 DO i = i_start, i_end t_2(i,k,j) = (t_2(i,k,j) - dts*number_of_small_timesteps*(c1h(k)*mut(i,j)+c2h(k))*h_diabatic(i,k,j) & + t_save(i,k,j)*(c1h(k)*mut(i,j)+c2h(k)))/(c1h(k)*muts(i,j)+c2h(k)) ENDDO ENDDO ENDDO ENDIF DO j = j_start, j_end DO i = i_start, i_end mu_2(i,j) = mu_2(i,j) + mu_save(i,j) ENDDO ENDDO END SUBROUTINE small_step_finish !----------------------------------------------------------------------- SUBROUTINE calc_p_rho( al, p, ph, & alt, t_2, t_1, c2a, pm1, & mu, mut, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & znu, t0, & rdnw, dnw, smdiv, & non_hydrostatic, step, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! religion first ! declarations for the stuff coming in 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 INTEGER, INTENT(IN ) :: step REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT( OUT) :: al, & p REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(IN ) :: alt, & t_2, & t_1, & c2a REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT) :: ph, pm1 REAL, DIMENSION(ims:ime, jms:jme) , INTENT(IN ) :: mu, & mut REAL, DIMENSION(kms:kme) , INTENT(IN ) :: dnw, & rdnw, & znu REAL, INTENT(IN ) :: t0, smdiv REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f LOGICAL, INTENT(IN ) :: non_hydrostatic ! local variables INTEGER :: i, j, k INTEGER :: i_start, i_end, j_start, j_end, k_start, k_end REAL :: ptmp ! ! ! For the nonhydrostatic option, ! calc_p_rho computes the perturbation inverse density and ! perturbation pressure from the hydrostatic relation and the ! linearized equation of state, respectively. ! ! For the hydrostatic option, ! calc_p_rho computes the perturbation pressure, perturbation density, ! and perturbation geopotential ! from the vertical coordinate definition, linearized equation of state ! and the hydrostatic relation, respectively. ! ! forward weighting of the pressure (divergence damping) is also ! computed here. ! ! 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) IF (non_hydrostatic) THEN DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_end ! al computation is all dry, so ok with moisture al(i,k,j)=-1./(c1h(k)*Mut(i,j)+c2h(k))*(alt(i,k,j)*(c1h(k)*mu(i,j)) & +rdnw(k)*(ph(i,k+1,j)-ph(i,k,j))) ! this is temporally linearized p, no moisture correction needed p(i,k,j)=c2a(i,k,j)*(alt(i,k,j)*(t_2(i,k,j)-(c1h(k)*mu(i,j))*t_1(i,k,j)) & /((c1h(k)*Mut(i,j)+c2h(k))*(t0+t_1(i,k,j)))-al (i,k,j)) ENDDO ENDDO ENDDO ELSE ! hydrostatic calculation DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_end p(i,k,j)=MU(i,j)*c3h(k) al(i,k,j)=alt(i,k,j)*(t_2(i,k,j)-(c1h(k)*mu(i,j))*t_1(i,k,j)) & /((c1h(k)*Mut(i,j)+c2h(k))*(t0+t_1(i,k,j)))-p(i,k,j)/c2a(i,k,j) ph(i,k+1,j)=ph(i,k,j)-dnw(k)*((c1h(k)*Mut(i,j)+c2h(k))*al (i,k,j) & +(c1h(k)*mu(i,j))*alt(i,k,j)) ENDDO ENDDO ENDDO END IF ! divergence damping setup IF (step == 0) then ! we're initializing small timesteps DO j=j_start, j_end DO k=k_start, k_end DO i=i_start, i_end pm1(i,k,j)=p(i,k,j) ENDDO ENDDO ENDDO ELSE ! we're in the small timesteps DO j=j_start, j_end ! and adding div damping component DO k=k_start, k_end DO i=i_start, i_end ptmp = p(i,k,j) p(i,k,j) = p(i,k,j) + smdiv*(p(i,k,j)-pm1(i,k,j)) pm1(i,k,j) = ptmp ENDDO ENDDO ENDDO END IF END SUBROUTINE calc_p_rho !---------------------------------------------------------------------- SUBROUTINE calc_coef_w( a,alpha,gamma, & mut, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & cqw, & rdn, rdnw, c2a, & dts, g, epssm, top_lid, & ids,ide, jds,jde, kds,kde, & ! domain dims ims,ime, jms,jme, kms,kme, & ! memory dims its,ite, jts,jte, kts,kte ) ! tile dims IMPLICIT NONE ! religion first ! passed in through the call 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 LOGICAL, INTENT(IN ) :: top_lid REAL, DIMENSION(ims:ime, kms:kme, jms:jme), INTENT(IN ) :: c2a, & cqw REAL, DIMENSION(ims:ime, kms:kme, jms:jme), INTENT(INOUT) :: alpha, & gamma, & a REAL, DIMENSION(ims:ime, jms:jme), INTENT(IN ) :: mut REAL, DIMENSION(kms:kme), INTENT(IN ) :: rdn, & rdnw REAL, INTENT(IN ) :: epssm, & dts, & g REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f ! Local stack data. REAL, DIMENSION(ims:ime) :: cof REAL :: b, c REAL :: muthmutf_kk, muthmutf_km1k, muthmutf_kkp1 INTEGER :: i, j, k, kk, i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: ij, ijp, ijm, lid_flag ! ! ! calc_coef_w calculates the coefficients needed for the ! implicit solution of the vertical momentum and geopotential equations. ! This requires solution of a tri-diagonal equation. ! ! i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) k_start = kts k_end = kte-1 lid_flag=1 IF(top_lid)lid_flag=0 outer_j_loop: DO j = j_start, j_end k = kde-1 DO i = i_start, i_end cof(i) = (.5*dts*g*(1.+epssm))**2 a(i, 2 ,j) = 0. a(i,kde,j) =-2.*cof(i)*rdnw(kde-1)**2*c2a(i,kde-1,j)*lid_flag/((c1h(k)*MUT(i,j)+c2h(k))*(c1f(k)*MUT(i,j)+c2f(k))) gamma(i,1 ,j) = 0. ENDDO DO kk=3,kde-1 k=kk-1 DO i=i_start, i_end a(i,kk,j) = -cqw(i,kk,j)*cof(i)*rdn(kk)* rdnw(kk-1)*c2a(i,kk-1,j)/((c1h(k)*MUT(i,j)+c2h(k))*(c1f(k)*MUT(i,j)+c2f(k))) ENDDO ENDDO DO k=2,kde-1 DO i=i_start, i_end b = 1.+cqw(i,k,j)*cof(i)*rdn(k)*(rdnw(k )*c2a(i,k, j)/((c1h(k)*MUT(i,j)+c2h(k))*(c1f(k)*MUT(i,j)+c2f(k))) & +rdnw(k-1)*c2a(i,k-1,j)/((c1h(k-1)*MUT(i,j)+c2h(k-1))*(c1f(k)*MUT(i,j)+c2f(k))) ) c = -cqw(i,k,j)*cof(i)*rdn(k)*rdnw(k )*c2a(i,k,j )/((c1h(k)*MUT(i,j)+c2h(k))*(c1f(k+1)*MUT(i,j)+c2f(k+1))) alpha(i,k,j) = 1./(b-a(i,k,j)*gamma(i,k-1,j)) gamma(i,k,j) = c*alpha(i,k,j) ENDDO ENDDO k=kde DO i=i_start, i_end b = 1.+2.*cof(i)*rdnw(kde-1)**2*c2a(i,kde-1,j)/((c1h(k-1)*MUT(i,j)+c2h(k-1))*(c1f(k)*MUT(i,j)+c2f(k))) c = 0. alpha(i,kde,j) = 1./(b-a(i,kde,j)*gamma(i,kde-1,j)) gamma(i,kde,j) = c*alpha(i,kde,j) ENDDO ENDDO outer_j_loop END SUBROUTINE calc_coef_w !---------------------------------------------------------------------- SUBROUTINE advance_uv ( u, ru_tend, v, rv_tend, & p, pb, & ph, php, alt, al, mu, & muu, cqu, muv, cqv, mudf, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & msfux, msfuy, msfvx, & msfvx_inv, msfvy, & rdx, rdy, dts, & cf1, cf2, cf3, fnm, fnp, & emdiv, & rdnw, config_flags, spec_zone, & non_hydrostatic, top_lid, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! religion first ! stuff coming in 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 INTEGER, INTENT(IN ) :: ims,ime, jms,jme, kms,kme INTEGER, INTENT(IN ) :: its,ite, jts,jte, kts,kte INTEGER, INTENT(IN ) :: spec_zone REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: & u, & v REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(IN ) :: & ru_tend, & rv_tend, & ph, & php, & p, & pb, & alt, & al, & cqu, & cqv REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: muu, & muv, & mu, & mudf REAL, DIMENSION( kms:kme ), INTENT(IN ) :: fnm, & fnp , & rdnw REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: msfux, & msfuy, & msfvx, & msfvy, & msfvx_inv REAL, INTENT(IN ) :: rdx, & rdy, & dts, & cf1, & cf2, & cf3, & emdiv REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f ! Local 3d array from the stack (note tile size) REAL, DIMENSION (its:ite, kts:kte) :: dpn, dpxy REAL, DIMENSION (its:ite) :: mudf_xy REAL :: dx, dy INTEGER :: i,j,k, i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: i_endu, j_endv, k_endw INTEGER :: i_start_up, i_end_up, j_start_up, j_end_up INTEGER :: i_start_vp, i_end_vp, j_start_vp, j_end_vp INTEGER :: i_start_u_tend, i_end_u_tend, j_start_v_tend, j_end_v_tend ! ! ! advance_uv advances the explicit perturbation horizontal momentum ! equations (u,v) by adding in the large-timestep tendency along with ! the small timestep pressure gradient tendency. ! ! ! now, the real work. ! set the loop bounds taking into account boundary conditions. IF( config_flags%nested .or. config_flags%specified ) THEN i_start = max( its,ids+spec_zone ) i_end = min( ite,ide-spec_zone-1 ) j_start = max( jts,jds+spec_zone ) j_end = min( jte,jde-spec_zone-1 ) k_start = kts k_end = min( kte, kde-1 ) i_endu = min( ite,ide-spec_zone ) j_endv = min( jte,jde-spec_zone ) k_endw = k_end IF( config_flags%periodic_x) THEN i_start = its i_end = min(ite,ide-1) i_endu = ite ENDIF ELSE i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) k_start = kts k_end = kte-1 i_endu = ite j_endv = jte k_endw = k_end ENDIF i_start_up = i_start i_end_up = i_endu j_start_up = j_start j_end_up = j_end i_start_vp = i_start i_end_vp = i_end j_start_vp = j_start j_end_vp = j_endv IF ( (config_flags%open_xs .or. & config_flags%symmetric_xs ) & .and. (its == ids) ) & i_start_up = i_start_up + 1 IF ( (config_flags%open_xe .or. & config_flags%symmetric_xe ) & .and. (ite == ide) ) & i_end_up = i_end_up - 1 IF ( (config_flags%open_ys .or. & config_flags%symmetric_ys .or. & config_flags%polar ) & .and. (jts == jds) ) & j_start_vp = j_start_vp + 1 IF ( (config_flags%open_ye .or. & config_flags%symmetric_ye .or. & config_flags%polar ) & .and. (jte == jde) ) & j_end_vp = j_end_vp - 1 i_start_u_tend = i_start i_end_u_tend = i_endu j_start_v_tend = j_start j_end_v_tend = j_endv IF ( config_flags%symmetric_xs .and. (its == ids) ) & i_start_u_tend = i_start_u_tend+1 IF ( config_flags%symmetric_xe .and. (ite == ide) ) & i_end_u_tend = i_end_u_tend-1 IF ( config_flags%symmetric_ys .and. (jts == jds) ) & j_start_v_tend = j_start_v_tend+1 IF ( config_flags%symmetric_ye .and. (jte == jde) ) & j_end_v_tend = j_end_v_tend-1 dx = 1./rdx dy = 1./rdy ! start real calculations. ! first, u u_outer_j_loop: DO j = j_start, j_end DO k = k_start, k_end DO i = i_start_u_tend, i_end_u_tend u(i,k,j) = u(i,k,j) + dts*ru_tend(i,k,j) ENDDO ENDDO DO i = i_start_up, i_end_up MUDF_XY(i)= -emdiv*dx*(MUDF(i,j)-MUDF(i-1,j))/msfuy(i,j) ENDDO DO k = k_start, k_end DO i = i_start_up, i_end_up ! Comments on map scale factors: ! x pressure gradient: ADT eqn 44, penultimate term on RHS ! = -(mx/my)*(mu/rho)*partial dp/dx ! [i.e., first rho->mu; 2nd still rho; alpha=1/rho] ! Klemp et al. splits into 2 terms: ! mu alpha partial dp/dx + partial dp/dnu * partial dphi/dx ! then into 4 terms: ! mu alpha partial dp'/dx + nu mu alpha' partial dmubar/dx + ! + mu partial dphi/dx + partial dphi'/dx * (partial dp'/dnu - mu') ! ! first 3 terms: ! ph, alt, p, al, pb not coupled ! since we want tendency to fit ADT eqn 44 (coupled) we need to ! multiply by (mx/my): ! dpxy(i,k)= (msfux(i,j)/msfuy(i,j))*.5*rdx*(c1h(k)*muu(i,j)+c2h(k))*( & ((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)) ) ENDDO ENDDO IF (non_hydrostatic) THEN DO i = i_start_up, i_end_up dpn(i,1) = .5*( cf1*(p(i,1,j)+p(i-1,1,j)) & +cf2*(p(i,2,j)+p(i-1,2,j)) & +cf3*(p(i,3,j)+p(i-1,3,j)) ) dpn(i,kde) = 0. ENDDO IF (top_lid) THEN DO i = i_start_up, i_end_up 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 = k_start+1, k_end DO i = i_start_up, i_end_up dpn(i,k) = .5*( fnm(k)*(p(i,k ,j)+p(i-1,k ,j)) & +fnp(k)*(p(i,k-1,j)+p(i-1,k-1,j)) ) ENDDO ENDDO ! Comments on map scale factors: ! 4th term: ! php, dpn, mu not coupled ! since we want tendency to fit ADT eqn 44 (coupled) we need to ! multiply by (mx/my): DO k = k_start, k_end DO i = i_start_up, i_end_up dpxy(i,k)=dpxy(i,k) + (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*((c1h(k)*mu(i-1,j))+(c1h(k)*mu(i,j)))) ENDDO ENDDO END IF DO k = k_start, k_end DO i = i_start_up, i_end_up u(i,k,j)=u(i,k,j)-dts*cqu(i,k,j)*dpxy(i,k)+(c1h(k)*mudf_xy(i)) ENDDO ENDDO ENDDO u_outer_j_loop ! now v v_outer_j_loop: DO j = j_start_v_tend, j_end_v_tend DO k = k_start, k_end DO i = i_start, i_end v(i,k,j) = v(i,k,j) + dts*rv_tend(i,k,j) ENDDO ENDDO DO i = i_start, i_end MUDF_XY(i)= -emdiv*dy*(MUDF(i,j)-MUDF(i,j-1))*msfvx_inv(i,j) ENDDO IF ( ( j >= j_start_vp) & .and.( j <= j_end_vp ) ) THEN DO k = k_start, k_end DO i = i_start, i_end ! Comments on map scale factors: ! y pressure gradient: ADT eqn 45, penultimate term on RHS ! = -(my/mx)*(mu/rho)*partial dp/dy ! [i.e., first rho->mu; 2nd still rho; alpha=1/rho] ! Klemp et al. splits into 2 terms: ! mu alpha partial dp/dy + partial dp/dnu * partial dphi/dy ! then into 4 terms: ! mu alpha partial dp'/dy + nu mu alpha' partial dmubar/dy + ! + mu partial dphi/dy + partial dphi'/dy * (partial dp'/dnu - mu') ! ! first 3 terms: ! ph, alt, p, al, pb not coupled ! since we want tendency to fit ADT eqn 45 (coupled) we need to ! multiply by (my/mx): ! mudf_xy is NOT a map scale factor coupling ! it is some sort of divergence damping dpxy(i,k)= (msfvy(i,j)/msfvx(i,j))*.5*rdy*(c1h(k)*muv(i,j)+c2h(k))*( & ((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)) ) ENDDO ENDDO IF (non_hydrostatic) THEN DO i = i_start, i_end dpn(i,1) = .5*( cf1*(p(i,1,j)+p(i,1,j-1)) & +cf2*(p(i,2,j)+p(i,2,j-1)) & +cf3*(p(i,3,j)+p(i,3,j-1)) ) dpn(i,kde) = 0. ENDDO IF (top_lid) THEN DO i = i_start, i_end 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 = k_start+1, k_end DO i = i_start, i_end dpn(i,k) = .5*( fnm(k)*(p(i,k ,j)+p(i,k ,j-1)) & +fnp(k)*(p(i,k-1,j)+p(i,k-1,j-1)) ) ENDDO ENDDO ! Comments on map scale factors: ! 4th term: ! php, dpn, mu not coupled ! since we want tendency to fit ADT eqn 45 (coupled) we need to ! multiply by (my/mx): DO k = k_start, k_end DO i = i_start, i_end dpxy(i,k)=dpxy(i,k) + (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*((c1h(k)*mu(i,j-1))+(c1h(k)*mu(i,j)))) ENDDO ENDDO END IF DO k = k_start, k_end DO i = i_start, i_end v(i,k,j)=v(i,k,j)-dts*cqv(i,k,j)*dpxy(i,k)+(c1h(k)*mudf_xy(i)) ENDDO ENDDO END IF ENDDO v_outer_j_loop ! The check for j_start_vp and j_end_vp makes sure that the edges in v ! are not updated. Let's add a polar boundary condition check here for ! safety to ensure that v at the poles never gets to be non-zero in the ! small time steps. IF (config_flags%polar) THEN IF (jts == jds) THEN DO k = k_start, k_end DO i = i_start, i_end v(i,k,jds) = 0. ENDDO ENDDO END IF IF (jte == jde) THEN DO k = k_start, k_end DO i = i_start, i_end v(i,k,jde) = 0. ENDDO ENDDO END IF END IF END SUBROUTINE advance_uv !--------------------------------------------------------------------- SUBROUTINE advance_mu_t( ww, ww_1, u, u_1, v, v_1, & mu, mut, muave, muts, muu, muv, mudf,& c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & uam, vam, wwam, t, t_1, & t_ave, ft, mu_tend, & rdx, rdy, dts, epssm, & dnw, fnm, fnp, rdnw, & msfux, msfuy, msfvx, msfvx_inv, & msfvy, msftx, msfty, & step, config_flags, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! religion first ! stuff coming in 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 INTEGER, INTENT(IN ) :: step REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(IN ) :: & u, & v, & u_1, & v_1, & t_1, & ft REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: & ww, & ww_1, & t, & t_ave, & uam, & vam, & wwam REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: muu, & muv, & mut, & msfux,& msfuy,& msfvx,& msfvx_inv,& msfvy,& msftx,& msfty,& mu_tend REAL, DIMENSION( ims:ime , jms:jme ), INTENT( OUT) :: muave, & muts, & mudf REAL, DIMENSION( ims:ime , jms:jme ), INTENT(INOUT) :: mu REAL, DIMENSION( kms:kme ), INTENT(IN ) :: fnm, & fnp, & dnw, & rdnw REAL, INTENT(IN ) :: rdx, & rdy, & dts, & epssm REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f ! Local arrays from the stack (note tile size) REAL, DIMENSION (its:ite, kts:kte) :: wdtn, dvdxi REAL, DIMENSION (its:ite) :: dmdt INTEGER :: i, j, k, kk, i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: i_endu, j_endv REAL :: acc ! ! ! advance_mu_t advances the explicit perturbation theta equation and the mass ! conservation equation. In addition, the small timestep omega is updated, ! and some quantities needed in other places are squirrelled away. ! ! ! now, the real work. ! set the loop bounds taking into account 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 = kte-1 IF ( .NOT. config_flags%periodic_x )THEN IF ( config_flags%specified .or. config_flags%nested ) then i_start = max(its,ids+1) i_end = min(ite,ide-2) ENDIF ENDIF IF ( config_flags%specified .or. config_flags%nested ) then j_start = max(jts,jds+1) j_end = min(jte,jde-2) ENDIF i_endu = ite j_endv = jte ! CALCULATION OF WW (dETA/dt) DO j = j_start, j_end DO i=i_start, i_end DMDT(i) = 0. ENDDO ! NOTE: mu is not coupled with the map scale factor. ! ww (omega) IS coupled with the map scale factor. ! Being coupled with the map scale factor means ! multiplication by (1/msft) in this case. ! Comments on map scale factors ! ADT eqn 47: ! partial drho/dt = -mx*my[partial d/dx(rho u/my) + partial d/dy(rho v/mx)] ! -partial d/dz(rho w) ! with rho -> mu, dividing by my, and with partial d/dnu(rho nu/my [=ww]) ! as the final term (because we're looking for d_nu_/dt) ! ! begin by integrating with respect to nu from bottom to top ! BCs are ww=0 at both ! final term gives 0 ! first term gives Integral([1/my]partial d mu/dt) over total column = dm/dt ! RHS remaining is Integral(-mx[partial d/dx(mu u/my) + ! partial d/dy(mu v/mx)]) over column ! lines below find RHS terms at each level then set dmdt = sum over all levels ! ! [don't divide the below by msfty until find ww, since dmdt is used in ! the meantime] DO k=k_start, k_end DO i=i_start, i_end dvdxi(i,k) = msftx(i,j)*msfty(i,j)*( & rdy*( (v(i,k,j+1)+(c1h(k)*muv(i,j+1)+c2h(k))*v_1(i,k,j+1)*msfvx_inv(i,j+1)) & -(v(i,k,j )+(c1h(k)*muv(i,j )+c2h(k))*v_1(i,k,j )*msfvx_inv(i,j )) ) & +rdx*( (u(i+1,k,j)+(c1h(k)*muu(i+1,j)+c2h(k))*u_1(i+1,k,j)/msfuy(i+1,j)) & -(u(i,k,j )+(c1h(k)*muu(i ,j)+c2h(k))*u_1(i,k,j )/msfuy(i ,j)) )) DMDT(i) = DMDT(i) + dnw(k)*dvdxi(i,k) ENDDO ENDDO DO i=i_start, i_end MUAVE(i,j) = MU(i,j) MU(i,j) = MU(i,j)+dts*(DMDT(i)+MU_TEND(i,j)) MUDF(i,j) = (DMDT(i)+MU_TEND(i,j)) ! save tendency for div damp filter MUTS(i,j) = MUT(i,j)+MU(i,j) MUAVE(i,j) =.5*((1.+epssm)*MU(i,j)+(1.-epssm)*MUAVE(i,j)) ENDDO DO kk=2,k_end k=kk-1 DO i=i_start, i_end ww(i,kk,j)=ww(i,kk-1,j)-dnw(kk-1)*((c1h(k)*dmdt(i))+dvdxi(i,kk-1)+(c1h(k)*mu_tend(i,j)))/msfty(i,j) ENDDO END DO ! NOTE: ww_1 (large timestep ww) is already coupled with the ! map scale factor DO k=1,k_end DO i=i_start, i_end ww(i,k,j)=ww(i,k,j)-ww_1(i,k,j) END DO END DO ENDDO ! CALCULATION OF THETA ! NOTE: theta'' is not coupled with the map-scale factor, ! while the theta'' tendency is coupled (i.e., mult by 1/msft) ! Comments on map scale factors ! BUT NOTE THAT both are mass coupled ! in flux form equations (Klemp et al.) Theta = mu*theta ! ! scalar eqn: partial d/dt(rho q/my) = -mx[partial d/dx(q rho u/my) + ! partial d/dy(q rho v/mx)] ! - partial d/dz(q rho w/my) ! with rho -> mu, and with partial d/dnu(q rho nu/my) as the final term ! ! adding previous tendency contribution which was map scale factor coupled ! (had been divided by msfty) ! need to uncouple before updating uncoupled Theta (by adding) DO j=j_start, j_end DO k=1,k_end DO i=i_start, i_end t_ave(i,k,j) = t(i,k,j) t (i,k,j) = t(i,k,j) + msfty(i,j)*dts*ft(i,k,j) END DO END DO ENDDO DO j=j_start, j_end DO i=i_start, i_end wdtn(i,1 )=0. wdtn(i,kde)=0. ENDDO DO k=2,k_end DO i=i_start, i_end ! for scalar eqn RHS term 3 wdtn(i,k)= ww(i,k,j)*(fnm(k)*t_1(i,k ,j)+fnp(k)*t_1(i,k-1,j)) ENDDO ENDDO ! scalar eqn, RHS terms 1, 2 and 3 ! multiply by msfty to uncouple result for Theta from map scale factor DO k=1,k_end DO i=i_start, i_end ! multiplication by msfty uncouples result for Theta t(i,k,j) = t(i,k,j) - dts*msfty(i,j)*( & ! multiplication by mx needed for RHS terms 1 & 2 msftx(i,j)*( & .5*rdy* & ( v(i,k,j+1)*(t_1(i,k,j+1)+t_1(i,k, j )) & -v(i,k,j )*(t_1(i,k, j )+t_1(i,k,j-1)) ) & + .5*rdx* & ( u(i+1,k,j)*(t_1(i+1,k,j)+t_1(i ,k,j)) & -u(i ,k,j)*(t_1(i ,k,j)+t_1(i-1,k,j)) ) ) & + rdnw(k)*( wdtn(i,k+1)-wdtn(i,k) ) ) ENDDO ENDDO ENDDO END SUBROUTINE advance_mu_t !------------------------------------------------------------ SUBROUTINE advance_w( w, rw_tend, ww, w_save, u, v, & mu1, mut, muave, muts, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & t_2ave, t_2, t_1, & ph, ph_1, phb, ph_tend, & ht, c2a, cqw, alt, alb, & a, alpha, gamma, & rdx, rdy, dts, t0, epssm, & dnw, fnm, fnp, rdnw, rdn, & cf1, cf2, cf3, msftx, msfty,& config_flags, top_lid, & ids,ide, jds,jde, kds,kde, & ! domain dims ims,ime, jms,jme, kms,kme, & ! memory dims its,ite, jts,jte, kts,kte ) ! tile dims ! We have used msfty for msft_inv but have not thought through w equation ! pieces properly yet, so we will have to hope that it is okay ! We think we have found a slight error in surface w calculation IMPLICIT NONE ! religion first ! stuff coming in 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 LOGICAL, INTENT(IN ) :: top_lid REAL, DIMENSION( ims:ime , kms:kme , jms:jme ), & INTENT(INOUT) :: & t_2ave, & w, & ph REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(IN ) :: & rw_tend, & ww, & w_save, & u, & v, & t_2, & t_1, & ph_1, & phb, & ph_tend, & alpha, & gamma, & a, & c2a, & cqw, & alb, & alt REAL, DIMENSION( ims:ime , jms:jme ), & INTENT(IN ) :: & mu1, & mut, & muave, & muts, & ht, & msftx, & msfty REAL, DIMENSION( kms:kme ), INTENT(IN ) :: fnp, & fnm, & rdnw, & rdn, & dnw REAL, INTENT(IN ) :: rdx, & rdy, & dts, & cf1, & cf2, & cf3, & t0, & epssm REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f ! Stack based 3d data, tile size. REAL, DIMENSION( its:ite ) :: mut_inv, msft_inv REAL, DIMENSION( its:ite, kts:kte ) :: rhs, wdwn INTEGER :: i,j,k, i_start, i_end, j_start, j_end, k_start, k_end REAL, DIMENSION (kts:kte) :: dampwt real :: htop,hbot,hdepth,hk real :: pi,dampmag REAL :: muthk, muthkm1 ! ! ! advance_w advances the implicit w and geopotential equations. ! ! ! set loop limits. ! Currently set for periodic 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 = kte-1 IF ( .NOT. config_flags%periodic_x )THEN IF ( config_flags%specified .or. config_flags%nested ) then i_start = max(its,ids+1) i_end = min(ite,ide-2) ENDIF ENDIF IF ( config_flags%specified .or. config_flags%nested ) then j_start = max(jts,jds+1) j_end = min(jte,jde-2) ENDIF pi = 4.*atan(1.) dampmag = dts*config_flags%dampcoef hdepth=config_flags%zdamp ! calculation of phi and w equations ! Comments on map scale factors: ! phi equation is: ! partial d/dt(rho phi/my) = -mx partial d/dx(phi rho u/my) ! -mx partial d/dy(phi rho v/mx) ! - partial d/dz(phi rho w/my) + rho g w/my ! as with scalar equation, use uncoupled value (here phi) to find the ! coupled tendency (rho phi/my) ! here as usual rho -> ~'mu' ! ! w eqn [divided by my] is: ! partial d/dt(rho w/my) = -mx partial d/dx(w rho u/my) ! -mx partial d/dy(v rho v/mx) ! - partial d/dz(w rho w/my) ! +rho[(u*u+v*v)/a + 2 u omega cos(lat) - ! (1/rho) partial dp/dz - g + Fz]/my ! here as usual rho -> ~'mu' ! ! 'u,v,w' sent here must be coupled variables (= rho w/my etc.) by their usage DO i=i_start, i_end rhs(i,1) = 0. ENDDO j_loop_w: DO j = j_start, j_end DO i=i_start, i_end msft_inv(i) = 1./msfty(i,j) ENDDO DO k=1, k_end DO i=i_start, i_end t_2ave(i,k,j)=.5*((1.+epssm)*t_2(i,k,j) & +(1.-epssm)*t_2ave(i,k,j)) t_2ave(i,k,j)=(t_2ave(i,k,j) + (c1h(k)*Muave(i,j))*t0) & /((c1h(k)*Muts(i,j)+c2h(k))*(t0+t_1(i,k,j))) wdwn(i,k+1)=.5*(ww(i,k+1,j)+ww(i,k,j))*rdnw(k) & *(ph_1(i,k+1,j)-ph_1(i,k,j)+phb(i,k+1,j)-phb(i,k,j)) rhs(i,k+1) = dts*(ph_tend(i,k+1,j) + .5*g*(1.-epssm)*w(i,k+1,j)) ENDDO ENDDO ! building up RHS of phi equation ! ph_tend contains terms 1 and 2; now adding 3 and 4 in stages: ! here rhs = delta t [ph_tend + ~g*w/2 - ~ww * partial d phi/dz] DO k=2,k_end DO i=i_start, i_end rhs(i,k) = rhs(i,k)-dts*( fnm(k)*wdwn(i,k+1) & +fnp(k)*wdwn(i,k ) ) ENDDO ENDDO ! NOTE: phi'' is not coupled with the map-scale factor (1/m), ! but it's tendency is, so must multiply by msft here ! Comments on map scale factors: ! building up RHS of phi equation ! ph_tend contains terms 1 and 2; now adding 3 and 4 in stages: ! here rhs = ph_previous + (msft/mu)*[rhs_previous - ~ww * delta t * ! partial d phi/dz] ! = ph_previous + (msft*delta t/mu)*[ph_tend + ~g*w/2 - ~ww * ! partial d phi/dz] DO k=2,k_end+1 DO i=i_start, i_end rhs(i,k) = ph(i,k,j) + msfty(i,j)*rhs(i,k)/(c1f(k)*mut(i,j)+c2f(k)) if(top_lid .and. k.eq.k_end+1)rhs(i,k)=0. ENDDO ENDDO ! lower boundary condition on w ! Comments 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] ! [cf1, cf2 and cf3 do vertical weighting of u or v values nearest ! the surface] DO i=i_start, i_end 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 ! ! Jammed 3 doubly nested loops over k/i into 1 for slight improvement ! in efficiency. No change in results (bit-for-bit). JM 20040514 ! (left a blank line where the other two k/i-loops were) ! ! above surface, begin by adding delta t * previous (coupled) w tendency DO k=2,k_end DO i=i_start, i_end w(i,k,j)=w(i,k,j)+dts*rw_tend(i,k,j) & + msft_inv(i)*cqw(i,k,j)*( & +.5*dts*g*rdn(k)* & (c2a(i,k ,j)*rdnw(k )/(c1h(k)*MUT(i,j)+c2h(k)) & *((1.+epssm)*(rhs(i,k+1 )-rhs(i,k )) & +(1.-epssm)*(ph(i,k+1,j)-ph(i,k ,j))) & -c2a(i,k-1,j)*rdnw(k-1)/(c1h(k-1)*MUT(i,j)+c2h(k-1)) & *((1.+epssm)*(rhs(i,k )-rhs(i,k-1 )) & +(1.-epssm)*(ph(i,k ,j)-ph(i,k-1,j))))) & +dts*g*msft_inv(i)*(rdn(k)* & (c2a(i,k ,j)*alt(i,k ,j)*t_2ave(i,k ,j) & -c2a(i,k-1,j)*alt(i,k-1,j)*t_2ave(i,k-1,j)) & - (c1f(k)*muave(i,j))) ENDDO ENDDO K=k_end+1 DO i=i_start, i_end w(i,k,j)=w(i,k,j)+dts*rw_tend(i,k,j) & +msft_inv(i)*( & -.5*dts*g/(c1h(k-1)*MUT(i,j)+c2h(k-1))*rdnw(k-1)**2*2.*c2a(i,k-1,j) & *((1.+epssm)*(rhs(i,k )-rhs(i,k-1 )) & +(1.-epssm)*(ph(i,k,j)-ph(i,k-1,j))) & -dts*g*(2.*rdnw(k-1)* & c2a(i,k-1,j)*alt(i,k-1,j)*t_2ave(i,k-1,j) & + (c1f(k)*muave(i,j))) ) if(top_lid)w(i,k,j) = 0. ENDDO DO k=2,k_end+1 DO i=i_start, i_end w(i,k,j)=(w(i,k,j)-a(i,k,j)*w(i,k-1,j))*alpha(i,k,j) ENDDO ENDDO DO k=k_end,2,-1 DO i=i_start, i_end w (i,k,j)=w (i,k,j)-gamma(i,k,j)*w(i,k+1,j) ENDDO ENDDO IF (config_flags%damp_opt .eq. 3) THEN DO k=k_end+1,2,-1 DO i=i_start, i_end htop=(ph_1(i,k_end+1,j)+phb(i,k_end+1,j))/g hk=(ph_1(i,k,j)+phb(i,k,j))/g hbot=htop-hdepth dampwt(k) = 0. if(hk .ge. hbot)then dampwt(k) = dampmag*sin(0.5*pi*(hk-hbot)/hdepth)*sin(0.5*pi*(hk-hbot)/hdepth) endif w(i,k,j) = (w(i,k,j) - dampwt(k)*(c1f(k)*mut(i,j)+c2f(k))*w_save(i,k,j))/(1.+dampwt(k)) ENDDO ENDDO ENDIF DO k=k_end+1,2,-1 DO i=i_start, i_end ph(i,k,j) = rhs(i,k)+msfty(i,j)*.5*dts*g*(1.+epssm) & *w(i,k,j)/(c1f(k)*muts(i,j)+c2f(k)) ENDDO ENDDO ENDDO j_loop_w END SUBROUTINE advance_w !--------------------------------------------------------------------- SUBROUTINE sumflux ( ru, rv, ww, & u_lin, v_lin, ww_lin, & muu, muv, & c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f, & ru_m, rv_m, ww_m, epssm, & msfux, msfuy, msfvx, msfvx_inv, msfvy, & iteration , number_of_small_timesteps, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! religion first ! declarations for the stuff coming in INTEGER, INTENT(IN ) :: number_of_small_timesteps INTEGER, INTENT(IN ) :: iteration 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(IN ) :: ru, & rv, & ww, & u_lin, & v_lin, & ww_lin REAL, DIMENSION(ims:ime, kms:kme, jms:jme) , INTENT(INOUT) :: ru_m, & rv_m, & ww_m REAL, DIMENSION(ims:ime, jms:jme) , INTENT(IN ) :: muu, muv, & msfux, msfuy, & msfvx, msfvy, msfvx_inv REAL, DIMENSION( kms:kme ),INTENT(IN ) :: c1h, c2h, c1f, c2f, & c3h, c4h, c3f, c4f INTEGER :: mini, minj, mink REAL, INTENT(IN ) :: epssm INTEGER :: i,j,k ! ! ! update the small-timestep time-averaged mass fluxes; these ! are needed for consistent mass-conserving scalar advection. ! ! IF (iteration == 1 )THEN DO j = jts, jte DO k = kts, kte DO i = its, ite ru_m(i,k,j) = 0. rv_m(i,k,j) = 0. ww_m(i,k,j) = 0. ENDDO ENDDO ENDDO ENDIF mini = min(ide-1,ite) minj = min(jde-1,jte) mink = min(kde-1,kte) DO j = jts, minj DO k = kts, mink DO i = its, mini ru_m(i,k,j) = ru_m(i,k,j) + ru(i,k,j) rv_m(i,k,j) = rv_m(i,k,j) + rv(i,k,j) ww_m(i,k,j) = ww_m(i,k,j) + ww(i,k,j) ENDDO ENDDO ENDDO IF (ite .GT. mini) THEN DO j = jts, minj DO k = kts, mink DO i = mini+1, ite ru_m(i,k,j) = ru_m(i,k,j) + ru(i,k,j) ENDDO ENDDO ENDDO END IF IF (jte .GT. minj) THEN DO j = minj+1, jte DO k = kts, mink DO i = its, mini rv_m(i,k,j) = rv_m(i,k,j) + rv(i,k,j) ENDDO ENDDO ENDDO END IF IF ( kte .GT. mink) THEN DO j = jts, minj DO k = mink+1, kte DO i = its, mini ww_m(i,k,j) = ww_m(i,k,j) + ww(i,k,j) ENDDO ENDDO ENDDO END IF IF (iteration == number_of_small_timesteps) THEN DO j = jts, minj DO k = kts, mink DO i = its, mini ru_m(i,k,j) = ru_m(i,k,j) / number_of_small_timesteps & + (c1h(k)*muu(i,j)+c2h(k))*u_lin(i,k,j)/msfuy(i,j) rv_m(i,k,j) = rv_m(i,k,j) / number_of_small_timesteps & + (c1h(k)*muv(i,j)+c2h(k))*v_lin(i,k,j)*msfvx_inv(i,j) ww_m(i,k,j) = ww_m(i,k,j) / number_of_small_timesteps & + ww_lin(i,k,j) ENDDO ENDDO ENDDO IF (ite .GT. mini) THEN DO j = jts, minj DO k = kts, mink DO i = mini+1, ite ru_m(i,k,j) = ru_m(i,k,j) / number_of_small_timesteps & + (c1h(k)*muu(i,j)+c2h(k))*u_lin(i,k,j)/msfuy(i,j) ENDDO ENDDO ENDDO END IF IF (jte .GT. minj) THEN DO j = minj+1, jte DO k = kts, mink DO i = its, mini rv_m(i,k,j) = rv_m(i,k,j) / number_of_small_timesteps & + (c1h(k)*muv(i,j)+c2h(k))*v_lin(i,k,j)*msfvx_inv(i,j) ENDDO ENDDO ENDDO END IF IF ( kte .GT. mink) THEN DO j = jts, minj DO k = mink+1, kte DO i = its, mini ww_m(i,k,j) = ww_m(i,k,j) / number_of_small_timesteps & + ww_lin(i,k,j) ENDDO ENDDO ENDDO END IF ENDIF END SUBROUTINE sumflux !--------------------------------------------------------------------- SUBROUTINE init_module_small_step END SUBROUTINE init_module_small_step #if ( WRFPLUS == 1 ) !---------------------------------------------------------------------- SUBROUTINE advance_all (u, ru_tend, v, rv_tend, & w, rw_tend, t, t_tend, & mu, mu_tend, ph, ph_tend, & muu, muv, mut, & msfuy, msfvx, msfty, & dts, & config_flags, spec_zone, & ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & ips, ipe, jps, jpe, kps, kpe, & its, ite, jts, jte, kts, kte ) IMPLICIT NONE ! religion first 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 ) :: ips,ipe, jps,jpe, kps,kpe INTEGER, INTENT(IN ) :: its,ite, jts,jte, kts,kte INTEGER, INTENT(IN ) :: spec_zone REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(INOUT) :: & u, & v, & w, & t, & ph REAL, DIMENSION( ims:ime , kms:kme, jms:jme ), & INTENT(IN ) :: & ru_tend, & rv_tend, & rw_tend, & t_tend, & ph_tend REAL, DIMENSION( ims:ime , jms:jme ), INTENT(INOUT) :: mu REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: mu_tend REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: muu, & muv, & mut REAL, DIMENSION( ims:ime , jms:jme ), INTENT(IN ) :: msfuy, & msfvx, & msfty REAL, INTENT(IN ) :: dts INTEGER :: i,j,k, i_start, i_end, j_start, j_end, k_start, k_end INTEGER :: i_endu, j_endv, k_endw INTEGER :: i_start_u_tend, i_end_u_tend, j_start_v_tend, j_end_v_tend ! ! ! advance_all advances the explicit perturbation horizontal momentum ! equations (u,v) by adding in the large-timestep tendency along with ! the small timestep pressure gradient tendency. ! ! ! now, the real work. ! set the loop bounds taking into account boundary conditions. IF( config_flags%nested .or. config_flags%specified ) THEN i_start = max( its,ids+spec_zone ) i_end = min( ite,ide-spec_zone-1 ) j_start = max( jts,jds+spec_zone ) j_end = min( jte,jde-spec_zone-1 ) k_start = kts k_end = min( kte, kde-1 ) i_endu = min( ite,ide-spec_zone ) j_endv = min( jte,jde-spec_zone ) k_endw = k_end IF( config_flags%periodic_x) THEN i_start = its i_end = min(ite,ide-1) i_endu = ite ENDIF ELSE i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) k_start = kts k_end = kte-1 i_endu = ite j_endv = jte k_endw = k_end ENDIF i_start_u_tend = i_start i_end_u_tend = i_endu j_start_v_tend = j_start j_end_v_tend = j_endv IF ( config_flags%symmetric_xs .and. (its == ids) ) & i_start_u_tend = i_start_u_tend+1 IF ( config_flags%symmetric_xe .and. (ite == ide) ) & i_end_u_tend = i_end_u_tend-1 IF ( config_flags%symmetric_ys .and. (jts == jds) ) & j_start_v_tend = j_start_v_tend+1 IF ( config_flags%symmetric_ye .and. (jte == jde) ) & j_end_v_tend = j_end_v_tend-1 u_outer_j_loop: DO j = j_start, j_end DO k = k_start, k_end DO i = i_start_u_tend, i_end_u_tend u(i,k,j) = u(i,k,j) + dts*ru_tend(i,k,j)*msfuy(i,j)/muu(i,j) ENDDO ENDDO ENDDO u_outer_j_loop v_outer_j_loop: DO j = j_start_v_tend, j_end_v_tend DO k = k_start, k_end DO i = i_start, i_end v(i,k,j) = v(i,k,j) + dts*rv_tend(i,k,j)*msfvx(i,j)/muv(i,j) ENDDO ENDDO ENDDO v_outer_j_loop i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) k_start = kts k_end = kte-1 IF ( .NOT. config_flags%periodic_x )THEN IF ( config_flags%specified .or. config_flags%nested ) then i_start = max(its,ids+1) i_end = min(ite,ide-2) ENDIF ENDIF IF ( config_flags%specified .or. config_flags%nested ) then j_start = max(jts,jds+1) j_end = min(jte,jde-2) ENDIF DO j = j_start, j_end DO i=i_start, i_end mu(i,j) = mu(i,j)+dts*mu_tend(i,j) ENDDO ENDDO DO j=j_start, j_end DO k=1,k_end DO i=i_start, i_end t(i,k,j) = t(i,k,j) + msfty(i,j)*dts*t_tend(i,k,j)/mut(i,j) END DO END DO ENDDO i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) k_start = kts k_end = kte-1 IF ( .NOT. config_flags%periodic_x )THEN IF ( config_flags%specified .or. config_flags%nested ) then i_start = max(its,ids+1) i_end = min(ite,ide-2) ENDIF ENDIF IF ( config_flags%specified .or. config_flags%nested ) then j_start = max(jts,jds+1) j_end = min(jte,jde-2) ENDIF IF ( config_flags%non_hydrostatic ) THEN j_loop_w: DO j = j_start, j_end DO k=2,k_end+1 DO i=i_start, i_end w(i,k,j)=w(i,k,j)+dts*rw_tend(i,k,j)*msfty(i,j)/mut(i,j) ph(i,k,j) = ph(i,k,j)+dts*ph_tend(i,k,j)*msfty(i,j)/mut(i,j) ENDDO ENDDO ENDDO j_loop_w ENDIF END SUBROUTINE advance_all !---------------------------------------------------------------------- SUBROUTINE save_ph_mu ( ph_1, ph_2, ph_save, & mu_1, mu_2, mu_save, & rk_step, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! religion first ! declarations for the stuff coming in 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 INTEGER, INTENT(IN ) :: rk_step REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT) :: ph_1 REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT( OUT) :: ph_save REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT) :: ph_2 REAL, DIMENSION(ims:ime, jms:jme), INTENT(INOUT) :: mu_1,mu_2 REAL, DIMENSION(ims:ime, jms:jme), INTENT( OUT) :: mu_save ! local variables INTEGER :: i, j, k INTEGER :: i_start, i_end, j_start, j_end, k_start, k_end 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) ! if this is the first RK step, reset *_1 to *_2 ! (we are replacing the t-dt fields with the time t fields) IF ((rk_step == 1) ) THEN DO j=j_start, j_end DO k=k_start, min(kde,kte) DO i=i_start, i_end ph_1(i,k,j) = ph_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO i=i_start, i_end mu_1(i,j)=mu_2(i,j) ENDDO ENDDO END IF ! set up the small timestep variables DO j=j_start, j_end ! DO k=k_start, min(kde,kte) DO k=k_start, kde DO i=i_start, i_end ph_save(i,k,j) = ph_2(i,k,j) ph_2(i,k,j) = ph_1(i,k,j)-ph_2(i,k,j) ENDDO ENDDO ENDDO DO j=j_start, j_end DO i=i_start, i_end mu_save(i,j)=mu_2(i,j) mu_2(i,j)=mu_1(i,j)-mu_2(i,j) ENDDO ENDDO END SUBROUTINE save_ph_mu !---------------------------------------------------------------------- SUBROUTINE restore_ph_mu ( ph_2, ph_save, & mu_2, mu_save, & ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte ) IMPLICIT NONE ! religion first ! declarations for the stuff coming in 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(IN ) :: ph_save REAL, DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT) :: ph_2 REAL, DIMENSION(ims:ime, jms:jme), INTENT(INOUT) :: mu_2 REAL, DIMENSION(ims:ime, jms:jme), INTENT(IN ) :: mu_save ! local variables INTEGER :: i, j, k INTEGER :: i_start, i_end, j_start, j_end i_start = its i_end = min(ite,ide-1) j_start = jts j_end = min(jte,jde-1) DO j = j_start, j_end DO k = kds, kde DO i = i_start, i_end ph_2(i,k,j) = ph_2(i,k,j) + ph_save(i,k,j) ENDDO ENDDO ENDDO DO j = j_start, j_end DO i = i_start, i_end mu_2(i,j) = mu_2(i,j) + mu_save(i,j) ENDDO ENDDO END SUBROUTINE restore_ph_mu !---------------------------------------------------------------------- #endif END MODULE module_small_step_em