16 implicit none ;
private
18 #include <MOM_memory.h>
20 public set_opacity, opacity_init, opacity_end, opacity_manizza, opacity_morel
21 public extract_optics_slice, extract_optics_fields, optics_nbands
22 public absorbremainingsw, sumswoverbands
28 real,
pointer,
dimension(:,:,:,:) :: opacity_band => null()
31 real,
pointer,
dimension(:,:,:) :: sw_pen_band => null()
35 real,
pointer,
dimension(:) :: &
36 min_wavelength_band => null(), &
37 max_wavelength_band => null()
39 real :: pensw_flux_absorb
41 real :: pensw_absorb_invlen
43 logical :: answers_2018
53 integer :: opacity_scheme
58 real :: pen_sw_scale_2nd
60 real :: sw_1st_exp_ratio
65 real :: opacity_land_value
71 integer :: id_sw_pen = -1, id_sw_vis_pen = -1
72 integer,
pointer :: id_opacity(:) => null()
77 integer,
parameter :: no_scheme = 0, manizza_05 = 1, morel_88 = 2, single_exp = 3, double_exp = 4
80 character*(10),
parameter :: manizza_05_string =
"MANIZZA_05"
81 character*(10),
parameter :: morel_88_string =
"MOREL_88"
82 character*(10),
parameter :: single_exp_string =
"SINGLE_EXP"
83 character*(10),
parameter :: double_exp_string =
"DOUBLE_EXP"
85 real,
parameter :: op_diag_len = 1e-10
91 subroutine set_opacity(optics, sw_total, sw_vis_dir, sw_vis_dif, sw_nir_dir, sw_nir_dif, &
92 G, GV, CS, chl_2d, chl_3d)
95 real,
dimension(:,:),
pointer :: sw_total
96 real,
dimension(:,:),
pointer :: sw_vis_dir
97 real,
dimension(:,:),
pointer :: sw_vis_dif
98 real,
dimension(:,:),
pointer :: sw_nir_dir
99 real,
dimension(:,:),
pointer :: sw_nir_dif
104 real,
dimension(SZI_(G),SZJ_(G)), &
105 optional,
intent(in) :: chl_2d
106 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
107 optional,
intent(in) :: chl_3d
110 integer :: i, j, k, n, is, ie, js, je, nz
111 real :: inv_sw_pen_scale
114 logical :: call_for_surface
115 real :: tmp(szi_(g),szj_(g),szk_(gv))
116 real :: chl(szi_(g),szj_(g),szk_(gv))
117 real :: pen_sw_tot(szi_(g),szj_(g))
119 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
121 if (.not.
associated(cs))
call mom_error(fatal,
"set_opacity: "// &
122 "Module must be initialized via opacity_init before it is used.")
124 if (
present(chl_2d) .or.
present(chl_3d))
then
126 call opacity_from_chl(optics, sw_total, sw_vis_dir, sw_vis_dif, sw_nir_dir, sw_nir_dif, &
127 g, gv, cs, chl_2d, chl_3d)
129 if (optics%nbands <= 1)
then ; inv_nbands = 1.0
130 else ; inv_nbands = 1.0 / real(optics%nbands) ;
endif
133 inv_sw_pen_scale = 1.0 / max(cs%pen_sw_scale, 0.1*gv%Angstrom_m, &
134 gv%H_to_m*gv%H_subroundoff)
135 if ( cs%Opacity_scheme == double_exp )
then
137 do k=1,nz ;
do j=js,je ;
do i=is,ie
138 optics%opacity_band(1,i,j,k) = inv_sw_pen_scale
139 optics%opacity_band(2,i,j,k) = 1.0 / max(cs%pen_sw_scale_2nd, &
140 0.1*gv%Angstrom_m,gv%H_to_m*gv%H_subroundoff)
141 enddo ;
enddo ;
enddo
142 if (.not.
associated(sw_total) .or. (cs%pen_SW_scale <= 0.0))
then
144 do j=js,je ;
do i=is,ie ;
do n=1,optics%nbands
145 optics%sw_pen_band(n,i,j) = 0.0
146 enddo ;
enddo ;
enddo
149 do j=js,je ;
do i=is,ie
150 optics%sw_pen_band(1,i,j) = (cs%SW_1st_EXP_RATIO) * sw_total(i,j)
151 optics%sw_pen_band(2,i,j) = (1.-cs%SW_1st_EXP_RATIO) * sw_total(i,j)
155 do k=1,nz ;
do j=js,je ;
do i=is,ie ;
do n=1,optics%nbands
156 optics%opacity_band(n,i,j,k) = inv_sw_pen_scale
157 enddo ;
enddo ;
enddo ;
enddo
158 if (.not.
associated(sw_total) .or. (cs%pen_SW_scale <= 0.0))
then
160 do j=js,je ;
do i=is,ie ;
do n=1,optics%nbands
161 optics%sw_pen_band(n,i,j) = 0.0
162 enddo ;
enddo ;
enddo
165 do j=js,je ;
do i=is,ie ;
do n=1,optics%nbands
166 optics%sw_pen_band(n,i,j) = cs%pen_SW_frac * inv_nbands * sw_total(i,j)
167 enddo ;
enddo ;
enddo
172 if (query_averaging_enabled(cs%diag))
then
173 if (cs%id_sw_pen > 0)
then
175 do j=js,je ;
do i=is,ie
176 pen_sw_tot(i,j) = 0.0
178 pen_sw_tot(i,j) = pen_sw_tot(i,j) + optics%sw_pen_band(n,i,j)
181 call post_data(cs%id_sw_pen, pen_sw_tot, cs%diag)
183 if (cs%id_sw_vis_pen > 0)
then
184 if (cs%opacity_scheme == manizza_05)
then
186 do j=js,je ;
do i=is,ie
187 pen_sw_tot(i,j) = 0.0
188 do n=1,min(optics%nbands,2)
189 pen_sw_tot(i,j) = pen_sw_tot(i,j) + optics%sw_pen_band(n,i,j)
194 do j=js,je ;
do i=is,ie
195 pen_sw_tot(i,j) = 0.0
197 pen_sw_tot(i,j) = pen_sw_tot(i,j) + optics%sw_pen_band(n,i,j)
201 call post_data(cs%id_sw_vis_pen, pen_sw_tot, cs%diag)
203 do n=1,optics%nbands ;
if (cs%id_opacity(n) > 0)
then
205 do k=1,nz ;
do j=js,je ;
do i=is,ie
209 tmp(i,j,k) = tanh(op_diag_len * optics%opacity_band(n,i,j,k)) / op_diag_len
210 enddo ;
enddo ;
enddo
211 call post_data(cs%id_opacity(n), tmp, cs%diag)
215 end subroutine set_opacity
220 subroutine opacity_from_chl(optics, sw_total, sw_vis_dir, sw_vis_dif, sw_nir_dir, sw_nir_dif, &
221 G, GV, CS, chl_2d, chl_3d)
224 real,
dimension(:,:),
pointer :: sw_total
225 real,
dimension(:,:),
pointer :: sw_vis_dir
226 real,
dimension(:,:),
pointer :: sw_vis_dif
227 real,
dimension(:,:),
pointer :: sw_nir_dir
228 real,
dimension(:,:),
pointer :: sw_nir_dif
232 real,
dimension(SZI_(G),SZJ_(G)), &
233 optional,
intent(in) :: chl_2d
234 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
235 optional,
intent(in) :: chl_3d
237 real :: chl_data(SZI_(G),SZJ_(G))
240 real :: Inv_nbands_nir
248 type(time_type) :: day
249 character(len=128) :: mesg
250 integer :: i, j, k, n, is, ie, js, je, nz, nbands
251 logical :: multiband_vis_input, multiband_nir_input
253 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
267 nbands = optics%nbands
269 if (nbands <= 1)
then ; inv_nbands = 1.0
270 else ; inv_nbands = 1.0 / real(nbands) ;
endif
272 if (nbands <= 2)
then ; inv_nbands_nir = 0.0
273 else ; inv_nbands_nir = 1.0 / real(nbands - 2.0) ;
endif
275 multiband_vis_input = (
associated(sw_vis_dir) .and. &
276 associated(sw_vis_dif))
277 multiband_nir_input = (
associated(sw_nir_dir) .and. &
278 associated(sw_nir_dif))
281 if (
present(chl_3d))
then
282 do j=js,je ;
do i=is,ie ; chl_data(i,j) = chl_3d(i,j,1) ;
enddo ;
enddo
283 do k=1,nz;
do j=js,je ;
do i=is,ie
284 if ((g%mask2dT(i,j) > 0.5) .and. (chl_3d(i,j,k) < 0.0))
then
285 write(mesg,
'(" Negative chl_3d of ",(1pe12.4)," found at i,j,k = ", &
286 & 3(1x,i3), " lon/lat = ",(1pe12.4)," E ", (1pe12.4), " N.")') &
287 chl_3d(i,j,k), i, j, k, g%geoLonT(i,j), g%geoLatT(i,j)
288 call mom_error(fatal,
"MOM_opacity opacity_from_chl: "//trim(mesg))
290 enddo ;
enddo ;
enddo
291 elseif (
present(chl_2d))
then
292 do j=js,je ;
do i=is,ie ; chl_data(i,j) = chl_2d(i,j) ;
enddo ;
enddo
293 do j=js,je ;
do i=is,ie
294 if ((g%mask2dT(i,j) > 0.5) .and. (chl_2d(i,j) < 0.0))
then
295 write(mesg,
'(" Negative chl_2d of ",(1pe12.4)," at i,j = ", &
296 & 2(i3), "lon/lat = ",(1pe12.4)," E ", (1pe12.4), " N.")') &
297 chl_data(i,j), i, j, g%geoLonT(i,j), g%geoLatT(i,j)
298 call mom_error(fatal,
"MOM_opacity opacity_from_chl: "//trim(mesg))
302 call mom_error(fatal,
"Either chl_2d or chl_3d must be preesnt in a call to opacity_form_chl.")
305 select case (cs%opacity_scheme)
308 do j=js,je ;
do i=is,ie
309 sw_vis_tot = 0.0 ; sw_nir_tot = 0.0
310 if (g%mask2dT(i,j) > 0.5)
then
311 if (multiband_vis_input)
then
312 sw_vis_tot = sw_vis_dir(i,j) + sw_vis_dif(i,j)
314 sw_vis_tot = 0.42 * sw_total(i,j)
316 if (multiband_nir_input)
then
317 sw_nir_tot = sw_nir_dir(i,j) + sw_nir_dif(i,j)
319 sw_nir_tot = sw_total(i,j) - sw_vis_tot
324 optics%sw_pen_band(1,i,j) = cs%blue_frac*sw_vis_tot
327 optics%sw_pen_band(2,i,j) = (1.0-cs%blue_frac)*sw_vis_tot
330 optics%sw_pen_band(n,i,j) = inv_nbands_nir * sw_nir_tot
335 do j=js,je ;
do i=is,ie
337 if (g%mask2dT(i,j) > 0.5)
then ;
if (multiband_vis_input)
then
338 sw_pen_tot = sw_pen_frac_morel(chl_data(i,j)) * &
339 (sw_vis_dir(i,j) + sw_vis_dif(i,j))
341 sw_pen_tot = sw_pen_frac_morel(chl_data(i,j)) * &
346 optics%sw_pen_band(n,i,j) = inv_nbands*sw_pen_tot
350 call mom_error(fatal,
"opacity_from_chl: CS%opacity_scheme is not valid.")
355 if (
present(chl_3d))
then
356 do j=js,je ;
do i=is,ie ; chl_data(i,j) = chl_3d(i,j,k) ;
enddo ;
enddo
359 select case (cs%opacity_scheme)
361 do j=js,je ;
do i=is,ie
362 if (g%mask2dT(i,j) <= 0.5)
then
364 optics%opacity_band(n,i,j,k) = cs%opacity_land_value
368 optics%opacity_band(1,i,j,k) = 0.0232 + 0.074*chl_data(i,j)**0.674
370 optics%opacity_band(2,i,j,k) = 0.225 + 0.037*chl_data(i,j)**0.629
372 do n=3,nbands ; optics%opacity_band(n,i,j,k) = 2.86 ;
enddo
376 do j=js,je ;
do i=is,ie
377 optics%opacity_band(1,i,j,k) = cs%opacity_land_value
378 if (g%mask2dT(i,j) > 0.5) &
379 optics%opacity_band(1,i,j,k) = opacity_morel(chl_data(i,j))
382 optics%opacity_band(n,i,j,k) = optics%opacity_band(1,i,j,k)
387 call mom_error(fatal,
"opacity_from_chl: CS%opacity_scheme is not valid.")
392 end subroutine opacity_from_chl
396 function opacity_morel(chl_data)
397 real,
intent(in) :: chl_data
398 real :: opacity_morel
405 real,
dimension(6),
parameter :: &
406 z2_coef=(/7.925, -6.644, 3.662, -1.815, -0.218, 0.502/)
409 chl = log10(min(max(chl_data,0.02),60.0)) ; chl2 = chl*chl
410 opacity_morel = 1.0 / ( (z2_coef(1) + z2_coef(2)*chl) + chl2 * &
411 ((z2_coef(3) + chl*z2_coef(4)) + chl2*(z2_coef(5) + chl*z2_coef(6))) )
416 function sw_pen_frac_morel(chl_data)
417 real,
intent(in) :: chl_data
418 real :: sw_pen_frac_morel
426 real,
dimension(6),
parameter :: &
427 v1_coef=(/0.321, 0.008, 0.132, 0.038, -0.017, -0.007/)
429 chl = log10(min(max(chl_data,0.02),60.0)) ; chl2 = chl*chl
430 sw_pen_frac_morel = 1.0 - ( (v1_coef(1) + v1_coef(2)*chl) + chl2 * &
431 ((v1_coef(3) + chl*v1_coef(4)) + chl2*(v1_coef(5) + chl*v1_coef(6))) )
432 end function sw_pen_frac_morel
436 function opacity_manizza(chl_data)
437 real,
intent(in) :: chl_data
438 real :: opacity_manizza
441 opacity_manizza = 0.0232 + 0.074*chl_data**0.674
446 subroutine extract_optics_slice(optics, j, G, GV, opacity, opacity_scale, penSW_top, penSW_scale)
449 integer,
intent(in) :: j
452 real,
dimension(max(optics%nbands,1),SZI_(G),SZK_(GV)), &
453 optional,
intent(out) :: opacity
454 real,
optional,
intent(in) :: opacity_scale
455 real,
dimension(max(optics%nbands,1),SZI_(G)), &
456 optional,
intent(out) :: pensw_top
459 real,
optional,
intent(in) :: pensw_scale
462 real :: scale_opacity, scale_pensw
463 integer :: i, is, ie, k, nz, n
464 is = g%isc ; ie = g%iec ; nz = g%ke
466 scale_opacity = 1.0 ;
if (
present(opacity_scale)) scale_opacity = opacity_scale
467 scale_pensw = 1.0 ;
if (
present(pensw_scale)) scale_pensw = pensw_scale
469 if (
present(opacity))
then ;
do k=1,nz ;
do i=is,ie
471 opacity(n,i,k) = scale_opacity * optics%opacity_band(n,i,j,k)
473 enddo ;
enddo ;
endif
475 if (
present(pensw_top))
then ;
do k=1,nz ;
do i=is,ie
477 pensw_top(n,i) = scale_pensw * optics%SW_pen_band(n,i,j)
479 enddo ;
enddo ;
endif
481 end subroutine extract_optics_slice
484 subroutine extract_optics_fields(optics, nbands)
487 integer,
optional,
intent(out) :: nbands
489 if (
present(nbands)) nbands = optics%nbands
491 end subroutine extract_optics_fields
494 function optics_nbands(optics)
497 integer :: optics_nbands
499 optics_nbands = optics%nbands
500 end function optics_nbands
509 subroutine absorbremainingsw(G, GV, US, h, opacity_band, nsw, optics, j, dt, H_limit_fluxes, &
510 adjustAbsorptionProfile, absorbAllSW, T, Pen_SW_bnd, &
511 eps, ksort, htot, Ttot, TKE, dSV_dT)
516 integer,
intent(in) :: nsw
518 real,
dimension(SZI_(G),SZK_(GV)),
intent(in) :: h
519 real,
dimension(max(1,nsw),SZI_(G),SZK_(GV)),
intent(in) :: opacity_band
524 integer,
intent(in) :: j
525 real,
intent(in) :: dt
526 real,
intent(in) :: h_limit_fluxes
532 logical,
intent(in) :: adjustabsorptionprofile
538 logical,
intent(in) :: absorballsw
544 real,
dimension(SZI_(G),SZK_(GV)),
intent(inout) :: t
546 real,
dimension(max(1,nsw),SZI_(G)),
intent(inout) :: pen_sw_bnd
551 real,
dimension(SZI_(G),SZK_(GV)),
optional,
intent(in) :: eps
554 integer,
dimension(SZI_(G),SZK_(GV)),
optional,
intent(in) :: ksort
555 real,
dimension(SZI_(G)),
optional,
intent(in) :: htot
556 real,
dimension(SZI_(G)),
optional,
intent(inout) :: ttot
558 real,
dimension(SZI_(G),SZK_(GV)),
optional,
intent(in) :: dsv_dt
560 real,
dimension(SZI_(G),SZK_(GV)),
optional,
intent(inout) :: tke
564 real,
dimension(SZI_(G),SZK_(GV)) :: &
572 real,
dimension(SZI_(G)) :: &
603 logical :: sw_remains
608 integer :: is, ie, nz, i, k, ks, n
611 min_sw_heat = optics%PenSW_flux_absorb * dt
612 i_habs = optics%PenSW_absorb_Invlen
614 h_min_heat = 2.0*gv%Angstrom_H + gv%H_subroundoff
615 is = g%isc ; ie = g%iec ; nz = g%ke
616 c1_6 = 1.0 / 6.0 ; c1_60 = 1.0 / 60.0
618 tke_calc = (
present(tke) .and.
present(dsv_dt))
620 if (optics%answers_2018)
then
621 g_hconv2 = (us%m_to_Z**2 * us%L_to_Z**2*gv%g_Earth * gv%H_to_kg_m2) * gv%H_to_kg_m2
623 g_hconv2 = us%m_to_Z**2 * us%L_to_Z**2*gv%g_Earth * gv%H_to_kg_m2**2
627 if (
present(htot))
then ;
do i=is,ie ; h_heat(i) = htot(i) ;
enddo ;
endif
631 do ks=1,nz ;
do i=is,ie
633 if (
present(ksort))
then
634 if (ksort(i,ks) <= 0) cycle
637 epsilon = 0.0 ;
if (
present(eps)) epsilon = eps(i,k)
639 t_chg_above(i,k) = 0.0
641 if (h(i,k) > 1.5*epsilon)
then
642 do n=1,nsw ;
if (pen_sw_bnd(n,i) > 0.0)
then
644 opt_depth = h(i,k) * opacity_band(n,i,k)
645 exp_od = exp(-opt_depth)
650 if (optics%answers_2018)
then
651 if (nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat*min(1.0, i_habs*h(i,k)) ) sw_trans = 0.0
652 elseif ((nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat) .and. (h(i,k) > h_min_heat))
then
653 if (nsw*pen_sw_bnd(n,i) <= min_sw_heat * (i_habs*(h(i,k) - h_min_heat)))
then
656 sw_trans = min(sw_trans, &
657 1.0 - (min_sw_heat*(i_habs*(h(i,k) - h_min_heat))) / (nsw*pen_sw_bnd(n,i)))
661 heat_bnd = pen_sw_bnd(n,i) * (1.0 - sw_trans)
662 if (adjustabsorptionprofile .and. (h_heat(i) > 0.0))
then
673 if (opt_depth > 1e-5)
then
674 swa = ((opt_depth + (opt_depth + 2.0)*exp_od) - 2.0) / &
675 ((opt_depth + opacity_band(n,i,k) * h_heat(i)) * &
680 swa = h(i,k) * (opt_depth * (1.0 - opt_depth)) / &
681 ((h_heat(i) + h(i,k)) * (6.0 - 3.0*opt_depth))
684 if (swa*(h_heat(i) + h(i,k)) > h_heat(i))
then
685 coswa_frac = (swa*(h_heat(i) + h(i,k)) - h_heat(i) ) / &
686 (swa*(h_heat(i) + h(i,k)))
687 swa = h_heat(i) / (h_heat(i) + h(i,k))
690 t_chg_above(i,k) = t_chg_above(i,k) + (swa * heat_bnd) / h_heat(i)
691 t(i,k) = t(i,k) + ((1.0 - swa) * heat_bnd) / h(i,k)
694 t(i,k) = t(i,k) + pen_sw_bnd(n,i) * (1.0 - sw_trans) / h(i,k)
698 if (opt_depth > 1e-2)
then
699 tke(i,k) = tke(i,k) - coswa_frac*heat_bnd*dsv_dt(i,k)* &
700 (0.5*h(i,k)*g_hconv2) * &
701 (opt_depth*(1.0+exp_od) - 2.0*(1.0-exp_od)) / (opt_depth*(1.0-exp_od))
705 tke(i,k) = tke(i,k) - coswa_frac*heat_bnd*dsv_dt(i,k)* &
706 (0.5*h(i,k)*g_hconv2) * &
707 (c1_6*opt_depth * (1.0 - c1_60*opt_depth**2))
711 pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
717 if (h(i,k) >= 2.0*h_min_heat)
then
718 h_heat(i) = h_heat(i) + h(i,k)
719 elseif (h(i,k) > h_min_heat)
then
720 h_heat(i) = h_heat(i) + (2.0*h(i,k) - 2.0*h_min_heat)
728 do i=is,ie ; t_chg(i) = 0.0 ;
enddo
730 if (absorballsw)
then
735 pen_sw_rem(i) = pen_sw_bnd(1,i)
736 do n=2,nsw ; pen_sw_rem(i) = pen_sw_rem(i) + pen_sw_bnd(n,i) ;
enddo
738 do i=is,ie ;
if (pen_sw_rem(i) > 0.0) sw_remains = .true. ;
enddo
740 ih_limit = 1.0 / h_limit_fluxes
741 do i=is,ie ;
if ((pen_sw_rem(i) > 0.0) .and. (h_heat(i) > 0.0))
then
742 if (h_heat(i)*ih_limit >= 1.0)
then
743 t_chg(i) = pen_sw_rem(i) / h_heat(i) ; unabsorbed = 0.0
745 t_chg(i) = pen_sw_rem(i) * ih_limit
746 unabsorbed = 1.0 - h_heat(i)*ih_limit
748 do n=1,nsw ; pen_sw_bnd(n,i) = unabsorbed * pen_sw_bnd(n,i) ;
enddo
752 if (absorballsw .or. adjustabsorptionprofile)
then
753 do ks=nz,1,-1 ;
do i=is,ie
755 if (
present(ksort))
then
756 if (ksort(i,ks) <= 0) cycle
760 if (t_chg(i) > 0.0)
then
762 if (h(i,k) >= 2.0*h_min_heat)
then ; t(i,k) = t(i,k) + t_chg(i)
763 elseif (h(i,k) > h_min_heat)
then
764 t(i,k) = t(i,k) + t_chg(i) * (2.0 - 2.0*h_min_heat/h(i,k))
768 t_chg(i) = t_chg(i) + t_chg_above(i,k)
770 if (
present(htot) .and.
present(ttot))
then
771 do i=is,ie ; ttot(i) = ttot(i) + t_chg(i) * htot(i) ;
enddo
775 end subroutine absorbremainingsw
781 subroutine sumswoverbands(G, GV, US, h, nsw, optics, j, dt, &
782 H_limit_fluxes, absorbAllSW, iPen_SW_bnd, netPen)
786 real,
dimension(SZI_(G),SZK_(GV)), &
788 integer,
intent(in) :: nsw
792 integer,
intent(in) :: j
793 real,
intent(in) :: dt
794 real,
intent(in) :: h_limit_fluxes
797 logical,
intent(in) :: absorballsw
799 real,
dimension(max(nsw,1),SZI_(G)),
intent(in) :: ipen_sw_bnd
803 real,
dimension(SZI_(G),SZK_(GV)+1), &
804 intent(inout) :: netpen
808 real :: h_heat(szi_(g))
810 real :: pen_sw_rem(szi_(g))
815 real,
dimension(max(nsw,1),SZI_(G)) :: pen_sw_bnd
830 logical :: sw_remains
833 integer :: is, ie, nz, i, k, ks, n
836 min_sw_heat = optics%PenSW_flux_absorb*dt
837 i_habs = 1e3*gv%H_to_m
839 h_min_heat = 2.0*gv%Angstrom_H + gv%H_subroundoff
840 is = g%isc ; ie = g%iec ; nz = g%ke
842 pen_sw_bnd(:,:) = ipen_sw_bnd(:,:)
843 do i=is,ie ; h_heat(i) = 0.0 ;
enddo
844 netpen(:,1) = sum( pen_sw_bnd(:,:), dim=1 )
853 if (h(i,k) > 0.0)
then
854 do n=1,nsw ;
if (pen_sw_bnd(n,i) > 0.0)
then
856 opt_depth = h(i,k)*gv%H_to_m * optics%opacity_band(n,i,j,k)
857 exp_od = exp(-opt_depth)
862 if (optics%answers_2018)
then
863 if (nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat*min(1.0, i_habs*h(i,k)) ) sw_trans = 0.0
864 elseif ((nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat) .and. (h(i,k) > h_min_heat))
then
865 if (nsw*pen_sw_bnd(n,i) <= min_sw_heat * (i_habs*(h(i,k) - h_min_heat)))
then
868 sw_trans = min(sw_trans, &
869 1.0 - (min_sw_heat*(i_habs*(h(i,k) - h_min_heat))) / (nsw*pen_sw_bnd(n,i)))
873 pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
874 netpen(i,k+1) = netpen(i,k+1) + pen_sw_bnd(n,i)
880 if (h(i,k) >= 2.0*h_min_heat)
then
881 h_heat(i) = h_heat(i) + h(i,k)
882 elseif (h(i,k) > h_min_heat)
then
883 h_heat(i) = h_heat(i) + (2.0*h(i,k) - 2.0*h_min_heat)
888 if (absorballsw)
then
894 pen_sw_rem(i) = pen_sw_bnd(1,i)
895 do n=2,nsw ; pen_sw_rem(i) = pen_sw_rem(i) + pen_sw_bnd(n,i) ;
enddo
897 do i=is,ie ;
if (pen_sw_rem(i) > 0.0) sw_remains = .true. ;
enddo
899 ih_limit = 1.0 / h_limit_fluxes
900 do i=is,ie ;
if ((pen_sw_rem(i) > 0.0) .and. (h_heat(i) > 0.0))
then
901 if (h_heat(i)*ih_limit < 1.0)
then
902 unabsorbed = 1.0 - h_heat(i)*ih_limit
906 do n=1,nsw ; pen_sw_bnd(n,i) = unabsorbed * pen_sw_bnd(n,i) ;
enddo
911 end subroutine sumswoverbands
916 subroutine opacity_init(Time, G, GV, US, param_file, diag, CS, optics)
917 type(time_type),
target,
intent(in) :: time
923 type(
diag_ctrl),
target,
intent(inout) :: diag
930 character(len=200) :: tmpstr
931 character(len=40) :: mdl =
"MOM_opacity"
932 character(len=40) :: bandnum, shortname
933 character(len=200) :: longname
934 character(len=40) :: scheme_string
936 # include "version_variable.h"
937 real :: pensw_absorb_minthick
939 real :: pensw_minthick_dflt
940 logical :: default_2018_answers
941 logical :: use_scheme
942 integer :: isd, ied, jsd, jed, nz, n
943 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
945 if (
associated(cs))
then
946 call mom_error(warning,
"opacity_init called with an associated"// &
947 "associated control structure.")
949 else ;
allocate(cs) ;
endif
957 call get_param(param_file, mdl,
"VAR_PEN_SW", cs%var_pen_sw, &
958 "If true, use one of the CHL_A schemes specified by "//&
959 "OPACITY_SCHEME to determine the e-folding depth of "//&
960 "incoming short wave radiation.", default=.false.)
962 cs%opacity_scheme = no_scheme ; scheme_string =
''
963 if (cs%var_pen_sw)
then
964 call get_param(param_file, mdl,
"OPACITY_SCHEME", tmpstr, &
965 "This character string specifies how chlorophyll "//&
966 "concentrations are translated into opacities. Currently "//&
967 "valid options include:\n"//&
968 " \t\t MANIZZA_05 - Use Manizza et al., GRL, 2005. \n"//&
969 " \t\t MOREL_88 - Use Morel, JGR, 1988.", &
970 default=manizza_05_string)
971 if (len_trim(tmpstr) > 0)
then
972 tmpstr = uppercase(tmpstr)
974 case (manizza_05_string)
975 cs%opacity_scheme = manizza_05 ; scheme_string = manizza_05_string
976 case (morel_88_string)
977 cs%opacity_scheme = morel_88 ; scheme_string = morel_88_string
979 call mom_error(fatal,
"opacity_init: #DEFINE OPACITY_SCHEME "//&
980 trim(tmpstr) //
"in input file is invalid.")
982 call mom_mesg(
'opacity_init: opacity scheme set to "'//trim(tmpstr)//
'".', 5)
984 if (cs%opacity_scheme == no_scheme)
then
985 call mom_error(warning,
"opacity_init: No scheme has successfully "//&
986 "been specified for the opacity. Using the default MANIZZA_05.")
987 cs%opacity_scheme = manizza_05 ; scheme_string = manizza_05_string
990 call get_param(param_file, mdl,
"BLUE_FRAC_SW", cs%blue_frac, &
991 "The fraction of the penetrating shortwave radiation "//&
992 "that is in the blue band.", default=0.5, units=
"nondim")
994 call get_param(param_file, mdl,
"EXP_OPACITY_SCHEME", tmpstr, &
995 "This character string specifies which exponential "//&
996 "opacity scheme to utilize. Currently "//&
997 "valid options include:\n"//&
998 " \t\t SINGLE_EXP - Single Exponent decay. \n"//&
999 " \t\t DOUBLE_EXP - Double Exponent decay.", &
1000 default=single_exp_string)
1001 if (len_trim(tmpstr) > 0)
then
1002 tmpstr = uppercase(tmpstr)
1003 select case (tmpstr)
1004 case (single_exp_string)
1005 cs%opacity_scheme = single_exp ; scheme_string = single_exp_string
1006 case (double_exp_string)
1007 cs%opacity_scheme = double_exp ; scheme_string = double_exp_string
1009 call mom_mesg(
'opacity_init: opacity scheme set to "'//trim(tmpstr)//
'".', 5)
1011 call get_param(param_file, mdl,
"PEN_SW_SCALE", cs%pen_sw_scale, &
1012 "The vertical absorption e-folding depth of the "//&
1013 "penetrating shortwave radiation.", units=
"m", default=0.0)
1015 if (cs%Opacity_scheme == double_exp )
then
1016 call get_param(param_file, mdl,
"PEN_SW_SCALE_2ND", cs%pen_sw_scale_2nd, &
1017 "The (2nd) vertical absorption e-folding depth of the "//&
1018 "penetrating shortwave radiation "//&
1019 "(use if SW_EXP_MODE==double.)",&
1020 units=
"m", default=0.0)
1021 call get_param(param_file, mdl,
"SW_1ST_EXP_RATIO", cs%sw_1st_exp_ratio, &
1022 "The fraction of 1st vertical absorption e-folding depth "//&
1023 "penetrating shortwave radiation if SW_EXP_MODE==double.",&
1024 units=
"m", default=0.0)
1025 elseif (cs%OPACITY_SCHEME == single_exp)
then
1027 cs%pen_sw_scale_2nd = 0.0
1028 cs%sw_1st_exp_ratio = 1.0
1030 call get_param(param_file, mdl,
"PEN_SW_FRAC", cs%pen_sw_frac, &
1031 "The fraction of the shortwave radiation that penetrates "//&
1032 "below the surface.", units=
"nondim", default=0.0)
1035 call get_param(param_file, mdl,
"PEN_SW_NBANDS", optics%nbands, &
1036 "The number of bands of penetrating shortwave radiation.", &
1038 if (cs%Opacity_scheme == double_exp )
then
1039 if (optics%nbands /= 2)
call mom_error(fatal, &
1040 "set_opacity: \Cannot use a double_exp opacity scheme with nbands!=2.")
1041 elseif (cs%Opacity_scheme == single_exp )
then
1042 if (optics%nbands /= 1)
call mom_error(fatal, &
1043 "set_opacity: \Cannot use a single_exp opacity scheme with nbands!=1.")
1046 call get_param(param_file, mdl,
"DEFAULT_2018_ANSWERS", default_2018_answers, &
1047 "This sets the default value for the various _2018_ANSWERS parameters.", &
1049 call get_param(param_file, mdl,
"OPTICS_2018_ANSWERS", optics%answers_2018, &
1050 "If true, use the order of arithmetic and expressions that recover the "//&
1051 "answers from the end of 2018. Otherwise, use updated expressions for "//&
1052 "handling the absorption of small remaining shortwave fluxes.", &
1053 default=default_2018_answers)
1055 call get_param(param_file, mdl,
"PEN_SW_FLUX_ABSORB", optics%PenSW_flux_absorb, &
1056 "A minimum remaining shortwave heating rate that will be simply absorbed in "//&
1057 "the next sufficiently thick layers for computational efficiency, instead of "//&
1058 "continuing to penetrate. The default, 2.5e-11 degC m s-1, is about 1e-4 W m-2 "//&
1059 "or 0.08 degC m century-1, but 0 is also a valid value.", &
1060 default=2.5e-11, units=
"degC m s-1", scale=gv%m_to_H*us%T_to_s)
1062 if (optics%answers_2018)
then ; pensw_minthick_dflt = 0.001 ;
else ; pensw_minthick_dflt = 1.0 ;
endif
1063 call get_param(param_file, mdl,
"PEN_SW_ABSORB_MINTHICK", pensw_absorb_minthick, &
1064 "A thickness that is used to absorb the remaining penetrating shortwave heat "//&
1065 "flux when it drops below PEN_SW_FLUX_ABSORB.", &
1066 default=pensw_minthick_dflt, units=
"m", scale=gv%m_to_H)
1067 optics%PenSW_absorb_Invlen = 1.0 / (pensw_absorb_minthick + gv%H_subroundoff)
1069 if (.not.
associated(optics%min_wavelength_band)) &
1070 allocate(optics%min_wavelength_band(optics%nbands))
1071 if (.not.
associated(optics%max_wavelength_band)) &
1072 allocate(optics%max_wavelength_band(optics%nbands))
1074 if (cs%opacity_scheme == manizza_05)
then
1075 optics%min_wavelength_band(1) =0
1076 optics%max_wavelength_band(1) =550
1077 if (optics%nbands >= 2)
then
1078 optics%min_wavelength_band(2)=550
1079 optics%max_wavelength_band(2)=700
1081 if (optics%nbands > 2)
then
1082 do n=3,optics%nbands
1083 optics%min_wavelength_band(n) =700
1084 optics%max_wavelength_band(n) =2800
1089 call get_param(param_file, mdl,
"OPACITY_LAND_VALUE", cs%opacity_land_value, &
1090 "The value to use for opacity over land. The default is "//&
1091 "10 m-1 - a value for muddy water.", units=
"m-1", default=10.0)
1093 if (.not.
associated(optics%opacity_band)) &
1094 allocate(optics%opacity_band(optics%nbands,isd:ied,jsd:jed,nz))
1095 if (.not.
associated(optics%sw_pen_band)) &
1096 allocate(optics%sw_pen_band(optics%nbands,isd:ied,jsd:jed))
1097 allocate(cs%id_opacity(optics%nbands)) ; cs%id_opacity(:) = -1
1099 cs%id_sw_pen = register_diag_field(
'ocean_model',
'SW_pen', diag%axesT1, time, &
1100 'Penetrating shortwave radiation flux into ocean',
'W m-2')
1101 cs%id_sw_vis_pen = register_diag_field(
'ocean_model',
'SW_vis_pen', diag%axesT1, time, &
1102 'Visible penetrating shortwave radiation flux into ocean',
'W m-2')
1103 do n=1,optics%nbands
1104 write(bandnum,
'(i3)') n
1105 shortname =
'opac_'//trim(adjustl(bandnum))
1106 longname =
'Opacity for shortwave radiation in band '//trim(adjustl(bandnum)) &
1107 //
', saved as L^-1 tanh(Opacity * L) for L = 10^-10 m'
1108 cs%id_opacity(n) = register_diag_field(
'ocean_model', shortname, diag%axesTL, time, &
1112 end subroutine opacity_init
1115 subroutine opacity_end(CS, optics)
1119 if (
associated(cs%id_opacity))
deallocate(cs%id_opacity)
1120 if (
associated(cs))
deallocate(cs)
1122 if (
present(optics))
then ;
if (
associated(optics))
then
1123 if (
associated(optics%opacity_band))
deallocate(optics%opacity_band)
1124 if (
associated(optics%sw_pen_band))
deallocate(optics%sw_pen_band)
1127 end subroutine opacity_end