8 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
18 use mom_remapping,
only : extract_member_remapping_cs, build_reconstructions_1d
19 use mom_remapping,
only : average_value_ppoly, remappingschemesdoc, remappingdefaultscheme
26 use iso_fortran_env,
only : stdout=>output_unit, stderr=>error_unit
28 implicit none ;
private 30 public near_boundary_unit_tests, lateral_boundary_diffusion, lateral_boundary_diffusion_init
31 public boundary_k_range
34 integer,
public,
parameter :: surface = -1
35 integer,
public,
parameter :: bottom = 1
36 #include <MOM_memory.h> 45 integer :: surface_boundary_scheme
53 type(
kpp_cs),
pointer :: kpp_csp => null()
60 #include "version_variable.h" 61 character(len=40) :: mdl =
"MOM_lateral_boundary_diffusion" 67 logical function lateral_boundary_diffusion_init(Time, G, param_file, diag, diabatic_CSp, CS)
68 type(time_type),
target,
intent(in) :: time
71 type(
diag_ctrl),
target,
intent(inout) :: diag
76 character(len=80) :: string
77 logical :: boundary_extrap
79 if (
ASSOCIATED(cs))
then 80 call mom_error(fatal,
"lateral_boundary_diffusion_init called with associated control structure.")
85 call get_param(param_file, mdl,
"USE_LATERAL_BOUNDARY_DIFFUSION", lateral_boundary_diffusion_init, &
86 default=.false., do_not_log=.true.)
88 "This module implements lateral diffusion of tracers near boundaries", &
89 all_default=.not.lateral_boundary_diffusion_init)
90 call get_param(param_file, mdl,
"USE_LATERAL_BOUNDARY_DIFFUSION", lateral_boundary_diffusion_init, &
91 "If true, enables the lateral boundary tracer's diffusion module.", &
94 if (.not. lateral_boundary_diffusion_init)
return 98 call extract_diabatic_member(diabatic_csp, kpp_csp=cs%KPP_CSp)
99 call extract_diabatic_member(diabatic_csp, energetic_pbl_csp=cs%energetic_PBL_CSp)
101 cs%surface_boundary_scheme = -1
102 if ( .not.
ASSOCIATED(cs%energetic_PBL_CSp) .and. .not.
ASSOCIATED(cs%KPP_CSp) )
then 103 call mom_error(fatal,
"Lateral boundary diffusion is true, but no valid boundary layer scheme was found")
107 call get_param(param_file, mdl,
"LATERAL_BOUNDARY_METHOD", cs%method, &
108 "Determine how to apply boundary lateral diffusion of tracers: \n"//&
109 "1. Along layer approach \n"//&
110 "2. Bulk layer approach (this option is not recommended)", default=1)
111 if (cs%method == 2)
then 112 call get_param(param_file, mdl,
"APPLY_LIMITER", cs%limiter, &
113 "If True, apply a flux limiter in the LBD. This is only available \n"//&
114 "when LATERAL_BOUNDARY_METHOD=2.", default=.false.)
116 call get_param(param_file, mdl,
"LBD_LINEAR_TRANSITION", cs%linear, &
117 "If True, apply a linear transition at the base/top of the boundary. \n"//&
118 "The flux will be fully applied at k=k_min and zero at k=k_max.", default=.false.)
119 call get_param(param_file, mdl,
"LBD_BOUNDARY_EXTRAP", boundary_extrap, &
120 "Use boundary extrapolation in LBD code", &
122 call get_param(param_file, mdl,
"LBD_REMAPPING_SCHEME", string, &
123 "This sets the reconstruction scheme used "//&
124 "for vertical remapping for all variables. "//&
125 "It can be one of the following schemes: "//&
126 trim(remappingschemesdoc), default=remappingdefaultscheme)
127 call initialize_remapping( cs%remap_CS, string, boundary_extrapolation = boundary_extrap )
128 call extract_member_remapping_cs(cs%remap_CS, degree=cs%deg)
130 end function lateral_boundary_diffusion_init
137 subroutine lateral_boundary_diffusion(G, GV, US, h, Coef_x, Coef_y, dt, Reg, CS)
141 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
143 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: coef_x
144 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: coef_y
145 real,
intent(in) :: dt
151 real,
dimension(SZI_(G),SZJ_(G)) :: hbl
152 real,
dimension(SZI_(G),SZJ_(G),SZK_(G),CS%deg+1) :: ppoly0_coefs
153 real,
dimension(SZI_(G),SZJ_(G),SZK_(G),2) :: ppoly0_e
154 real,
dimension(SZK_(G),CS%deg+1) :: ppoly_s
155 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)) :: uflx
156 real,
dimension(SZIB_(G),SZJ_(G)) :: uflx_bulk
157 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)) :: vflx
158 real,
dimension(SZI_(G),SZJB_(G)) :: vflx_bulk
159 real,
dimension(SZIB_(G),SZJ_(G)) :: uwork_2d
160 real,
dimension(SZI_(G),SZJB_(G)) :: vwork_2d
161 real,
dimension(SZI_(G),SZJ_(G),G%ke) :: tendency
162 real,
dimension(SZI_(G),SZJ_(G)) :: tendency_2d
164 integer :: remap_method
170 if (
ASSOCIATED(cs%KPP_CSp))
call kpp_get_bld(cs%KPP_CSp, hbl, g, us, m_to_bld_units=gv%m_to_H)
171 if (
ASSOCIATED(cs%energetic_PBL_CSp)) &
172 call energetic_pbl_get_mld(cs%energetic_PBL_CSp, hbl, g, us, m_to_mld_units=gv%m_to_H)
179 if (tracer%id_lbdxy_conc > 0 .or. tracer%id_lbdxy_cont > 0 .or. tracer%id_lbdxy_cont_2d > 0)
then 180 tendency(:,:,:) = 0.0
184 do j=g%jsc-1,g%jec+1 ;
do i=g%isc-1,g%iec+1
185 call build_reconstructions_1d( cs%remap_CS, g%ke, h(i,j,:), tracer%t(i,j,:), ppoly0_coefs(i,j,:,:), &
186 ppoly0_e(i,j,:,:), ppoly_s, remap_method, gv%H_subroundoff, gv%H_subroundoff)
196 if (cs%method == 1)
then 199 if (g%mask2dCu(i,j)>0.)
then 200 call fluxes_layer_method(surface, gv%ke, cs%deg, h(i,j,:), h(i+1,j,:), hbl(i,j), hbl(i+1,j), &
201 g%areaT(i,j), g%areaT(i+1,j), tracer%t(i,j,:), tracer%t(i+1,j,:), ppoly0_coefs(i,j,:,:), &
202 ppoly0_coefs(i+1,j,:,:), ppoly0_e(i,j,:,:), ppoly0_e(i+1,j,:,:), remap_method, coef_x(i,j), &
203 uflx(i,j,:), cs%linear)
209 if (g%mask2dCv(i,j)>0.)
then 210 call fluxes_layer_method(surface, gv%ke, cs%deg, h(i,j,:), h(i,j+1,:), hbl(i,j), hbl(i,j+1), &
211 g%areaT(i,j), g%areaT(i,j+1), tracer%t(i,j,:), tracer%t(i,j+1,:), ppoly0_coefs(i,j,:,:), &
212 ppoly0_coefs(i,j+1,:,:), ppoly0_e(i,j,:,:), ppoly0_e(i,j+1,:,:), remap_method, coef_y(i,j), &
213 vflx(i,j,:), cs%linear)
219 elseif (cs%method == 2)
then 222 if (g%mask2dCu(i,j)>0.)
then 223 call fluxes_bulk_method(surface, gv%ke, cs%deg, h(i,j,:), h(i+1,j,:), hbl(i,j), hbl(i+1,j), &
224 g%areaT(i,j), g%areaT(i+1,j), tracer%t(i,j,:), tracer%t(i+1,j,:), &
225 ppoly0_coefs(i,j,:,:), ppoly0_coefs(i+1,j,:,:), ppoly0_e(i,j,:,:), &
226 ppoly0_e(i+1,j,:,:), remap_method, coef_x(i,j), uflx_bulk(i,j), uflx(i,j,:), cs%limiter, &
233 if (g%mask2dCv(i,j)>0.)
then 234 call fluxes_bulk_method(surface, gv%ke, cs%deg, h(i,j,:), h(i,j+1,:), hbl(i,j), hbl(i,j+1), &
235 g%areaT(i,j), g%areaT(i,j+1), tracer%t(i,j,:), tracer%t(i,j+1,:), &
236 ppoly0_coefs(i,j,:,:), ppoly0_coefs(i,j+1,:,:), ppoly0_e(i,j,:,:), &
237 ppoly0_e(i,j+1,:,:), remap_method, coef_y(i,j), vflx_bulk(i,j), vflx(i,j,:), cs%limiter, &
243 if (tracer%id_lbd_bulk_dfx>0)
call post_data(tracer%id_lbd_bulk_dfx, uflx_bulk*idt, cs%diag)
244 if (tracer%id_lbd_bulk_dfy>0)
call post_data(tracer%id_lbd_bulk_dfy, vflx_bulk*idt, cs%diag)
248 do k=1,gv%ke ;
do j=g%jsc,g%jec ;
do i=g%isc,g%iec
249 if (g%mask2dT(i,j)>0.)
then 250 tracer%t(i,j,k) = tracer%t(i,j,k) + (( (uflx(i-1,j,k)-uflx(i,j,k)) ) + ( (vflx(i,j-1,k)-vflx(i,j,k) ) ))* &
251 (g%IareaT(i,j)/( h(i,j,k) + gv%H_subroundoff))
253 if (tracer%id_lbdxy_conc > 0 .or. tracer%id_lbdxy_cont > 0 .or. tracer%id_lbdxy_cont_2d > 0 )
then 254 tendency(i,j,k) = (( (uflx(i-1,j,k)-uflx(i,j,k)) ) + ( (vflx(i,j-1,k)-vflx(i,j,k) ) )) * g%IareaT(i,j) * idt
258 enddo ;
enddo ;
enddo 261 if (tracer%id_lbd_dfx>0)
call post_data(tracer%id_lbd_dfx, uflx*idt, cs%diag)
262 if (tracer%id_lbd_dfy>0)
call post_data(tracer%id_lbd_dfy, vflx*idt, cs%diag)
263 if (tracer%id_lbd_dfx_2d>0)
then 265 do k=1,gv%ke ;
do j=g%jsc,g%jec ;
do i=g%isc-1,g%iec
266 uwork_2d(i,j) = uwork_2d(i,j) + (uflx(i,j,k) * idt)
267 enddo ;
enddo ;
enddo 268 call post_data(tracer%id_lbd_dfx_2d, uwork_2d, cs%diag)
271 if (tracer%id_lbd_dfy_2d>0)
then 273 do k=1,gv%ke ;
do j=g%jsc-1,g%jec ;
do i=g%isc,g%iec
274 vwork_2d(i,j) = vwork_2d(i,j) + (vflx(i,j,k) * idt)
275 enddo ;
enddo ;
enddo 276 call post_data(tracer%id_lbd_dfy_2d, vwork_2d, cs%diag)
280 if (tracer%id_lbdxy_cont > 0)
then 281 call post_data(tracer%id_lbdxy_cont, tendency, cs%diag)
285 if (tracer%id_lbdxy_cont_2d > 0)
then 286 tendency_2d(:,:) = 0.
287 do j=g%jsc,g%jec ;
do i=g%isc,g%iec
289 tendency_2d(i,j) = tendency_2d(i,j) + tendency(i,j,k)
292 call post_data(tracer%id_lbdxy_cont_2d, tendency_2d, cs%diag)
298 if (tracer%id_lbdxy_conc > 0)
then 299 do k=1,gv%ke ;
do j=g%jsc,g%jec ;
do i=g%isc,g%iec
300 tendency(i,j,k) = tendency(i,j,k) / ( h(i,j,k) + gv%H_subroundoff )
301 enddo ;
enddo ;
enddo 302 call post_data(tracer%id_lbdxy_conc, tendency, cs%diag)
307 end subroutine lateral_boundary_diffusion
310 real function bulk_average(boundary, nk, deg, h, hBLT, phi, ppoly0_E, ppoly0_coefs, method, k_top, zeta_top, k_bot, &
315 real,
dimension(nk) :: h
317 real,
dimension(nk) :: phi
318 real,
dimension(nk,2) :: ppoly0_e
319 real,
dimension(nk,deg+1) :: ppoly0_coefs
337 if (hblt == 0.)
return 338 if (boundary == surface)
then 339 htot = (h(k_bot) * zeta_bot)
340 bulk_average = average_value_ppoly( nk, phi, ppoly0_e, ppoly0_coefs, method, k_bot, 0., zeta_bot) * htot
342 bulk_average = bulk_average + phi(k)*h(k)
345 elseif (boundary == bottom)
then 346 htot = (h(k_top) * zeta_top)
348 bulk_average = average_value_ppoly( nk, phi, ppoly0_e, ppoly0_coefs, method, k_top, (1.-zeta_top), 1.) * htot
350 bulk_average = bulk_average + phi(k)*h(k)
354 call mom_error(fatal,
"bulk_average: a valid boundary type must be provided.")
357 bulk_average = bulk_average / hblt
359 end function bulk_average
363 real function harmonic_mean(h1,h2)
366 if (h1 + h2 == 0.)
then 369 harmonic_mean = 2.*(h1*h2)/(h1+h2)
371 end function harmonic_mean
374 subroutine boundary_k_range(boundary, nk, h, hbl, k_top, zeta_top, k_bot, zeta_bot)
375 integer,
intent(in ) :: boundary
376 integer,
intent(in ) :: nk
377 real,
dimension(nk),
intent(in ) :: h
378 real,
intent(in ) :: hbl
381 integer,
intent( out) :: k_top
382 real,
intent( out) :: zeta_top
384 integer,
intent( out) :: k_bot
385 real,
intent( out) :: zeta_bot
391 if ( boundary == surface )
then 397 if (hbl == 0.)
return 398 if (hbl >= sum(h(:)))
then 405 if ( htot >= hbl)
then 407 zeta_bot = 1 - (htot - hbl)/h(k)
412 elseif ( boundary == bottom )
then 418 if (hbl == 0.)
return 419 if (hbl >= sum(h(:)))
then 426 if (htot >= hbl)
then 428 zeta_top = 1 - (htot - hbl)/h(k)
433 call mom_error(fatal,
"Houston, we've had a problem in boundary_k_range")
436 end subroutine boundary_k_range
441 subroutine fluxes_layer_method(boundary, nk, deg, h_L, h_R, hbl_L, hbl_R, area_L, area_R, phi_L, phi_R, &
442 ppoly0_coefs_L, ppoly0_coefs_R, ppoly0_E_L, ppoly0_E_R, method, khtr_u, &
443 F_layer, linear_decay)
445 integer,
intent(in ) :: boundary
446 integer,
intent(in ) :: nk
447 integer,
intent(in ) :: deg
448 real,
dimension(nk),
intent(in ) :: h_L
449 real,
dimension(nk),
intent(in ) :: h_R
450 real,
intent(in ) :: hbl_L
452 real,
intent(in ) :: hbl_R
454 real,
intent(in ) :: area_L
455 real,
intent(in ) :: area_R
456 real,
dimension(nk),
intent(in ) :: phi_L
457 real,
dimension(nk),
intent(in ) :: phi_R
458 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_L
459 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_R
460 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_L
461 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_R
462 integer,
intent(in ) :: method
463 real,
intent(in ) :: khtr_u
465 real,
dimension(nk),
intent( out) :: F_layer
467 logical,
optional,
intent(in ) :: linear_decay
470 real,
dimension(nk) :: h_means
477 real :: phi_L_avg, phi_R_avg
481 integer :: k, k_bot_min, k_top_max
482 integer :: k_bot_max, k_top_min
483 integer :: k_bot_diff, k_top_diff
484 integer :: k_top_L, k_bot_L
485 integer :: k_top_R, k_bot_R
486 real :: zeta_top_L, zeta_top_R
488 real :: zeta_bot_L, zeta_bot_R
490 real :: h_work_L, h_work_R
497 if (hbl_l == 0. .or. hbl_r == 0.)
then 502 if (
PRESENT(linear_decay))
then 503 linear = linear_decay
507 call boundary_k_range(boundary, nk, h_l, hbl_l, k_top_l, zeta_top_l, k_bot_l, zeta_bot_l)
508 call boundary_k_range(boundary, nk, h_r, hbl_r, k_top_r, zeta_top_r, k_bot_r, zeta_bot_r)
510 if (boundary == surface)
then 511 k_bot_min = min(k_bot_l, k_bot_r)
512 k_bot_max = max(k_bot_l, k_bot_r)
513 k_bot_diff = (k_bot_max - k_bot_min)
516 if (k_bot_min .ne. k_bot_l)
then 520 if (k_bot_min .ne. k_bot_r)
then 525 h_work_l = (h_l(k_bot_l) * zeta_bot_l)
526 h_work_r = (h_r(k_bot_r) * zeta_bot_r)
528 phi_l_avg = average_value_ppoly( nk, phi_l, ppoly0_e_l, ppoly0_coefs_l, method, k_bot_l, 0., zeta_bot_l)
529 phi_r_avg = average_value_ppoly( nk, phi_r, ppoly0_e_r, ppoly0_coefs_r, method, k_bot_r, 0., zeta_bot_r)
530 heff = harmonic_mean(h_work_l, h_work_r)
533 if ((linear) .and. (k_bot_diff .gt. 1))
then 535 do k = k_bot_min,1,-1
536 heff = harmonic_mean(h_l(k), h_r(k))
537 f_layer(k) = -(heff * khtr_u) * (phi_r(k) - phi_l(k))
541 do k = k_bot_min+1,k_bot_max, 1
542 heff_tot = heff_tot + harmonic_mean(h_l(k), h_r(k))
547 do k = k_bot_min+1,k_bot_max, 1
548 heff = harmonic_mean(h_l(k), h_r(k))
549 wgt = (a*(heff_tot + (heff * 0.5))) + 1.0
550 f_layer(k) = -(heff * khtr_u) * (phi_r(k) - phi_l(k)) * wgt
551 heff_tot = heff_tot + heff
554 f_layer(k_bot_min) = -(heff * khtr_u) * (phi_r_avg - phi_l_avg)
555 do k = k_bot_min-1,1,-1
556 heff = harmonic_mean(h_l(k), h_r(k))
557 f_layer(k) = -(heff * khtr_u) * (phi_r(k) - phi_l(k))
562 if (boundary == bottom)
then 564 k_top_max = max(k_top_l, k_top_r)
566 if (k_top_max .ne. k_top_l)
then 570 if (k_top_max .ne. k_top_r)
then 575 h_work_l = (h_l(k_top_l) * zeta_top_l)
576 h_work_r = (h_r(k_top_r) * zeta_top_r)
578 phi_l_avg = average_value_ppoly( nk, phi_l, ppoly0_e_l, ppoly0_coefs_l, method, k_top_l, 1.0-zeta_top_l, 1.0)
579 phi_r_avg = average_value_ppoly( nk, phi_r, ppoly0_e_r, ppoly0_coefs_r, method, k_top_r, 1.0-zeta_top_r, 1.0)
580 heff = harmonic_mean(h_work_l, h_work_r)
583 f_layer(k_top_max) = (-heff * khtr_u) * (phi_r_avg - phi_l_avg)
585 do k = k_top_max+1,nk
586 heff = harmonic_mean(h_l(k), h_r(k))
587 f_layer(k) = -(heff * khtr_u) * (phi_r(k) - phi_l(k))
591 end subroutine fluxes_layer_method
595 subroutine fluxes_bulk_method(boundary, nk, deg, h_L, h_R, hbl_L, hbl_R, area_L, area_R, phi_L, phi_R, ppoly0_coefs_L, &
596 ppoly0_coefs_R, ppoly0_E_L, ppoly0_E_R, method, khtr_u, F_bulk, F_layer, F_limit, &
599 integer,
intent(in ) :: boundary
600 integer,
intent(in ) :: nk
601 integer,
intent(in ) :: deg
602 real,
dimension(nk),
intent(in ) :: h_L
603 real,
dimension(nk),
intent(in ) :: h_R
604 real,
intent(in ) :: hbl_L
606 real,
intent(in ) :: hbl_R
608 real,
intent(in ) :: area_L
609 real,
intent(in ) :: area_R
610 real,
dimension(nk),
intent(in ) :: phi_L
611 real,
dimension(nk),
intent(in ) :: phi_R
612 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_L
613 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_R
614 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_L
615 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_R
616 integer,
intent(in ) :: method
617 real,
intent(in ) :: khtr_u
619 real,
intent( out) :: F_bulk
621 real,
dimension(nk),
intent( out) :: F_layer
623 logical,
optional,
intent(in ) :: F_limit
624 logical,
optional,
intent(in ) :: linear_decay
628 real,
dimension(nk) :: h_means
636 real :: phi_L_avg, phi_R_avg
639 integer :: k, k_min, k_max
641 integer :: k_top_L, k_bot_L
642 integer :: k_top_R, k_bot_R
643 real :: zeta_top_L, zeta_top_R
645 real :: zeta_bot_L, zeta_bot_R
647 real :: h_work_L, h_work_R
661 if (hbl_l == 0. .or. hbl_r == 0.)
then 666 if (
PRESENT(f_limit))
then 670 if (
PRESENT(linear_decay))
then 671 linear = linear_decay
675 call boundary_k_range(boundary, nk, h_l, hbl_l, k_top_l, zeta_top_l, k_bot_l, zeta_bot_l)
676 call boundary_k_range(boundary, nk, h_r, hbl_r, k_top_r, zeta_top_r, k_bot_r, zeta_bot_r)
679 phi_l_avg = bulk_average(boundary, nk, deg, h_l, hbl_l, phi_l, ppoly0_e_l, ppoly0_coefs_l, method, k_top_l, &
680 zeta_top_l, k_bot_l, zeta_bot_l)
681 phi_r_avg = bulk_average(boundary, nk, deg, h_r, hbl_r, phi_r, ppoly0_e_r, ppoly0_coefs_r, method, k_top_r, &
682 zeta_top_r, k_bot_r, zeta_bot_r)
685 heff = harmonic_mean(hbl_l, hbl_r)
686 f_bulk = -(khtr_u * heff) * (phi_r_avg - phi_l_avg)
690 if (boundary == surface)
then 691 k_min = min(k_bot_l, k_bot_r)
692 k_max = max(k_bot_l, k_bot_r)
693 k_diff = (k_max - k_min)
694 if ((linear) .and. (k_diff .gt. 1))
then 696 h_means(k) = harmonic_mean(h_l(k),h_r(k))
700 do k = k_min+1,k_max, 1
701 heff_tot = heff_tot + harmonic_mean(h_l(k), h_r(k))
707 do k = k_min+1,k_max, 1
708 heff = harmonic_mean(h_l(k), h_r(k))
709 wgt = (a*(heff_tot + (heff * 0.5))) + 1.0
710 h_means(k) = harmonic_mean(h_l(k), h_r(k)) * wgt
711 heff_tot = heff_tot + heff
715 if (k_bot_l == k_min)
then 716 h_work_l = h_l(k_min) * zeta_bot_l
718 h_work_l = h_l(k_min)
722 if (k_bot_r == k_min)
then 723 h_work_r = h_r(k_min) * zeta_bot_r
725 h_work_r = h_r(k_min)
728 h_means(k_min) = harmonic_mean(h_work_l,h_work_r)
731 h_means(k) = harmonic_mean(h_l(k),h_r(k))
735 elseif (boundary == bottom)
then 737 k_max = max(k_top_l, k_top_r)
739 if (k_top_l == k_max)
then 740 h_work_l = h_l(k_max) * zeta_top_l
742 h_work_l = h_l(k_max)
746 if (k_top_r == k_max)
then 747 h_work_r = h_r(k_max) * zeta_top_r
749 h_work_r = h_r(k_max)
752 h_means(k_max) = harmonic_mean(h_work_l,h_work_r)
755 h_means(k) = harmonic_mean(h_l(k),h_r(k))
759 if ( sum(h_means) == 0. .or. f_bulk == 0.)
then 764 inv_heff = 1./sum(h_means)
766 if ((h_means(k) > 0.) .and. (phi_l(k) /= phi_r(k)))
then 767 hfrac = h_means(k)*inv_heff
768 f_layer(k) = f_bulk * hfrac
778 f_max = -0.2 * ((area_r*(phi_r(k)*h_r(k)))-(area_l*(phi_l(k)*h_r(k))))
781 if ( sign(1.,f_bulk) == sign(1., f_max))
then 783 if (f_max >= 0.)
then 784 f_layer(k) = min(f_layer(k),f_max)
786 f_layer(k) = max(f_layer(k),f_max)
793 dphi = -(phi_r(k) - phi_l(k))
794 if (.not. sign(1.,f_bulk) == sign(1., dphi))
then 803 end subroutine fluxes_bulk_method
806 logical function near_boundary_unit_tests( verbose )
807 logical,
intent(in) :: verbose
810 integer,
parameter :: nk = 2
811 integer,
parameter :: deg = 1
812 integer,
parameter :: method = 1
813 real,
dimension(nk) :: phi_l, phi_r
814 real,
dimension(nk) :: phi_l_avg, phi_r_avg
815 real,
dimension(nk,deg+1) :: phi_pp_l, phi_pp_r
818 real,
dimension(nk,2) :: ppoly0_e_l, ppoly0_e_r
819 real,
dimension(nk) :: h_l, h_r
823 real,
dimension(nk) :: f_layer
828 character(len=120) :: test_name
833 real :: area_l,area_r
834 area_l = 1.; area_r = 1.
836 near_boundary_unit_tests = .false.
839 test_name =
'Surface boundary spans the entire top cell' 841 call boundary_k_range(surface, nk, h_l, 5., k_top, zeta_top, k_bot, zeta_bot)
842 near_boundary_unit_tests = near_boundary_unit_tests .or. &
843 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 0., 1, 1., test_name, verbose)
845 test_name =
'Surface boundary spans the entire column' 847 call boundary_k_range(surface, nk, h_l, 10., k_top, zeta_top, k_bot, zeta_bot)
848 near_boundary_unit_tests = near_boundary_unit_tests .or. &
849 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 0., 2, 1., test_name, verbose)
851 test_name =
'Bottom boundary spans the entire bottom cell' 853 call boundary_k_range(bottom, nk, h_l, 5., k_top, zeta_top, k_bot, zeta_bot)
854 near_boundary_unit_tests = near_boundary_unit_tests .or. &
855 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 2, 1., 2, 0., test_name, verbose)
857 test_name =
'Bottom boundary spans the entire column' 859 call boundary_k_range(bottom, nk, h_l, 10., k_top, zeta_top, k_bot, zeta_bot)
860 near_boundary_unit_tests = near_boundary_unit_tests .or. &
861 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 1., 2, 0., test_name, verbose)
863 test_name =
'Surface boundary intersects second layer' 865 call boundary_k_range(surface, nk, h_l, 17.5, k_top, zeta_top, k_bot, zeta_bot)
866 near_boundary_unit_tests = near_boundary_unit_tests .or. &
867 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 0., 2, 0.75, test_name, verbose)
869 test_name =
'Surface boundary intersects first layer' 871 call boundary_k_range(surface, nk, h_l, 2.5, k_top, zeta_top, k_bot, zeta_bot)
872 near_boundary_unit_tests = near_boundary_unit_tests .or. &
873 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 0., 1, 0.25, test_name, verbose)
875 test_name =
'Surface boundary is deeper than column thickness' 877 call boundary_k_range(surface, nk, h_l, 21.0, k_top, zeta_top, k_bot, zeta_bot)
878 near_boundary_unit_tests = near_boundary_unit_tests .or. &
879 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 0., 2, 1., test_name, verbose)
881 test_name =
'Bottom boundary intersects first layer' 883 call boundary_k_range(bottom, nk, h_l, 17.5, k_top, zeta_top, k_bot, zeta_bot)
884 near_boundary_unit_tests = near_boundary_unit_tests .or. &
885 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 1, 0.75, 2, 0., test_name, verbose)
887 test_name =
'Bottom boundary intersects second layer' 889 call boundary_k_range(bottom, nk, h_l, 2.5, k_top, zeta_top, k_bot, zeta_bot)
890 near_boundary_unit_tests = near_boundary_unit_tests .or. &
891 test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, 2, 0.25, 2, 0., test_name, verbose)
894 test_name =
'Equal hbl and same layer thicknesses (gradient from right to left)' 895 hbl_l = 10; hbl_r = 10
896 h_l = (/5.,5./) ; h_r = (/5.,5./)
897 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
898 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
899 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
900 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
901 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
902 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
903 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
904 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
905 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
908 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r, &
909 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
910 near_boundary_unit_tests = near_boundary_unit_tests .or. &
911 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-5.0,-5.0/) )
914 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r, &
915 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer, .true.)
916 near_boundary_unit_tests = near_boundary_unit_tests .or. &
917 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-1.0,-1.0/) )
919 test_name =
'Equal hbl and same layer thicknesses (gradient from left to right)' 920 hbl_l = 10.; hbl_r = 10.
921 h_l = (/5.,5./) ; h_r = (/5.,5./)
922 phi_l = (/1.,1./) ; phi_r = (/0.,0./)
923 phi_pp_l(1,1) = 1.; phi_pp_l(1,2) = 0.
924 phi_pp_l(2,1) = 1.; phi_pp_l(2,2) = 0.
925 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 0.
926 phi_pp_r(2,1) = 0.; phi_pp_r(2,2) = 0.
927 ppoly0_e_l(1,1) = 1.; ppoly0_e_l(1,2) = 1.
928 ppoly0_e_l(2,1) = 1.; ppoly0_e_l(2,2) = 1.
929 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 0.
930 ppoly0_e_r(2,1) = 0.; ppoly0_e_r(2,2) = 0.
932 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
933 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
934 near_boundary_unit_tests = near_boundary_unit_tests .or. &
935 test_layer_fluxes( verbose, nk, test_name, f_layer, (/5.0,5.0/) )
937 test_name =
'Equal hbl and same layer thicknesses (no gradient)' 938 hbl_l = 10; hbl_r = 10
939 h_l = (/5.,5./) ; h_r = (/5.,5./)
940 phi_l = (/1.,1./) ; phi_r = (/1.,1./)
941 phi_pp_l(1,1) = 1.; phi_pp_l(1,2) = 0.
942 phi_pp_l(2,1) = 1.; phi_pp_l(2,2) = 0.
943 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
944 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
945 ppoly0_e_l(1,1) = 1.; ppoly0_e_l(1,2) = 1.
946 ppoly0_e_l(2,1) = 1.; ppoly0_e_l(2,2) = 1.
947 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
948 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
950 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
951 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
952 near_boundary_unit_tests = near_boundary_unit_tests .or. &
953 test_layer_fluxes( verbose, nk, test_name, f_layer, (/0.0,0.0/) )
955 test_name =
'Equal hbl and different layer thicknesses (gradient right to left)' 956 hbl_l = 16.; hbl_r = 16.
957 h_l = (/10.,6./) ; h_r = (/6.,10./)
958 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
959 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
960 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
961 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
962 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
963 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
964 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
965 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
966 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
968 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
969 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
970 near_boundary_unit_tests = near_boundary_unit_tests .or. &
971 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-8.0,-8.0/) )
973 test_name =
'Equal hbl and same layer thicknesses (diagonal tracer values)' 974 hbl_l = 10.; hbl_r = 10.
975 h_l = (/5.,5./) ; h_r = (/5.,5./)
976 phi_l = (/1.,0./) ; phi_r = (/0.,1./)
977 phi_pp_l(1,1) = 1.; phi_pp_l(1,2) = 0.
978 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
979 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 0.
980 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
981 ppoly0_e_l(1,1) = 1.; ppoly0_e_l(1,2) = 1.
982 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
983 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 0.
984 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
986 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
987 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
988 near_boundary_unit_tests = near_boundary_unit_tests .or. &
989 test_layer_fluxes( verbose, nk, test_name, f_layer, (/0.0,0.0/) )
991 test_name =
'Different hbl and different layer thicknesses (gradient from right to left)' 992 hbl_l = 12; hbl_r = 20
993 h_l = (/6.,6./) ; h_r = (/10.,10./)
994 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
995 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
996 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
997 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
998 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
999 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
1000 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
1001 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
1002 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
1004 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
1005 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
1006 near_boundary_unit_tests = near_boundary_unit_tests .or. &
1007 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-7.5,-7.5/) )
1011 test_name =
'hbl < column thickness, hbl same, constant concentration each column' 1012 hbl_l = 2; hbl_r = 2
1013 h_l = (/1.,2./) ; h_r = (/1.,2./)
1014 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
1015 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
1016 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
1017 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
1018 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
1019 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
1020 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
1021 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
1022 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
1024 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
1025 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
1026 near_boundary_unit_tests = near_boundary_unit_tests .or. &
1027 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-1.,-1./) )
1029 test_name =
'hbl < column thickness, hbl same, linear profile right' 1030 hbl_l = 2; hbl_r = 2
1031 h_l = (/1.,2./) ; h_r = (/1.,2./)
1032 phi_l = (/0.,0./) ; phi_r = (/0.5,2./)
1033 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
1034 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
1035 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 1.
1036 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 2.
1038 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
1039 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
1040 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 1.
1041 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 3.
1042 call fluxes_bulk_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, phi_pp_r,&
1043 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
1044 near_boundary_unit_tests = near_boundary_unit_tests .or. &
1045 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-1.,-1./) )
1047 test_name =
'hbl < column thickness, hbl same, linear profile right, khtr=2' 1048 hbl_l = 2; hbl_r = 2
1049 h_l = (/1.,2./) ; h_r = (/1.,2./)
1050 phi_l = (/0.,0./) ; phi_r = (/0.5,2./)
1051 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
1052 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
1053 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 1.
1054 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 2.
1056 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
1057 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
1058 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 1.
1059 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 3.
1060 call fluxes_layer_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, &
1061 phi_pp_r, ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_layer)
1062 near_boundary_unit_tests = near_boundary_unit_tests .or. &
1063 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-1.,-3./) )
1066 test_name =
'Different hbl and different column thicknesses (gradient from right to left)' 1067 hbl_l = 12; hbl_r = 20
1068 h_l = (/6.,6./) ; h_r = (/10.,10./)
1069 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
1070 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
1071 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
1072 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
1073 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
1074 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
1075 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
1076 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
1077 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
1079 call fluxes_layer_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, &
1080 phi_pp_r, ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_layer)
1081 near_boundary_unit_tests = near_boundary_unit_tests .or. &
1082 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-7.5,-7.5/) )
1084 test_name =
'Different hbl and different column thicknesses (linear profile right)' 1086 hbl_l = 15; hbl_r = 6
1087 h_l = (/10.,10./) ; h_r = (/12.,10./)
1088 phi_l = (/0.,0./) ; phi_r = (/1.,3./)
1089 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
1090 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
1091 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 2.
1092 phi_pp_r(2,1) = 2.; phi_pp_r(2,2) = 2.
1093 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
1094 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
1095 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 2.
1096 ppoly0_e_r(2,1) = 2.; ppoly0_e_r(2,2) = 4.
1098 call fluxes_layer_method(surface, nk, deg, h_l, h_r, hbl_l, hbl_r, area_l, area_r, phi_l, phi_r, phi_pp_l, &
1099 phi_pp_r, ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_layer)
1100 near_boundary_unit_tests = near_boundary_unit_tests .or. &
1101 test_layer_fluxes( verbose, nk, test_name, f_layer, (/-3.75,0.0/) )
1102 end function near_boundary_unit_tests
1106 logical function test_layer_fluxes(verbose, nk, test_name, F_calc, F_ans)
1107 logical,
intent(in) :: verbose
1108 character(len=80),
intent(in) :: test_name
1109 integer,
intent(in) :: nk
1110 real,
dimension(nk),
intent(in) :: f_calc
1111 real,
dimension(nk),
intent(in) :: f_ans
1114 integer,
parameter :: stdunit = stdout
1116 test_layer_fluxes = .false.
1118 if ( f_calc(k) /= f_ans(k) )
then 1119 test_layer_fluxes = .true.
1120 write(stdunit,*)
"MOM_lateral_boundary_diffusion, UNIT TEST FAILED: ", test_name
1121 write(stdunit,10) k, f_calc(k), f_ans(k)
1122 elseif (verbose)
then 1123 write(stdunit,10) k, f_calc(k), f_ans(k)
1127 10
format(
"Layer=",i3,
" F_calc=",f20.16,
" F_ans",f20.16)
1128 end function test_layer_fluxes
1131 logical function test_boundary_k_range(k_top, zeta_top, k_bot, zeta_bot, k_top_ans, zeta_top_ans,&
1132 k_bot_ans, zeta_bot_ans, test_name, verbose)
1137 integer :: k_top_ans
1138 real :: zeta_top_ans
1139 integer :: k_bot_ans
1140 real :: zeta_bot_ans
1141 character(len=80) :: test_name
1144 integer,
parameter :: stdunit = stdout
1146 test_boundary_k_range = k_top .ne. k_top_ans
1147 test_boundary_k_range = test_boundary_k_range .or. (zeta_top .ne. zeta_top_ans)
1148 test_boundary_k_range = test_boundary_k_range .or. (k_bot .ne. k_bot_ans)
1149 test_boundary_k_range = test_boundary_k_range .or. (zeta_bot .ne. zeta_bot_ans)
1151 if (test_boundary_k_range)
write(stdunit,*)
"UNIT TEST FAILED: ", test_name
1152 if (test_boundary_k_range .or. verbose)
then 1153 write(stdunit,20)
"k_top", k_top,
"k_top_ans", k_top_ans
1154 write(stdunit,20)
"k_bot", k_bot,
"k_bot_ans", k_bot_ans
1155 write(stdunit,30)
"zeta_top", zeta_top,
"zeta_top_ans", zeta_top_ans
1156 write(stdunit,30)
"zeta_bot", zeta_bot,
"zeta_bot_ans", zeta_bot_ans
1159 20
format(a,
"=",i3,x,a,
"=",i3)
1160 30
format(a,
"=",f20.16,x,a,
"=",f20.16)
1163 end function test_boundary_k_range
Calculates and applies diffusive fluxes as a parameterization of lateral mixing (non-neutral) by meso...
Ocean grid type. See mom_grid for details.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Provides column-wise vertical remapping functions.
Wraps the MPP cpu clock functions.
This routine drives the diabatic/dianeutral physics for MOM.
Sets parameters for lateral boundary mixing module.
This control structure holds parameters for the MOM_energetic_PBL module.
The MOM6 facility to parse input files for runtime parameters.
Container for remapping parameters.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Type to carry basic tracer information.
Routines for error handling and I/O management.
Control structure for containing KPP parameters/data.
Energetically consistent planetary boundary layer parameterization.
Control structure for this module.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Provides a transparent vertical ocean grid type and supporting routines.
Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix.
Do a halo update on an array.
An overloaded interface to read and log the values of various types of parameters.