4 USE module_model_constants
7 REAL(KIND=8), PARAMETER :: eps = 1.0d-08
8 REAL, PARAMETER :: alpha_max = 1.1
9 REAL, PARAMETER :: alpha_min = 0.8
13 LOGICAL FUNCTION CHK_IEVA( config_flags, rk_step )
17 TYPE(grid_config_rec_type), INTENT(IN) :: config_flags
18 INTEGER, INTENT(IN) :: rk_step
20 INTEGER :: zadvect_implicit
23 rk_order = config_flags%rk_ord
24 zadvect_implicit = config_flags%zadvect_implicit
28 ! These option to run on the sub-steps are off - they dont make much of a difference
30 ! IF( zadvect_implicit .eq. 3 ) THEN ! DO IEVA on all sub-steps of RK integrator
34 ! IF( zadvect_implicit .eq. 2 .and. rk_step .ge. rk_order-1 ) THEN ! DO IEVA on last two sub-steps of RK integrator
38 IF( zadvect_implicit .gt. 0 .and. rk_step .eq. rk_order ) THEN ! DO IEVA on last sub-step of RK integrator
45 !-------------------------------------------------------------------------------
46 ! IEVA code for splitting vertical velocity into pieces for explicit and implicit
47 ! advection by the routines based on Shchepetkin (2015)
49 SUBROUTINE WW_SPLIT(wwE, wwI, &
53 rdx, rdy, msfux, msfuy, &
55 config_flags, rk_step, &
56 ids, ide, jds, jde, kds, kde, &
57 ims, ime, jms, jme, kms, kme, &
58 its, ite, jts, jte, kts, kte )
60 TYPE( grid_config_rec_type ) , INTENT(IN ) :: config_flags
62 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
63 ims, ime, jms, jme, kms, kme, &
64 its, ite, jts, jte, kts, kte, &
67 REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(IN ) :: u, v, ww
69 REAL, DIMENSION( ims:ime, kms:kme , jms:jme ), INTENT(INOUT) :: wwE, wwI
71 REAL, DIMENSION( ims:ime, jms:jme ), INTENT(IN ) :: mut
73 REAL, DIMENSION( kms:kme ), INTENT(IN ) :: rdnw
74 REAL, DIMENSION( kms:kme ), INTENT(IN ) :: c1f, c2f
76 REAL, INTENT(IN) :: dt
77 REAL, INTENT(IN) :: rdx, rdy
78 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, msfuy
79 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfvx, msfvy, msfty
83 REAL(KIND=4) :: cr, cx, cy, c0, c2d, cw_max2, cw_min, cw, cff, rdz
84 INTEGER :: i, j, k, ii, jj, i_start, i_end, j_start, j_end, ktf
85 LOGICAL :: print_flag = .true.
87 LOGICAL :: degrade_xs, degrade_ys, degrade_xe, degrade_ye
89 ! Implicit advection parameters based on Shchepetkin (2015)
90 ! Moved these to the top of the module.
92 ! REAL, PARAMETER :: alpha_max = 1.1
93 ! REAL, PARAMETER :: alpha_min = 0.9
94 REAL, PARAMETER :: cmnx_ratio = alpha_min/alpha_max
95 REAL, PARAMETER :: cutoff = 2.0 - cmnx_ratio
96 REAL, PARAMETER :: r4cmx = 1.0/(4.0 - 4.0*cmnx_ratio )
97 REAL, PARAMETER :: Ceps = 0.9
103 ! REAL, PARAMETER :: binfrac = 0.1
104 ! INTEGER, PARAMETER :: binsize = 11
105 ! INTEGER :: count(binsize)
106 ! real(KIND=4) :: binavg(binsize), crs(binsize)
108 ! Check to see if IEVA is on for this RK3 substep
110 ieva = CHK_IEVA(config_flags, rk_step)
112 ! =========================================================================
113 ! Loop limits: need to compute wwE & wwI one halo ring out for staggered variables.
117 i_end = MIN(ite,ide-1)+1
119 j_end = MIN(jte,jde-1)+1
122 ! =========================================================================
123 ! PRINT OUT IEVA INFO
125 IF( print_flag .and. ieva ) THEN
126 write(wrf_err_message,*) '-- BEGIN WW_SPLIT INFO ----------------------------------------'
127 CALL wrf_debug( 0, wrf_err_message )
128 write(wrf_err_message,*) 'RK_STEP ##', rk_step
129 CALL wrf_debug( 0, wrf_err_message )
130 write(wrf_err_message,*) 'IMS:IME / JME:JME ', ims, ime, jms, jme
131 CALL wrf_debug( 0, wrf_err_message )
132 write(wrf_err_message,*) 'ISTART:IEND / JSTART:JEND ', i_start,i_end,j_start,j_end
133 CALL wrf_debug( 0, wrf_err_message )
134 write(wrf_err_message,*) 'KMS:KME / KDS:KDE KTS:KTE ', kms,kme,kds,kde,kts,kte
135 CALL wrf_debug( 0, wrf_err_message )
136 write(wrf_err_message,*) '----------------------------------------'
137 CALL wrf_debug( 0, wrf_err_message )
138 write(wrf_err_message,*) 'WW_SPLIT: ZADVECT_IMPLICT = ', config_flags%zadvect_implicit
139 CALL wrf_debug( 0, wrf_err_message )
140 write(wrf_err_message,*) 'WW_SPLIT: IEVA = ', ieva
141 CALL wrf_debug( 0, wrf_err_message )
142 IF( config_flags%zadvect_implicit > 1 ) THEN
143 write(wrf_err_message,*) 'WW_SPLIT: WARNING: IEVA IS CONFIG TO ONLY RUN ON LAST RK-substep'
144 CALL wrf_debug( 0, wrf_err_message )
146 write(wrf_err_message,*) 'WW_SPLIT: dt = ', dt
147 CALL wrf_debug( 0, wrf_err_message )
148 write(wrf_err_message,*) 'WW_SPLIT: alpha_max/min = ', alpha_max, alpha_min
149 CALL wrf_debug( 0, wrf_err_message )
150 write(wrf_err_message,*) '-- END WW_SPLIT INFO ----------------------------------------'
151 CALL wrf_debug( 0, wrf_err_message )
155 ! =========================================================================
158 IF( ieva ) THEN ! Implicit adaptive advection
160 !=========================================================================
167 !=========================================================================
169 DO j = j_start, j_end
171 DO i = i_start, i_end
178 ! Set upper and lower boundary values to be explicit advection
180 DO j = j_start, j_end
183 wwE(i,1,j) = ww(i, 1,j)
186 wwE(i,ktf,j) = ww(i,ktf,j)
192 DO j = j_start, j_end
198 !===================================================================================================
200 ! Translating Shchepetkin (2015, hereafter S2015), all the volumes and surface areas cancel out (not obvious
201 ! unless you read the definitions of U, V, and W right after equation 3.7; they are u*dy*dz, v*dx*dz, w*dx*dy)...
202 ! You can write the algorithm using the adjusted maximum vertical courant number (alpha_max - eps*hor_div)
203 ! versus the actual vertical courant number. This code is based on the appendix C of Shchepetkin (2015).
204 ! The CX and CY measure the maximum possible divergence for a zone, e.g., the Lipschlitz number. If
205 ! this number ~O(1), then the maximum allowed vertical courant number for the explicit advection is close
206 ! to zeros, the scheme switches to fully implicit. Ceps is a fudge factor for when the vertical and
207 ! horizontal discretizations are of different order. It is set to 0.9, which allows the some headroom for
208 ! the maximum horizontal Courant number since we are using an RK3 integrator which has a larger stability
209 ! region than the integrators used in Shchepetkin (2015).
211 !===================================================================================================
213 ! S2015 Lipshlitz courant number. Sometimes it can be touchy so we use simpler estimate below
215 ! IF( ww(i,k,j) < 0.0 ) THEN !! Omega has opposite sign of W
216 ! cx = rdx*(max(u(i+1,k,j ), 0.0) - min(u(i,k,j), 0.0))
217 ! cy = rdy*(max(v(i, k,j+1), 0.0) - min(v(i,k,j), 0.0))
219 ! cx = rdx*(max(u(i+1,k-1,j ), 0.0) - min(u(i,k-1,j), 0.0))
220 ! cy = rdy*(max(v(i, k-1,j+1), 0.0) - min(v(i,k-1,j), 0.0))
223 ! cw_max = max(alpha_max - dt*Ceps*(cx + cy),0.0) ! S2015 adjusted max vertical courant
225 ! Compute a mean flow courant number to adjust the max vertical courant number
227 cx = 0.25*rdx*(u(i+1,k,j ) + u(i,k,j) + u(i+1,k-1,j ) + u(i,k-1,j))
228 cy = 0.25*rdy*(v(i, k,j+1) + v(i,k,j) + v(i ,k-1,j+1) + v(i,k-1,j))
230 cw_max = max(alpha_max - dt*Ceps*sqrt(cx**2 + cy**2),0.0) ! simpler adjusted max vertical courant
232 cr = ww(i,k,j) * dt * rdnw(k) / (c1f(k)*mut(i,j)+c2f(k)) ! the actual vertical courant number
234 IF( cw_max > 0.0 ) THEN
236 wfrac = 1.0 ! initialize wfrac
239 cw_min = cw_max*cmnx_ratio
242 if ( cw < cw_min ) then
244 elseif ( cw < cutoff*cw_min ) then
245 cff = cw_max2 + r4cmx*(cw-cw_min)**2
250 wfrac = cw_max2 / cff
251 wfrac = amax1(amin1(wfrac, 1.0), 0.0)
253 wwE(i,k,j) = ww(i,k,j) * wfrac
254 wwI(i,k,j) = ww(i,k,j) * (1.0 - wfrac)
256 !=========================================================================
257 ! DEBUG CODE BLOCK: compute distribution of wfrac
260 ! IF( (mm-1)*binfrac / wfrac <= 1.0 .and. &
261 ! mm*binfrac / wfrac > 1.0 ) THEN
262 ! count(mm) = count(mm) + 1
263 ! binavg(mm) = binavg(mm) + wfrac
264 ! crs(mm) = crs(mm) + cw
268 !=========================================================================
270 ELSE ! If cw_max <= 0 - then the horizontal flow is very fast
271 ! so do all vertical transport implicitly
273 !=========================================================================
274 ! DEBUG CODE BLOCK: write out information when fully implicit
276 ! write(wrf_err_message,*) '-- BEGIN WW_SPLIT ----------------------------------------'
277 ! CALL wrf_debug(100, wrf_err_message )
278 ! write(wrf_err_message,*) ' MAX VERTICAL CFL ~ 0: i,j,k, cw_max, dt*(cx+cy) ',i,j,k,cw_max,Ceps*dt*(cx+cy)
279 ! CALL wrf_debug(100, wrf_err_message )
280 ! write(wrf_err_message,*) '-- END WW_SPLIT ----------------------------------------'
281 ! CALL wrf_debug( 100, wrf_err_message )
283 !=========================================================================
286 wwI(i,k,j) = ww(i,k,j)
294 ELSE ! NOT doing IEVA, pure explicit advection
296 DO j = j_start, j_end
299 wwE(i,k,j) = ww(i,k,j)
307 !=========================================================================
308 ! DEBUG - print distribution of wfrac
310 ! write(wrf_err_message,*) '-- BEGIN WW_SPLIT ----------------------------------------'
311 ! CALL wrf_debug( 100, wrf_err_message )
313 ! write(wrf_err_message,FMT='(a, 2(2x,f4.2),2x,i9,2(2x,f6.4))' ) &
314 ! 'WW_SPLIT: BIN #, count', (mm-1)*binfrac, mm*binfrac, count(mm), binavg(mm)/(count(mm)+1), crs(mm)/(count(mm)+1)
315 ! CALL wrf_debug( 100, wrf_err_message )
317 ! write(wrf_err_message,*) '-- END WW_SPLIT ----------------------------------------'
318 ! CALL wrf_debug( 100, wrf_err_message )
320 !=========================================================================
323 END SUBROUTINE WW_SPLIT
326 SUBROUTINE TRIDIAG2D(a, b, c, r, bb, is, ie, istart, iend, ks, ke, kstart, kend)
327 !--------------------------------------------------------------------------------------------------
328 ! Solves for a vector u of length n the tridiagonal linear set ! from numerical recipes
329 ! m u = r, where a, b and c are the three main diagonals of matrix !
330 ! m(n,n), the other terms are 0. r is the right side vector. !
332 ! a(1) and c(n) are not used in the calculation
333 !--------------------------------------------------------------------------------------------------
335 integer, intent(in) :: is, ie, ks, ke, istart, iend, kstart, kend
336 real(kind=8), dimension(is:ie,ks:ke), intent(in) :: a, b, c, r
337 real(kind=8), dimension(is:ie,ks:ke), intent(inout) :: bb
341 ! real(kind=8), dimension(ks:ke) :: gam
342 ! real(kind=8), dimension(is:ie) :: bet
343 real(kind=8), dimension(ks:ke) :: gam
344 real(kind=8), dimension(is:ie) :: bet
347 ! Copy into temp storage...
355 ! IF ( ANY( bet < 1.0e-15 ) ) THEN
356 ! write(wrf_err_message,*) '----------------------------------------'
357 ! CALL wrf_debug( 0, wrf_err_message )
358 ! write(wrf_err_message,*) "TriDiag2D Error!!! Min value of diagonal is ", minval(bet)
359 ! CALL wrf_debug( 0, wrf_err_message )
360 ! write(wrf_err_message,*) '----------------------------------------'
361 ! CALL wrf_debug( 0, wrf_err_message )
367 bb(i,kstart) = r(i,kstart)/bet(i)
369 DO k = kstart+1, kend
371 gam(k) = c(i,k-1) / bet(i)
372 bet(i) = b(i,k) - a(i,k) * gam(k)
374 bb(i,k) = ( r(i,k) - a(i,k) * bb(i,k-1) ) / bet(i)
378 DO k = kend-1, kstart, -1
380 bb(i,k) = bb(i,k) - gam(k+1) * bb(i,k+1)
386 END SUBROUTINE TRIDIAG2D
387 !--------------------------------------------------------------------------------------------------
388 SUBROUTINE TRIDIAG(a, b, c, r, bb, ks, ke, kstart, kend)
389 !--------------------------------------------------------------------------------------------------
390 ! Solves for a vector u of length n the tridiagonal linear set ! from numerical recipes
391 ! m u = r, where a, b and c are the three main diagonals of matrix !
392 ! m(n,n), the other terms are 0. r is the right side vector. !
394 ! a(1) and c(n) are not used in the calculation
395 !--------------------------------------------------------------------------------------------------
398 integer, intent(in) :: ks, ke, kstart, kend
399 real(kind=4), dimension(ks:ke), intent(in ) :: a, b, c, r
400 real(kind=4), dimension(ks:ke), intent(out) :: bb
406 real(kind=4), dimension(size(b,1)) :: gam
412 bb(kstart) = r(kstart)/bet
414 DO k = kstart+1, kend
416 gam(k) = c(k-1) / bet
417 bet = b(k) - a(k) * gam(k)
419 bb(k) = ( r(k) - a(k) * bb(k-1) ) / bet
423 DO k = kend-1, kstart, -1
424 bb(k) = bb(k) - gam(k+1) * bb(k+1)
427 END SUBROUTINE TRIDIAG
428 !-------------------------------------------------------------------------------
431 SUBROUTINE CALC_MUT_NEW( u, v, c1h, c2h, &
432 mut_old, muu, muv, mut_new, &
433 dt, rdx, rdy, msftx, msfty, &
434 msfux, msfuy, msfvx, msfvx_inv, &
436 ids, ide, jds, jde, kds, kde, &
437 ims, ime, jms, jme, kms, kme, &
438 its, ite, jts, jte, kts, kte )
445 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
446 ims, ime, jms, jme, kms, kme, &
447 its, ite, jts, jte, kts, kte
449 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: u, v
450 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mut_old, muu, muv, &
455 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: rdnw
456 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: c1h, c2h
458 REAL , DIMENSION( ims:ime, jms:jme ) , INTENT(OUT ) :: mut_new
459 REAL , INTENT(IN) :: dt, rdx, rdy
463 INTEGER :: i, j, k, ktf, i_start, i_end, j_start, j_end
464 REAL , DIMENSION( its-1:ite ) :: dmdt
465 REAL , DIMENSION( its-1:ite, kts:kte ) :: divv
470 ! The algorithm integrates the continuity equation through the column
471 ! to find a new column mass needed for IEVA calculations
479 i_end = MIN(ite,ide-1)
481 j_end = MIN(jte,jde-1)
484 DO j = j_start, j_end
486 DO i = i_start, i_end
490 ! Comments on the modifications for map scale factors
491 ! ADT eqn 47 / my (putting rho -> 'mu') is:
492 ! (1/my) partial d mu/dt = -mx partial d/dx(mu u/my)
493 ! -mx partial d/dy(mu v/mx)
494 ! -partial d/dz(mu w/my)
496 ! Using nu instead of z the last term becomes:
497 ! -partial d/dnu((c1(k)*mu(dnu/dt))/my)
499 ! Integrating with respect to nu over ALL levels, with dnu/dt=0 at top
500 ! and bottom, the last term becomes = 0
502 ! Integral|bot->top[(1/my) partial d mu/dt]dnu =
503 ! Integral|bot->top[-mx partial d/dx(mu u/my)
504 ! -mx partial d/dy(mu v/mx)]dnu
506 ! muu='mu'[on u]/my, muv='mu'[on v]/mx
507 ! (1/my) partial d mu/dt is independent of nu
508 ! => LHS = Integral|bot->top[con]dnu = conservation*(-1) = -dmdt
510 ! => dmdt = mx*Integral|bot->top[partial d/dx(mu u/my) +
511 ! partial d/dy(mu v/mx)]dnu
512 ! => dmdt = sum_bot->top[divv]
514 ! divv=mx*[partial d/dx(mu u/my) + partial d/dy(mu v/mx)]*delta nu
517 DO i = i_start, i_end
519 divv(i,k) = (msftx(i,j) / rdnw(k)) * &
520 (rdx*((c1h(k)*muu(i+1,j)+c2h(k))*u(i+1,k,j)/msfuy(i+1,j)-(c1h(k)*muu(i,j)+c2h(k))*u(i,k,j)/msfuy(i,j)) &
521 +rdy*((c1h(k)*muv(i,j+1)+c2h(k))*v(i,k,j+1)*msfvx_inv(i,j+1)-(c1h(k)*muv(i,j)+c2h(k))*v(i,k,j)*msfvx_inv(i,j)) )
523 dmdt(i) = dmdt(i) + divv(i,k)
528 ! Further map scale factor notes:
529 ! Now integrate from bottom to top, level by level:
530 ! mu dnu/dt/my [k+1] = mu dnu/dt/my [k] + [-(1/my) partial d mu/dt
531 ! -mx partial d/dx(mu u/my)
532 ! -mx partial d/dy(mu v/mx)]*dnu[k->k+1]
533 ! ww [k+1] = ww [k] -(1/my) partial d mu/dt * dnu[k->k+1] - divv[k]
534 ! = ww [k] -dmdt * dnw[k] - divv[k]
537 DO i = i_start, i_end
539 mut_new(i,j) = mut_old(i,j) - dt*dmdt(i)
542 ! bigerr = (mut_new(i,j) / mut_old(i,j))
544 ! IF( abs(bigerr) > 2.0 .or. mut_old(i,j) < 0.0 ) THEN
545 ! write(wrf_err_message,*) '------------- CALC_MU_TMP ---------------------------'
546 ! CALL wrf_debug( 0, wrf_err_message )
547 ! write(wrf_err_message,*) 'MU_ERR: ', bigerr, mut_new(i,j), mut_old(i,j), dt, dt*dmdt(i)
548 ! CALL wrf_debug( 0, wrf_err_message )
557 END SUBROUTINE CALC_MUT_NEW
558 !-------------------------------------------------------------------------------
560 SUBROUTINE advect_ph_implicit( ph, pho, tendency, phb, &
561 ru, rv, wwE, wwI, w, &
564 msfux, msfuy, msfvx, msfvy, &
569 ids, ide, jds, jde, kds, kde, &
570 ims, ime, jms, jme, kms, kme, &
571 its, ite, jts, jte, kts, kte )
577 TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags
579 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
580 ims, ime, jms, jme, kms, kme, &
581 its, ite, jts, jte, kts, kte
583 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: ph, &
592 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: mut
593 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency
595 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, &
602 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, &
608 REAL , INTENT(IN ) :: rdx, &
610 REAL , INTENT(IN ) :: dt_rk
614 INTEGER :: i, j, k, itf, jtf, ktf
615 INTEGER :: i_start, i_end, j_start, j_end
616 INTEGER :: i_start_f, i_end_f, j_start_f, j_end_f
617 INTEGER :: jmin, jmax, jp, jm, imin, imax, im, ip
618 REAL :: wiL, wiR, wiC, weL, weR, dz
620 REAL(KIND=8), DIMENSION(its:ite,kts:kte) :: at, bt, ct, rt, bb
621 REAL(KIND=8), DIMENSION(its:ite) :: btmp(ims:ime)
624 INTEGER :: iup, jup, kup, idn, jdn, kdn, kp1, km1, valid_ik
628 i_end = MIN(ite,ide-1)
630 j_end = MIN(jte,jde-1)
632 ! Vertical loop to do implicit advection.....
633 ! Different from the other schemes - the advection here is not in flux form...
635 DO j = j_start, j_end
638 DO i = i_start, i_end
640 ! We are choosing to do the vertical advection here the same as in RHS_PH,
641 ! e.g., 2nd order box averaging instead of the usual upwinding...
642 ! Divide my mu(i,j) to make sure the diagnonal term is ~O(1)
645 wiC = 0.5*wwI(i,k,j)*(rdzw(k-1)+rdzw(k)) * msfty(i,j) / (c1(k)*mut(i,j)+c2(k))
646 at(i,k) = - dt_rk*max(wiC,0.0)
647 ct(i,k) = dt_rk*min(wiC,0.0)
648 btmp(i) = - at(i,k) - ct(i,k)
650 ! 2nd order centered for both implicit piece of advection
651 ! wiL = 0.5*(wwI(i,k-1,j)+wwI(i,k,j)) * rdzw(k-1) * msfty(i,j) / mut(i,j)
652 ! wiR = 0.5*(wwI(i,k+1,j)+wwI(i,k,j)) * rdzw(k) * msfty(i,j) / mut(i,j)
653 ! at(i,k) = - dt_rk*wiL*fzp(k)
654 ! ct(i,k) = dt_rk*wiR*fzm(k)
655 ! btmp(i) = - at(i,k) - ct(i,k)
659 bt(i,k) = 1.0 + btmp(i)
661 ! 2nd order centered for explict piece of advection (TURNED OFF AND COMPUTED IN RHS_PH)
663 ! weL = -dt_rk*fzp(k)*0.5*(wwE(i,k-1,j)+wwE(i,k,j)) * rdzw(k-1) * msfty(i,j) / mut(i,j)
664 ! weR = dt_rk*fzm(k)*0.5*(wwE(i,k+1,j)+wwE(i,k,j)) * rdzw(k) * msfty(i,j) / mut(i,j)
666 ! Eq here is more complicated because the solution to the tridiagonal is in phi', not total
667 ! phi. So we retain the vertical advection of phb on RHS.
669 rt(i,k) = tendency(i,k,j) * dt_rk * msfty(i,j) / (c1(k)*mut(i,j)+c2(k)) &
670 ! - weL*ph (i,k-1,j) + (weL + weR)*ph (i,k,j) - weR*ph (i,k+1,j) &
671 ! - weL*phb(i,k-1,j) + (weL + weR)*phb(i,k,j) - weR*phb(i,k+1,j) &
672 - at(i,k)*pho(i,k-1,j) - btmp(i)*pho(i,k,j) - ct(i,k)*pho(i,k+1,j) &
673 - at(i,k)*phb(i,k-1,j) - btmp(i)*phb(i,k,j) - ct(i,k)*phb(i,k+1,j)
675 ! BC's need because tendencies of phi, at kts and kte are not zero, so add them to RHS of Tridiagonal eqs
677 ! IF( k == kts+1 ) THEN
678 ! rt(i,k) = rt(i,k) - at(i,k)*(ph(i,k-1,j) - pho(i,k-1,j)) ! lower boundary condition
681 ! IF( k == ktf ) THEN ! upper boundary condition
682 ! rt(i,k) = rt(i,k) - ct(i,k) * (ph(i,k+1,j) - pho(i,k+1,j))
688 CALL tridiag2D(at, bt, ct, rt, bb, its, ite, i_start, i_end, kts, kte, kts+1, ktf)
691 DO i = i_start, i_end
693 tendency(i,k,j) = sngl(bb(i,k)) * (c1(k)*mut(i,j)+c2(k)) / dt_rk / msfty(i,j)
702 END SUBROUTINE advect_ph_implicit
703 !-------------------------------------------------------------------------------
705 SUBROUTINE advect_s_implicit( s, s_old, tendency, &
708 mut_old, mut, mut_new, &
710 msfux, msfuy, msfvx, msfvy, &
715 ids, ide, jds, jde, kds, kde, &
716 ims, ime, jms, jme, kms, kme, &
717 its, ite, jts, jte, kts, kte )
723 TYPE(grid_config_rec_type), INTENT(IN) :: config_flags
725 INTEGER , INTENT(IN) :: ids, ide, jds, jde, kds, kde, &
726 ims, ime, jms, jme, kms, kme, &
727 its, ite, jts, jte, kts, kte
729 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN) :: s, &
734 !-------------------------------------------------------------------------------
735 ! LWJ: definitions of various column masses
736 ! mut ==> current column mass from sub-step
737 ! mut_old ==> "n" time level column mass
738 ! mut_new ==> "n+1*" estimated column needed for dynamical variables where we dont
739 ! have time-avg column mass. For scalars (not theta) mut_new == mut
741 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN) :: mut, mut_old, mut_new
743 !-------------------------------------------------------------------------------
745 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency
747 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, &
754 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, &
760 REAL , INTENT(IN ) :: rdx, &
762 REAL , INTENT(IN ) :: dt_rk
766 INTEGER :: i, j, k, itf, jtf, ktf
767 INTEGER :: i_start, i_end, j_start, j_end
768 INTEGER :: i_start_f, i_end_f, j_start_f, j_end_f
769 INTEGER :: jmin, jmax, jp, jm, imin, imax, im, ip
770 INTEGER :: jp1, jp0, jtmp
772 INTEGER :: horz_order, vert_order
774 REAL :: mrdx, mrdy, ub, vb, uw, vw, dvm, dvp, wiL, wiR, dz
776 REAL(KIND=8), DIMENSION(its:ite,kts:kte) :: at, bt, ct, rt, bb
777 REAL(KIND=8), DIMENSION(its:ite) :: btmp
779 INTEGER :: iup, jup, kup, idn, jdn, kdn, kp1, km1
780 INTEGER :: valid_ik, skip
786 !-- horizontal loop bounds copied from module_advect_em.F/advect_scalar
789 i_end = MIN(ite,ide-1)
791 j_end = MIN(jte,jde-1)
793 ! J outer loop to do implicit advection.....
795 DO j = j_start, j_end
801 IF( k .eq. ktf ) kp1 = ktf
802 IF( k .eq. kts ) km1 = kts
804 DO i = i_start, i_end
806 ! Redefine mass fluxes with new temporary column mass
808 wiL = rom(i,k, j) * rdzw(k) / (c1(k)*mut_new(i,j)+c2(k))
809 wiR = rom(i,k+1,j) * rdzw(k) / (c1(k)*mut_new(i,j)+c2(k))
811 at(i,k) = - dt_rk*max(wiL,0.0)
812 ct(i,k) = dt_rk*min(wiR,0.0)
813 btmp(i) = dt_rk*(max(wiR,0.0) - min(wiL,0.0))
814 bt(i,k) = 1.0 + btmp(i)
815 rt(i,k) = dt_rk*tendency(i,k,j) &
816 - (c1(k)*mut_old(i,j)+c2(k))*(at(i,k)*s_old(i,km1,j) + btmp(i)*s_old(i,k,j) + ct(i,k)*s_old(i,kp1,j))
820 CALL tridiag2D(at, bt, ct, rt, bb, its, ite, i_start, i_end, kts, kte, kts, ktf)
823 DO i = i_start, i_end
825 ! Rescale tendency with old column mass for consistency in update step.
827 tendency(i,k,j) = sngl(bb(i,k)) / dt_rk
835 END SUBROUTINE advect_s_implicit
836 !-------------------------------------------------------------------------------
838 SUBROUTINE advect_u_implicit( u, u_old, tendency, &
841 muu_old, muu, muu_new, &
843 msfux, msfuy, msfvx, msfvy, &
848 ids, ide, jds, jde, kds, kde, &
849 ims, ime, jms, jme, kms, kme, &
850 its, ite, jts, jte, kts, kte )
856 TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags
858 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
859 ims, ime, jms, jme, kms, kme, &
860 its, ite, jts, jte, kts, kte
862 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: u, &
868 !-------------------------------------------------------------------------------
869 ! LWJ: definitions of various column masses
870 ! mut ==> current column mass from sub-step
871 ! mu_old ==> "n" time level column mass
872 ! mu_new ==> "n+1*" estimated column needed for dynamical variables where we dont
873 ! have time-avg column mass. For scalars (not theta) mut_new == mut
875 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN) :: muu, muu_old, muu_new
877 !-------------------------------------------------------------------------------
879 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency
881 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, &
888 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, &
894 REAL , INTENT(IN ) :: rdx, &
896 REAL , INTENT(IN ) :: dt_rk
900 INTEGER :: i, j, k, itf, jtf, ktf
901 INTEGER :: i_start, i_end, j_start, j_end
902 INTEGER :: i_start_f, i_end_f, j_start_f, j_end_f
903 INTEGER :: jmin, jmax, jp, jm, imin, imax, im, ip
904 INTEGER :: jp1, jp0, jtmp
906 INTEGER :: horz_order, vert_order
910 REAL(KIND=8), DIMENSION(its:ite,kts:kte) :: at, bt, ct, rt, bb
911 REAL(KIND=8), DIMENSION(its:ite) :: btmp
914 INTEGER :: iup, jup, kup, idn, jdn, kdn, kp1, km1
919 !-- loop bounds copied from module_advect_em.F/advect_u
922 if(config_flags%specified .or. config_flags%nested) specified = .true.
927 j_end = min(jte,jde-1)
929 ! IF ( config_flags%open_xs ) i_start = MAX(ids+1,its)
930 ! IF ( config_flags%open_xe ) i_end = MIN(ide-1,ite)
932 IF ( config_flags%open_ys .or. specified ) i_start = MAX(ids+1,its)
933 IF ( config_flags%open_ye .or. specified ) i_end = MIN(ide-1,ite)
934 IF ( config_flags%periodic_x ) i_start = its
935 IF ( config_flags%periodic_x ) i_end = ite
937 ! Vertical loop to do implicit advection.....
939 DO j = j_start, j_end
945 IF( k .eq. ktf ) kp1 = ktf
946 IF( k .eq. kts ) km1 = kts
948 DO i = i_start, i_end
950 ! SO IMPORTANT to * 1/DZ HERE CAUSE IT CHANGES Wi* SIGN TO BE CORRECT FOR UPWINDING!!!!
951 wiL = 0.5*(rom(i-1,k, j)+rom(i,k, j)) * rdzw(k) * msfuy(i,j) / (c1(k)*muu_new(i,j)+c2(k))
952 wiR = 0.5*(rom(i-1,k+1,j)+rom(i,k+1,j)) * rdzw(k) * msfuy(i,j) / (c1(k)*muu_new(i,j)+c2(k))
954 at(i,k) = - dt_rk*max(wiL,0.0)
955 ct(i,k) = dt_rk*min(wiR,0.0)
956 btmp(i) = dt_rk*(max(wiR,0.0) - min(wiL,0.0))
957 bt(i,k) = 1.0 + btmp(i)
958 rt(i,k) = dt_rk*tendency(i,k,j)*msfuy(i,j) &
959 - (c1(k)*muu_old(i,j)+c2(k))*(at(i,k)*u_old(i,km1,j) + btmp(i)*u_old(i,k,j) + ct(i,k)*u_old(i,kp1,j))
964 CALL tridiag2D(at, bt, ct, rt, bb, its, ite, i_start, i_end, kts, kte, kts, ktf)
967 DO i = i_start, i_end
969 tendency(i,k,j) = sngl(bb(i,k)) / dt_rk / msfuy(i,j)
977 END SUBROUTINE advect_u_implicit
978 !-------------------------------------------------------------------------------
980 SUBROUTINE advect_v_implicit( v, v_old, tendency, &
983 muv_old, muv, muv_new, &
985 msfux, msfuy, msfvx, msfvy, &
990 ids, ide, jds, jde, kds, kde, &
991 ims, ime, jms, jme, kms, kme, &
992 its, ite, jts, jte, kts, kte )
998 TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags
1000 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
1001 ims, ime, jms, jme, kms, kme, &
1002 its, ite, jts, jte, kts, kte
1004 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: v, &
1010 !-------------------------------------------------------------------------------
1011 ! LWJ: definitions of various column masses
1012 ! mut ==> current column mass from sub-step
1013 ! mu_old ==> "n" time level column mass
1014 ! mu_new ==> "n+1*" estimated column needed for dynamical variables where we dont
1015 ! have time-avg column mass. For scalars (not theta) mut_new == mut
1017 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN) :: muv, muv_old, muv_new
1019 !-------------------------------------------------------------------------------
1021 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency
1023 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, &
1030 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, &
1036 REAL , INTENT(IN ) :: rdx, &
1038 REAL , INTENT(IN ) :: dt_rk
1042 INTEGER :: i, j, k, itf, jtf, ktf
1043 INTEGER :: i_start, i_end, j_start, j_end
1044 INTEGER :: i_start_f, i_end_f, j_start_f, j_end_f
1045 INTEGER :: jmin, jmax, jp, jm, imin, imax, im, ip
1046 INTEGER :: jp1, jp0, jtmp
1048 INTEGER :: horz_order, vert_order
1050 REAL :: mrdx, mrdy, ub, vb, uw, vw, dvm, dvp, wiL, wiR, dz
1052 REAL(KIND=8), DIMENSION(its:ite,kts:kte) :: at, bt, ct, rt, bb
1053 REAL(KIND=8), DIMENSION(its:ite) :: btmp
1055 LOGICAL :: specified
1056 INTEGER :: iup, jup, kup, idn, jdn, kdn, kp1, km1
1059 ktf = MIN(kte,kde-1)
1061 !-- loop bounds copied from module_advect_em.F/advect_v
1064 if(config_flags%specified .or. config_flags%nested) specified = .true.
1067 i_end = MIN(ite,ide-1)
1071 ! Polar boundary conditions are like open or specified
1072 ! We don't want to calculate vertical v tendencies at the N or S pole
1073 IF ( config_flags%open_ys .or. specified .or. config_flags%polar ) j_start = MAX(jds+1,jts)
1074 IF ( config_flags%open_ye .or. specified .or. config_flags%polar ) j_end = MIN(jde-1,jte)
1078 DO j = j_start, j_end
1084 IF( k .eq. ktf ) kp1 = ktf
1085 IF( k .eq. kts ) km1 = kts
1087 DO i = i_start, i_end
1090 wiL = 0.5*(rom(i,k, j-1)+rom(i,k, j)) * rdzw(k) * msfvy(i,j) / (c1(k)*muv_new(i,j)+c2(k))
1091 wiR = 0.5*(rom(i,k+1,j-1)+rom(i,k+1,j)) * rdzw(k) * msfvy(i,j) / (c1(k)*muv_new(i,j)+c2(k))
1093 at(i,k) = - dt_rk*max(wiL,0.0)
1094 ct(i,k) = dt_rk*min(wiR,0.0)
1095 btmp(i) = dt_rk*(max(wiR,0.0) - min(wiL,0.0))
1096 bt(i,k) = 1.0 + btmp(i)
1097 rt(i,k) = dt_rk*tendency(i,k,j) * msfvx(i,j) &
1098 - (c1(k)*muv_old(i,j)+c2(k))*(at(i,k)*v_old(i,km1,j) + btmp(i)*v_old(i,k,j) + ct(i,k)*v_old(i,kp1,j))
1103 CALL tridiag2D(at, bt, ct, rt, bb, its, ite, i_start, i_end, kts, kte, kts, ktf)
1106 DO i = i_start, i_end
1108 tendency(i,k,j) = sngl(bb(i,k)) / dt_rk / msfvx(i,j)
1116 END SUBROUTINE advect_v_implicit
1118 !-------------------------------------------------------------------------------
1120 SUBROUTINE advect_w_implicit( w, w_old, tendency, &
1121 utend, vtend, ht, rom, &
1122 ph_new, ph_old, ph_tend, &
1125 mut_old, mut, mut_new, &
1127 msfux, msfuy, msfvx, msfvy, &
1132 ids, ide, jds, jde, kds, kde, &
1133 ims, ime, jms, jme, kms, kme, &
1134 its, ite, jts, jte, kts, kte )
1140 TYPE(grid_config_rec_type), INTENT(IN ) :: config_flags
1142 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
1143 ims, ime, jms, jme, kms, kme, &
1144 its, ite, jts, jte, kts, kte
1146 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(IN ) :: w, &
1155 !-------------------------------------------------------------------------------
1156 ! LWJ: definitions of various column masses
1157 ! mut ==> current column mass from sub-step
1158 ! mu_old ==> "n" time level column mass
1159 ! mu_new ==> "n+1*" estimated column needed for dynamical variables where we dont
1160 ! have time-avg column mass. For scalars (not theta) mut_new == mut
1162 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN) :: mut, mut_old, mut_new
1164 !-------------------------------------------------------------------------------
1166 REAL , DIMENSION( ims:ime , kms:kme , jms:jme ) , INTENT(INOUT) :: tendency
1168 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN ) :: msfux, &
1176 REAL , DIMENSION( kms:kme ) , INTENT(IN ) :: fzm, &
1182 REAL , INTENT(IN ) :: rdx, &
1188 REAL , INTENT(IN ) :: dt_rk
1192 INTEGER :: i, j, k, itf, jtf, ktf
1193 INTEGER :: i_start, i_end, j_start, j_end
1194 INTEGER :: i_start_f, i_end_f, j_start_f, j_end_f
1195 REAL :: wiL, wiR, dz, dw
1197 REAL(KIND=8), DIMENSION(its:ite,kts:kte) :: at, bt, ct, rt, bb
1198 REAL(KIND=8), DIMENSION(its:ite) :: btmp
1200 LOGICAL :: specified
1201 INTEGER :: iup, jup, kup, idn, jdn, kdn, kp1, km1
1204 ktf = MIN(kte,kde-1)
1206 i_end = MIN(ite,ide-1)
1208 j_end = MIN(jte,jde-1)
1212 DO j = j_start, j_end
1215 DO i = i_start, i_end
1217 ! SO IMPORTANT to * 1/DZ HERE CAUSE IT CHANGES Wi* SIGN TO BE CORRECT FOR UPWINDING!!!!
1218 wiL = 0.5*(rom(i,k-1,j)+rom(i,k,j)) * rdzu(k) * msfty(i,j) / (c1(k)*mut_new(i,j)+c2(k))
1219 wiR = 0.5*(rom(i,k+1,j)+rom(i,k,j)) * rdzu(k) * msfty(i,j) / (c1(k)*mut_new(i,j)+c2(k))
1221 at(i,k) = - dt_rk*max(wiL,0.0)
1222 ct(i,k) = dt_rk*min(wiR,0.0)
1223 btmp(i) = dt_rk*(max(wiR,0.0) - min(wiL,0.0))
1224 bt(i,k) = 1.0 + btmp(i)
1225 rt(i,k) = dt_rk*tendency(i,k,j) * msfty(i,j) &
1226 - (c1(k)*mut_old(i,j)+c2(k))*(at(i,k)*w_old(i,k-1,j) + btmp(i)*w_old(i,k,j) + ct(i,k)*w_old(i,k+1,j))
1228 ! BC at lower boundary needed because (W(i,kts,j) .ne. 0) and value need for RHS of tridiagonal at kts+1
1229 ! Since we already included w_old, just need to compute dw increment from UTEND, VTEND at kts
1231 IF( k == kts+1 ) THEN
1232 dw = msfty(i,j)*.5*rdy*( &
1233 (ht(i,j+1)-ht(i,j )) &
1234 *(cf1*vtend(i,1,j+1)+cf2*vtend(i,2,j+1)+cf3*vtend(i,3,j+1)) &
1235 +(ht(i,j )-ht(i,j-1)) &
1236 *(cf1*vtend(i,1,j )+cf2*vtend(i,2,j )+cf3*vtend(i,3,j )) ) &
1237 +msftx(i,j)*.5*rdx*( &
1238 (ht(i+1,j)-ht(i,j )) &
1239 *(cf1*utend(i+1,1,j)+cf2*utend(i+1,2,j)+cf3*utend(i+1,3,j)) &
1240 +(ht(i,j )-ht(i-1,j)) &
1241 *(cf1*utend(i ,1,j)+cf2*utend(i ,2,j)+cf3*utend(i ,3,j)) )
1243 rt(i,k) = rt(i,k) - (c1(k)*mut(i,j)+c2(k))*at(i,k)*dt_rk*dw
1246 ! W-increment at upper boundary is computed from phi
1248 IF( k == ktf ) THEN ! upper boundary condition
1249 dw = msfty(i,j)*( (ph_new(i,k+1,j)-ph_old(i,k+1,j))/dt_rk &
1250 - ph_tend(i,k+1,j)/(c1(k)*mut(i,j)+c2(k))/g)
1252 rt(i,k) = rt(i,k) - (c1(k)*mut(i,j)+c2(k))*ct(i,k) * (dw - w_old(i,k+1,j))
1258 CALL tridiag2D(at, bt, ct, rt, bb, its, ite, i_start, i_end, kts, kte, kts+1, ktf)
1261 DO i = i_start, i_end
1263 tendency(i,k,j) = sngl(bb(i,k)) / dt_rk / msfty(i,j)
1271 END SUBROUTINE advect_w_implicit
1273 END MODULE module_ieva_em
1275 !-----------------------------------