MOM6
mom_opacity Module Reference

Detailed Description

Routines used to calculate the opacity of the ocean.

opacity_from_chl: In this routine, the Morel (modified) or Manizza (modified) schemes use the "blue" band in the paramterizations to determine the e-folding depth of the incoming shortwave attenuation. The red portion is lumped into the net heating at the surface.

Morel, A., 1988: Optical modeling of the upper ocean in relation to its biogenous matter content (case-i waters)., J. Geo. Res., 93, 10,749-10,768.

Manizza, M., C. LeQuere, A. J. Watson, and E. T. Buitenhuis, 2005: Bio-optical feedbacks among phytoplankton, upper ocean physics and sea-ice in a global model, Geophys. Res. Let., 32, L05603, doi:10.1029/2004GL020778.

Data Types

type  opacity_cs
 The control structure with paramters for the MOM_opacity module. More...
 
type  optics_type
 This type is used to store information about ocean optical properties. More...
 

Functions/Subroutines

subroutine, public set_opacity (optics, sw_total, sw_vis_dir, sw_vis_dif, sw_nir_dir, sw_nir_dif, G, GV, US, CS, chl_2d, chl_3d)
 This sets the opacity of sea water based based on one of several different schemes. More...
 
subroutine opacity_from_chl (optics, sw_total, sw_vis_dir, sw_vis_dif, sw_nir_dir, sw_nir_dif, G, GV, US, CS, chl_2d, chl_3d)
 This sets the "blue" band opacity based on chloophyll A concencentrations The red portion is lumped into the net heating at the surface. More...
 
real function, public opacity_morel (chl_data)
 This sets the blue-wavelength opacity according to the scheme proposed by Morel and Antoine (1994). More...
 
real function sw_pen_frac_morel (chl_data)
 This sets the penetrating shortwave fraction according to the scheme proposed by Morel and Antoine (1994). More...
 
real function, public opacity_manizza (chl_data)
 This sets the blue-wavelength opacity according to the scheme proposed by Manizza, M. et al, 2005. More...
 
subroutine, public extract_optics_slice (optics, j, G, GV, opacity, opacity_scale, penSW_top, penSW_scale)
 This subroutine returns a 2-d slice at constant j of fields from an optics_type, with the potential for rescaling these fields. More...
 
subroutine, public extract_optics_fields (optics, nbands)
 Set arguments to fields from the optics type. More...
 
integer function, public optics_nbands (optics)
 Return the number of bands of penetrating shortwave radiation. More...
 
subroutine, public absorbremainingsw (G, GV, US, h, opacity_band, nsw, optics, j, dt, H_limit_fluxes, adjustAbsorptionProfile, absorbAllSW, T, Pen_SW_bnd, eps, ksort, htot, Ttot, TKE, dSV_dT)
 Apply shortwave heating below the boundary layer (when running with the bulk mixed layer inhereted from GOLD) or throughout the water column. More...
 
subroutine, public sumswoverbands (G, GV, US, h, nsw, optics, j, dt, H_limit_fluxes, absorbAllSW, iPen_SW_bnd, netPen)
 This subroutine calculates the total shortwave heat flux integrated over bands as a function of depth. This routine is only called for computing buoyancy fluxes for use in KPP. This routine does not updat e the state. More...
 
subroutine, public opacity_init (Time, G, GV, US, param_file, diag, CS, optics)
 This routine initalizes the opacity module, including an optics_type. More...
 
subroutine, public opacity_end (CS, optics)
 

Variables

character *(10), parameter manizza_05_string = "MANIZZA_05"
 String to specify the opacity scheme.
 
character *(10), parameter morel_88_string = "MOREL_88"
 String to specify the opacity scheme.
 
character *(10), parameter single_exp_string = "SINGLE_EXP"
 String to specify the opacity scheme.
 
character *(10), parameter double_exp_string = "DOUBLE_EXP"
 String to specify the opacity scheme.
 
real, parameter op_diag_len = 1e-10
 Lengthscale L used to remap opacity from op to 1/L * tanh(op * L)
 

Function/Subroutine Documentation

◆ absorbremainingsw()

subroutine, public mom_opacity::absorbremainingsw ( type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  h,
real, dimension(max(1,nsw), g %isd: g %ied, gv %ke), intent(in)  opacity_band,
integer, intent(in)  nsw,
type(optics_type), intent(in)  optics,
integer, intent(in)  j,
real, intent(in)  dt,
real, intent(in)  H_limit_fluxes,
logical, intent(in)  adjustAbsorptionProfile,
logical, intent(in)  absorbAllSW,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  T,
real, dimension(max(1,nsw), g %isd: g %ied), intent(inout)  Pen_SW_bnd,
real, dimension( g %isd: g %ied, gv %ke), intent(in), optional  eps,
integer, dimension( g %isd: g %ied, gv %ke), intent(in), optional  ksort,
real, dimension( g %isd: g %ied), intent(in), optional  htot,
real, dimension( g %isd: g %ied), intent(inout), optional  Ttot,
real, dimension( g %isd: g %ied, gv %ke), intent(inout), optional  TKE,
real, dimension( g %isd: g %ied, gv %ke), intent(in), optional  dSV_dT 
)

Apply shortwave heating below the boundary layer (when running with the bulk mixed layer inhereted from GOLD) or throughout the water column.

In addition, it causes all of the remaining SW radiation to be absorbed, provided that the total water column thickness is greater than H_limit_fluxes. For thinner water columns, the heating is scaled down proportionately, the assumption being that the remaining heating (which is left in Pen_SW) should go into an (absent for now) ocean bottom sediment layer.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in]nswNumber of bands of penetrating shortwave radiation.
[in]hLayer thicknesses [H ~> m or kg m-2].
[in]opacity_bandOpacity in each band of penetrating shortwave radiation [H-1 ~> m-1 or m2 kg-1]. The indicies are band, i, k.
[in]opticsAn optics structure that has values of opacities and shortwave fluxes.
[in]jj-index to work on.
[in]dtTime step [T ~> s].
[in]h_limit_fluxesIf the total ocean depth is less than this, they are scaled away to avoid numerical instabilities [H ~> m or kg m-2]. This would not be necessary if a finite heat capacity mud-layer were added.
[in]adjustabsorptionprofileIf true, apply heating above the layers in which it should have occurred to get the correct mean depth (and potential energy change) of the shortwave that should be absorbed by each layer.
[in]absorballswIf true, apply heating above the layers in which it should have occurred to get the correct mean depth (and potential energy change) of the shortwave that should be absorbed by each layer.
[in,out]tLayer potential/conservative temperatures [degC]
[in,out]pen_sw_bndPenetrating shortwave heating in each band that hits the bottom and will will be redistributed through the water column [degC H ~> degC m or degC kg m-2], size nsw x G isd: G ied.
[in]epsSmall thickness that must remain in each layer, and which will not be subject to heating [H ~> m or kg m-2]
[in]ksortDensity-sorted k-indicies.
[in]htotTotal mixed layer thickness [H ~> m or kg m-2].
[in,out]ttotDepth integrated mixed layer temperature [degC H ~> degC m or degC kg m-2]
[in]dsv_dtThe partial derivative of specific volume with temperature [R-1 degC-1].
[in,out]tkeThe TKE sink from mixing the heating throughout a layer [R Z3 T-2 ~> J m-2].

Definition at line 511 of file MOM_opacity.F90.

511 
512  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
513  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
514  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
515  integer, intent(in) :: nsw !< Number of bands of penetrating
516  !! shortwave radiation.
517  real, dimension(SZI_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2].
518  real, dimension(max(1,nsw),SZI_(G),SZK_(GV)), intent(in) :: opacity_band !< Opacity in each band of penetrating
519  !! shortwave radiation [H-1 ~> m-1 or m2 kg-1].
520  !! The indicies are band, i, k.
521  type(optics_type), intent(in) :: optics !< An optics structure that has values of
522  !! opacities and shortwave fluxes.
523  integer, intent(in) :: j !< j-index to work on.
524  real, intent(in) :: dt !< Time step [T ~> s].
525  real, intent(in) :: H_limit_fluxes !< If the total ocean depth is
526  !! less than this, they are scaled away
527  !! to avoid numerical instabilities
528  !! [H ~> m or kg m-2]. This would
529  !! not be necessary if a finite heat
530  !! capacity mud-layer were added.
531  logical, intent(in) :: adjustAbsorptionProfile !< If true, apply
532  !! heating above the layers in which it
533  !! should have occurred to get the
534  !! correct mean depth (and potential
535  !! energy change) of the shortwave that
536  !! should be absorbed by each layer.
537  logical, intent(in) :: absorbAllSW !< If true, apply heating above the
538  !! layers in which it should have occurred
539  !! to get the correct mean depth (and
540  !! potential energy change) of the
541  !! shortwave that should be absorbed by
542  !! each layer.
543  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: T !< Layer potential/conservative
544  !! temperatures [degC]
545  real, dimension(max(1,nsw),SZI_(G)), intent(inout) :: Pen_SW_bnd !< Penetrating shortwave heating in
546  !! each band that hits the bottom and will
547  !! will be redistributed through the water
548  !! column [degC H ~> degC m or degC kg m-2],
549  !! size nsw x SZI_(G).
550  real, dimension(SZI_(G),SZK_(GV)), optional, intent(in) :: eps !< Small thickness that must remain in
551  !! each layer, and which will not be
552  !! subject to heating [H ~> m or kg m-2]
553  integer, dimension(SZI_(G),SZK_(GV)), optional, intent(in) :: ksort !< Density-sorted k-indicies.
554  real, dimension(SZI_(G)), optional, intent(in) :: htot !< Total mixed layer thickness [H ~> m or kg m-2].
555  real, dimension(SZI_(G)), optional, intent(inout) :: Ttot !< Depth integrated mixed layer
556  !! temperature [degC H ~> degC m or degC kg m-2]
557  real, dimension(SZI_(G),SZK_(GV)), optional, intent(in) :: dSV_dT !< The partial derivative of specific
558  !! volume with temperature [R-1 degC-1].
559  real, dimension(SZI_(G),SZK_(GV)), optional, intent(inout) :: TKE !< The TKE sink from mixing the heating
560  !! throughout a layer [R Z3 T-2 ~> J m-2].
561 
562  ! Local variables
563  real, dimension(SZI_(G),SZK_(GV)) :: &
564  T_chg_above ! A temperature change that will be applied to all the thick
565  ! layers above a given layer [degC]. This is only nonzero if
566  ! adjustAbsorptionProfile is true, in which case the net
567  ! change in the temperature of a layer is the sum of the
568  ! direct heating of that layer plus T_chg_above from all of
569  ! the layers below, plus any contribution from absorbing
570  ! radiation that hits the bottom.
571  real, dimension(SZI_(G)) :: &
572  h_heat, & ! The thickness of the water column that will be heated by
573  ! any remaining shortwave radiation [H ~> m or kg m-2].
574  t_chg, & ! The temperature change of thick layers due to the remaining
575  ! shortwave radiation and contributions from T_chg_above [degC].
576  pen_sw_rem ! The sum across all wavelength bands of the penetrating shortwave
577  ! heating that hits the bottom and will be redistributed through
578  ! the water column [degC H ~> degC m or degC kg m-2]
579  real :: SW_trans ! fraction of shortwave radiation that is not
580  ! absorbed in a layer [nondim]
581  real :: unabsorbed ! fraction of the shortwave radiation that
582  ! is not absorbed because the layers are too thin
583  real :: Ih_limit ! inverse of the total depth at which the
584  ! surface fluxes start to be limited [H-1 ~> m-1 or m2 kg-1]
585  real :: h_min_heat ! minimum thickness layer that should get heated [H ~> m or kg m-2]
586  real :: opt_depth ! optical depth of a layer [nondim]
587  real :: exp_OD ! exp(-opt_depth) [nondim]
588  real :: heat_bnd ! heating due to absorption in the current
589  ! layer by the current band, including any piece that
590  ! is moved upward [degC H ~> degC m or degC kg m-2]
591  real :: SWa ! fraction of the absorbed shortwave that is
592  ! moved to layers above with adjustAbsorptionProfile [nondim]
593  real :: coSWa_frac ! The fraction of SWa that is actually moved upward.
594  real :: min_SW_heat ! A minimum remaining shortwave heating within a timestep that will be simply
595  ! absorbed in the next layer for computational efficiency, instead of
596  ! continuing to penetrate [degC H ~> degC m or degC kg m-2].
597  real :: I_Habs ! The inverse of the absorption length for a minimal flux [H-1 ~> m-1 or m2 kg-1]
598  real :: epsilon ! A small thickness that must remain in each
599  ! layer, and which will not be subject to heating [H ~> m or kg m-2]
600  real :: g_Hconv2 ! A conversion factor for use in the TKE calculation
601  ! in units of [Z3 R2 T-2 H-2 ~> kg2 m-5 s-2 or m s-2].
602  logical :: SW_Remains ! If true, some column has shortwave radiation that
603  ! was not entirely absorbed.
604  logical :: TKE_calc ! If true, calculate the implications to the
605  ! TKE budget of the shortwave heating.
606  real :: C1_6, C1_60
607  integer :: is, ie, nz, i, k, ks, n
608  sw_remains = .false.
609 
610  min_sw_heat = optics%PenSW_flux_absorb * dt
611  i_habs = optics%PenSW_absorb_Invlen
612 
613  h_min_heat = 2.0*gv%Angstrom_H + gv%H_subroundoff
614  is = g%isc ; ie = g%iec ; nz = g%ke
615  c1_6 = 1.0 / 6.0 ; c1_60 = 1.0 / 60.0
616 
617  tke_calc = (present(tke) .and. present(dsv_dt))
618 
619  if (optics%answers_2018) then
620  g_hconv2 = (us%L_to_Z**2*gv%g_Earth * gv%H_to_RZ) * gv%H_to_RZ
621  else
622  g_hconv2 = us%L_to_Z**2*gv%g_Earth * gv%H_to_RZ**2
623  endif
624 
625  h_heat(:) = 0.0
626  if (present(htot)) then ; do i=is,ie ; h_heat(i) = htot(i) ; enddo ; endif
627 
628  ! Apply penetrating SW radiation to remaining parts of layers.
629  ! Excessively thin layers are not heated to avoid runaway temps.
630  do ks=1,nz ; do i=is,ie
631  k = ks
632  if (present(ksort)) then
633  if (ksort(i,ks) <= 0) cycle
634  k = ksort(i,ks)
635  endif
636  epsilon = 0.0 ; if (present(eps)) epsilon = eps(i,k)
637 
638  t_chg_above(i,k) = 0.0
639 
640  if (h(i,k) > 1.5*epsilon) then
641  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
642  ! SW_trans is the SW that is transmitted THROUGH the layer
643  opt_depth = h(i,k) * opacity_band(n,i,k)
644  exp_od = exp(-opt_depth)
645  sw_trans = exp_od
646 
647  ! Heating at a very small rate can be absorbed by a sufficiently thick layer or several
648  ! thin layers without further penetration.
649  if (optics%answers_2018) then
650  if (nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat*min(1.0, i_habs*h(i,k)) ) sw_trans = 0.0
651  elseif ((nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat) .and. (h(i,k) > h_min_heat)) then
652  if (nsw*pen_sw_bnd(n,i) <= min_sw_heat * (i_habs*(h(i,k) - h_min_heat))) then
653  sw_trans = 0.0
654  else
655  sw_trans = min(sw_trans, &
656  1.0 - (min_sw_heat*(i_habs*(h(i,k) - h_min_heat))) / (nsw*pen_sw_bnd(n,i)))
657  endif
658  endif
659 
660  heat_bnd = pen_sw_bnd(n,i) * (1.0 - sw_trans)
661  if (adjustabsorptionprofile .and. (h_heat(i) > 0.0)) then
662  ! In this case, a fraction of the heating is applied to the
663  ! overlying water so that the mean pressure at which the shortwave
664  ! heating occurs is exactly what it would have been with a careful
665  ! pressure-weighted averaging of the exponential heating profile,
666  ! hence there should be no TKE budget requirements due to this
667  ! layer. Very clever, but this is also limited so that the
668  ! water above is not heated at a faster rate than the layer
669  ! actually being heated, i.e., SWA <= h_heat / (h_heat + h(i,k))
670  ! and takes the energetics of the rest of the heating into account.
671  ! (-RWH, ~7 years later.)
672  if (opt_depth > 1e-5) then
673  swa = ((opt_depth + (opt_depth + 2.0)*exp_od) - 2.0) / &
674  ((opt_depth + opacity_band(n,i,k) * h_heat(i)) * &
675  (1.0 - exp_od))
676  else
677  ! Use Taylor series expansion of the expression above for a
678  ! more accurate form with very small layer optical depths.
679  swa = h(i,k) * (opt_depth * (1.0 - opt_depth)) / &
680  ((h_heat(i) + h(i,k)) * (6.0 - 3.0*opt_depth))
681  endif
682  coswa_frac = 0.0
683  if (swa*(h_heat(i) + h(i,k)) > h_heat(i)) then
684  coswa_frac = (swa*(h_heat(i) + h(i,k)) - h_heat(i) ) / &
685  (swa*(h_heat(i) + h(i,k)))
686  swa = h_heat(i) / (h_heat(i) + h(i,k))
687  endif
688 
689  t_chg_above(i,k) = t_chg_above(i,k) + (swa * heat_bnd) / h_heat(i)
690  t(i,k) = t(i,k) + ((1.0 - swa) * heat_bnd) / h(i,k)
691  else
692  coswa_frac = 1.0
693  t(i,k) = t(i,k) + pen_sw_bnd(n,i) * (1.0 - sw_trans) / h(i,k)
694  endif
695 
696  if (tke_calc) then
697  if (opt_depth > 1e-2) then
698  tke(i,k) = tke(i,k) - coswa_frac*heat_bnd*dsv_dt(i,k)* &
699  (0.5*h(i,k)*g_hconv2) * &
700  (opt_depth*(1.0+exp_od) - 2.0*(1.0-exp_od)) / (opt_depth*(1.0-exp_od))
701  else
702  ! Use Taylor series-derived approximation to the above expression
703  ! that is well behaved and more accurate when opt_depth is small.
704  tke(i,k) = tke(i,k) - coswa_frac*heat_bnd*dsv_dt(i,k)* &
705  (0.5*h(i,k)*g_hconv2) * &
706  (c1_6*opt_depth * (1.0 - c1_60*opt_depth**2))
707  endif
708  endif
709 
710  pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
711  endif ; enddo
712  endif
713 
714  ! Add to the accumulated thickness above that could be heated.
715  ! Only layers greater than h_min_heat thick should get heated.
716  if (h(i,k) >= 2.0*h_min_heat) then
717  h_heat(i) = h_heat(i) + h(i,k)
718  elseif (h(i,k) > h_min_heat) then
719  h_heat(i) = h_heat(i) + (2.0*h(i,k) - 2.0*h_min_heat)
720  endif
721  enddo ; enddo ! i & k loops
722 
723 ! if (.not.absorbAllSW .and. .not.adjustAbsorptionProfile) return
724 
725  ! Unless modified, there is no temperature change due to fluxes from the bottom.
726  do i=is,ie ; t_chg(i) = 0.0 ; enddo
727 
728  if (absorballsw) then
729  ! If there is still shortwave radiation at this point, it could go into
730  ! the bottom (with a bottom mud model), or it could be redistributed back
731  ! through the water column.
732  do i=is,ie
733  pen_sw_rem(i) = pen_sw_bnd(1,i)
734  do n=2,nsw ; pen_sw_rem(i) = pen_sw_rem(i) + pen_sw_bnd(n,i) ; enddo
735  enddo
736  do i=is,ie ; if (pen_sw_rem(i) > 0.0) sw_remains = .true. ; enddo
737 
738  ih_limit = 1.0 / h_limit_fluxes
739  do i=is,ie ; if ((pen_sw_rem(i) > 0.0) .and. (h_heat(i) > 0.0)) then
740  if (h_heat(i)*ih_limit >= 1.0) then
741  t_chg(i) = pen_sw_rem(i) / h_heat(i) ; unabsorbed = 0.0
742  else
743  t_chg(i) = pen_sw_rem(i) * ih_limit
744  unabsorbed = 1.0 - h_heat(i)*ih_limit
745  endif
746  do n=1,nsw ; pen_sw_bnd(n,i) = unabsorbed * pen_sw_bnd(n,i) ; enddo
747  endif ; enddo
748  endif ! absorbAllSW
749 
750  if (absorballsw .or. adjustabsorptionprofile) then
751  do ks=nz,1,-1 ; do i=is,ie
752  k = ks
753  if (present(ksort)) then
754  if (ksort(i,ks) <= 0) cycle
755  k = ksort(i,ks)
756  endif
757 
758  if (t_chg(i) > 0.0) then
759  ! Only layers greater than h_min_heat thick should get heated.
760  if (h(i,k) >= 2.0*h_min_heat) then ; t(i,k) = t(i,k) + t_chg(i)
761  elseif (h(i,k) > h_min_heat) then
762  t(i,k) = t(i,k) + t_chg(i) * (2.0 - 2.0*h_min_heat/h(i,k))
763  endif
764  endif
765  ! Increase the heating for layers above.
766  t_chg(i) = t_chg(i) + t_chg_above(i,k)
767  enddo ; enddo
768  if (present(htot) .and. present(ttot)) then
769  do i=is,ie ; ttot(i) = ttot(i) + t_chg(i) * htot(i) ; enddo
770  endif
771  endif ! absorbAllSW .or. adjustAbsorptionProfile
772 

◆ extract_optics_fields()

subroutine, public mom_opacity::extract_optics_fields ( type(optics_type), intent(in)  optics,
integer, intent(out), optional  nbands 
)

Set arguments to fields from the optics type.

Parameters
[in]opticsAn optics structure that has values of opacities and shortwave fluxes.
[out]nbandsThe number of penetrating bands of SW radiation

Definition at line 484 of file MOM_opacity.F90.

484  type(optics_type), intent(in) :: optics !< An optics structure that has values of opacities
485  !! and shortwave fluxes.
486  integer, optional, intent(out) :: nbands !< The number of penetrating bands of SW radiation
487 
488  if (present(nbands)) nbands = optics%nbands
489 

◆ extract_optics_slice()

subroutine, public mom_opacity::extract_optics_slice ( type(optics_type), intent(in)  optics,
integer, intent(in)  j,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
real, dimension(max(optics%nbands,1), g %isd: g %ied, gv %ke), intent(out), optional  opacity,
real, intent(in), optional  opacity_scale,
real, dimension(max(optics%nbands,1), g %isd: g %ied), intent(out), optional  penSW_top,
real, intent(in), optional  penSW_scale 
)

This subroutine returns a 2-d slice at constant j of fields from an optics_type, with the potential for rescaling these fields.

Parameters
[in]opticsAn optics structure that has values of opacities and shortwave fluxes.
[in]jj-index to extract
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[out]opacityThe opacity in each band, i-point, and layer
[in]opacity_scaleA factor by which to rescale the opacity.
[out]pensw_topThe shortwave radiation [Q R Z T-1 ~> W m-2]
[in]pensw_scaleA factor by which to rescale the shortwave flux.

Definition at line 446 of file MOM_opacity.F90.

446  type(optics_type), intent(in) :: optics !< An optics structure that has values of opacities
447  !! and shortwave fluxes.
448  integer, intent(in) :: j !< j-index to extract
449  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
450  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
451  real, dimension(max(optics%nbands,1),SZI_(G),SZK_(GV)), &
452  optional, intent(out) :: opacity !< The opacity in each band, i-point, and layer
453  real, optional, intent(in) :: opacity_scale !< A factor by which to rescale the opacity.
454  real, dimension(max(optics%nbands,1),SZI_(G)), &
455  optional, intent(out) :: penSW_top !< The shortwave radiation [Q R Z T-1 ~> W m-2]
456  !! at the surface in each of the nbands bands
457  !! that penetrates beyond the surface skin layer.
458  real, optional, intent(in) :: penSW_scale !< A factor by which to rescale the shortwave flux.
459 
460  ! Local variables
461  real :: scale_opacity, scale_penSW ! Rescaling factors
462  integer :: i, is, ie, k, nz, n
463  is = g%isc ; ie = g%iec ; nz = g%ke
464 
465  scale_opacity = 1.0 ; if (present(opacity_scale)) scale_opacity = opacity_scale
466  scale_pensw = 1.0 ; if (present(pensw_scale)) scale_pensw = pensw_scale
467 
468  if (present(opacity)) then ; do k=1,nz ; do i=is,ie
469  do n=1,optics%nbands
470  opacity(n,i,k) = scale_opacity * optics%opacity_band(n,i,j,k)
471  enddo
472  enddo ; enddo ; endif
473 
474  if (present(pensw_top)) then ; do k=1,nz ; do i=is,ie
475  do n=1,optics%nbands
476  pensw_top(n,i) = scale_pensw * optics%sw_pen_band(n,i,j)
477  enddo
478  enddo ; enddo ; endif
479 

◆ opacity_end()

subroutine, public mom_opacity::opacity_end ( type(opacity_cs), pointer  CS,
type(optics_type), optional, pointer  optics 
)
Parameters
csAn opacity control structure that should be deallocated.
opticsAn optics type structure that should be deallocated.

Definition at line 1119 of file MOM_opacity.F90.

1119  type(opacity_CS), pointer :: CS !< An opacity control structure that should be deallocated.
1120  type(optics_type), optional, pointer :: optics !< An optics type structure that should be deallocated.
1121 
1122  if (associated(cs%id_opacity)) deallocate(cs%id_opacity)
1123  if (associated(cs)) deallocate(cs)
1124 
1125  if (present(optics)) then ; if (associated(optics)) then
1126  if (associated(optics%opacity_band)) deallocate(optics%opacity_band)
1127  if (associated(optics%sw_pen_band)) deallocate(optics%sw_pen_band)
1128  endif ; endif
1129 

◆ opacity_from_chl()

subroutine mom_opacity::opacity_from_chl ( type(optics_type), intent(inout)  optics,
real, dimension(:,:), pointer  sw_total,
real, dimension(:,:), pointer  sw_vis_dir,
real, dimension(:,:), pointer  sw_vis_dif,
real, dimension(:,:), pointer  sw_nir_dir,
real, dimension(:,:), pointer  sw_nir_dif,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(opacity_cs), pointer  CS,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in), optional  chl_2d,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(in), optional  chl_3d 
)
private

This sets the "blue" band opacity based on chloophyll A concencentrations The red portion is lumped into the net heating at the surface.

Parameters
[in,out]opticsAn optics structure that has values set based on the opacities.
sw_totalTotal shortwave flux into the ocean [Q R Z T-1 ~> W m-2]
sw_vis_dirVisible, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
sw_vis_difVisible, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
sw_nir_dirNear-IR, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
sw_nir_difNear-IR, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
csThe control structure.
[in]chl_2dVertically uniform chlorophyll-A concentractions [mg m-3]
[in]chl_3dA 3-d field of chlorophyll-A concentractions [mg m-3]

Definition at line 222 of file MOM_opacity.F90.

222  type(optics_type), intent(inout) :: optics !< An optics structure that has values
223  !! set based on the opacities.
224  real, dimension(:,:), pointer :: sw_total !< Total shortwave flux into the ocean [Q R Z T-1 ~> W m-2]
225  real, dimension(:,:), pointer :: sw_vis_dir !< Visible, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
226  real, dimension(:,:), pointer :: sw_vis_dif !< Visible, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
227  real, dimension(:,:), pointer :: sw_nir_dir !< Near-IR, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
228  real, dimension(:,:), pointer :: sw_nir_dif !< Near-IR, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
229  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
230  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
231  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
232  type(opacity_CS), pointer :: CS !< The control structure.
233  real, dimension(SZI_(G),SZJ_(G)), &
234  optional, intent(in) :: chl_2d !< Vertically uniform chlorophyll-A concentractions [mg m-3]
235  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
236  optional, intent(in) :: chl_3d !< A 3-d field of chlorophyll-A concentractions [mg m-3]
237 
238  real :: chl_data(SZI_(G),SZJ_(G)) ! The chlorophyll A concentrations in a layer [mg m-3].
239  real :: Inv_nbands ! The inverse of the number of bands of penetrating
240  ! shortwave radiation.
241  real :: Inv_nbands_nir ! The inverse of the number of bands of penetrating
242  ! near-infrafed radiation.
243  real :: SW_pen_tot ! The sum across the bands of the penetrating
244  ! shortwave radiation [Q R Z T-1 ~> W m-2].
245  real :: SW_vis_tot ! The sum across the visible bands of shortwave
246  ! radiation [Q R Z T-1 ~> W m-2].
247  real :: SW_nir_tot ! The sum across the near infrared bands of shortwave
248  ! radiation [Q R Z T-1 ~> W m-2].
249  type(time_type) :: day
250  character(len=128) :: mesg
251  integer :: i, j, k, n, is, ie, js, je, nz, nbands
252  logical :: multiband_vis_input, multiband_nir_input
253 
254  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
255 
256 ! In this model, the Morel (modified) and Manizza (modified) schemes
257 ! use the "blue" band in the parameterizations to determine the e-folding
258 ! depth of the incoming shortwave attenuation. The red portion is lumped
259 ! into the net heating at the surface.
260 !
261 ! Morel, A., Optical modeling of the upper ocean in relation to its biogenous
262 ! matter content (case-i waters).,J. Geo. Res., {93}, 10,749--10,768, 1988.
263 !
264 ! Manizza, M., C.~L. Quere, A.~Watson, and E.~T. Buitenhuis, Bio-optical
265 ! feedbacks among phytoplankton, upper ocean physics and sea-ice in a
266 ! global model, Geophys. Res. Let., , L05,603, 2005.
267 
268  nbands = optics%nbands
269 
270  if (nbands <= 1) then ; inv_nbands = 1.0
271  else ; inv_nbands = 1.0 / real(nbands) ; endif
272 
273  if (nbands <= 2) then ; inv_nbands_nir = 0.0
274  else ; inv_nbands_nir = 1.0 / real(nbands - 2.0) ; endif
275 
276  multiband_vis_input = (associated(sw_vis_dir) .and. &
277  associated(sw_vis_dif))
278  multiband_nir_input = (associated(sw_nir_dir) .and. &
279  associated(sw_nir_dif))
280 
281  chl_data(:,:) = 0.0
282  if (present(chl_3d)) then
283  do j=js,je ; do i=is,ie ; chl_data(i,j) = chl_3d(i,j,1) ; enddo ; enddo
284  do k=1,nz; do j=js,je ; do i=is,ie
285  if ((g%mask2dT(i,j) > 0.5) .and. (chl_3d(i,j,k) < 0.0)) then
286  write(mesg,'(" Negative chl_3d of ",(1pe12.4)," found at i,j,k = ", &
287  & 3(1x,i3), " lon/lat = ",(1pe12.4)," E ", (1pe12.4), " N.")') &
288  chl_3d(i,j,k), i, j, k, g%geoLonT(i,j), g%geoLatT(i,j)
289  call mom_error(fatal, "MOM_opacity opacity_from_chl: "//trim(mesg))
290  endif
291  enddo ; enddo ; enddo
292  elseif (present(chl_2d)) then
293  do j=js,je ; do i=is,ie ; chl_data(i,j) = chl_2d(i,j) ; enddo ; enddo
294  do j=js,je ; do i=is,ie
295  if ((g%mask2dT(i,j) > 0.5) .and. (chl_2d(i,j) < 0.0)) then
296  write(mesg,'(" Negative chl_2d of ",(1pe12.4)," at i,j = ", &
297  & 2(i3), "lon/lat = ",(1pe12.4)," E ", (1pe12.4), " N.")') &
298  chl_data(i,j), i, j, g%geoLonT(i,j), g%geoLatT(i,j)
299  call mom_error(fatal, "MOM_opacity opacity_from_chl: "//trim(mesg))
300  endif
301  enddo ; enddo
302  else
303  call mom_error(fatal, "Either chl_2d or chl_3d must be preesnt in a call to opacity_form_chl.")
304  endif
305 
306  select case (cs%opacity_scheme)
307  case (manizza_05)
308  !$OMP parallel do default(shared) private(SW_vis_tot,SW_nir_tot)
309  do j=js,je ; do i=is,ie
310  sw_vis_tot = 0.0 ; sw_nir_tot = 0.0
311  if (g%mask2dT(i,j) > 0.5) then
312  if (multiband_vis_input) then
313  sw_vis_tot = sw_vis_dir(i,j) + sw_vis_dif(i,j)
314  else ! Follow Manizza 05 in assuming that 42% of SW is visible.
315  sw_vis_tot = 0.42 * sw_total(i,j)
316  endif
317  if (multiband_nir_input) then
318  sw_nir_tot = sw_nir_dir(i,j) + sw_nir_dif(i,j)
319  else
320  sw_nir_tot = sw_total(i,j) - sw_vis_tot
321  endif
322  endif
323 
324  ! Band 1 is Manizza blue.
325  optics%sw_pen_band(1,i,j) = cs%blue_frac*sw_vis_tot
326  ! Band 2 (if used) is Manizza red.
327  if (nbands > 1) &
328  optics%sw_pen_band(2,i,j) = (1.0-cs%blue_frac)*sw_vis_tot
329  ! All remaining bands are NIR, for lack of something better to do.
330  do n=3,nbands
331  optics%sw_pen_band(n,i,j) = inv_nbands_nir * sw_nir_tot
332  enddo
333  enddo ; enddo
334  case (morel_88)
335  !$OMP parallel do default(shared) private(SW_pen_tot)
336  do j=js,je ; do i=is,ie
337  sw_pen_tot = 0.0
338  if (g%mask2dT(i,j) > 0.5) then ; if (multiband_vis_input) then
339  sw_pen_tot = sw_pen_frac_morel(chl_data(i,j)) * (sw_vis_dir(i,j) + sw_vis_dif(i,j))
340  else
341  sw_pen_tot = sw_pen_frac_morel(chl_data(i,j)) * 0.5*sw_total(i,j)
342  endif ; endif
343 
344  do n=1,nbands
345  optics%sw_pen_band(n,i,j) = inv_nbands*sw_pen_tot
346  enddo
347  enddo ; enddo
348  case default
349  call mom_error(fatal, "opacity_from_chl: CS%opacity_scheme is not valid.")
350  end select
351 
352  !$OMP parallel do default(shared) firstprivate(chl_data)
353  do k=1,nz
354  if (present(chl_3d)) then
355  do j=js,je ; do i=is,ie ; chl_data(i,j) = chl_3d(i,j,k) ; enddo ; enddo
356  endif
357 
358  select case (cs%opacity_scheme)
359  case (manizza_05)
360  do j=js,je ; do i=is,ie
361  if (g%mask2dT(i,j) <= 0.5) then
362  do n=1,optics%nbands
363  optics%opacity_band(n,i,j,k) = cs%opacity_land_value
364  enddo
365  else
366  ! Band 1 is Manizza blue.
367  optics%opacity_band(1,i,j,k) = 0.0232 + 0.074*chl_data(i,j)**0.674
368  if (nbands >= 2) & ! Band 2 is Manizza red.
369  optics%opacity_band(2,i,j,k) = 0.225 + 0.037*chl_data(i,j)**0.629
370  ! All remaining bands are NIR, for lack of something better to do.
371  do n=3,nbands ; optics%opacity_band(n,i,j,k) = 2.86 ; enddo
372  endif
373  enddo ; enddo
374  case (morel_88)
375  do j=js,je ; do i=is,ie
376  optics%opacity_band(1,i,j,k) = cs%opacity_land_value
377  if (g%mask2dT(i,j) > 0.5) &
378  optics%opacity_band(1,i,j,k) = opacity_morel(chl_data(i,j))
379 
380  do n=2,optics%nbands
381  optics%opacity_band(n,i,j,k) = optics%opacity_band(1,i,j,k)
382  enddo
383  enddo ; enddo
384 
385  case default
386  call mom_error(fatal, "opacity_from_chl: CS%opacity_scheme is not valid.")
387  end select
388  enddo
389 
390 

◆ opacity_init()

subroutine, public mom_opacity::opacity_init ( type(time_type), intent(in), target  Time,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(param_file_type), intent(in)  param_file,
type(diag_ctrl), intent(inout), target  diag,
type(opacity_cs), pointer  CS,
type(optics_type), pointer  optics 
)

This routine initalizes the opacity module, including an optics_type.

Parameters
[in]timeThe current model time.
[in]gThe ocean's grid structure.
[in]gvmodel vertical grid structure
[in]usA dimensional unit scaling type
[in]param_fileA structure to parse for run-time parameters.
[in,out]diagA structure that is used to regulate diagnostic output.
csA pointer that is set to point to the control structure for this module.
opticsAn optics structure that has parameters set and arrays allocated here.

Definition at line 920 of file MOM_opacity.F90.

920  type(time_type), target, intent(in) :: Time !< The current model time.
921  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
922  type(verticalGrid_type), intent(in) :: GV !< model vertical grid structure
923  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
924  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
925  !! parameters.
926  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate diagnostic
927  !! output.
928  type(opacity_CS), pointer :: CS !< A pointer that is set to point to the control
929  !! structure for this module.
930  type(optics_type), pointer :: optics !< An optics structure that has parameters
931  !! set and arrays allocated here.
932  ! Local variables
933  character(len=200) :: tmpstr
934  character(len=40) :: mdl = "MOM_opacity"
935  character(len=40) :: bandnum, shortname
936  character(len=200) :: longname
937  character(len=40) :: scheme_string
938  ! This include declares and sets the variable "version".
939 # include "version_variable.h"
940  real :: PenSW_absorb_minthick ! A thickness that is used to absorb the remaining shortwave heat
941  ! flux when that flux drops below PEN_SW_FLUX_ABSORB [m].
942  real :: PenSW_minthick_dflt ! The default for PenSW_absorb_minthick [m]
943  logical :: default_2018_answers
944  logical :: use_scheme
945  integer :: isd, ied, jsd, jed, nz, n
946  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
947 
948  if (associated(cs)) then
949  call mom_error(warning, "opacity_init called with an associated"// &
950  "associated control structure.")
951  return
952  else ; allocate(cs) ; endif
953 
954  cs%diag => diag
955 
956  ! Read all relevant parameters and write them to the model log.
957  call log_version(param_file, mdl, version, '')
958 
959 ! parameters for CHL_A routines
960  call get_param(param_file, mdl, "VAR_PEN_SW", cs%var_pen_sw, &
961  "If true, use one of the CHL_A schemes specified by "//&
962  "OPACITY_SCHEME to determine the e-folding depth of "//&
963  "incoming short wave radiation.", default=.false.)
964 
965  cs%opacity_scheme = no_scheme ; scheme_string = ''
966  if (cs%var_pen_sw) then
967  call get_param(param_file, mdl, "OPACITY_SCHEME", tmpstr, &
968  "This character string specifies how chlorophyll "//&
969  "concentrations are translated into opacities. Currently "//&
970  "valid options include:\n"//&
971  " \t\t MANIZZA_05 - Use Manizza et al., GRL, 2005. \n"//&
972  " \t\t MOREL_88 - Use Morel, JGR, 1988.", &
973  default=manizza_05_string)
974  if (len_trim(tmpstr) > 0) then
975  tmpstr = uppercase(tmpstr)
976  select case (tmpstr)
977  case (manizza_05_string)
978  cs%opacity_scheme = manizza_05 ; scheme_string = manizza_05_string
979  case (morel_88_string)
980  cs%opacity_scheme = morel_88 ; scheme_string = morel_88_string
981  case default
982  call mom_error(fatal, "opacity_init: #DEFINE OPACITY_SCHEME "//&
983  trim(tmpstr) // "in input file is invalid.")
984  end select
985  call mom_mesg('opacity_init: opacity scheme set to "'//trim(tmpstr)//'".', 5)
986  endif
987  if (cs%opacity_scheme == no_scheme) then
988  call mom_error(warning, "opacity_init: No scheme has successfully "//&
989  "been specified for the opacity. Using the default MANIZZA_05.")
990  cs%opacity_scheme = manizza_05 ; scheme_string = manizza_05_string
991  endif
992 
993  call get_param(param_file, mdl, "BLUE_FRAC_SW", cs%blue_frac, &
994  "The fraction of the penetrating shortwave radiation "//&
995  "that is in the blue band.", default=0.5, units="nondim")
996  else
997  call get_param(param_file, mdl, "EXP_OPACITY_SCHEME", tmpstr, &
998  "This character string specifies which exponential "//&
999  "opacity scheme to utilize. Currently "//&
1000  "valid options include:\n"//&
1001  " \t\t SINGLE_EXP - Single Exponent decay. \n"//&
1002  " \t\t DOUBLE_EXP - Double Exponent decay.", &
1003  default=single_exp_string)!New default for "else" above (non-Chl scheme)
1004  if (len_trim(tmpstr) > 0) then
1005  tmpstr = uppercase(tmpstr)
1006  select case (tmpstr)
1007  case (single_exp_string)
1008  cs%opacity_scheme = single_exp ; scheme_string = single_exp_string
1009  case (double_exp_string)
1010  cs%opacity_scheme = double_exp ; scheme_string = double_exp_string
1011  end select
1012  call mom_mesg('opacity_init: opacity scheme set to "'//trim(tmpstr)//'".', 5)
1013  endif
1014  call get_param(param_file, mdl, "PEN_SW_SCALE", cs%pen_sw_scale, &
1015  "The vertical absorption e-folding depth of the "//&
1016  "penetrating shortwave radiation.", units="m", default=0.0)
1017  !BGR/ Added for opacity_scheme==double_exp read in 2nd exp-decay and fraction
1018  if (cs%Opacity_scheme == double_exp ) then
1019  call get_param(param_file, mdl, "PEN_SW_SCALE_2ND", cs%pen_sw_scale_2nd, &
1020  "The (2nd) vertical absorption e-folding depth of the "//&
1021  "penetrating shortwave radiation "//&
1022  "(use if SW_EXP_MODE==double.)",&
1023  units="m", default=0.0)
1024  call get_param(param_file, mdl, "SW_1ST_EXP_RATIO", cs%sw_1st_exp_ratio, &
1025  "The fraction of 1st vertical absorption e-folding depth "//&
1026  "penetrating shortwave radiation if SW_EXP_MODE==double.",&
1027  units="m", default=0.0)
1028  elseif (cs%OPACITY_SCHEME == single_exp) then
1029  !/Else disable 2nd_exp scheme
1030  cs%pen_sw_scale_2nd = 0.0
1031  cs%sw_1st_exp_ratio = 1.0
1032  endif
1033  call get_param(param_file, mdl, "PEN_SW_FRAC", cs%pen_sw_frac, &
1034  "The fraction of the shortwave radiation that penetrates "//&
1035  "below the surface.", units="nondim", default=0.0)
1036 
1037  endif
1038  call get_param(param_file, mdl, "PEN_SW_NBANDS", optics%nbands, &
1039  "The number of bands of penetrating shortwave radiation.", &
1040  default=1)
1041  if (cs%Opacity_scheme == double_exp ) then
1042  if (optics%nbands /= 2) call mom_error(fatal, &
1043  "set_opacity: \Cannot use a double_exp opacity scheme with nbands!=2.")
1044  elseif (cs%Opacity_scheme == single_exp ) then
1045  if (optics%nbands /= 1) call mom_error(fatal, &
1046  "set_opacity: \Cannot use a single_exp opacity scheme with nbands!=1.")
1047  endif
1048 
1049  call get_param(param_file, mdl, "DEFAULT_2018_ANSWERS", default_2018_answers, &
1050  "This sets the default value for the various _2018_ANSWERS parameters.", &
1051  default=.false.)
1052  call get_param(param_file, mdl, "OPTICS_2018_ANSWERS", optics%answers_2018, &
1053  "If true, use the order of arithmetic and expressions that recover the "//&
1054  "answers from the end of 2018. Otherwise, use updated expressions for "//&
1055  "handling the absorption of small remaining shortwave fluxes.", &
1056  default=default_2018_answers)
1057 
1058  call get_param(param_file, mdl, "PEN_SW_FLUX_ABSORB", optics%PenSW_flux_absorb, &
1059  "A minimum remaining shortwave heating rate that will be simply absorbed in "//&
1060  "the next sufficiently thick layers for computational efficiency, instead of "//&
1061  "continuing to penetrate. The default, 2.5e-11 degC m s-1, is about 1e-4 W m-2 "//&
1062  "or 0.08 degC m century-1, but 0 is also a valid value.", &
1063  default=2.5e-11, units="degC m s-1", scale=gv%m_to_H*us%T_to_s)
1064 
1065  if (optics%answers_2018) then ; pensw_minthick_dflt = 0.001 ; else ; pensw_minthick_dflt = 1.0 ; endif
1066  call get_param(param_file, mdl, "PEN_SW_ABSORB_MINTHICK", pensw_absorb_minthick, &
1067  "A thickness that is used to absorb the remaining penetrating shortwave heat "//&
1068  "flux when it drops below PEN_SW_FLUX_ABSORB.", &
1069  default=pensw_minthick_dflt, units="m", scale=gv%m_to_H)
1070  optics%PenSW_absorb_Invlen = 1.0 / (pensw_absorb_minthick + gv%H_subroundoff)
1071 
1072  if (.not.associated(optics%min_wavelength_band)) &
1073  allocate(optics%min_wavelength_band(optics%nbands))
1074  if (.not.associated(optics%max_wavelength_band)) &
1075  allocate(optics%max_wavelength_band(optics%nbands))
1076 
1077  if (cs%opacity_scheme == manizza_05) then
1078  optics%min_wavelength_band(1) =0
1079  optics%max_wavelength_band(1) =550
1080  if (optics%nbands >= 2) then
1081  optics%min_wavelength_band(2)=550
1082  optics%max_wavelength_band(2)=700
1083  endif
1084  if (optics%nbands > 2) then
1085  do n=3,optics%nbands
1086  optics%min_wavelength_band(n) =700
1087  optics%max_wavelength_band(n) =2800
1088  enddo
1089  endif
1090  endif
1091 
1092  call get_param(param_file, mdl, "OPACITY_LAND_VALUE", cs%opacity_land_value, &
1093  "The value to use for opacity over land. The default is "//&
1094  "10 m-1 - a value for muddy water.", units="m-1", default=10.0)
1095 
1096  if (.not.associated(optics%opacity_band)) &
1097  allocate(optics%opacity_band(optics%nbands,isd:ied,jsd:jed,nz))
1098  if (.not.associated(optics%sw_pen_band)) &
1099  allocate(optics%sw_pen_band(optics%nbands,isd:ied,jsd:jed))
1100  allocate(cs%id_opacity(optics%nbands)) ; cs%id_opacity(:) = -1
1101 
1102  cs%id_sw_pen = register_diag_field('ocean_model', 'SW_pen', diag%axesT1, time, &
1103  'Penetrating shortwave radiation flux into ocean', 'W m-2', conversion=us%QRZ_T_to_W_m2)
1104  cs%id_sw_vis_pen = register_diag_field('ocean_model', 'SW_vis_pen', diag%axesT1, time, &
1105  'Visible penetrating shortwave radiation flux into ocean', 'W m-2', conversion=us%QRZ_T_to_W_m2)
1106  do n=1,optics%nbands
1107  write(bandnum,'(i3)') n
1108  shortname = 'opac_'//trim(adjustl(bandnum))
1109  longname = 'Opacity for shortwave radiation in band '//trim(adjustl(bandnum)) &
1110  // ', saved as L^-1 tanh(Opacity * L) for L = 10^-10 m'
1111  cs%id_opacity(n) = register_diag_field('ocean_model', shortname, diag%axesTL, time, &
1112  longname, 'm-1')
1113  enddo
1114 

◆ opacity_manizza()

real function, public mom_opacity::opacity_manizza ( real, intent(in)  chl_data)

This sets the blue-wavelength opacity according to the scheme proposed by Manizza, M. et al, 2005.

Parameters
[in]chl_dataThe chlorophyll-A concentration in mg m-3.
Returns
The returned opacity [m-1]

Definition at line 436 of file MOM_opacity.F90.

436  real, intent(in) :: chl_data !< The chlorophyll-A concentration in mg m-3.
437  real :: opacity_manizza !< The returned opacity [m-1]
438 ! This sets the blue-wavelength opacity according to the scheme proposed by Manizza, M. et al, 2005.
439 
440  opacity_manizza = 0.0232 + 0.074*chl_data**0.674

◆ opacity_morel()

real function, public mom_opacity::opacity_morel ( real, intent(in)  chl_data)

This sets the blue-wavelength opacity according to the scheme proposed by Morel and Antoine (1994).

Parameters
[in]chl_dataThe chlorophyll-A concentration in mg m-3.
Returns
The returned opacity [m-1]

Definition at line 396 of file MOM_opacity.F90.

396  real, intent(in) :: chl_data !< The chlorophyll-A concentration in mg m-3.
397  real :: opacity_morel !< The returned opacity [m-1]
398 
399  ! The following are coefficients for the optical model taken from Morel and
400  ! Antoine (1994). These coeficients represent a non uniform distribution of
401  ! chlorophyll-a through the water column. Other approaches may be more
402  ! appropriate when using an interactive ecosystem model that predicts
403  ! three-dimensional chl-a values.
404  real, dimension(6), parameter :: &
405  Z2_coef=(/7.925, -6.644, 3.662, -1.815, -0.218, 0.502/)
406  real :: Chl, Chl2 ! The log10 of chl_data (in mg m-3), and Chl^2.
407 
408  chl = log10(min(max(chl_data,0.02),60.0)) ; chl2 = chl*chl
409  opacity_morel = 1.0 / ( (z2_coef(1) + z2_coef(2)*chl) + chl2 * &
410  ((z2_coef(3) + chl*z2_coef(4)) + chl2*(z2_coef(5) + chl*z2_coef(6))) )

◆ optics_nbands()

integer function, public mom_opacity::optics_nbands ( type(optics_type), intent(in)  optics)

Return the number of bands of penetrating shortwave radiation.

Parameters
[in]opticsAn optics structure that has values of opacities and shortwave fluxes.
Returns
The number of penetrating bands of SW radiation

Definition at line 494 of file MOM_opacity.F90.

494  type(optics_type), intent(in) :: optics !< An optics structure that has values of opacities
495  !! and shortwave fluxes.
496  integer :: optics_nbands !< The number of penetrating bands of SW radiation
497 
498  optics_nbands = optics%nbands

◆ set_opacity()

subroutine, public mom_opacity::set_opacity ( type(optics_type), intent(inout)  optics,
real, dimension(:,:), pointer  sw_total,
real, dimension(:,:), pointer  sw_vis_dir,
real, dimension(:,:), pointer  sw_vis_dif,
real, dimension(:,:), pointer  sw_nir_dir,
real, dimension(:,:), pointer  sw_nir_dif,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(opacity_cs), pointer  CS,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in), optional  chl_2d,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(in), optional  chl_3d 
)

This sets the opacity of sea water based based on one of several different schemes.

Parameters
[in,out]opticsAn optics structure that has values set based on the opacities.
sw_totalTotal shortwave flux into the ocean [Q R Z T-1 ~> W m-2]
sw_vis_dirVisible, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
sw_vis_difVisible, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
sw_nir_dirNear-IR, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
sw_nir_difNear-IR, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
csThe control structure earlier set up by opacity_init.
[in]chl_2dVertically uniform chlorophyll-A concentractions [mg m-3]
[in]chl_3dThe chlorophyll-A concentractions of each layer [mg m-3]

Definition at line 93 of file MOM_opacity.F90.

93  type(optics_type), intent(inout) :: optics !< An optics structure that has values
94  !! set based on the opacities.
95  real, dimension(:,:), pointer :: sw_total !< Total shortwave flux into the ocean [Q R Z T-1 ~> W m-2]
96  real, dimension(:,:), pointer :: sw_vis_dir !< Visible, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
97  real, dimension(:,:), pointer :: sw_vis_dif !< Visible, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
98  real, dimension(:,:), pointer :: sw_nir_dir !< Near-IR, direct shortwave into the ocean [Q R Z T-1 ~> W m-2]
99  real, dimension(:,:), pointer :: sw_nir_dif !< Near-IR, diffuse shortwave into the ocean [Q R Z T-1 ~> W m-2]
100  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
101  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
102  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
103  type(opacity_CS), pointer :: CS !< The control structure earlier set up by opacity_init.
104  real, dimension(SZI_(G),SZJ_(G)), &
105  optional, intent(in) :: chl_2d !< Vertically uniform chlorophyll-A concentractions [mg m-3]
106  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
107  optional, intent(in) :: chl_3d !< The chlorophyll-A concentractions of each layer [mg m-3]
108 
109  ! Local variables
110  integer :: i, j, k, n, is, ie, js, je, nz
111  real :: inv_sw_pen_scale ! The inverse of the e-folding scale [m-1].
112  real :: Inv_nbands ! The inverse of the number of bands of penetrating
113  ! shortwave radiation.
114  logical :: call_for_surface ! if horizontal slice is the surface layer
115  real :: tmp(SZI_(G),SZJ_(G),SZK_(GV)) ! A 3-d temporary array.
116  real :: chl(SZI_(G),SZJ_(G),SZK_(GV)) ! The concentration of chlorophyll-A [mg m-3].
117  real :: Pen_SW_tot(SZI_(G),SZJ_(G)) ! The penetrating shortwave radiation
118  ! summed across all bands [Q R Z T-1 ~> W m-2].
119  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
120 
121  if (.not. associated(cs)) call mom_error(fatal, "set_opacity: "// &
122  "Module must be initialized via opacity_init before it is used.")
123 
124  if (present(chl_2d) .or. present(chl_3d)) then
125  ! The optical properties are based on cholophyll concentrations.
126  call opacity_from_chl(optics, sw_total, sw_vis_dir, sw_vis_dif, sw_nir_dir, sw_nir_dif, &
127  g, gv, us, cs, chl_2d, chl_3d)
128  else ! Use sw e-folding scale set by MOM_input
129  if (optics%nbands <= 1) then ; inv_nbands = 1.0
130  else ; inv_nbands = 1.0 / real(optics%nbands) ; endif
131 
132  ! Make sure there is no division by 0.
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
136  !$OMP parallel do default(shared)
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
143  !$OMP parallel do default(shared)
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
147  else
148  !$OMP parallel do default(shared)
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)
152  enddo ; enddo
153  endif
154  else
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
159  !$OMP parallel do default(shared)
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
163  else
164  !$OMP parallel do default(shared)
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
168  endif
169  endif
170  endif
171 
172  if (query_averaging_enabled(cs%diag)) then
173  if (cs%id_sw_pen > 0) then
174  !$OMP parallel do default(shared)
175  do j=js,je ; do i=is,ie
176  pen_sw_tot(i,j) = 0.0
177  do n=1,optics%nbands
178  pen_sw_tot(i,j) = pen_sw_tot(i,j) + optics%sw_pen_band(n,i,j)
179  enddo
180  enddo ; enddo
181  call post_data(cs%id_sw_pen, pen_sw_tot, cs%diag)
182  endif
183  if (cs%id_sw_vis_pen > 0) then
184  if (cs%opacity_scheme == manizza_05) then
185  !$OMP parallel do default(shared)
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)
190  enddo
191  enddo ; enddo
192  else
193  !$OMP parallel do default(shared)
194  do j=js,je ; do i=is,ie
195  pen_sw_tot(i,j) = 0.0
196  do n=1,optics%nbands
197  pen_sw_tot(i,j) = pen_sw_tot(i,j) + optics%sw_pen_band(n,i,j)
198  enddo
199  enddo ; enddo
200  endif
201  call post_data(cs%id_sw_vis_pen, pen_sw_tot, cs%diag)
202  endif
203  do n=1,optics%nbands ; if (cs%id_opacity(n) > 0) then
204  !$OMP parallel do default(shared)
205  do k=1,nz ; do j=js,je ; do i=is,ie
206  ! Remap opacity (op) to 1/L * tanh(op * L) where L is one Angstrom.
207  ! This gives a nearly identical value when op << 1/L but allows one to
208  ! store the values when opacity is divergent (i.e. opaque).
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)
212  endif ; enddo
213  endif
214 

◆ sumswoverbands()

subroutine, public mom_opacity::sumswoverbands ( type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  h,
integer, intent(in)  nsw,
type(optics_type), intent(in)  optics,
integer, intent(in)  j,
real, intent(in)  dt,
real, intent(in)  H_limit_fluxes,
logical, intent(in)  absorbAllSW,
real, dimension(max(nsw,1), g %isd: g %ied), intent(in)  iPen_SW_bnd,
real, dimension( g %isd: g %ied, gv %ke+1), intent(inout)  netPen 
)

This subroutine calculates the total shortwave heat flux integrated over bands as a function of depth. This routine is only called for computing buoyancy fluxes for use in KPP. This routine does not updat e the state.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in]hLayer thicknesses [H ~> m or kg m-2].
[in]nswThe number of bands of penetrating shortwave radiation, perhaps from optics_nbands(optics),
[in]opticsAn optics structure that has values set based on the opacities.
[in]jj-index to work on.
[in]dtTime step [T ~> s].
[in]h_limit_fluxesthe total depth at which the surface fluxes start to be limited to avoid excessive heating of a thin ocean [H ~> m or kg m-2]
[in]absorballswIf true, ensure that all shortwave radiation is absorbed in the ocean water column.
[in]ipen_sw_bndThe incident penetrating shortwave heating in each band that hits the bottom and will be redistributed through the water column [degC H ~> degC m or degC kg m-2]; size nsw x G isd: G ied.
[in,out]netpenNet penetrating shortwave heat flux at each

Definition at line 781 of file MOM_opacity.F90.

781  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
782  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
783  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
784  real, dimension(SZI_(G),SZK_(GV)), &
785  intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2].
786  integer, intent(in) :: nsw !< The number of bands of penetrating shortwave
787  !! radiation, perhaps from optics_nbands(optics),
788  type(optics_type), intent(in) :: optics !< An optics structure that has values
789  !! set based on the opacities.
790  integer, intent(in) :: j !< j-index to work on.
791  real, intent(in) :: dt !< Time step [T ~> s].
792  real, intent(in) :: H_limit_fluxes !< the total depth at which the
793  !! surface fluxes start to be limited to avoid
794  !! excessive heating of a thin ocean [H ~> m or kg m-2]
795  logical, intent(in) :: absorbAllSW !< If true, ensure that all shortwave
796  !! radiation is absorbed in the ocean water column.
797  real, dimension(max(nsw,1),SZI_(G)), intent(in) :: iPen_SW_bnd !< The incident penetrating shortwave
798  !! heating in each band that hits the bottom and
799  !! will be redistributed through the water column
800  !! [degC H ~> degC m or degC kg m-2]; size nsw x SZI_(G).
801  real, dimension(SZI_(G),SZK_(GV)+1), &
802  intent(inout) :: netPen !< Net penetrating shortwave heat flux at each
803  !! interface, summed across all bands
804  !! [degC H ~> degC m or degC kg m-2].
805  ! Local variables
806  real :: h_heat(SZI_(G)) ! thickness of the water column that receives
807  ! remaining shortwave radiation [H ~> m or kg m-2].
808  real :: Pen_SW_rem(SZI_(G)) ! sum across all wavelength bands of the
809  ! penetrating shortwave heating that hits the bottom
810  ! and will be redistributed through the water column
811  ! [degC H ~> degC m or degC kg m-2]
812 
813  real, dimension(max(nsw,1),SZI_(G)) :: Pen_SW_bnd ! The remaining penetrating shortwave radiation
814  ! in each band, initially iPen_SW_bnd [degC H ~> degC m or degC kg m-2]
815  real :: SW_trans ! fraction of shortwave radiation not
816  ! absorbed in a layer [nondim]
817  real :: unabsorbed ! fraction of the shortwave radiation
818  ! not absorbed because the layers are too thin.
819  real :: Ih_limit ! inverse of the total depth at which the
820  ! surface fluxes start to be limited [H-1 ~> m-1 or m2 kg-1]
821  real :: min_SW_heat ! A minimum remaining shortwave heating within a timestep that will be simply
822  ! absorbed in the next layer for computational efficiency, instead of
823  ! continuing to penetrate [degC H ~> degC m or degC kg m-2].
824  real :: I_Habs ! The inverse of the absorption length for a minimal flux [H-1 ~> m-1 or m2 kg-1]
825  real :: h_min_heat ! minimum thickness layer that should get heated [H ~> m or kg m-2]
826  real :: opt_depth ! optical depth of a layer [nondim]
827  real :: exp_OD ! exp(-opt_depth) [nondim]
828  logical :: SW_Remains ! If true, some column has shortwave radiation that
829  ! was not entirely absorbed.
830 
831  integer :: is, ie, nz, i, k, ks, n
832  sw_remains = .false.
833 
834  min_sw_heat = optics%PenSW_flux_absorb*dt ! Default of 2.5e-11*US%T_to_s*GV%m_to_H
835  i_habs = 1e3*gv%H_to_m ! optics%PenSW_absorb_Invlen
836 
837  h_min_heat = 2.0*gv%Angstrom_H + gv%H_subroundoff
838  is = g%isc ; ie = g%iec ; nz = g%ke
839 
840  pen_sw_bnd(:,:) = ipen_sw_bnd(:,:)
841  do i=is,ie ; h_heat(i) = 0.0 ; enddo
842  do i=is,ie
843  netpen(i,1) = 0.
844  do n=1,max(nsw,1)
845  netpen(i,1) = netpen(i,1) + pen_sw_bnd(n,i) ! Surface interface
846  enddo
847  enddo
848 
849  ! Apply penetrating SW radiation to remaining parts of layers.
850  ! Excessively thin layers are not heated to avoid runaway temps.
851  do k=1,nz
852 
853  do i=is,ie
854  netpen(i,k+1) = 0.
855 
856  if (h(i,k) > 0.0) then
857  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
858  ! SW_trans is the SW that is transmitted THROUGH the layer
859  opt_depth = h(i,k)*gv%H_to_m * optics%opacity_band(n,i,j,k)
860  exp_od = exp(-opt_depth)
861  sw_trans = exp_od
862 
863  ! Heating at a very small rate can be absorbed by a sufficiently thick layer or several
864  ! thin layers without further penetration.
865  if (optics%answers_2018) then
866  if (nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat*min(1.0, i_habs*h(i,k)) ) sw_trans = 0.0
867  elseif ((nsw*pen_sw_bnd(n,i)*sw_trans < min_sw_heat) .and. (h(i,k) > h_min_heat)) then
868  if (nsw*pen_sw_bnd(n,i) <= min_sw_heat * (i_habs*(h(i,k) - h_min_heat))) then
869  sw_trans = 0.0
870  else
871  sw_trans = min(sw_trans, &
872  1.0 - (min_sw_heat*(i_habs*(h(i,k) - h_min_heat))) / (nsw*pen_sw_bnd(n,i)))
873  endif
874  endif
875 
876  pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
877  netpen(i,k+1) = netpen(i,k+1) + pen_sw_bnd(n,i)
878  endif ; enddo
879  endif ! h(i,k) > 0.0
880 
881  ! Add to the accumulated thickness above that could be heated.
882  ! Only layers greater than h_min_heat thick should get heated.
883  if (h(i,k) >= 2.0*h_min_heat) then
884  h_heat(i) = h_heat(i) + h(i,k)
885  elseif (h(i,k) > h_min_heat) then
886  h_heat(i) = h_heat(i) + (2.0*h(i,k) - 2.0*h_min_heat)
887  endif
888  enddo ! i loop
889  enddo ! k loop
890 
891  if (absorballsw) then
892 
893  ! If there is still shortwave radiation at this point, it could go into
894  ! the bottom (with a bottom mud model), or it could be redistributed back
895  ! through the water column.
896  do i=is,ie
897  pen_sw_rem(i) = pen_sw_bnd(1,i)
898  do n=2,nsw ; pen_sw_rem(i) = pen_sw_rem(i) + pen_sw_bnd(n,i) ; enddo
899  enddo
900  do i=is,ie ; if (pen_sw_rem(i) > 0.0) sw_remains = .true. ; enddo
901 
902  ih_limit = 1.0 / h_limit_fluxes
903  do i=is,ie ; if ((pen_sw_rem(i) > 0.0) .and. (h_heat(i) > 0.0)) then
904  if (h_heat(i)*ih_limit < 1.0) then
905  unabsorbed = 1.0 - h_heat(i)*ih_limit
906  else
907  unabsorbed = 0.0
908  endif
909  do n=1,nsw ; pen_sw_bnd(n,i) = unabsorbed * pen_sw_bnd(n,i) ; enddo
910  endif ; enddo
911 
912  endif ! absorbAllSW
913 

◆ sw_pen_frac_morel()

real function mom_opacity::sw_pen_frac_morel ( real, intent(in)  chl_data)
private

This sets the penetrating shortwave fraction according to the scheme proposed by Morel and Antoine (1994).

Parameters
[in]chl_dataThe chlorophyll-A concentration in mg m-3.
Returns
The returned penetrating shortwave fraction [nondim]

Definition at line 416 of file MOM_opacity.F90.

416  real, intent(in) :: chl_data !< The chlorophyll-A concentration in mg m-3.
417  real :: SW_pen_frac_morel !< The returned penetrating shortwave fraction [nondim]
418 
419  ! The following are coefficients for the optical model taken from Morel and
420  ! Antoine (1994). These coeficients represent a non uniform distribution of
421  ! chlorophyll-a through the water column. Other approaches may be more
422  ! appropriate when using an interactive ecosystem model that predicts
423  ! three-dimensional chl-a values.
424  real :: Chl, Chl2 ! The log10 of chl_data in mg m-3, and Chl^2.
425  real, dimension(6), parameter :: &
426  V1_coef=(/0.321, 0.008, 0.132, 0.038, -0.017, -0.007/)
427 
428  chl = log10(min(max(chl_data,0.02),60.0)) ; chl2 = chl*chl
429  sw_pen_frac_morel = 1.0 - ( (v1_coef(1) + v1_coef(2)*chl) + chl2 * &
430  ((v1_coef(3) + chl*v1_coef(4)) + chl2*(v1_coef(5) + chl*v1_coef(6))) )