19 implicit none ;
private 23 #include <MOM_memory.h> 27 integer :: coriolis_scheme
40 integer :: pv_adv_scheme
44 real :: f_eff_max_blend
59 logical :: bound_coriolis
65 logical :: coriolis_en_dis
71 type(time_type),
pointer :: time
73 integer :: id_rv = -1, id_pv = -1, id_gkeu = -1, id_gkev = -1
74 integer :: id_rvxu = -1, id_rvxv = -1
106 subroutine coradcalc(u, v, h, uh, vh, CAu, CAv, OBC, AD, G, GV, CS)
109 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
110 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
111 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
112 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: uh
113 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: vh
114 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out) :: CAu
116 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out) :: CAv
123 real,
dimension(SZIB_(G),SZJB_(G)) :: &
130 real,
dimension(SZIB_(G),SZJ_(G)) :: &
136 real,
dimension(SZI_(G),SZJ_(G)) :: &
140 real,
dimension(SZIB_(G),SZJ_(G)) :: &
146 real,
dimension(SZI_(G),SZJB_(G)) :: &
152 real,
dimension(SZI_(G),SZJ_(G)) :: &
158 real,
dimension(SZIB_(G),SZJB_(G)) :: &
166 real,
dimension(SZIB_(G),SZJB_(G),SZK_(G)) :: &
169 real :: fv1, fv2, fu1, fu2
170 real :: max_fv, max_fu
171 real :: min_fv, min_fu
173 real,
parameter :: C1_12=1.0/12.0
174 real,
parameter :: C1_24=1.0/24.0
175 real :: absolute_vorticity
176 real :: relative_vorticity
178 real :: max_Ihq, min_Ihq
184 real,
parameter :: eps_vel=1.0e-10
188 real :: c1, c2, c3, slope
205 real :: QUHeff,QVHeff
206 integer :: i, j, k, n, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
216 if (.not.
associated(cs))
call mom_error(fatal, &
217 "MOM_CoriolisAdv: Module must be initialized before it is used.")
218 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
219 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB ; nz = g%ke
220 h_neglect = gv%H_subroundoff
224 do j=jsq-1,jeq+2 ;
do i=isq-1,ieq+2
225 area_h(i,j) = g%mask2dT(i,j) * g%areaT(i,j)
228 do j=jsq-1,jeq+1 ;
do i=isq-1,ieq+1
229 area_q(i,j) = (area_h(i,j) + area_h(i+1,j+1)) + &
230 (area_h(i+1,j) + area_h(i,j+1))
241 do j=jsq-1,jeq+1 ;
do i=isq-1,ieq+1
242 dvdx(i,j) = v(i+1,j,k)*g%dyCv(i+1,j) - v(i,j,k)*g%dyCv(i,j)
243 dudy(i,j) = u(i,j+1,k)*g%dxCu(i,j+1) - u(i,j,k)*g%dxCu(i,j)
245 do j=jsq-1,jeq+1 ;
do i=isq-1,ieq+2
246 harea_v(i,j) = 0.5*(area_h(i,j) * h(i,j,k) + area_h(i,j+1) * h(i,j+1,k))
248 do j=jsq-1,jeq+2 ;
do i=isq-1,ieq+1
249 harea_u(i,j) = 0.5*(area_h(i,j) * h(i,j,k) + area_h(i+1,j) * h(i+1,j,k))
251 if (cs%Coriolis_En_Dis)
then 252 do j=jsq,jeq+1 ;
do i=is-1,ie
253 uh_center(i,j) = 0.5 * (g%dy_Cu(i,j) * u(i,j,k)) * (h(i,j,k) + h(i+1,j,k))
255 do j=js-1,je ;
do i=isq,ieq+1
256 vh_center(i,j) = 0.5 * (g%dx_Cv(i,j) * v(i,j,k)) * (h(i,j,k) + h(i,j+1,k))
262 if (
associated(obc))
then ;
do n=1,obc%number_of_segments
263 if (.not. obc%segment(n)%on_pe) cycle
264 i = obc%segment(n)%HI%IsdB ; j = obc%segment(n)%HI%JsdB
265 if (obc%segment(n)%is_N_or_S .and. (j >= jsq-1) .and. (j <= jeq+1))
then 266 if (obc%zero_vorticity)
then ;
do i=obc%segment(n)%HI%IsdB,obc%segment(n)%HI%IedB
267 dvdx(i,j) = 0. ; dudy(i,j) = 0.
269 if (obc%freeslip_vorticity)
then ;
do i=obc%segment(n)%HI%IsdB,obc%segment(n)%HI%IedB
274 do i = max(isq-1,obc%segment(n)%HI%isd), min(ieq+2,obc%segment(n)%HI%ied)
276 harea_v(i,j) = 0.5 * (area_h(i,j) + area_h(i,j+1)) * h(i,j,k)
278 harea_v(i,j) = 0.5 * (area_h(i,j) + area_h(i,j+1)) * h(i,j+1,k)
282 if (cs%Coriolis_En_Dis)
then 283 do i = max(isq-1,obc%segment(n)%HI%isd), min(ieq+2,obc%segment(n)%HI%ied)
285 vh_center(i,j) = g%dx_Cv(i,j) * v(i,j,k) * h(i,j,k)
287 vh_center(i,j) = g%dx_Cv(i,j) * v(i,j,k) * h(i,j+1,k)
291 elseif (obc%segment(n)%is_E_or_W .and. (i >= isq-1) .and. (i <= ieq+1))
then 292 if (obc%zero_vorticity)
then ;
do j=obc%segment(n)%HI%JsdB,obc%segment(n)%HI%JedB
293 dvdx(i,j) = 0. ; dudy(i,j) = 0.
295 if (obc%freeslip_vorticity)
then ;
do j=obc%segment(n)%HI%JsdB,obc%segment(n)%HI%JedB
300 do j = max(jsq-1,obc%segment(n)%HI%jsd), min(jeq+2,obc%segment(n)%HI%jed)
301 if (obc%segment(n)%direction == obc_direction_e)
then 302 harea_u(i,j) = 0.5*(area_h(i,j) + area_h(i+1,j)) * h(i,j,k)
304 harea_u(i,j) = 0.5*(area_h(i,j) + area_h(i+1,j)) * h(i+1,j,k)
307 if (cs%Coriolis_En_Dis)
then 308 do j = max(jsq-1,obc%segment(n)%HI%jsd), min(jeq+2,obc%segment(n)%HI%jed)
309 if (obc%segment(n)%direction == obc_direction_e)
then 310 uh_center(i,j) = g%dy_Cu(i,j) * u(i,j,k) * h(i,j,k)
312 uh_center(i,j) = g%dy_Cu(i,j) * u(i,j,k) * h(i+1,j,k)
319 if (
associated(obc))
then ;
do n=1,obc%number_of_segments
320 if (.not. obc%segment(n)%on_pe) cycle
323 i = obc%segment(n)%HI%IsdB ; j = obc%segment(n)%HI%JsdB
324 if (obc%segment(n)%is_N_or_S .and. (j >= jsq-1) .and. (j <= jeq+1))
then 325 do i = max(isq-1,obc%segment(n)%HI%IsdB), min(ieq+1,obc%segment(n)%HI%IedB)
327 if (area_h(i,j) + area_h(i+1,j) > 0.0)
then 328 harea_u(i,j+1) = harea_u(i,j) * ((area_h(i,j+1) + area_h(i+1,j+1)) / &
329 (area_h(i,j) + area_h(i+1,j)))
330 else ; harea_u(i,j+1) = 0.0 ;
endif 332 if (area_h(i,j+1) + area_h(i+1,j+1) > 0.0)
then 333 harea_u(i,j) = harea_u(i,j+1) * ((area_h(i,j) + area_h(i+1,j)) / &
334 (area_h(i,j+1) + area_h(i+1,j+1)))
335 else ; harea_u(i,j) = 0.0 ;
endif 338 elseif (obc%segment(n)%is_E_or_W .and. (i >= isq-1) .and. (i <= ieq+1))
then 339 do j = max(jsq-1,obc%segment(n)%HI%JsdB), min(jeq+1,obc%segment(n)%HI%JedB)
340 if (obc%segment(n)%direction == obc_direction_e)
then 341 if (area_h(i,j) + area_h(i,j+1) > 0.0)
then 342 harea_v(i+1,j) = harea_v(i,j) * ((area_h(i+1,j) + area_h(i+1,j+1)) / &
343 (area_h(i,j) + area_h(i,j+1)))
344 else ; harea_v(i+1,j) = 0.0 ;
endif 346 harea_v(i,j) = 0.5 * (area_h(i,j) + area_h(i,j+1)) * h(i,j+1,k)
347 if (area_h(i+1,j) + area_h(i+1,j+1) > 0.0)
then 348 harea_v(i,j) = harea_v(i+1,j) * ((area_h(i,j) + area_h(i,j+1)) / &
349 (area_h(i+1,j) + area_h(i+1,j+1)))
350 else ; harea_v(i,j) = 0.0 ;
endif 356 do j=jsq-1,jeq+1 ;
do i=isq-1,ieq+1
357 if (cs%no_slip )
then 358 relative_vorticity = (2.0-g%mask2dBu(i,j)) * (dvdx(i,j) - dudy(i,j)) * &
361 relative_vorticity = g%mask2dBu(i,j) * (dvdx(i,j) - dudy(i,j)) * &
364 absolute_vorticity = g%CoriolisBu(i,j) + relative_vorticity
366 if (area_q(i,j) > 0.0)
then 367 harea_q = (harea_u(i,j) + harea_u(i,j+1)) + (harea_v(i,j) + harea_v(i+1,j))
368 ih = area_q(i,j) / (harea_q + h_neglect*area_q(i,j))
370 q(i,j) = absolute_vorticity * ih
371 abs_vort(i,j) = absolute_vorticity
374 if (cs%bound_Coriolis)
then 375 fv1 = absolute_vorticity*v(i+1,j,k)
376 fv2 = absolute_vorticity*v(i,j,k)
377 fu1 = -absolute_vorticity*u(i,j+1,k)
378 fu2 = -absolute_vorticity*u(i,j,k)
380 max_fvq(i,j) = fv1 ; min_fvq(i,j) = fv2
382 max_fvq(i,j) = fv2 ; min_fvq(i,j) = fv1
385 max_fuq(i,j) = fu1 ; min_fuq(i,j) = fu2
387 max_fuq(i,j) = fu2 ; min_fuq(i,j) = fu1
391 if (cs%id_rv > 0) rv(i,j,k) = relative_vorticity
392 if (cs%id_PV > 0) pv(i,j,k) = q(i,j)
393 if (
ASSOCIATED(ad%rv_x_v) .or.
ASSOCIATED(ad%rv_x_u)) &
394 q2(i,j) = relative_vorticity * ih
404 a(i,j) = (q(i,j) + (q(i+1,j) + q(i,j-1))) * c1_12
405 d(i,j) = ((q(i,j) + q(i+1,j-1)) + q(i,j-1)) * c1_12
408 b(i,j) = (q(i,j) + (q(i-1,j) + q(i,j-1))) * c1_12
409 c(i,j) = ((q(i,j) + q(i-1,j-1)) + q(i,j-1)) * c1_12
413 do j=jsq,jeq+1 ;
do i=isq,ieq+1
414 a(i-1,j) = (2.0*(q(i,j) + q(i-1,j-1)) + (q(i-1,j) + q(i,j-1))) * c1_24
415 d(i-1,j) = ((q(i,j) + q(i-1,j-1)) + 2.0*(q(i-1,j) + q(i,j-1))) * c1_24
416 b(i,j) = ((q(i,j) + q(i-1,j-1)) + 2.0*(q(i-1,j) + q(i,j-1))) * c1_24
417 c(i,j) = (2.0*(q(i,j) + q(i-1,j-1)) + (q(i-1,j) + q(i,j-1))) * c1_24
418 ep_u(i,j) = ((q(i,j) - q(i-1,j-1)) + (q(i-1,j) - q(i,j-1))) * c1_24
419 ep_v(i,j) = (-(q(i,j) - q(i-1,j-1)) + (q(i-1,j) - q(i,j-1))) * c1_24
421 elseif (cs%Coriolis_Scheme ==
al_blend)
then 422 fe_m2 = cs%F_eff_max_blend - 2.0
423 rat_lin = 1.5 * fe_m2 / max(cs%wt_lin_blend, 1.0e-16)
426 if (cs%F_eff_max_blend <= 2.0)
then ; fe_m2 = -1. ; rat_lin = -1.0 ;
endif 428 do j=jsq,jeq+1 ;
do i=isq,ieq+1
429 min_ihq = min(ih_q(i-1,j-1), ih_q(i,j-1), ih_q(i-1,j), ih_q(i,j))
430 max_ihq = max(ih_q(i-1,j-1), ih_q(i,j-1), ih_q(i-1,j), ih_q(i,j))
432 if (max_ihq < 1.0e15*min_ihq) rat_m1 = max_ihq / min_ihq - 1.0
439 if (rat_m1 <= fe_m2)
then ; al_wt = 1.0
440 elseif (rat_m1 < 1.5*fe_m2)
then ; al_wt = 3.0*fe_m2 / rat_m1 - 2.0
441 else ; al_wt = 0.0 ;
endif 444 if (rat_m1 <= 1.5*fe_m2)
then ; sad_wt = 0.0
445 elseif (rat_m1 <= rat_lin)
then 446 sad_wt = 1.0 - (1.5*fe_m2) / rat_m1
447 elseif (rat_m1 < 2.0*rat_lin)
then 448 sad_wt = 1.0 - (cs%wt_lin_blend / rat_lin) * (rat_m1 - 2.0*rat_lin)
449 else ; sad_wt = 1.0 ;
endif 451 a(i-1,j) = sad_wt * 0.25 * q(i-1,j) + (1.0 - sad_wt) * &
452 ( ((2.0-al_wt)* q(i-1,j) + al_wt*q(i,j-1)) + &
453 2.0 * (q(i,j) + q(i-1,j-1)) ) * c1_24
454 d(i-1,j) = sad_wt * 0.25 * q(i-1,j-1) + (1.0 - sad_wt) * &
455 ( ((2.0-al_wt)* q(i-1,j-1) + al_wt*q(i,j)) + &
456 2.0 * (q(i-1,j) + q(i,j-1)) ) * c1_24
457 b(i,j) = sad_wt * 0.25 * q(i,j) + (1.0 - sad_wt) * &
458 ( ((2.0-al_wt)* q(i,j) + al_wt*q(i-1,j-1)) + &
459 2.0 * (q(i-1,j) + q(i,j-1)) ) * c1_24
460 c(i,j) = sad_wt * 0.25 * q(i,j-1) + (1.0 - sad_wt) * &
461 ( ((2.0-al_wt)* q(i,j-1) + al_wt*q(i-1,j)) + &
462 2.0 * (q(i,j) + q(i-1,j-1)) ) * c1_24
463 ep_u(i,j) = al_wt * ((q(i,j) - q(i-1,j-1)) + (q(i-1,j) - q(i,j-1))) * c1_24
464 ep_v(i,j) = al_wt * (-(q(i,j) - q(i-1,j-1)) + (q(i-1,j) - q(i,j-1))) * c1_24
468 if (cs%Coriolis_En_Dis)
then 470 c1 = 1.0-1.5*0.5 ; c2 = 1.0-0.5 ; c3 = 2.0 ; slope = 0.5
472 do j=jsq,jeq+1 ;
do i=is-1,ie
476 if (g%dy_Cu(i,j) == 0.0) uhc = uhm
478 if (abs(uhc) < 0.1*abs(uhm))
then 480 elseif (abs(uhc) > c1*abs(uhm))
then 481 if (abs(uhc) < c2*abs(uhm))
then ; uhc = (3.0*uhc+(1.0-c2*3.0)*uhm)
482 elseif (abs(uhc) <= c3*abs(uhm))
then ; uhc = uhm
483 else ; uhc = slope*uhc+(1.0-c3*slope)*uhm
488 uh_min(i,j) = uhm ; uh_max(i,j) = uhc
490 uh_max(i,j) = uhm ; uh_min(i,j) = uhc
493 do j=js-1,je ;
do i=isq,ieq+1
497 if (g%dx_Cv(i,j) == 0.0) vhc = vhm
499 if (abs(vhc) < 0.1*abs(vhm))
then 501 elseif (abs(vhc) > c1*abs(vhm))
then 502 if (abs(vhc) < c2*abs(vhm))
then ; vhc = (3.0*vhc+(1.0-c2*3.0)*vhm)
503 else if (abs(vhc) <= c3*abs(vhm))
then ; vhc = vhm
504 else ; vhc = slope*vhc+(1.0-c3*slope)*vhm
509 vh_min(i,j) = vhm ; vh_max(i,j) = vhc
511 vh_max(i,j) = vhm ; vh_min(i,j) = vhc
517 call gradke(u, v, h, ke, kex, key, k, obc, g, cs)
523 if (cs%Coriolis_En_Dis)
then 525 do j=js,je ;
do i=isq,ieq
526 if (q(i,j)*u(i,j,k) == 0.0)
then 527 temp1 = q(i,j) * ( (vh_max(i,j)+vh_max(i+1,j)) &
528 + (vh_min(i,j)+vh_min(i+1,j)) )*0.5
529 elseif (q(i,j)*u(i,j,k) < 0.0)
then 530 temp1 = q(i,j) * (vh_max(i,j)+vh_max(i+1,j))
532 temp1 = q(i,j) * (vh_min(i,j)+vh_min(i+1,j))
534 if (q(i,j-1)*u(i,j,k) == 0.0)
then 535 temp2 = q(i,j-1) * ( (vh_max(i,j-1)+vh_max(i+1,j-1)) &
536 + (vh_min(i,j-1)+vh_min(i+1,j-1)) )*0.5
537 elseif (q(i,j-1)*u(i,j,k) < 0.0)
then 538 temp2 = q(i,j-1) * (vh_max(i,j-1)+vh_max(i+1,j-1))
540 temp2 = q(i,j-1) * (vh_min(i,j-1)+vh_min(i+1,j-1))
542 cau(i,j,k) = 0.25 * g%IdxCu(i,j) * (temp1 + temp2)
546 do j=js,je ;
do i=isq,ieq
547 cau(i,j,k) = 0.25 * &
548 (q(i,j) * (vh(i+1,j,k) + vh(i,j,k)) + &
549 q(i,j-1) * (vh(i,j-1,k) + vh(i+1,j-1,k))) * g%IdxCu(i,j)
553 do j=js,je ;
do i=isq,ieq
554 cau(i,j,k) = 0.125 * (g%IdxCu(i,j) * (q(i,j) + q(i,j-1))) * &
555 ((vh(i+1,j,k) + vh(i,j,k)) + (vh(i,j-1,k) + vh(i+1,j-1,k)))
559 (cs%Coriolis_Scheme ==
al_blend))
then 561 do j=js,je ;
do i=isq,ieq
562 cau(i,j,k) = ((a(i,j) * vh(i+1,j,k) + &
563 c(i,j) * vh(i,j-1,k)) &
564 + (b(i,j) * vh(i,j,k) + &
565 d(i,j) * vh(i+1,j-1,k))) * g%IdxCu(i,j)
571 do j=js,je ;
do i=isq,ieq
572 heff1 = abs(vh(i,j,k)*g%IdxCv(i,j))/(eps_vel+abs(v(i,j,k)))
573 heff1 = max(heff1,min(h(i,j,k),h(i,j+1,k)))
574 heff1 = min(heff1,max(h(i,j,k),h(i,j+1,k)))
575 heff2 = abs(vh(i,j-1,k)*g%IdxCv(i,j-1))/(eps_vel+abs(v(i,j-1,k)))
576 heff2 = max(heff2,min(h(i,j-1,k),h(i,j,k)))
577 heff2 = min(heff2,max(h(i,j-1,k),h(i,j,k)))
578 heff3 = abs(vh(i+1,j,k)*g%IdxCv(i+1,j))/(eps_vel+abs(v(i+1,j,k)))
579 heff3 = max(heff3,min(h(i+1,j,k),h(i+1,j+1,k)))
580 heff3 = min(heff3,max(h(i+1,j,k),h(i+1,j+1,k)))
581 heff4 = abs(vh(i+1,j-1,k)*g%IdxCv(i+1,j-1))/(eps_vel+abs(v(i+1,j-1,k)))
582 heff4 = max(heff4,min(h(i+1,j-1,k),h(i+1,j,k)))
583 heff4 = min(heff4,max(h(i+1,j-1,k),h(i+1,j,k)))
585 cau(i,j,k) = 0.5*(abs_vort(i,j)+abs_vort(i,j-1)) * &
586 ((vh(i ,j ,k)+vh(i+1,j-1,k)) + &
587 (vh(i ,j-1,k)+vh(i+1,j ,k)) ) / &
588 (h_tiny +((heff1+heff4) +(heff2+heff3)) ) * g%IdxCu(i,j)
590 vheff = ((vh(i ,j ,k)+vh(i+1,j-1,k)) + &
591 (vh(i ,j-1,k)+vh(i+1,j ,k)) )
592 qvheff = 0.5*( (abs_vort(i,j)+abs_vort(i,j-1))*vheff &
593 -(abs_vort(i,j)-abs_vort(i,j-1))*abs(vheff) )
594 cau(i,j,k) = qvheff / &
595 (h_tiny +((heff1+heff4) +(heff2+heff3)) ) * g%IdxCu(i,j)
601 (cs%Coriolis_Scheme ==
al_blend))
then ;
do j=js,je ;
do i=isq,ieq
602 cau(i,j,k) = cau(i,j,k) + &
603 (ep_u(i,j)*uh(i-1,j,k) - ep_u(i+1,j)*uh(i+1,j,k)) * g%IdxCu(i,j)
604 enddo ;
enddo ;
endif 607 if (cs%bound_Coriolis)
then 608 do j=js,je ;
do i=isq,ieq
609 max_fv = max(max_fvq(i,j),max_fvq(i,j-1))
610 min_fv = min(min_fvq(i,j),min_fvq(i,j-1))
613 if (cau(i,j,k) > max_fv)
then 616 if (cau(i,j,k) < min_fv) cau(i,j,k) = min_fv
622 do j=js,je ;
do i=isq,ieq
623 cau(i,j,k) = cau(i,j,k) - kex(i,j)
624 if (
ASSOCIATED(ad%gradKEu)) ad%gradKEu(i,j,k) = -kex(i,j)
632 if (cs%Coriolis_En_Dis)
then 634 do j=jsq,jeq ;
do i=is,ie
635 if (q(i-1,j)*v(i,j,k) == 0.0)
then 636 temp1 = q(i-1,j) * ( (uh_max(i-1,j)+uh_max(i-1,j+1)) &
637 + (uh_min(i-1,j)+uh_min(i-1,j+1)) )*0.5
638 elseif (q(i-1,j)*v(i,j,k) > 0.0)
then 639 temp1 = q(i-1,j) * (uh_max(i-1,j)+uh_max(i-1,j+1))
641 temp1 = q(i-1,j) * (uh_min(i-1,j)+uh_min(i-1,j+1))
643 if (q(i,j)*v(i,j,k) == 0.0)
then 644 temp2 = q(i,j) * ( (uh_max(i,j)+uh_max(i,j+1)) &
645 + (uh_min(i,j)+uh_min(i,j+1)) )*0.5
646 elseif (q(i,j)*v(i,j,k) > 0.0)
then 647 temp2 = q(i,j) * (uh_max(i,j)+uh_max(i,j+1))
649 temp2 = q(i,j) * (uh_min(i,j)+uh_min(i,j+1))
651 cav(i,j,k) = - 0.25 * g%IdyCv(i,j) * (temp1 + temp2)
655 do j=jsq,jeq ;
do i=is,ie
656 cav(i,j,k) = - 0.25* &
657 (q(i-1,j)*(uh(i-1,j,k) + uh(i-1,j+1,k)) + &
658 q(i,j)*(uh(i,j,k) + uh(i,j+1,k))) * g%IdyCv(i,j)
662 do j=jsq,jeq ;
do i=is,ie
663 cav(i,j,k) = -0.125 * (g%IdyCv(i,j) * (q(i-1,j) + q(i,j))) * &
664 ((uh(i-1,j,k) + uh(i-1,j+1,k)) + (uh(i,j,k) + uh(i,j+1,k)))
668 (cs%Coriolis_Scheme ==
al_blend))
then 670 do j=jsq,jeq ;
do i=is,ie
671 cav(i,j,k) = - ((a(i-1,j) * uh(i-1,j,k) + &
672 c(i,j+1) * uh(i,j+1,k)) &
673 + (b(i,j) * uh(i,j,k) + &
674 d(i-1,j+1) * uh(i-1,j+1,k))) * g%IdyCv(i,j)
680 do j=jsq,jeq ;
do i=is,ie
681 heff1 = abs(uh(i,j,k)*g%IdyCu(i,j))/(eps_vel+abs(u(i,j,k)))
682 heff1 = max(heff1,min(h(i,j,k),h(i+1,j,k)))
683 heff1 = min(heff1,max(h(i,j,k),h(i+1,j,k)))
684 heff2 = abs(uh(i-1,j,k)*g%IdyCu(i-1,j))/(eps_vel+abs(u(i-1,j,k)))
685 heff2 = max(heff2,min(h(i-1,j,k),h(i,j,k)))
686 heff2 = min(heff2,max(h(i-1,j,k),h(i,j,k)))
687 heff3 = abs(uh(i,j+1,k)*g%IdyCu(i,j+1))/(eps_vel+abs(u(i,j+1,k)))
688 heff3 = max(heff3,min(h(i,j+1,k),h(i+1,j+1,k)))
689 heff3 = min(heff3,max(h(i,j+1,k),h(i+1,j+1,k)))
690 heff4 = abs(uh(i-1,j+1,k)*g%IdyCu(i-1,j+1))/(eps_vel+abs(u(i-1,j+1,k)))
691 heff4 = max(heff4,min(h(i-1,j+1,k),h(i,j+1,k)))
692 heff4 = min(heff4,max(h(i-1,j+1,k),h(i,j+1,k)))
694 cav(i,j,k) = - 0.5*(abs_vort(i,j)+abs_vort(i-1,j)) * &
695 ((uh(i ,j ,k)+uh(i-1,j+1,k)) + &
696 (uh(i-1,j ,k)+uh(i ,j+1,k)) ) / &
697 (h_tiny + ((heff1+heff4) +(heff2+heff3)) ) * g%IdyCv(i,j)
699 uheff = ((uh(i ,j ,k)+uh(i-1,j+1,k)) + &
700 (uh(i-1,j ,k)+uh(i ,j+1,k)) )
701 quheff = 0.5*( (abs_vort(i,j)+abs_vort(i-1,j))*uheff &
702 -(abs_vort(i,j)-abs_vort(i-1,j))*abs(uheff) )
703 cav(i,j,k) = - quheff / &
704 (h_tiny + ((heff1+heff4) +(heff2+heff3)) ) * g%IdyCv(i,j)
710 (cs%Coriolis_Scheme ==
al_blend))
then ;
do j=jsq,jeq ;
do i=is,ie
711 cav(i,j,k) = cav(i,j,k) + &
712 (ep_v(i,j)*vh(i,j-1,k) - ep_v(i,j+1)*vh(i,j+1,k)) * g%IdyCv(i,j)
713 enddo ;
enddo ;
endif 715 if (cs%bound_Coriolis)
then 716 do j=jsq,jeq ;
do i=is,ie
717 max_fu = max(max_fuq(i,j),max_fuq(i-1,j))
718 min_fu = min(min_fuq(i,j),min_fuq(i-1,j))
719 if (cav(i,j,k) > max_fu)
then 722 if (cav(i,j,k) < min_fu) cav(i,j,k) = min_fu
728 do j=jsq,jeq ;
do i=is,ie
729 cav(i,j,k) = cav(i,j,k) - key(i,j)
730 if (
ASSOCIATED(ad%gradKEv)) ad%gradKEv(i,j,k) = -key(i,j)
733 if (
ASSOCIATED(ad%rv_x_u) .or.
ASSOCIATED(ad%rv_x_v))
then 736 if (
ASSOCIATED(ad%rv_x_u))
then 737 do j=jsq,jeq ;
do i=is,ie
738 ad%rv_x_u(i,j,k) = - 0.25* &
739 (q2(i-1,j)*(uh(i-1,j,k) + uh(i-1,j+1,k)) + &
740 q2(i,j)*(uh(i,j,k) + uh(i,j+1,k))) * g%IdyCv(i,j)
744 if (
ASSOCIATED(ad%rv_x_v))
then 745 do j=js,je ;
do i=isq,ieq
746 ad%rv_x_v(i,j,k) = 0.25 * &
747 (q2(i,j) * (vh(i+1,j,k) + vh(i,j,k)) + &
748 q2(i,j-1) * (vh(i,j-1,k) + vh(i+1,j-1,k))) * g%IdxCu(i,j)
752 if (
ASSOCIATED(ad%rv_x_u))
then 753 do j=jsq,jeq ;
do i=is,ie
754 ad%rv_x_u(i,j,k) = -g%IdyCv(i,j) * c1_12 * &
755 ((q2(i,j) + q2(i-1,j) + q2(i-1,j-1)) * uh(i-1,j,k) + &
756 (q2(i-1,j) + q2(i,j) + q2(i,j-1)) * uh(i,j,k) + &
757 (q2(i-1,j) + q2(i,j+1) + q2(i,j)) * uh(i,j+1,k) + &
758 (q2(i,j) + q2(i-1,j+1) + q2(i-1,j)) * uh(i-1,j+1,k))
762 if (
ASSOCIATED(ad%rv_x_v))
then 763 do j=js,je ;
do i=isq,ieq
764 ad%rv_x_v(i,j,k) = g%IdxCu(i,j) * c1_12 * &
765 ((q2(i+1,j) + q2(i,j) + q2(i,j-1)) * vh(i+1,j,k) + &
766 (q2(i-1,j) + q2(i,j) + q2(i,j-1)) * vh(i,j,k) + &
767 (q2(i-1,j-1) + q2(i,j) + q2(i,j-1)) * vh(i,j-1,k) + &
768 (q2(i+1,j-1) + q2(i,j) + q2(i,j-1)) * vh(i+1,j-1,k))
777 if (query_averaging_enabled(cs%diag))
then 778 if (cs%id_rv > 0)
call post_data(cs%id_rv, rv, cs%diag)
779 if (cs%id_PV > 0)
call post_data(cs%id_PV, pv, cs%diag)
780 if (cs%id_gKEu>0)
call post_data(cs%id_gKEu, ad%gradKEu, cs%diag)
781 if (cs%id_gKEv>0)
call post_data(cs%id_gKEv, ad%gradKEv, cs%diag)
782 if (cs%id_rvxu > 0)
call post_data(cs%id_rvxu, ad%rv_x_u, cs%diag)
783 if (cs%id_rvxv > 0)
call post_data(cs%id_rvxv, ad%rv_x_v, cs%diag)
790 subroutine gradke(u, v, h, KE, KEx, KEy, k, OBC, G, CS)
792 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
793 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
794 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
795 real,
dimension(SZI_(G) ,SZJ_(G) ),
intent(out) :: KE
796 real,
dimension(SZIB_(G),SZJ_(G) ),
intent(out) :: KEx
798 real,
dimension(SZI_(G) ,SZJB_(G)),
intent(out) :: KEy
800 integer,
intent(in) :: k
804 real :: um, up, vm, vp
805 real :: um2, up2, vm2, vp2
806 real :: um2a, up2a, vm2a, vp2a
807 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, n
809 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
810 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
818 do j=jsq,jeq+1 ;
do i=isq,ieq+1
819 ke(i,j) = ( ( g%areaCu( i ,j)*(u( i ,j,k)*u( i ,j,k)) &
820 +g%areaCu(i-1,j)*(u(i-1,j,k)*u(i-1,j,k)) ) &
821 +( g%areaCv(i, j )*(v(i, j ,k)*v(i, j ,k)) &
822 +g%areaCv(i,j-1)*(v(i,j-1,k)*v(i,j-1,k)) ) &
828 do j=jsq,jeq+1 ;
do i=isq,ieq+1
829 up = 0.5*( u(i-1,j,k) + abs( u(i-1,j,k) ) ) ; up2 = up*up
830 um = 0.5*( u( i ,j,k) - abs( u( i ,j,k) ) ) ; um2 = um*um
831 vp = 0.5*( v(i,j-1,k) + abs( v(i,j-1,k) ) ) ; vp2 = vp*vp
832 vm = 0.5*( v(i, j ,k) - abs( v(i, j ,k) ) ) ; vm2 = vm*vm
833 ke(i,j) = ( max(up2,um2) + max(vp2,vm2) ) *0.5
838 do j=jsq,jeq+1 ;
do i=isq,ieq+1
839 up = 0.5*( u(i-1,j,k) + abs( u(i-1,j,k) ) ) ; up2a = up*up*g%areaCu(i-1,j)
840 um = 0.5*( u( i ,j,k) - abs( u( i ,j,k) ) ) ; um2a = um*um*g%areaCu( i ,j)
841 vp = 0.5*( v(i,j-1,k) + abs( v(i,j-1,k) ) ) ; vp2a = vp*vp*g%areaCv(i,j-1)
842 vm = 0.5*( v(i, j ,k) - abs( v(i, j ,k) ) ) ; vm2a = vm*vm*g%areaCv(i, j )
843 ke(i,j) = ( max(um2a,up2a) + max(vm2a,vp2a) )*0.5*g%IareaT(i,j)
848 do j=js,je ;
do i=isq,ieq
849 kex(i,j) = (ke(i+1,j) - ke(i,j)) * g%IdxCu(i,j)
853 do j=jsq,jeq ;
do i=is,ie
854 key(i,j) = (ke(i,j+1) - ke(i,j)) * g%IdyCv(i,j)
857 if (
associated(obc))
then 858 do n=1,obc%number_of_segments
859 if (obc%segment(n)%is_N_or_S)
then 860 do i=obc%segment(n)%HI%isd,obc%segment(n)%HI%ied
861 key(i,obc%segment(n)%HI%JsdB) = 0.
863 elseif (obc%segment(n)%is_E_or_W)
then 864 do j=obc%segment(n)%HI%jsd,obc%segment(n)%HI%jed
865 kex(obc%segment(n)%HI%IsdB,j) = 0.
875 type(time_type),
target,
intent(in) :: Time
878 type(
diag_ctrl),
target,
intent(inout) :: diag
883 #include "version_variable.h" 884 character(len=40) :: mdl =
"MOM_CoriolisAdv" 885 character(len=20) :: tmpstr
886 character(len=400) :: mesg
887 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz
889 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
890 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
892 if (
associated(cs))
then 893 call mom_error(warning,
"CoriolisAdv_init called with associated control structure.")
898 cs%diag => diag ; cs%Time => time
902 call get_param(param_file, mdl,
"NOSLIP", cs%no_slip, &
903 "If true, no slip boundary conditions are used; otherwise \n"//&
904 "free slip boundary conditions are assumed. The \n"//&
905 "implementation of the free slip BCs on a C-grid is much \n"//&
906 "cleaner than the no slip BCs. The use of free slip BCs \n"//&
907 "is strongly encouraged, and no slip BCs are not used with \n"//&
908 "the biharmonic viscosity.", default=.false.)
910 call get_param(param_file, mdl,
"CORIOLIS_EN_DIS", cs%Coriolis_En_Dis, &
911 "If true, two estimates of the thickness fluxes are used \n"//&
912 "to estimate the Coriolis term, and the one that \n"//&
913 "dissipates energy relative to the other one is used.", &
918 call get_param(param_file, mdl,
"CORIOLIS_SCHEME", tmpstr, &
919 "CORIOLIS_SCHEME selects the discretization for the \n"//&
920 "Coriolis terms. Valid values are: \n"//&
921 "\t SADOURNY75_ENERGY - Sadourny, 1975; energy cons. \n"//&
922 "\t ARAKAWA_HSU90 - Arakawa & Hsu, 1990 \n"//&
923 "\t SADOURNY75_ENSTRO - Sadourny, 1975; enstrophy cons. \n"//&
924 "\t ARAKAWA_LAMB81 - Arakawa & Lamb, 1981; En. + Enst.\n"//&
925 "\t ARAKAWA_LAMB_BLEND - A blend of Arakawa & Lamb with \n"//&
926 "\t Arakawa & Hsu and Sadourny energy", &
942 cs%Coriolis_En_Dis = .false.
944 call mom_mesg(
'CoriolisAdv_init: Coriolis_Scheme ="'//trim(tmpstr)//
'"', 0)
945 call mom_error(fatal,
"CoriolisAdv_init: Unrecognized setting "// &
946 "#define CORIOLIS_SCHEME "//trim(tmpstr)//
" found in input file.")
948 if (cs%Coriolis_Scheme ==
al_blend)
then 949 call get_param(param_file, mdl,
"CORIOLIS_BLEND_WT_LIN", cs%wt_lin_blend, &
950 "A weighting value for the ratio of inverse thicknesses, \n"//&
951 "beyond which the blending between Sadourny Energy and \n"//&
952 "Arakawa & Hsu goes linearly to 0 when CORIOLIS_SCHEME \n"//&
953 "is ARAWAKA_LAMB_BLEND. This must be between 1 and 1e-16.", &
954 units=
"nondim", default=0.125)
955 call get_param(param_file, mdl,
"CORIOLIS_BLEND_F_EFF_MAX", cs%F_eff_max_blend, &
956 "The factor by which the maximum effective Coriolis \n"//&
957 "acceleration from any point can be increased when \n"//&
958 "blending different discretizations with the \n"//&
959 "ARAKAWA_LAMB_BLEND Coriolis scheme. This must be \n"//&
960 "greater than 2.0 (the max value for Sadourny energy).", &
961 units=
"nondim", default=4.0)
962 cs%wt_lin_blend = min(1.0, max(cs%wt_lin_blend,1e-16))
963 if (cs%F_eff_max_blend < 2.0)
call mom_error(warning,
"CoriolisAdv_init: "//&
964 "CORIOLIS_BLEND_F_EFF_MAX should be at least 2.")
967 mesg =
"If true, the Coriolis terms at u-points are bounded by \n"//&
968 "the four estimates of (f+rv)v from the four neighboring \n"//&
969 "v-points, and similarly at v-points." 971 mesg = trim(mesg)//
" This option is \n"//&
972 "always effectively false with CORIOLIS_EN_DIS defined and \n"//&
975 mesg = trim(mesg)//
" This option would \n"//&
976 "have no effect on the SADOURNY Coriolis scheme if it \n"//&
977 "were possible to use centered difference thickness fluxes." 979 call get_param(param_file, mdl,
"BOUND_CORIOLIS", cs%bound_Coriolis, mesg, &
982 (cs%Coriolis_Scheme ==
robust_enstro)) cs%bound_Coriolis = .false.
985 call get_param(param_file, mdl,
"KE_SCHEME", tmpstr, &
986 "KE_SCHEME selects the discretization for acceleration \n"//&
987 "due to the kinetic energy gradient. Valid values are: \n"//&
988 "\t KE_ARAKAWA, KE_SIMPLE_GUDONOV, KE_GUDONOV", &
996 call mom_mesg(
'CoriolisAdv_init: KE_Scheme ="'//trim(tmpstr)//
'"', 0)
997 call mom_error(fatal,
"CoriolisAdv_init: "// &
998 "#define KE_SCHEME "//trim(tmpstr)//
" in input file is invalid.")
1002 call get_param(param_file, mdl,
"PV_ADV_SCHEME", tmpstr, &
1003 "PV_ADV_SCHEME selects the discretization for PV \n"//&
1004 "advection. Valid values are: \n"//&
1005 "\t PV_ADV_CENTERED - centered (aka Sadourny, 75) \n"//&
1006 "\t PV_ADV_UPWIND1 - upwind, first order", &
1014 call mom_mesg(
'CoriolisAdv_init: PV_Adv_Scheme ="'//trim(tmpstr)//
'"', 0)
1015 call mom_error(fatal,
"CoriolisAdv_init: "// &
1016 "#DEFINE PV_ADV_SCHEME in input file is invalid.")
1020 'Relative Vorticity',
'second-1')
1023 'Potential Vorticity',
'meter-1 second-1')
1026 'Zonal Acceleration from Grad. Kinetic Energy',
'meter-1 second-2')
1027 if (cs%id_gKEu > 0)
call safe_alloc_ptr(ad%gradKEu,isdb,iedb,jsd,jed,nz)
1030 'Meridional Acceleration from Grad. Kinetic Energy',
'meter-1 second-2')
1031 if (cs%id_gKEv > 0)
call safe_alloc_ptr(ad%gradKEv,isd,ied,jsdb,jedb,nz)
1034 'Meridional Acceleration from Relative Vorticity',
'meter-1 second-2')
1035 if (cs%id_rvxu > 0)
call safe_alloc_ptr(ad%rv_x_u,isd,ied,jsdb,jedb,nz)
1038 'Zonal Acceleration from Relative Vorticity',
'meter-1 second-2')
1039 if (cs%id_rvxv > 0)
call safe_alloc_ptr(ad%rv_x_v,isdb,iedb,jsd,jed,nz)
integer, parameter, public obc_direction_s
Indicates the boundary is an effective southern boundary.
subroutine, public coradcalc(u, v, h, uh, vh, CAu, CAv, OBC, AD, G, GV, CS)
Calculates the Coriolis and momentum advection contributions to the acceleration. ...
integer, parameter, public obc_direction_w
Indicates the boundary is an effective western boundary.
character *(20), parameter robust_enstro_string
integer, parameter, public obc_direction_n
Indicates the boundary is an effective northern boundary.
integer, parameter sadourny75_energy
character *(20), parameter ke_arakawa_string
integer, parameter pv_adv_upwind1
Ocean grid type. See mom_grid for details.
character *(20), parameter arakawa_lamb_string
character *(20), parameter ke_simple_gudonov_string
Provides the ocean grid type.
character *(20), parameter sadourny75_enstro_string
Accelerations due to the Coriolis force and momentum advection.
The accel_diag_ptrs structure contains pointers to arrays with accelerations, which can later be used...
subroutine gradke(u, v, h, KE, KEx, KEy, k, OBC, G, CS)
Calculates the acceleration due to the gradient of kinetic energy.
integer, parameter sadourny75_enstro
subroutine, public coriolisadv_init(Time, G, param_file, diag, AD, CS)
Initializes the control structure for coriolisadv_cs.
integer, parameter ke_simple_gudonov
Control structure for mom_coriolisadv.
character *(20), parameter pv_adv_upwind1_string
character *(20), parameter ke_gudonov_string
character(len=len(input_string)) function, public uppercase(input_string)
character *(20), parameter arakawa_hsu_string
character *(20), parameter sadourny75_energy_string
integer, parameter robust_enstro
subroutine, public mom_mesg(message, verb, all_print)
integer, parameter al_blend
integer, parameter, public obc_direction_e
Indicates the boundary is an effective eastern boundary.
integer, parameter pv_adv_centered
integer, parameter arakawa_lamb81
subroutine, public coriolisadv_end(CS)
Destructor for coriolisadv_cs.
integer, parameter ke_gudonov
integer, parameter arakawa_hsu90
Controls where open boundary conditions are applied.
character *(20), parameter pv_adv_centered_string
character *(20), parameter al_blend_string
subroutine, public mom_error(level, message, all_print)
integer, parameter ke_arakawa