8 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
27 implicit none ;
private
33 integer,
public,
parameter ::
surface = -1
34 integer,
public,
parameter ::
bottom = 1
35 #include <MOM_memory.h>
44 integer :: surface_boundary_scheme
47 type(
kpp_cs),
pointer :: kpp_csp => null()
54 #include "version_variable.h"
55 character(len=40) ::
mdl =
"MOM_lateral_boundary_diffusion"
62 type(time_type),
target,
intent(in) :: time
65 type(
diag_ctrl),
target,
intent(inout) :: diag
70 character(len=80) :: string
71 logical :: boundary_extrap
73 if (
ASSOCIATED(cs))
then
74 call mom_error(fatal,
"lateral_boundary_diffusion_init called with associated control structure.")
80 "This module implements lateral diffusion of tracers near boundaries")
82 "If true, enables the lateral boundary tracer's diffusion module.", &
94 cs%surface_boundary_scheme = -1
95 if ( .not.
ASSOCIATED(cs%energetic_PBL_CSp) .and. .not.
ASSOCIATED(cs%KPP_CSp) )
then
96 call mom_error(fatal,
"Lateral boundary diffusion is true, but no valid boundary layer scheme was found")
100 call get_param(param_file,
mdl,
"LATERAL_BOUNDARY_METHOD", cs%method, &
101 "Determine how to apply boundary lateral diffusion of tracers: \n"//&
102 "1. Bulk layer approach \n"//&
103 "2. Along layer approach", default=1)
104 call get_param(param_file,
mdl,
"LBD_BOUNDARY_EXTRAP", boundary_extrap, &
105 "Use boundary extrapolation in LBD code", &
107 call get_param(param_file,
mdl,
"LBD_REMAPPING_SCHEME", string, &
108 "This sets the reconstruction scheme used "//&
109 "for vertical remapping for all variables. "//&
110 "It can be one of the following schemes: "//&
112 call initialize_remapping( cs%remap_CS, string, boundary_extrapolation = boundary_extrap )
113 call extract_member_remapping_cs(cs%remap_CS, degree=cs%deg)
126 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
128 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: coef_x
129 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: coef_y
130 real,
intent(in) :: dt
136 real,
dimension(SZI_(G),SZJ_(G)) :: hbl
137 real,
dimension(SZI_(G),SZJ_(G),SZK_(G),CS%deg+1) :: ppoly0_coefs
138 real,
dimension(SZI_(G),SZJ_(G),SZK_(G),2) :: ppoly0_e
139 real,
dimension(SZK_(G),CS%deg+1) :: ppoly_s
140 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)) :: uflx
141 real,
dimension(SZIB_(G),SZJ_(G)) :: uflx_bulk
142 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)) :: vflx
143 real,
dimension(SZI_(G),SZJB_(G)) :: vflx_bulk
144 real,
dimension(SZIB_(G),SZJ_(G)) :: uwork_2d
145 real,
dimension(SZI_(G),SZJB_(G)) :: vwork_2d
146 real,
dimension(SZI_(G),SZJ_(G),G%ke) :: tendency
147 real,
dimension(SZI_(G),SZJ_(G)) :: tendency_2d
149 integer :: remap_method
155 if (
ASSOCIATED(cs%KPP_CSp))
call kpp_get_bld(cs%KPP_CSp, hbl, g)
163 if (tracer%id_lbdxy_conc > 0 .or. tracer%id_lbdxy_cont > 0 .or. tracer%id_lbdxy_cont_2d > 0)
then
164 tendency(:,:,:) = 0.0
167 do j = g%jsc-1, g%jec+1
169 do i = g%isc-1, g%iec+1
170 call build_reconstructions_1d( cs%remap_CS, g%ke, h(i,j,:), tracer%t(i,j,:), ppoly0_coefs(i,j,:,:), &
171 ppoly0_e(i,j,:,:), ppoly_s, remap_method, gv%H_subroundoff, gv%H_subroundoff)
181 if ( cs%method == 1 )
then
184 if (g%mask2dCu(i,j)>0.)
then
185 call fluxes_bulk_method(
surface, gv%ke, cs%deg, h(i,j,:), h(i+1,j,:), hbl(i,j), hbl(i+1,j), &
186 g%areaT(i,j), g%areaT(i+1,j), tracer%t(i,j,:), tracer%t(i+1,j,:), &
187 ppoly0_coefs(i,j,:,:), ppoly0_coefs(i+1,j,:,:), ppoly0_e(i,j,:,:), &
188 ppoly0_e(i+1,j,:,:), remap_method, coef_x(i,j), uflx_bulk(i,j), uflx(i,j,:))
194 if (g%mask2dCv(i,j)>0.)
then
195 call fluxes_bulk_method(
surface, gv%ke, cs%deg, h(i,j,:), h(i,j+1,:), hbl(i,j), hbl(i,j+1), &
196 g%areaT(i,j), g%areaT(i,j+1), tracer%t(i,j,:), tracer%t(i,j+1,:), &
197 ppoly0_coefs(i,j,:,:), ppoly0_coefs(i,j+1,:,:), ppoly0_e(i,j,:,:), &
198 ppoly0_e(i,j+1,:,:), remap_method, coef_y(i,j), vflx_bulk(i,j), vflx(i,j,:))
203 if (tracer%id_lbd_bulk_dfx>0)
call post_data(tracer%id_lbd_bulk_dfx, uflx_bulk*idt, cs%diag)
204 if (tracer%id_lbd_bulk_dfy>0)
call post_data(tracer%id_lbd_bulk_dfy, vflx_bulk*idt, cs%diag)
207 elseif (cs%method == 2)
then
210 if (g%mask2dCu(i,j)>0.)
then
211 call fluxes_layer_method(
surface, gv%ke, cs%deg, h(i,j,:), h(i+1,j,:), hbl(i,j), hbl(i+1,j), &
212 g%areaT(i,j), g%areaT(i+1,j), tracer%t(i,j,:), tracer%t(i+1,j,:), ppoly0_coefs(i,j,:,:), &
213 ppoly0_coefs(i+1,j,:,:), ppoly0_e(i,j,:,:), ppoly0_e(i+1,j,:,:), remap_method, coef_x(i,j), uflx(i,j,:))
219 if (g%mask2dCv(i,j)>0.)
then
220 call fluxes_layer_method(
surface, gv%ke, cs%deg, h(i,j,:), h(i,j+1,:), hbl(i,j), hbl(i,j+1), &
221 g%areaT(i,j), g%areaT(i,j+1), tracer%t(i,j,:), tracer%t(i,j+1,:), ppoly0_coefs(i,j,:,:), &
222 ppoly0_coefs(i,j+1,:,:), ppoly0_e(i,j,:,:), ppoly0_e(i,j+1,:,:), remap_method, coef_y(i,j), vflx(i,j,:))
229 do k=1,gv%ke ;
do j=g%jsc,g%jec ;
do i=g%isc,g%iec
230 if (g%mask2dT(i,j)>0.)
then
231 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) ) ))* &
232 (g%IareaT(i,j)/( h(i,j,k) + gv%H_subroundoff))
234 if (tracer%id_lbdxy_conc > 0 .or. tracer%id_lbdxy_cont > 0 .or. tracer%id_lbdxy_cont_2d > 0 )
then
235 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
239 enddo ;
enddo ;
enddo
242 if (tracer%id_lbd_dfx>0)
call post_data(tracer%id_lbd_dfx, uflx*idt, cs%diag)
243 if (tracer%id_lbd_dfy>0)
call post_data(tracer%id_lbd_dfy, vflx*idt, cs%diag)
244 if (tracer%id_lbd_dfx_2d>0)
then
246 do k=1,gv%ke;
do j=g%jsc,g%jec;
do i=g%isc-1,g%iec
247 uwork_2d(i,j) = uwork_2d(i,j) + (uflx(i,j,k) * idt)
249 call post_data(tracer%id_lbd_dfx_2d, uwork_2d, cs%diag)
252 if (tracer%id_lbd_dfy_2d>0)
then
254 do k=1,gv%ke;
do j=g%jsc-1,g%jec;
do i=g%isc,g%iec
255 vwork_2d(i,j) = vwork_2d(i,j) + (vflx(i,j,k) * idt)
257 call post_data(tracer%id_lbd_dfy_2d, vwork_2d, cs%diag)
261 if (tracer%id_lbdxy_cont > 0)
then
262 call post_data(tracer%id_lbdxy_cont, tendency(:,:,:), cs%diag)
266 if (tracer%id_lbdxy_cont_2d > 0)
then
267 tendency_2d(:,:) = 0.
268 do j = g%jsc,g%jec ;
do i = g%isc,g%iec
270 tendency_2d(i,j) = tendency_2d(i,j) + tendency(i,j,k)
273 call post_data(tracer%id_lbdxy_cont_2d, tendency_2d(:,:), cs%diag)
279 if (tracer%id_lbdxy_conc > 0)
then
280 do k = 1, gv%ke ;
do j = g%jsc,g%jec ;
do i = g%isc,g%iec
281 tendency(i,j,k) = tendency(i,j,k) / ( h(i,j,k) + gv%H_subroundoff )
282 enddo ;
enddo ;
enddo
283 call post_data(tracer%id_lbdxy_conc, tendency, cs%diag)
291 real function bulk_average(boundary, nk, deg, h, hBLT, phi, ppoly0_E, ppoly0_coefs, method, k_top, zeta_top, k_bot, &
296 real,
dimension(nk) :: h
298 real,
dimension(nk) :: phi
299 real,
dimension(nk,2) :: ppoly0_e(:,:)
300 real,
dimension(nk,deg+1) :: ppoly0_coefs(:,:)
318 if (hblt == 0.)
return
320 htot = (h(k_bot) * zeta_bot)
326 elseif (boundary ==
bottom)
then
327 htot = (h(k_top) * zeta_top)
335 call mom_error(fatal,
"bulk_average: a valid boundary type must be provided.")
347 if (h1 + h2 == 0.)
then
355 subroutine boundary_k_range(boundary, nk, h, hbl, k_top, zeta_top, k_bot, zeta_bot)
356 integer,
intent(in ) :: boundary
357 integer,
intent(in ) :: nk
358 real,
dimension(nk),
intent(in ) :: h
359 real,
intent(in ) :: hbl
362 integer,
intent( out) :: k_top
363 real,
intent( out) :: zeta_top
365 integer,
intent( out) :: k_bot
366 real,
intent( out) :: zeta_bot
372 if ( boundary ==
surface )
then
378 if (hbl == 0.)
return
379 if (hbl >= sum(h(:)))
then
386 if ( htot >= hbl)
then
388 zeta_bot = 1 - (htot - hbl)/h(k)
393 elseif ( boundary ==
bottom )
then
399 if (hbl == 0.)
return
400 if (hbl >= sum(h(:)))
then
407 if (htot >= hbl)
then
409 zeta_top = 1 - (htot - hbl)/h(k)
414 call mom_error(fatal,
"Houston, we've had a problem in boundary_k_range")
422 subroutine fluxes_layer_method(boundary, nk, deg, h_L, h_R, hbl_L, hbl_R, area_L, area_R, phi_L, phi_R, &
423 ppoly0_coefs_L, ppoly0_coefs_R, ppoly0_E_L, ppoly0_E_R, method, khtr_u, F_layer)
425 integer,
intent(in ) :: boundary
426 integer,
intent(in ) :: nk
427 integer,
intent(in ) :: deg
428 real,
dimension(nk),
intent(in ) :: h_L
429 real,
dimension(nk),
intent(in ) :: h_R
430 real,
intent(in ) :: hbl_L
432 real,
intent(in ) :: hbl_R
434 real,
intent(in ) :: area_L
435 real,
intent(in ) :: area_R
436 real,
dimension(nk),
intent(in ) :: phi_L
437 real,
dimension(nk),
intent(in ) :: phi_R
438 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_L
439 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_R
440 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_L
441 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_R
442 integer,
intent(in ) :: method
443 real,
intent(in ) :: khtr_u
444 real,
dimension(nk),
intent( out) :: F_layer
447 real,
dimension(nk) :: h_means
453 real :: phi_L_avg, phi_R_avg
456 integer :: k, k_bot_min, k_top_max
457 integer :: k_top_L, k_bot_L
458 integer :: k_top_R, k_bot_R
459 real :: zeta_top_L, zeta_top_R
461 real :: zeta_bot_L, zeta_bot_R
463 real :: h_work_L, h_work_R
467 if (hbl_l == 0. .or. hbl_r == 0.)
then
472 call boundary_k_range(boundary, nk, h_l, hbl_l, k_top_l, zeta_top_l, k_bot_l, zeta_bot_l)
473 call boundary_k_range(boundary, nk, h_r, hbl_r, k_top_r, zeta_top_r, k_bot_r, zeta_bot_r)
476 k_bot_min = min(k_bot_l, k_bot_r)
478 if (k_bot_min .ne. k_bot_l)
then
482 if (k_bot_min .ne. k_bot_r)
then
487 h_work_l = (h_l(k_bot_l) * zeta_bot_l)
488 h_work_r = (h_r(k_bot_r) * zeta_bot_r)
490 phi_l_avg =
average_value_ppoly( nk, phi_l, ppoly0_e_l, ppoly0_coefs_l, method, k_bot_l, 0., zeta_bot_l)
491 phi_r_avg =
average_value_ppoly( nk, phi_r, ppoly0_e_r, ppoly0_coefs_r, method, k_bot_r, 0., zeta_bot_r)
495 f_layer(k_bot_min) = -(heff * khtr_u) * (phi_r_avg - phi_l_avg)
497 do k = k_bot_min-1,1,-1
499 f_layer(k) = -(heff * khtr_u) * (phi_r(k) - phi_l(k))
503 if (boundary ==
bottom)
then
504 k_top_max = max(k_top_l, k_top_r)
506 if (k_top_max .ne. k_top_l)
then
510 if (k_top_max .ne. k_top_r)
then
515 h_work_l = (h_l(k_top_l) * zeta_top_l)
516 h_work_r = (h_r(k_top_r) * zeta_top_r)
518 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)
519 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)
523 f_layer(k_top_max) = (-heff * khtr_u) * (phi_r_avg - phi_l_avg)
525 do k = k_top_max+1,nk
527 f_layer(k) = -(heff * khtr_u) * (phi_r(k) - phi_l(k))
535 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, &
536 ppoly0_coefs_R, ppoly0_E_L, ppoly0_E_R, method, khtr_u, F_bulk, F_layer, F_limit)
538 integer,
intent(in ) :: boundary
539 integer,
intent(in ) :: nk
540 integer,
intent(in ) :: deg
541 real,
dimension(nk),
intent(in ) :: h_L
542 real,
dimension(nk),
intent(in ) :: h_R
543 real,
intent(in ) :: hbl_L
545 real,
intent(in ) :: hbl_R
547 real,
intent(in ) :: area_L
548 real,
intent(in ) :: area_R
549 real,
dimension(nk),
intent(in ) :: phi_L
550 real,
dimension(nk),
intent(in ) :: phi_R
551 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_L
552 real,
dimension(nk,deg+1),
intent(in ) :: ppoly0_coefs_R
553 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_L
554 real,
dimension(nk,2),
intent(in ) :: ppoly0_E_R
555 integer,
intent(in ) :: method
556 real,
intent(in ) :: khtr_u
557 real,
intent( out) :: F_bulk
558 real,
dimension(nk),
intent( out) :: F_layer
559 real,
optional,
dimension(nk),
intent( out) :: F_limit
562 real,
dimension(nk) :: h_means
568 real :: phi_L_avg, phi_R_avg
571 integer :: k, k_min, k_max
572 integer :: k_top_L, k_bot_L
573 integer :: k_top_R, k_bot_R
574 real :: zeta_top_L, zeta_top_R
576 real :: zeta_bot_L, zeta_bot_R
578 real :: h_work_L, h_work_R
582 real :: hfrac, F_bulk_remain
584 if (hbl_l == 0. .or. hbl_r == 0.)
then
591 call boundary_k_range(boundary, nk, h_l, hbl_l, k_top_l, zeta_top_l, k_bot_l, zeta_bot_l)
592 call boundary_k_range(boundary, nk, h_r, hbl_r, k_top_r, zeta_top_r, k_bot_r, zeta_bot_r)
595 phi_l_avg =
bulk_average(boundary, nk, deg, h_l, hbl_l, phi_l, ppoly0_e_l, ppoly0_coefs_l, method, k_top_l, &
596 zeta_top_l, k_bot_l, zeta_bot_l)
597 phi_r_avg =
bulk_average(boundary, nk, deg, h_r, hbl_r, phi_r, ppoly0_e_r, ppoly0_coefs_r, method, k_top_r, &
598 zeta_top_r, k_bot_r, zeta_bot_r)
603 f_bulk = -(khtr_u * heff) * (phi_r_avg - phi_l_avg)
604 f_bulk_remain = f_bulk
610 k_min = min(k_bot_l, k_bot_r)
613 if (k_bot_l == k_min)
then
614 h_work_l = h_l(k_min) * zeta_bot_l
616 h_work_l = h_l(k_min)
620 if (k_bot_r == k_min)
then
621 h_work_r = h_r(k_min) * zeta_bot_r
623 h_work_r = h_r(k_min)
632 elseif (boundary ==
bottom)
then
633 k_max = max(k_top_l, k_top_r)
635 if (k_top_l == k_max)
then
636 h_work_l = h_l(k_max) * zeta_top_l
638 h_work_l = h_l(k_max)
642 if (k_top_r == k_max)
then
643 h_work_r = h_r(k_max) * zeta_top_r
645 h_work_r = h_r(k_max)
655 if ( sum(h_means) == 0. )
then
660 inv_heff = 1./sum(h_means)
662 if (h_means(k) > 0.)
then
663 hfrac = h_means(k)*inv_heff
664 f_layer(k) = f_bulk * hfrac
672 f_max = -0.2 * ((area_r*(phi_r(k)*h_r(k)))-(area_l*(phi_l(k)*h_r(k))))
675 if ( sign(1.,f_bulk) == sign(1., f_max))
then
677 if ( ((boundary ==
surface) .and. (k == k_min)) .or. ((boundary ==
bottom) .and. (k == nk)) )
then
678 f_layer(k) = f_bulk_remain
680 f_bulk_remain = f_bulk_remain - f_layer(k)
683 if (f_max >= 0.)
then
684 limited = f_layer(k) > f_max
685 f_layer(k) = min(f_layer(k),f_max)
687 limited = f_layer(k) < f_max
688 f_layer(k) = max(f_layer(k),f_max)
692 if (
PRESENT(f_limit))
then
694 f_limit(k) = f_layer(k) - f_max
701 f_bulk_remain = f_bulk_remain - f_layer(k)
714 logical,
intent(in) :: verbose
717 integer,
parameter :: nk = 2
718 integer,
parameter :: deg = 1
719 integer,
parameter :: method = 1
720 real,
dimension(nk) :: phi_l, phi_r
721 real,
dimension(nk) :: phi_l_avg, phi_r_avg
722 real,
dimension(nk,deg+1) :: phi_pp_l, phi_pp_r
725 real,
dimension(nk,2) :: ppoly0_e_l, ppoly0_e_r
726 real,
dimension(nk) :: h_l, h_r
730 real,
dimension(nk) :: f_layer
735 character(len=120) :: test_name
740 real :: area_l,area_r
741 area_l = 1.; area_r = 1.
746 test_name =
'Surface boundary spans the entire top cell'
751 test_name =
'Surface boundary spans the entire column'
756 test_name =
'Bottom boundary spans the entire bottom cell'
761 test_name =
'Bottom boundary spans the entire column'
766 test_name =
'Surface boundary intersects second layer'
771 test_name =
'Surface boundary intersects first layer'
776 test_name =
'Surface boundary is deeper than column thickness'
781 test_name =
'Bottom boundary intersects first layer'
786 test_name =
'Bottom boundary intersects second layer'
792 test_name =
'Equal hbl and same layer thicknesses (gradient from right to left)'
793 hbl_l = 10; hbl_r = 10
794 h_l = (/5.,5./) ; h_r = (/5.,5./)
795 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
796 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
797 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
798 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
799 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
800 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
801 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
802 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
803 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
805 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, &
806 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
809 test_name =
'Equal hbl and same layer thicknesses (gradient from left to right)'
810 hbl_l = 10.; hbl_r = 10.
811 h_l = (/5.,5./) ; h_r = (/5.,5./)
812 phi_l = (/1.,1./) ; phi_r = (/0.,0./)
813 phi_pp_l(1,1) = 1.; phi_pp_l(1,2) = 0.
814 phi_pp_l(2,1) = 1.; phi_pp_l(2,2) = 0.
815 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 0.
816 phi_pp_r(2,1) = 0.; phi_pp_r(2,2) = 0.
817 ppoly0_e_l(1,1) = 1.; ppoly0_e_l(1,2) = 1.
818 ppoly0_e_l(2,1) = 1.; ppoly0_e_l(2,2) = 1.
819 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 0.
820 ppoly0_e_r(2,1) = 0.; ppoly0_e_r(2,2) = 0.
822 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,&
823 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
826 test_name =
'Equal hbl and same layer thicknesses (no gradient)'
827 hbl_l = 10; hbl_r = 10
828 h_l = (/5.,5./) ; h_r = (/5.,5./)
829 phi_l = (/1.,1./) ; phi_r = (/1.,1./)
830 phi_pp_l(1,1) = 1.; phi_pp_l(1,2) = 0.
831 phi_pp_l(2,1) = 1.; phi_pp_l(2,2) = 0.
832 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
833 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
834 ppoly0_e_l(1,1) = 1.; ppoly0_e_l(1,2) = 0.
835 ppoly0_e_l(2,1) = 1.; ppoly0_e_l(2,2) = 0.
836 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
837 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
839 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,&
840 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
843 test_name =
'Equal hbl and different layer thicknesses (gradient right to left)'
844 hbl_l = 16.; hbl_r = 16.
845 h_l = (/10.,6./) ; h_r = (/6.,10./)
846 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
847 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
848 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
849 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
850 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
851 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
852 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
853 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
854 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
856 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,&
857 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
860 test_name =
'Equal hbl and same layer thicknesses (diagonal tracer values)'
861 hbl_l = 10.; hbl_r = 10.
862 h_l = (/5.,5./) ; h_r = (/5.,5./)
863 phi_l = (/1.,0./) ; phi_r = (/0.,1./)
864 phi_pp_l(1,1) = 1.; phi_pp_l(1,2) = 0.
865 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
866 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 0.
867 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
868 ppoly0_e_l(1,1) = 1.; ppoly0_e_l(1,2) = 1.
869 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
870 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 0.
871 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
873 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,&
874 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
877 test_name =
'Different hbl and different layer thicknesses (gradient from right to left)'
878 hbl_l = 12; hbl_r = 20
879 h_l = (/6.,6./) ; h_r = (/10.,10./)
880 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
881 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
882 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
883 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
884 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
885 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
886 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
887 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
888 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
890 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,&
891 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
896 test_name =
'hbl < column thickness, hbl same, constant concentration each column'
898 h_l = (/1.,2./) ; h_r = (/1.,2./)
899 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
900 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
901 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
902 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
903 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
905 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,&
906 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
909 test_name =
'hbl < column thickness, hbl same, linear profile right'
911 h_l = (/1.,2./) ; h_r = (/1.,2./)
912 phi_l = (/0.,0./) ; phi_r = (/0.5,2./)
913 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
914 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
915 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 1.
916 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 2.
918 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
919 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
920 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 1.
921 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 3.
922 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,&
923 ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_bulk, f_layer)
926 test_name =
'hbl < column thickness, hbl same, linear profile right, khtr=2'
928 h_l = (/1.,2./) ; h_r = (/1.,2./)
929 phi_l = (/0.,0./) ; phi_r = (/0.5,2./)
930 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
931 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
932 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 1.
933 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 2.
935 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
936 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
937 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 1.
938 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 3.
939 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, &
940 phi_pp_r, ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_layer)
944 test_name =
'Different hbl and different column thicknesses (gradient from right to left)'
945 hbl_l = 12; hbl_r = 20
946 h_l = (/6.,6./) ; h_r = (/10.,10./)
947 phi_l = (/0.,0./) ; phi_r = (/1.,1./)
948 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
949 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
950 phi_pp_r(1,1) = 1.; phi_pp_r(1,2) = 0.
951 phi_pp_r(2,1) = 1.; phi_pp_r(2,2) = 0.
952 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
953 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
954 ppoly0_e_r(1,1) = 1.; ppoly0_e_r(1,2) = 1.
955 ppoly0_e_r(2,1) = 1.; ppoly0_e_r(2,2) = 1.
957 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, &
958 phi_pp_r, ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_layer)
961 test_name =
'Different hbl and different column thicknesses (linear profile right)'
963 hbl_l = 15; hbl_r = 6
964 h_l = (/10.,10./) ; h_r = (/12.,10./)
965 phi_l = (/0.,0./) ; phi_r = (/1.,3./)
966 phi_pp_l(1,1) = 0.; phi_pp_l(1,2) = 0.
967 phi_pp_l(2,1) = 0.; phi_pp_l(2,2) = 0.
968 phi_pp_r(1,1) = 0.; phi_pp_r(1,2) = 2.
969 phi_pp_r(2,1) = 2.; phi_pp_r(2,2) = 2.
970 ppoly0_e_l(1,1) = 0.; ppoly0_e_l(1,2) = 0.
971 ppoly0_e_l(2,1) = 0.; ppoly0_e_l(2,2) = 0.
972 ppoly0_e_r(1,1) = 0.; ppoly0_e_r(1,2) = 2.
973 ppoly0_e_r(2,1) = 2.; ppoly0_e_r(2,2) = 4.
975 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, &
976 phi_pp_r, ppoly0_e_l, ppoly0_e_r, method, khtr_u, f_layer)
983 logical,
intent(in) :: verbose
984 character(len=80),
intent(in) :: test_name
985 integer,
intent(in) :: nk
986 real,
dimension(nk),
intent(in) :: f_calc
987 real,
dimension(nk),
intent(in) :: f_ans
990 integer,
parameter :: stdunit = 6
994 if ( f_calc(k) /= f_ans(k) )
then
996 write(stdunit,*)
"UNIT TEST FAILED: ", test_name
997 write(stdunit,10) k, f_calc(k), f_ans(k)
998 elseif (verbose)
then
999 write(stdunit,10) k, f_calc(k), f_ans(k)
1003 10
format(
"Layer=",i3,
" F_calc=",f20.16,
" F_ans",f20.16)
1008 k_bot_ans, zeta_bot_ans, test_name, verbose)
1013 integer :: k_top_ans
1014 real :: zeta_top_ans
1015 integer :: k_bot_ans
1016 real :: zeta_bot_ans
1017 character(len=80) :: test_name
1020 integer,
parameter :: stdunit = 6
1029 write(stdunit,20)
"k_top", k_top,
"k_top_ans", k_top_ans
1030 write(stdunit,20)
"k_bot", k_bot,
"k_bot_ans", k_bot_ans
1031 write(stdunit,30)
"zeta_top", zeta_top,
"zeta_top_ans", zeta_top_ans
1032 write(stdunit,30)
"zeta_bot", zeta_bot,
"zeta_bot_ans", zeta_bot_ans
1035 20
format(a,
"=",i3,x,a,
"=",i3)
1036 30
format(a,
"=",f20.16,x,a,
"=",f20.16)