69 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
70 use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
85 implicit none ;
private 87 #include <MOM_memory.h> 94 logical :: do_rivermix = .false.
96 real :: rivermix_depth = 0.0
98 logical :: reclaim_frazil
101 logical :: pressure_dependent_frazil
105 logical :: ignore_fluxes_over_land
109 logical :: use_river_heat_content
112 logical :: use_calving_heat_content
119 integer :: id_createdh = -1
120 integer :: id_brine_lay = -1
121 integer :: id_pensw_diag = -1
122 integer :: id_penswflux_diag = -1
123 integer :: id_nonpensw_diag = -1
126 real,
allocatable,
dimension(:,:) :: createdh
127 real,
allocatable,
dimension(:,:,:) :: pensw_diag
128 real,
allocatable,
dimension(:,:,:) :: penswflux_diag
129 real,
allocatable,
dimension(:,:) :: nonpensw_diag
140 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
143 real,
dimension(SZI_(G),SZJ_(G)),
intent(in),
optional :: p_surf
159 real,
dimension(SZI_(G)) :: &
163 real,
dimension(SZI_(G),SZK_(G)) :: &
168 integer :: i, j, k, is, ie, js, je, nz
169 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
173 if (.not.cs%pressure_dependent_frazil)
then 174 do k=1,nz ;
do i=is,ie ; pressure(i,k) = 0.0 ;
enddo ;
enddo 180 if (
PRESENT(p_surf))
then ;
do i=is,ie
184 do i=is,ie ; fraz_col(i) = 0.0 ;
enddo 186 if (cs%pressure_dependent_frazil)
then 188 pressure(i,1) = ps(i) + (0.5*gv%H_to_Pa)*h(i,j,1)
190 do k=2,nz ;
do i=is,ie
191 pressure(i,k) = pressure(i,k-1) + &
192 (0.5*gv%H_to_Pa) * (h(i,j,k) + h(i,j,k-1))
196 if (cs%reclaim_frazil)
then 198 do i=is,ie ;
if (tv%frazil(i,j) > 0.0)
then 199 if (.not.t_fr_set)
then 201 1, ie-i+1, tv%eqn_of_state)
205 if (tv%T(i,j,1) > t_freeze(i))
then 208 hc = (tv%C_p*gv%H_to_kg_m2) * h(i,j,1)
209 if (tv%frazil(i,j) - hc * (tv%T(i,j,1) - t_freeze(i)) <= 0.0)
then 210 tv%T(i,j,1) = tv%T(i,j,1) - tv%frazil(i,j)/hc
213 tv%frazil(i,j) = tv%frazil(i,j) - hc * (tv%T(i,j,1) - t_freeze(i))
214 tv%T(i,j,1) = t_freeze(i)
223 if ((g%mask2dT(i,j) > 0.0) .and. &
224 ((tv%T(i,j,k) < 0.0) .or. (fraz_col(i) > 0.0)))
then 225 if (.not.t_fr_set)
then 227 1, ie-i+1, tv%eqn_of_state)
231 hc = (tv%C_p*gv%H_to_kg_m2) * h(i,j,k)
232 if (h(i,j,k) <= 10.0*gv%Angstrom)
then 234 if (tv%T(i,j,k) < t_freeze(i))
then 235 fraz_col(i) = fraz_col(i) + hc * (t_freeze(i) - tv%T(i,j,k))
236 tv%T(i,j,k) = t_freeze(i)
239 if (fraz_col(i) + hc * (t_freeze(i) - tv%T(i,j,k)) <= 0.0)
then 240 tv%T(i,j,k) = tv%T(i,j,k) - fraz_col(i)/hc
243 fraz_col(i) = fraz_col(i) + hc * (t_freeze(i) - tv%T(i,j,k))
244 tv%T(i,j,k) = t_freeze(i)
251 tv%frazil(i,j) = tv%frazil(i,j) + fraz_col(i)
261 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
264 real,
intent(in) :: dt
278 real,
dimension(SZI_(G)) :: &
281 real,
dimension(SZI_(G),SZK_(G)) :: &
283 real,
dimension(SZI_(G),SZK_(G)+1) :: &
295 integer :: i, j, k, is, ie, js, je, nz
296 real,
pointer :: T(:,:,:), S(:,:,:), Kd_T(:,:,:), Kd_S(:,:,:)
297 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
298 h_neglect = gv%H_subroundoff
300 if (.not.
associated(tv%T))
call mom_error(fatal, &
301 "differential_diffuse_T_S: Called with an unassociated tv%T")
302 if (.not.
associated(tv%S))
call mom_error(fatal, &
303 "differential_diffuse_T_S: Called with an unassociated tv%S")
304 if (.not.
associated(visc%Kd_extra_T))
call mom_error(fatal, &
305 "differential_diffuse_T_S: Called with an unassociated visc%Kd_extra_T")
306 if (.not.
associated(visc%Kd_extra_S))
call mom_error(fatal, &
307 "differential_diffuse_T_S: Called with an unassociated visc%Kd_extra_S")
309 t => tv%T ; s => tv%S
310 kd_t => visc%Kd_extra_T ; kd_s => visc%Kd_extra_S
316 i_h_int = 1.0 / (0.5 * (h(i,j,1) + h(i,j,2)) + h_neglect)
317 mix_t(i,2) = ((dt * kd_t(i,j,2)) * gv%m_to_H**2) * i_h_int
318 mix_s(i,2) = ((dt * kd_s(i,j,2)) * gv%m_to_H**2) * i_h_int
320 h_tr = h(i,j,1) + h_neglect
321 b1_t(i) = 1.0 / (h_tr + mix_t(i,2))
322 b1_s(i) = 1.0 / (h_tr + mix_s(i,2))
323 d1_t(i) = h_tr * b1_t(i)
324 d1_s(i) = h_tr * b1_s(i)
325 t(i,j,1) = (b1_t(i)*h_tr)*t(i,j,1)
326 s(i,j,1) = (b1_s(i)*h_tr)*s(i,j,1)
328 do k=2,nz-1 ;
do i=is,ie
330 i_h_int = 1.0 / (0.5 * (h(i,j,k) + h(i,j,k+1)) + h_neglect)
331 mix_t(i,k+1) = ((dt * kd_t(i,j,k+1)) * gv%m_to_H**2) * i_h_int
332 mix_s(i,k+1) = ((dt * kd_s(i,j,k+1)) * gv%m_to_H**2) * i_h_int
334 c1_t(i,k) = mix_t(i,k) * b1_t(i)
335 c1_s(i,k) = mix_s(i,k) * b1_s(i)
337 h_tr = h(i,j,k) + h_neglect
338 b_denom_t = h_tr + d1_t(i)*mix_t(i,k)
339 b_denom_s = h_tr + d1_s(i)*mix_s(i,k)
340 b1_t(i) = 1.0 / (b_denom_t + mix_t(i,k+1))
341 b1_s(i) = 1.0 / (b_denom_s + mix_s(i,k+1))
342 d1_t(i) = b_denom_t * b1_t(i)
343 d1_s(i) = b_denom_s * b1_s(i)
345 t(i,j,k) = b1_t(i) * (h_tr*t(i,j,k) + mix_t(i,k)*t(i,j,k-1))
346 s(i,j,k) = b1_s(i) * (h_tr*s(i,j,k) + mix_s(i,k)*s(i,j,k-1))
349 c1_t(i,nz) = mix_t(i,nz) * b1_t(i)
350 c1_s(i,nz) = mix_s(i,nz) * b1_s(i)
352 h_tr = h(i,j,nz) + h_neglect
353 b1_t(i) = 1.0 / (h_tr + d1_t(i)*mix_t(i,nz))
354 b1_s(i) = 1.0 / (h_tr + d1_s(i)*mix_s(i,nz))
356 t(i,j,nz) = b1_t(i) * (h_tr*t(i,j,nz) + mix_t(i,nz)*t(i,j,nz-1))
357 s(i,j,nz) = b1_s(i) * (h_tr*s(i,j,nz) + mix_s(i,nz)*s(i,j,nz-1))
359 do k=nz-1,1,-1 ;
do i=is,ie
360 t(i,j,k) = t(i,j,k) + c1_t(i,k+1)*t(i,j,k+1)
361 s(i,j,k) = s(i,j,k) + c1_s(i,k+1)*s(i,j,k+1)
370 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
385 real :: salt_add_col(szi_(g),szj_(g))
388 integer :: i, j, k, is, ie, js, je, nz
389 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
395 salt_add_col(:,:) = 0.0
400 do k=nz,1,-1 ;
do i=is,ie
401 if ((g%mask2dT(i,j) > 0.0) .and. &
402 ((tv%S(i,j,k) < s_min) .or. (salt_add_col(i,j) > 0.0)))
then 403 mc = gv%H_to_kg_m2 * h(i,j,k)
404 if (h(i,j,k) <= 10.0*gv%Angstrom)
then 406 if (tv%S(i,j,k) < s_min)
then 407 salt_add_col(i,j) = salt_add_col(i,j) + mc * (s_min - tv%S(i,j,k))
411 if (salt_add_col(i,j) + mc * (s_min - tv%S(i,j,k)) <= 0.0)
then 412 tv%S(i,j,k) = tv%S(i,j,k) - salt_add_col(i,j)/mc
413 salt_add_col(i,j) = 0.0
415 salt_add_col(i,j) = salt_add_col(i,j) + mc * (s_min - tv%S(i,j,k))
422 tv%salt_deficit(i,j) = tv%salt_deficit(i,j) + salt_add_col(i,j)
429 subroutine insert_brine(h, tv, G, GV, fluxes, nkmb, CS, dt, id_brine_lay)
432 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
434 type(
forcing),
intent(in) :: fluxes
435 integer,
intent(in) :: nkmb
437 real,
intent(in) :: dt
438 integer,
intent(in) :: id_brine_lay
456 real :: salt(szi_(g))
458 real :: dzbr(szi_(g))
459 real :: inject_layer(szi_(g),szj_(g))
461 real :: p_ref_cv(szi_(g))
462 real :: T(szi_(g),szk_(g))
463 real :: S(szi_(g),szk_(g))
464 real :: h_2d(szi_(g),szk_(g))
465 real :: Rcv(szi_(g),szk_(g))
467 real :: s_new,R_new,t0,scale, cdz
468 integer :: i, j, k, is, ie, js, je, nz, ks
470 real,
parameter :: brine_dz = 1.0
471 real,
parameter :: s_max = 45.0
473 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
475 if (.not.
ASSOCIATED(fluxes%salt_flux))
return 477 p_ref_cv(:) = tv%P_ref
483 salt(:)=0.0 ; dzbr(:)=0.0
485 do i=is,ie ;
if (g%mask2dT(i,j) > 0.)
then 486 salt(i) = dt * (1000. * fluxes%salt_flux(i,j))
491 t(i,k)=tv%T(i,j,k); s(i,k)=tv%S(i,j,k)
493 h_2d(i,k)=max(h(i,j,k), gv%Angstrom)
497 ie-is+1, tv%eqn_of_state)
504 do k=nkmb+1,nz-1 ;
do i=is,ie
505 if ((g%mask2dT(i,j) > 0.0) .and. dzbr(i) < brine_dz .and. salt(i) > 0.)
then 506 mc = gv%H_to_kg_m2 * h_2d(i,k)
507 s_new = s(i,k) + salt(i)/mc
510 if (r_new < 0.5*(rcv(i,k)+rcv(i,k+1)) .and. s_new<s_max)
then 511 dzbr(i)=dzbr(i)+h_2d(i,k)
512 inject_layer(i,j) = min(inject_layer(i,j),
real(k))
518 do k=nkmb,gv%nkml+1,-1 ;
do i=is,ie
519 if ((g%mask2dT(i,j) > 0.0) .and. dzbr(i) < brine_dz .and. salt(i) > 0.)
then 520 mc = gv%H_to_kg_m2 * h_2d(i,k)
521 dzbr(i)=dzbr(i)+h_2d(i,k)
522 inject_layer(i,j) = min(inject_layer(i,j),
real(k))
528 do k=1,gv%nkml ;
do i=is,ie
529 if ((g%mask2dT(i,j) > 0.0) .and. dzbr(i) < brine_dz .and. salt(i) > 0.)
then 530 mc = gv%H_to_kg_m2 * h_2d(i,k)
531 dzbr(i)=dzbr(i)+h_2d(i,k)
532 inject_layer(i,j) = min(inject_layer(i,j),
real(k))
538 if ((g%mask2dT(i,j) > 0.0) .and. salt(i) > 0.)
then 543 mc = gv%H_to_kg_m2 * h_2d(i,k)
544 scale = h_2d(i,k)/dzbr(i)
547 tv%S(i,j,k) = tv%S(i,j,k) + scale*salt(i)/mc
554 if (cs%id_brine_lay > 0)
call post_data(cs%id_brine_lay,inject_layer,cs%diag)
558 subroutine tridiagts(G, GV, is, ie, js, je, hold, ea, eb, T, S)
564 integer,
intent(in) :: is, ie, js, je
565 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: hold, ea, eb
566 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: T, S
568 real :: b1(szib_(g)), d1(szib_(g))
569 real :: c1(szib_(g),szk_(g))
570 real :: h_tr, b_denom_1
576 h_tr = hold(i,j,1) + gv%H_subroundoff
577 b1(i) = 1.0 / (h_tr + eb(i,j,1))
579 t(i,j,1) = (b1(i)*h_tr)*t(i,j,1)
580 s(i,j,1) = (b1(i)*h_tr)*s(i,j,1)
582 do k=2,g%ke ;
do i=is,ie
583 c1(i,k) = eb(i,j,k-1) * b1(i)
584 h_tr = hold(i,j,k) + gv%H_subroundoff
585 b_denom_1 = h_tr + d1(i)*ea(i,j,k)
586 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
587 d1(i) = b_denom_1 * b1(i)
588 t(i,j,k) = b1(i) * (h_tr*t(i,j,k) + ea(i,j,k)*t(i,j,k-1))
589 s(i,j,k) = b1(i) * (h_tr*s(i,j,k) + ea(i,j,k)*s(i,j,k-1))
591 do k=g%ke-1,1,-1 ;
do i=is,ie
592 t(i,j,k) = t(i,j,k) + c1(i,k+1)*t(i,j,k+1)
593 s(i,j,k) = s(i,j,k) + c1(i,k+1)*s(i,j,k+1)
599 subroutine find_uv_at_h(u, v, h, u_h, v_h, G, GV, ea, eb)
602 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
603 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
604 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
605 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(out) :: u_h, v_h
606 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in),
optional :: ea, eb
630 real :: b1(szi_(g)), d1(szi_(g)), c1(szi_(g),szk_(g))
631 real :: a_n(szi_(g)), a_s(szi_(g))
632 real :: a_e(szi_(g)), a_w(szi_(g))
635 logical :: mix_vertically
636 integer :: i, j, k, is, ie, js, je, nz
637 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
639 h_neglect = gv%H_subroundoff
641 mix_vertically =
present(ea)
642 if (
present(ea) .neqv.
present(eb))
call mom_error(fatal, &
643 "find_uv_at_h: Either both ea and eb or neither one must be present "// &
644 "in call to find_uv_at_h.")
650 s = g%areaCu(i-1,j)+g%areaCu(i,j)
652 idenom = sqrt(0.5*g%IareaT(i,j)/s)
653 a_w(i) = g%areaCu(i-1,j)*idenom
654 a_e(i) = g%areaCu(i,j)*idenom
656 a_w(i) = 0.0 ; a_e(i) = 0.0
659 s = g%areaCv(i,j-1)+g%areaCv(i,j)
661 idenom = sqrt(0.5*g%IareaT(i,j)/s)
662 a_s(i) = g%areaCv(i,j-1)*idenom
663 a_n(i) = g%areaCv(i,j)*idenom
665 a_s(i) = 0.0 ; a_n(i) = 0.0
669 if (mix_vertically)
then 671 b_denom_1 = h(i,j,1) + h_neglect
672 b1(i) = 1.0 / (b_denom_1 + eb(i,j,1))
673 d1(i) = b_denom_1 * b1(i)
674 u_h(i,j,1) = (h(i,j,1)*b1(i)) * (a_e(i)*u(i,j,1) + a_w(i)*u(i-1,j,1))
675 v_h(i,j,1) = (h(i,j,1)*b1(i)) * (a_n(i)*v(i,j,1) + a_s(i)*v(i,j-1,1))
677 do k=2,nz ;
do i=is,ie
678 c1(i,k) = eb(i,j,k-1) * b1(i)
679 b_denom_1 = h(i,j,k) + d1(i)*ea(i,j,k) + h_neglect
680 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
681 d1(i) = b_denom_1 * b1(i)
682 u_h(i,j,k) = (h(i,j,k) * (a_e(i)*u(i,j,k) + a_w(i)*u(i-1,j,k)) + &
683 ea(i,j,k)*u_h(i,j,k-1))*b1(i)
684 v_h(i,j,k) = (h(i,j,k) * (a_n(i)*v(i,j,k) + a_s(i)*v(i,j-1,k)) + &
685 ea(i,j,k)*v_h(i,j,k-1))*b1(i)
687 do k=nz-1,1,-1 ;
do i=is,ie
688 u_h(i,j,k) = u_h(i,j,k) + c1(i,k+1)*u_h(i,j,k+1)
689 v_h(i,j,k) = v_h(i,j,k) + c1(i,k+1)*v_h(i,j,k+1)
692 do k=1,nz ;
do i=is,ie
693 u_h(i,j,k) = a_e(i)*u(i,j,k) + a_w(i)*u(i-1,j,k)
694 v_h(i,j,k) = a_n(i)*v(i,j,k) + a_s(i)*v(i,j-1,k)
708 integer,
intent(in) :: id_MLD
709 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
711 real,
intent(in) :: densityDiff
713 integer,
optional,
intent(in) :: id_N2subML
714 integer,
optional,
intent(in) :: id_MLDsq
717 real,
dimension(SZI_(G)) :: rhoSurf, deltaRhoAtKm1, deltaRhoAtK, dK, dKm1, pRef_MLD
718 real,
dimension(SZI_(G)) :: rhoAtK, rho1, d1, pRef_N2
719 real,
dimension(SZI_(G), SZJ_(G)) :: MLD
720 real,
dimension(SZI_(G), SZJ_(G)) :: subMLN2
721 real,
dimension(SZI_(G), SZJ_(G)) :: MLD2
722 real,
parameter :: dz_subML = 50.
723 integer :: i, j, is, ie, js, je, k, nz, id_N2, id_SQ
727 if (
PRESENT(id_n2subml)) id_n2 = id_n2subml
730 if (
PRESENT(id_n2subml)) id_sq = id_mldsq
732 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
733 pref_mld(:) = 0. ; pref_n2(:) = 0.
735 do i=is,ie ; dk(i) = 0.5 * h(i,j,1) * gv%H_to_m ;
enddo 736 call calculate_density(tv%T(:,j,1), tv%S(:,j,1), pref_mld, rhosurf, is, ie-is+1, tv%eqn_of_state)
744 pref_n2(i) = gv%g_Earth * gv%Rho0 * h(i,j,1) * gv%H_to_m
751 dk(i) = dk(i) + 0.5 * ( h(i,j,k) + h(i,j,k-1) ) * gv%H_to_m
757 pref_n2(i) = pref_n2(i) + gv%g_Earth * gv%Rho0 * h(i,j,k) * gv%H_to_m
760 call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pref_n2, rhoatk, is, ie-is+1, tv%eqn_of_state)
762 if (mld(i,j)>0. .and. submln2(i,j)==0.)
then 768 pref_n2(i) = pref_n2(i) + gv%g_Earth * gv%Rho0 * h(i,j,k) * gv%H_to_m
771 if (d1(i)>0. .and. dk(i)-d1(i)>=dz_subml)
then 772 submln2(i,j) = gv%g_Earth/ gv%Rho0 * (rho1(i)-rhoatk(i)) / (d1(i) - dk(i))
779 do i=is,ie ; deltarhoatkm1(i) = deltarhoatk(i) ;
enddo 780 call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pref_mld, deltarhoatk, is, ie-is+1, tv%eqn_of_state)
782 deltarhoatk(i) = deltarhoatk(i) - rhosurf(i)
783 ddrho = deltarhoatk(i) - deltarhoatkm1(i)
784 if ((mld(i,j)==0.) .and. (ddrho>0.) .and. &
785 (deltarhoatkm1(i)<densitydiff) .and. (deltarhoatk(i)>=densitydiff))
then 786 afac = ( densitydiff - deltarhoatkm1(i) ) / ddrho
787 mld(i,j) = dk(i) * afac + dkm1(i) * (1. - afac)
789 if (id_sq > 0) mld2(i,j) = mld(i,j)**2
793 if ((mld(i,j)==0.) .and. (deltarhoatk(i)<densitydiff)) mld(i,j) = dk(i)
801 if (id_mld > 0)
call post_data(id_mld, mld, diagptr)
802 if (id_n2 > 0)
call post_data(id_n2, submln2 , diagptr)
803 if (id_sq > 0)
call post_data(id_sq, mld2, diagptr)
811 aggregate_FW_forcing, evap_CFL_limit, &
812 minimum_forcing_depth, cTKE, dSV_dT, dSV_dS, &
817 real,
intent(in) :: dt
818 type(
forcing),
intent(inout) :: fluxes
820 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
823 logical,
intent(in) :: aggregate_FW_forcing
825 real,
intent(in) :: evap_CFL_limit
827 real,
intent(in) :: minimum_forcing_depth
829 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
optional,
intent(out) :: cTKE
831 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
optional,
intent(out) :: dSV_dT
833 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
optional,
intent(out) :: dSV_dS
835 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(out) :: SkinBuoyFlux
838 integer,
parameter :: maxGroundings = 5
839 integer :: numberOfGroundings, iGround(maxgroundings), jGround(maxgroundings)
840 real :: H_limit_fluxes, IforcingDepthScale, Idt
841 real :: dThickness, dTemp, dSalt
842 real :: fractionOfForcing, hOld, Ithickness
843 real :: RivermixConst
844 real,
dimension(SZI_(G)) :: &
861 real,
dimension(SZI_(G), SZK_(G)) :: h2d, T2d
862 real,
dimension(SZI_(G), SZK_(G)) :: pen_TKE_2d, dSV_dT_2d
863 real,
dimension(SZI_(G),SZK_(G)+1) :: netPen
864 real,
dimension(max(optics%nbands,1),SZI_(G)) :: Pen_SW_bnd, Pen_SW_bnd_rate
866 real,
dimension(max(optics%nbands,1),SZI_(G),SZK_(G)) :: opacityBand
867 real :: hGrounding(maxgroundings)
868 real :: Temp_in, Salin_in
869 real :: I_G_Earth, g_Hconv2
871 logical :: calculate_energetics
872 logical :: calculate_buoyancy
873 integer :: i, j, is, ie, js, je, k, nz, n, nsw
874 integer :: start, npts
875 character(len=45) :: mesg
877 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
880 if (.not.
ASSOCIATED(fluxes%sw))
return 886 calculate_energetics = (
present(ctke) .and.
present(dsv_dt) .and.
present(dsv_ds))
887 calculate_buoyancy =
present(skinbuoyflux)
888 if (calculate_buoyancy) skinbuoyflux(:,:) = 0.0
889 i_g_earth = 1.0 / gv%g_Earth
890 g_hconv2 = gv%g_Earth * gv%H_to_kg_m2**2
892 if (
present(ctke)) ctke(:,:,:) = 0.0
893 if (calculate_buoyancy)
then 894 surfpressure(:) = 0.0
895 gorho = gv%g_Earth / gv%Rho0
896 start = 1 + g%isc - g%isd
897 npts = 1 + g%iec - g%isc
905 h_limit_fluxes = max(gv%Angstrom, 1.e-30*gv%m_to_H)
908 if (cs%id_createdH>0) cs%createdH(:,:) = 0.
909 numberofgroundings = 0
931 do k=1,nz ;
do i=is,ie
933 t2d(i,k) = tv%T(i,j,k)
935 opacityband(n,i,k) = (1.0 / gv%m_to_H)*optics%opacity_band(n,i,j,k)
939 if (calculate_energetics)
then 943 do i=is,ie ; pres(i) = 0.0 ;
enddo 946 d_pres(i) = gv%g_Earth * gv%H_to_kg_m2 * h2d(i,k)
947 p_lay(i) = pres(i) + 0.5*d_pres(i)
948 pres(i) = pres(i) + d_pres(i)
951 dsv_dt(:,j,k), dsv_ds(:,j,k), is, ie-is+1, tv%eqn_of_state)
952 do i=is,ie ; dsv_dt_2d(i,k) = dsv_dt(i,j,k) ;
enddo 958 pen_tke_2d(:,:) = 0.0
1004 if (calculate_buoyancy)
then 1006 h_limit_fluxes, cs%use_river_heat_content, cs%use_calving_heat_content, &
1007 h2d, t2d, netmassinout, netmassout, netheat, netsalt, &
1008 pen_sw_bnd, tv, aggregate_fw_forcing, nonpensw=nonpensw, &
1009 net_heat_rate=netheat_rate,net_salt_rate=netsalt_rate, &
1010 netmassinout_rate=netmassinout_rate,pen_sw_bnd_rate=pen_sw_bnd_rate)
1013 h_limit_fluxes, cs%use_river_heat_content, cs%use_calving_heat_content, &
1014 h2d, t2d, netmassinout, netmassout, netheat, netsalt, &
1015 pen_sw_bnd, tv, aggregate_fw_forcing, nonpensw=nonpensw)
1020 if (aggregate_fw_forcing)
then 1021 netmassout(i) = netmassinout(i)
1024 netmassin(i) = netmassinout(i) - netmassout(i)
1026 if (g%mask2dT(i,j)>0.0)
then 1027 fluxes%netMassOut(i,j) = netmassout(i)
1028 fluxes%netMassIn(i,j) = netmassin(i)
1030 fluxes%netMassOut(i,j) = 0.0
1031 fluxes%netMassIn(i,j) = 0.0
1041 if (g%mask2dT(i,j)>0.)
then 1047 dthickness = netmassin(i)
1053 netmassin(i) = netmassin(i) - dthickness
1057 dtemp = dtemp + dthickness*temp_in
1060 if (
ASSOCIATED(fluxes%heat_content_massin)) &
1061 fluxes%heat_content_massin(i,j) = fluxes%heat_content_massin(i,j) + &
1062 t2d(i,k) * max(0.,dthickness) * gv%H_to_kg_m2 * fluxes%C_p * idt
1063 if (
ASSOCIATED(fluxes%heat_content_massout)) &
1064 fluxes%heat_content_massout(i,j) = fluxes%heat_content_massout(i,j) + &
1065 t2d(i,k) * min(0.,dthickness) * gv%H_to_kg_m2 * fluxes%C_p * idt
1066 if (
ASSOCIATED(tv%TempxPmE)) tv%TempxPmE(i,j) = tv%TempxPmE(i,j) + &
1067 t2d(i,k) * dthickness * gv%H_to_kg_m2
1070 if (calculate_energetics .and.
associated(fluxes%lrunoff) .and. cs%do_rivermix)
then 1081 rivermixconst = -0.5*(cs%rivermix_depth*dt)*gv%m_to_H*gv%H_to_Pa
1083 ctke(i,j,k) = ctke(i,j,k) + max(0.0, rivermixconst*dsv_ds(i,j,1) * &
1084 (fluxes%lrunoff(i,j) + fluxes%frunoff(i,j)) * tv%S(i,j,1))
1089 h2d(i,k) = h2d(i,k) + dthickness
1090 if (h2d(i,k) > 0.0)
then 1091 if (calculate_energetics .and. (dthickness > 0.))
then 1094 ctke(i,j,k) = ctke(i,j,k) + 0.5*g_hconv2*(hold*dthickness) * &
1095 ((t2d(i,k) - temp_in) * dsv_dt(i,j,k) + (tv%S(i,j,k) - salin_in) * dsv_ds(i,j,k))
1097 ithickness = 1.0/h2d(i,k)
1099 if (dthickness /= 0. .or. dtemp /= 0.) t2d(i,k) = (hold*t2d(i,k) + dtemp)*ithickness
1100 if (dthickness /= 0. .or. dsalt /= 0.) tv%S(i,j,k) = (hold*tv%S(i,j,k) + dsalt)*ithickness
1112 iforcingdepthscale = 1. / max(gv%H_subroundoff, minimum_forcing_depth*gv%m_to_H - netmassout(i) )
1114 fractionofforcing = min(1.0, h2d(i,k)*iforcingdepthscale)
1119 if (-fractionofforcing*netmassout(i) > evap_cfl_limit*h2d(i,k))
then 1120 fractionofforcing = -evap_cfl_limit*h2d(i,k)/netmassout(i)
1125 dthickness = max( fractionofforcing*netmassout(i), -h2d(i,k) )
1126 dtemp = fractionofforcing*netheat(i)
1128 dsalt = max( fractionofforcing*netsalt(i), -0.9999*h2d(i,k)*tv%S(i,j,k))
1132 netmassout(i) = netmassout(i) - dthickness
1133 netheat(i) = netheat(i) - dtemp
1134 netsalt(i) = netsalt(i) - dsalt
1137 dtemp = dtemp + dthickness*t2d(i,k)
1140 if (
ASSOCIATED(fluxes%heat_content_massin)) &
1141 fluxes%heat_content_massin(i,j) = fluxes%heat_content_massin(i,j) + &
1142 tv%T(i,j,k) * max(0.,dthickness) * gv%H_to_kg_m2 * fluxes%C_p * idt
1143 if (
ASSOCIATED(fluxes%heat_content_massout)) &
1144 fluxes%heat_content_massout(i,j) = fluxes%heat_content_massout(i,j) + &
1145 tv%T(i,j,k) * min(0.,dthickness) * gv%H_to_kg_m2 * fluxes%C_p * idt
1146 if (
ASSOCIATED(tv%TempxPmE)) tv%TempxPmE(i,j) = tv%TempxPmE(i,j) + &
1147 tv%T(i,j,k) * dthickness * gv%H_to_kg_m2
1152 h2d(i,k) = h2d(i,k) + dthickness
1154 if (h2d(i,k) > 0.)
then 1155 if (calculate_energetics)
then 1161 ctke(i,j,k) = ctke(i,j,k) - (0.5*h2d(i,k)*g_hconv2) * &
1162 ((dtemp - dthickness*t2d(i,k)) * dsv_dt(i,j,k) + &
1163 (dsalt - dthickness*tv%S(i,j,k)) * dsv_ds(i,j,k))
1165 ithickness = 1.0/h2d(i,k)
1166 t2d(i,k) = (hold*t2d(i,k) + dtemp)*ithickness
1167 tv%S(i,j,k) = (hold*tv%S(i,j,k) + dsalt)*ithickness
1168 elseif (h2d(i,k) < 0.0)
then 1170 write(0,*)
'applyBoundaryFluxesInOut(): lon,lat=',g%geoLonT(i,j),g%geoLatT(i,j)
1171 write(0,*)
'applyBoundaryFluxesInOut(): netT,netS,netH=',netheat(i),netsalt(i),netmassinout(i)
1172 write(0,*)
'applyBoundaryFluxesInOut(): dT,dS,dH=',dtemp,dsalt,dthickness
1173 write(0,*)
'applyBoundaryFluxesInOut(): h(n),h(n+1),k=',hold,h2d(i,k),k
1174 call mom_error(fatal,
"MOM_diabatic_driver.F90, applyBoundaryFluxesInOut(): "//&
1175 "Complete mass loss in column!")
1181 elseif((abs(netheat(i))+abs(netsalt(i))+abs(netmassin(i))+abs(netmassout(i)))>0.)
then 1183 if (.not. cs%ignore_fluxes_over_land)
then 1185 write(0,*)
'applyBoundaryFluxesInOut(): lon,lat=',g%geoLonT(i,j),g%geoLatT(i,j)
1186 write(0,*)
'applyBoundaryFluxesInOut(): netHeat,netSalt,netMassIn,netMassOut=',&
1187 netheat(i),netsalt(i),netmassin(i),netmassout(i)
1189 call mom_error(fatal,
"MOM_diabatic_driver.F90, applyBoundaryFluxesInOut(): "//&
1190 "Mass loss over land?")
1196 if (netmassin(i)+netmassout(i) /= 0.0)
then 1198 numberofgroundings = numberofgroundings +1
1199 if (numberofgroundings<=maxgroundings)
then 1200 iground(numberofgroundings) = i
1201 jground(numberofgroundings) = j
1202 hgrounding(numberofgroundings) = netmassin(i)+netmassout(i)
1205 if (cs%id_createdH>0) cs%createdH(i,j) = cs%createdH(i,j) - (netmassin(i)+netmassout(i))/dt
1216 if(cs%id_penSW_diag > 0 .or. cs%id_penSWflux_diag > 0)
then 1217 do k=1,nz ;
do i=is,ie
1218 cs%penSW_diag(i,j,k) = t2d(i,k)
1219 cs%penSWflux_diag(i,j,k) = 0.0
1222 cs%penSWflux_diag(i,j,k) = 0.0
1226 if (calculate_energetics)
then 1228 .false., .true., t2d, pen_sw_bnd, tke=pen_tke_2d, dsv_dt=dsv_dt_2d)
1230 do k=1,nz ;
do i=is,ie
1231 ctke(i,j,k) = ctke(i,j,k) + pen_tke_2d(i,k)
1235 .false., .true., t2d, pen_sw_bnd)
1241 do k=1,nz ;
do i=is,ie
1243 tv%T(i,j,k) = t2d(i,k)
1248 if(cs%id_penSW_diag > 0 .or. cs%id_penSWflux_diag > 0)
then 1251 do k=1,nz ;
do i=is,ie
1252 cs%penSW_diag(i,j,k) = (t2d(i,k)-cs%penSW_diag(i,j,k))*h(i,j,k) * idt * tv%C_p * gv%H_to_kg_m2
1261 if(cs%id_penSWflux_diag > 0)
then 1262 do k=nz,1,-1 ;
do i=is,ie
1263 cs%penSWflux_diag(i,j,k) = cs%penSW_diag(i,j,k) + cs%penSWflux_diag(i,j,k+1)
1270 if(cs%id_nonpenSW_diag > 0)
then 1272 cs%nonpenSW_diag(i,j) = nonpensw(i)
1281 if (calculate_buoyancy)
then 1287 call sumswoverbands(g, gv, h2d(:,:), optics%opacity_band(:,:,j,:), nsw, j, dt, &
1288 h_limit_fluxes, .true., pen_sw_bnd_rate, netpen)
1291 drhodt, drhods, start, npts, tv%eqn_of_state)
1297 skinbuoyflux(g%isc:g%iec,j) = - gorho * ( drhods(g%isc:g%iec) * (netsalt_rate(g%isc:g%iec) &
1298 - tv%S(g%isc:g%iec,j,1) * netmassinout_rate(g%isc:g%iec)* gv%H_to_m )&
1299 + drhodt(g%isc:g%iec) * ( netheat_rate(g%isc:g%iec) + &
1300 netpen(g%isc:g%iec,1))) * gv%H_to_m
1306 if (cs%id_createdH > 0)
call post_data(cs%id_createdH , cs%createdH , cs%diag)
1307 if (cs%id_penSW_diag > 0)
call post_data(cs%id_penSW_diag , cs%penSW_diag , cs%diag)
1308 if (cs%id_penSWflux_diag > 0)
call post_data(cs%id_penSWflux_diag, cs%penSWflux_diag, cs%diag)
1309 if (cs%id_nonpenSW_diag > 0)
call post_data(cs%id_nonpenSW_diag , cs%nonpenSW_diag , cs%diag)
1312 if (numberofgroundings>0 .and. .not. cs%ignore_fluxes_over_land)
then 1313 do i = 1, min(numberofgroundings, maxgroundings)
1315 write(mesg(1:45),
'(3es15.3)') g%geoLonT( iground(i), jground(i) ), &
1316 g%geoLatT( iground(i), jground(i)) , hgrounding(i)
1317 call mom_error(warning,
"MOM_diabatic_driver.F90, applyBoundaryFluxesInOut(): "//&
1318 "Mass created. x,y,dh= "//trim(mesg), all_print=.true.)
1321 if (numberofgroundings - maxgroundings > 0)
then 1322 write(mesg,
'(i4)') numberofgroundings - maxgroundings
1323 call mom_error(warning,
"MOM_diabatic_driver:F90, applyBoundaryFluxesInOut(): "//&
1324 trim(mesg) //
" groundings remaining")
1330 subroutine diabatic_aux_init(Time, G, GV, param_file, diag, CS, useALEalgorithm, use_ePBL)
1331 type(time_type),
intent(in) :: Time
1335 type(
diag_ctrl),
target,
intent(inout) :: diag
1337 logical,
intent(in) :: useALEalgorithm
1338 logical,
intent(in) :: use_ePBL
1353 #include "version_variable.h" 1354 character(len=40) :: mod =
"MOM_diabatic_aux" 1355 character(len=48) :: thickness_units
1356 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz, nbands
1357 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
1358 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1360 if (
associated(cs))
then 1361 call mom_error(warning,
"diabatic_aux_init called with an "// &
1362 "associated control structure.")
1372 "The following parameters are used for auxiliary diabatic processes.")
1374 call get_param(param_file, mod,
"RECLAIM_FRAZIL", cs%reclaim_frazil, &
1375 "If true, try to use any frazil heat deficit to cool any\n"//&
1376 "overlying layers down to the freezing point, thereby \n"//&
1377 "avoiding the creation of thin ice when the SST is above \n"//&
1378 "the freezing point.", default=.true.)
1379 call get_param(param_file, mod,
"PRESSURE_DEPENDENT_FRAZIL", &
1380 cs%pressure_dependent_frazil, &
1381 "If true, use a pressure dependent freezing temperature \n"//&
1382 "when making frazil. The default is false, which will be \n"//&
1383 "faster but is inappropriate with ice-shelf cavities.", &
1387 call get_param(param_file, mod,
"IGNORE_FLUXES_OVER_LAND", cs%ignore_fluxes_over_land,&
1388 "If true, the model does not check if fluxes are being applied\n"//&
1389 "over land points. This is needed when the ocean is coupled \n"//&
1390 "with ice shelves and sea ice, since the sea ice mask needs to \n"//&
1391 "be different than the ocean mask to avoid sea ice formation \n"//&
1392 "under ice shelves. This flag only works when use_ePBL = True.", default=.false.)
1393 call get_param(param_file, mod,
"DO_RIVERMIX", cs%do_rivermix, &
1394 "If true, apply additional mixing whereever there is \n"//&
1395 "runoff, so that it is mixed down to RIVERMIX_DEPTH \n"//&
1396 "if the ocean is that deep.", default=.false.)
1397 if (cs%do_rivermix) &
1398 call get_param(param_file, mod,
"RIVERMIX_DEPTH", cs%rivermix_depth, &
1399 "The depth to which rivers are mixed if DO_RIVERMIX is \n"//&
1400 "defined.", units=
"m", default=0.0)
1401 else ; cs%do_rivermix = .false. ; cs%rivermix_depth = 0.0 ;
endif 1402 if (gv%nkml == 0)
then 1403 call get_param(param_file, mod,
"USE_RIVER_HEAT_CONTENT", cs%use_river_heat_content, &
1404 "If true, use the fluxes%runoff_Hflx field to set the \n"//&
1405 "heat carried by runoff, instead of using SST*CP*liq_runoff.", &
1407 call get_param(param_file, mod,
"USE_CALVING_HEAT_CONTENT", cs%use_calving_heat_content, &
1408 "If true, use the fluxes%calving_Hflx field to set the \n"//&
1409 "heat carried by runoff, instead of using SST*CP*froz_runoff.", &
1412 cs%use_river_heat_content = .false.
1413 cs%use_calving_heat_content = .false.
1416 if (usealealgorithm)
then 1417 cs%id_createdH = register_diag_field(
'ocean_model',
"created_H",diag%axesT1, &
1418 time,
"The volume flux added to stop the ocean from drying out and becoming negative in depth", &
1420 if (cs%id_createdH>0)
allocate(cs%createdH(isd:ied,jsd:jed))
1423 cs%id_penSW_diag = register_diag_field(
'ocean_model',
'rsdoabsorb', &
1424 diag%axesTL, time,
'Convergence of Penetrative Shortwave Flux in Sea Water Layer',&
1425 'Watt meter-2', standard_name=
'net_rate_of_absorption_of_shortwave_energy_in_ocean_layer',v_extensive=.true.)
1429 cs%id_penSWflux_diag = register_diag_field(
'ocean_model',
'rsdo', &
1430 diag%axesTi, time,
'Downwelling Shortwave Flux in Sea Water at Grid Cell Upper Interface',&
1431 'Watt meter-2', standard_name=
'downwelling_shortwave_flux_in_sea_water')
1434 if (cs%id_penSW_diag>0 .or. cs%id_penSWflux_diag>0)
then 1435 allocate(cs%penSW_diag(isd:ied,jsd:jed,nz))
1436 cs%penSW_diag(:,:,:) = 0.0
1437 allocate(cs%penSWflux_diag(isd:ied,jsd:jed,nz+1))
1438 cs%penSWflux_diag(:,:,:) = 0.0
1442 cs%id_nonpenSW_diag = register_diag_field(
'ocean_model',
'nonpenSW', &
1443 diag%axesT1, time, &
1444 'Non-downwelling SW radiation (i.e., SW absorbed in ocean surface with LW,SENS,LAT)',&
1445 'Watt meter-2', standard_name=
'nondownwelling_shortwave_flux_in_sea_water')
1446 if (cs%id_nonpenSW_diag > 0)
then 1447 allocate(cs%nonpenSW_diag(isd:ied,jsd:jed))
1448 cs%nonpenSW_diag(:,:) = 0.0
1452 id_clock_uv_at_h = cpu_clock_id(
'(Ocean find_uv_at_h)', grain=clock_routine)
1461 if (.not.
associated(cs))
return 1463 if (cs%id_createdH >0)
deallocate(cs%createdH)
1464 if (cs%id_penSW_diag >0)
deallocate(cs%penSW_diag)
1465 if (cs%id_penSWflux_diag >0)
deallocate(cs%penSWflux_diag)
1466 if (cs%id_nonpenSW_diag >0)
deallocate(cs%nonpenSW_diag)
1468 if (
associated(cs))
deallocate(cs)
subroutine, public differential_diffuse_t_s(h, tv, visc, dt, G, GV)
subroutine, public diabatic_aux_init(Time, G, GV, param_file, diag, CS, useALEalgorithm, use_ePBL)
This module implements boundary forcing for MOM6.
subroutine, public insert_brine(h, tv, G, GV, fluxes, nkmb, CS, dt, id_brine_lay)
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
Calculates the freezing point of sea water from T, S and P.
Provides the ocean grid type.
subroutine, public absorbremainingsw(G, GV, h, opacity_band, nsw, j, dt, H_limit_fluxes, adjustAbsorptionProfile, absorbAllSW, T, Pen_SW_bnd, eps, ksort, htot, Ttot, TKE, dSV_dT)
Apply shortwave heating below surface boundary layer.
The vertvisc_type structure contains vertical viscosities, drag coefficients, and related fields...
subroutine, public calculate_specific_vol_derivs(T, S, pressure, dSV_dT, dSV_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate specific volume derivatives for an array.
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
This module contains I/O framework code.
subroutine, public applyboundaryfluxesinout(CS, G, GV, dt, fluxes, optics, h, tv, aggregate_FW_forcing, evap_CFL_limit, minimum_forcing_depth, cTKE, dSV_dT, dSV_dS, SkinBuoyFlux)
Update the thickness, temperature, and salinity due to thermodynamic boundary forcing (contained in f...
subroutine, public sumswoverbands(G, GV, h, opacity_band, nsw, j, dt, H_limit_fluxes, absorbAllSW, iPen_SW_bnd, netPen)
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
Control structure for diabatic_aux.
subroutine, public find_uv_at_h(u, v, h, u_h, v_h, G, GV, ea, eb)
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Provides subroutines for quantities specific to the equation of state.
logical function, public calltree_showquery()
Returns True, if the verbosity>=6 indicating to show the call tree.
Type for describing a variable, typically a tracer.
subroutine, public extractfluxes1d(G, GV, fluxes, optics, nsw, j, dt, DepthBeforeScalingFluxes, useRiverHeatContent, useCalvingHeatContent, h, T, netMassInOut, netMassOut, net_heat, net_salt, pen_SW_bnd, tv, aggregate_FW_forcing, nonpenSW, netmassInOut_rate, net_Heat_Rate, net_salt_rate, pen_sw_bnd_Rate, skip_diags)
This subroutine extracts fluxes from the surface fluxes type. It works on a j-row for optimization pu...
subroutine, public diabatic_aux_end(CS)
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public tridiagts(G, GV, is, ie, js, je, hold, ea, eb, T, S)
subroutine, public diagnosemldbydensitydifference(id_MLD, h, tv, densityDiff, G, GV, diagPtr, id_N2subML, id_MLDsq)
Diagnose a mixed layer depth (MLD) determined by a given density difference with the surface...
subroutine, public make_frazil(h, tv, G, GV, CS, p_surf)
subroutine, public adjust_salt(h, tv, G, GV, CS)
subroutine, public mom_error(level, message, all_print)
subroutine, public forcing_singlepointprint(fluxes, G, i, j, mesg)
Write out values of the fluxes arrays at the i,j location. This is a debugging tool.
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.