!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !! GNU General Public License !! !! !! !! This file is part of the Flexible Modeling System (FMS). !! !! !! !! FMS is free software; you can redistribute it and/or modify !! !! it and are expected to follow the terms of the GNU General Public !! !! License as published by the Free Software Foundation. !! !! !! !! FMS is distributed in the hope that it will be useful, !! !! but WITHOUT ANY WARRANTY; without even the implied warranty of !! !! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !! !! GNU General Public License for more details. !! !! !! !! You should have received a copy of the GNU General Public License !! !! along with FMS; if not, write to: !! !! Free Software Foundation, Inc. !! !! 59 Temple Place, Suite 330 !! !! Boston, MA 02111-1307 USA !! !! or see: !! !! http://www.gnu.org/licenses/gpl.txt !! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! module ocean_frazil_mod ! ! Stephen Griffies ! ! ! David Jackett ! ! ! ! This module computes the heating of seawater due to ! frazil ice formation. ! ! ! ! Frazil can generally form at any vertical level, although ! it is common for climate models to assume it is formed ! only at k=1. In this case, pressure is assumed to be ! atmospheric for purposes of computing the freezing ! temperature of seawater. ! ! The freezing temperature of seawater is computed one of two ! possible ways: ! ! (1) simple way uses a linear function of salinity ! and assumes zero (i.e. atmospheric) pressure, ! ! tfreeze(deg C) = a1*salinity(psu) ! with a1 = -0.054 ! ! (2) accurate way uses a nonlinear function of ! salinity(psu) and gauge pressure(dbar), where ! gauge pressure=absolute pressure - 10.1325 dbar. ! ! tfreeze (deg C) = tf_num/tf_den ! tf_num = a0 + s*(a1 + sqrt(s)*(a2 + sqrt(s)*a3)) + p*(a4 + p*(a5 + s*a6)) ! tf_dem = b0 + p*(b1 + p*b2) + s*s*sqrt(s)*b3 ! ! check value : fp_theta(35,200,'air-sat') = -2.076426227617581 deg C ! fp_theta(35,200,'air-free') = -2.074408175943127 deg C ! ! This method results in a more accurate freezing ! temperature than the simpler approach. It is also ! important for ice-shelf modelling to include a ! pressure dependence when the shelf penetrates ! into the water column. ! ! ! ! ! ! ! "Updated algorithms for density, potential temperature, ! conservative temperature and freezing temperature of ! seawater", Jackett, McDougall, Feistel, Wright, and Griffies ! Journal of Atmospheric and Oceanic Technology, in press 2005. ! ! ! ! ! ! ! ! If true, then compute frazil heating. ! ! ! For debugging this module ! ! ! ! This factor accounts for possibly different time stepping used ! in the sea ice model relative to the ocean model. If sea-ice ! and ocean use same time stepping schemes, then frazil_factor=1.0. ! If sea-ice uses a twolevel scheme and ocean a threelevel leap-frog, ! then frazil_factor=0.5. Default is 1.0 since the GFDL sea ice model ! SIS uses a two-level time stepping scheme and mom4 defaults to ! a staggered two-level scheme. ! ! ! ! To use the simplefied freezing point temperature of seawater, ! as used in mom4p0. This is the default, since it is ! the equation used in the GFDL ice model. ! ! ! To use the accurate freezing point temperature of seawater, ! which is a nonlinear function of salinity and pressure. ! This equation is recommended for use with ice-shelf modelling. ! ! ! ! For typical case where compute frazil heating only in ! the surface grid cell. Will assume the gauge ! pressure is zero in this case when computing freezing ! temperature. ! ! ! use constants_mod, only: epsln use diag_manager_mod, only: register_diag_field, send_data use fms_mod, only: open_namelist_file, check_nml_error, close_file use fms_mod, only: FATAL, NOTE, stdout, stdlog use mpp_mod, only: mpp_error use ocean_domains_mod, only: get_local_indices use ocean_parameters_mod, only: missing_value, cp_ocean use ocean_parameters_mod, only: TWO_LEVEL, THREE_LEVEL use ocean_tpm_util_mod, only: otpm_set_diag_tracer use ocean_types_mod, only: ocean_grid_type, ocean_domain_type, ocean_thickness_type use ocean_types_mod, only: ocean_time_type, ocean_time_steps_type, ocean_options_type use ocean_types_mod, only: ocean_prog_tracer_type, ocean_diag_tracer_type implicit none private #include logical :: module_initialized = .false. character(len=256) :: version='CVS $$' character(len=256) :: tagname='Tag $Name: mom4p1_pubrel_dec2009_nnz $' type(ocean_grid_type), pointer :: Grd =>NULL() type(ocean_domain_type), pointer :: Dom =>NULL() integer :: index_frazil=-1 integer :: index_temp=-1 integer :: index_salt=-1 integer :: tendency real :: dtimer ! for diagnostics logical :: used integer :: id_frazil_2d=-1 integer :: id_frazil_3d=-1 ! for ascii output integer :: unit=6 ! coefficients in freezing temperature real :: a0, a1, a2, a3, a4, a5, a6 real :: b0, b1, b2, b3 real :: c1, c2 public compute_frazil_heating public ocean_frazil_init ! nml defaults logical :: use_this_module = .false. logical :: debug_this_module = .false. logical :: freezing_temp_simple = .false. logical :: freezing_temp_accurate = .false. logical :: air_saturated_water = .true. logical :: frazil_only_in_surface = .true. real :: frazil_factor = 1.0 namelist /ocean_frazil_nml/ use_this_module, debug_this_module, & freezing_temp_simple, freezing_temp_accurate, & frazil_factor, air_saturated_water, frazil_only_in_surface contains !####################################################################### ! ! ! ! Initialization code for the frazil diagnostic tracer. ! ! subroutine ocean_frazil_init (Domain, Grid, Time, Time_steps, Ocean_options, & itemp, isalt, debug) type(ocean_domain_type), intent(in), target :: Domain type(ocean_grid_type), intent(in), target :: Grid type(ocean_time_type), intent(in) :: Time type(ocean_time_steps_type), intent(in) :: Time_steps type(ocean_options_type), intent(inout) :: Ocean_options integer, intent(in) :: itemp integer, intent(in) :: isalt logical, intent(in), optional :: debug integer :: ierr, ioun, io_status real :: s, sqrts, press real :: tf_num, tf_den real :: tfreeze, tfreeze_check integer :: stdoutunit,stdlogunit stdoutunit=stdout();stdlogunit=stdlog() if (module_initialized) then call mpp_error(FATAL, '==>Error: ocean_frazil_mod: module already initialized') endif write( stdlogunit,'(/a/)') trim(version) ioun = open_namelist_file() read (ioun, ocean_frazil_nml,iostat=io_status) write (stdoutunit,'(/)') write (stdoutunit, ocean_frazil_nml) write (stdlogunit, ocean_frazil_nml) ierr = check_nml_error(io_status,'ocean_frazil_nml') call close_file (ioun) if(.not. use_this_module) then write(stdoutunit,'(a)') & '==>Note: NOT running with frazil. Be sure there is no frazil entry in field_table.' call mpp_error(NOTE, '==>Note: ocean_frazil_mod: NOT using frazil heating.') Ocean_options%frazil_ice = 'Did NOT use frazil ice formation.' return else Ocean_options%frazil_ice = 'Allowed for the formation of frazil ice.' endif if (PRESENT(debug) .and. .not. debug_this_module) then debug_this_module = debug endif call mpp_error(NOTE, '==>Note from ocean_frazil_mod: USING frazil heating.') if(debug_this_module) then write(stdoutunit,'(a)') '==>Note: running with debug_this_module=.true.' endif if(freezing_temp_simple) then write(stdoutunit,'(a)') & '==>Note: Using simple equation for seawater freezing temperature.' freezing_temp_accurate=.false. endif if(freezing_temp_accurate) then write(stdoutunit,'(a)') & '==>Note: Using accurate equation for seawater freezing temperature.' freezing_temp_simple=.false. if(air_saturated_water) then write(stdoutunit,'(a)') & '==>Note: Assuming seawater is saturated w/ air for freezing temperature calculation.' endif endif if(.not. freezing_temp_simple .and. .not. freezing_temp_accurate) then call mpp_error(FATAL, & '==>Error from ocean_frazil_mod: Choose a freezing equation for frazil heating.') endif if(frazil_only_in_surface) then write(stdoutunit,'(a)') & 'Assuming that frazil forms only in the surface(k=1) ocean grid cell.' write(stdoutunit,'(a)') & 'Setting gauge pressure to zero when computing seawater freezing temperature.' endif index_frazil = otpm_set_diag_tracer('frazil', & caller='ocean_frazil_mod/ocean_frazil_init', & longname='frazil heating', units='J/m^2', & conversion=1.0, offset=0.0, min_tracer=0.0, max_tracer=1.e20, & min_range=-10.0, max_range=100.0, const_init_tracer=.true.,const_init_value=0.0, & restart_file='ocean_frazil.res.nc' ) tendency = Time_steps%tendency dtimer = 1.0/(Time_steps%dtime_t + epsln) index_salt = isalt index_temp = itemp Grd => Grid Dom => Domain #ifndef MOM4_STATIC_ARRAYS call get_local_indices(Dom, isd, ied, jsd, jed, isc, iec, jsc, jec) nk=Grd%nk #endif write(stdoutunit,'(/a,f5.2)') '==>Note from ocean_frazil_mod: using frazil_factor= ',frazil_factor if(tendency ==TWO_LEVEL .and. frazil_factor==0.5) then call mpp_error(FATAL,& '==>ocean_sbc_mod: with 2-level tendencies for mom4 and SIS, set frazil_factor==1.0 ') write(stdoutunit,'(/a)') & '==>Error in ocean_sbc_mod: SIS is two-time ice level model. You are also running' write(stdoutunit,'(a) ') & ' mom4 with two-time level scheme. In this case, frazil_factor==1.0 must be set.' write(stdoutunit,'(a/) ')& ' With another ice model w/ different time stepping, set frazil_factor accordingly.' endif if(tendency ==THREE_LEVEL .and. frazil_factor==1.0) then call mpp_error(FATAL,& '==>ocean_frazil_mod: with 3-level tendency for mom4 and 2-level for SIS, set frazil_factor==.50 ') write(stdoutunit,'(/a)') & '==>Error in ocean_sbc_mod: SIS is two-time level ice model. You are running mom4' write(stdoutunit,'(a) ') & ' with three-time level leap-frog. In this case, frazil_factor==.50 should be set.' write(stdoutunit,'(a/) ') & ' With another ice model w/ different time stepping, set frazil_factor accordingly.' endif ! coefficients in the freezing point of seawater ! assume prognostic temperature variable is potential temp a0 = 2.5180516744541290e-03 a1 = -5.8545863698926184e-02 a2 = 2.2979985780124325e-03 a3 = -3.0086338218235500e-04 a4 = -7.0023530029351803e-04 a5 = 8.4149607219833806e-09 a6 = 1.1845857563107403e-11 b0 = 1.0000000000000000e+00 b1 = -3.8493266309172074e-05 b2 = 9.1686537446749641e-10 b3 = 1.3632481944285909e-06 if(air_saturated_water) then c1 = -2.5180516744541290e-03 c2 = 1.428571428571429e-05 tfreeze_check = -2.076426227617581 else c1 = 0.0 c2 = 0.0 tfreeze_check = -2.074408175943127 endif if( freezing_temp_simple) then a1 = -0.054 else s = 35.0 press = 200.0 sqrts = sqrt(s) tf_num = a0 + s*(a1 + sqrts*(a2 + sqrts*a3)) + press*(a4 + press*(a5 + s*a6)) tf_den = b0 + press*(b1 + press*b2) + s*s*sqrts*b3 tfreeze = tf_num/tf_den + (c1 + s*c2) write(stdoutunit,'(a,e24.16)')'Check value for freezing temperature(C) at (35psu,200dbar) = ',tfreeze write(stdoutunit,'(a,e24.16)')'This value differs from published check value by ', tfreeze-tfreeze_check endif ! when ice forms only in k=1 cell, only require frazil saved as 2d field id_frazil_2d = register_diag_field ('ocean_model', 'frazil_2d', Grd%tracer_axes(1:2), & Time%model_time, 'ocn frazil heat flux over time step', 'W/m^2',& missing_value=missing_value, range=(/-1.e10,1.e10/)) ! when ice forms at any depth, require frazil to be saved as 3d field id_frazil_3d = register_diag_field ('ocean_model', 'frazil_3d', Grd%tracer_axes(1:3), & Time%model_time, 'ocn frazil heat flux over time step', 'W/m^2',& missing_value=missing_value, range=(/-1.e10,1.e10/)) end subroutine ocean_frazil_init ! NAME="ocean_frazil_init"> !####################################################################### ! ! ! ! Compute ocean heating due to formation of frazil-ice (Joules/m^2) ! ! Note that "frazil_factor" accounts for possibly different time ! stepping used in ocean model and the sea ice model. With mom4 ! using a leap-frog, and the GFDL ocean model SIS using forward, ! then frazil_factor=0.5. If use recommended tendency=twolevel ! in mom4, then frazil_factor=1.0 ! ! ! subroutine compute_frazil_heating (Time, Thickness, pressure_at_depth, T_prog, T_diag) type(ocean_time_type), intent(in) :: Time type(ocean_thickness_type), intent(in) :: Thickness real, dimension(isd:,jsd:,:), intent(in) :: pressure_at_depth type(ocean_prog_tracer_type), intent(inout) :: T_prog(:) type(ocean_diag_tracer_type), intent(inout) :: T_diag(:) integer :: i,j,k integer :: taup1 real :: tf_num, tf_den, tfreeze real :: s, sqrts real :: press if(.not. use_this_module) return taup1 = Time%taup1 if(freezing_temp_simple) then k=1 do j=jsc,jec do i=isc,iec T_diag(index_frazil)%field(i,j,k) = 0.0 if(Grd%tmask(i,j,k) > 0.0) then tfreeze = a1*T_prog(index_salt)%field(i,j,k,taup1) if(T_prog(index_temp)%field(i,j,k,taup1) < tfreeze) then T_diag(index_frazil)%field(i,j,k) = & (tfreeze-T_prog(index_temp)%field(i,j,k,taup1)) & *Thickness%rho_dzt(i,j,k,taup1)*cp_ocean*frazil_factor T_prog(index_temp)%field(i,j,k,taup1) = tfreeze endif endif enddo enddo else if(frazil_only_in_surface) then k=1 do j=jsc,jec do i=isc,iec T_diag(index_frazil)%field(i,j,k) = 0.0 if(Grd%tmask(i,j,k) > 0.0) then s = T_prog(index_salt)%field(i,j,k,taup1) sqrts = sqrt(s) tf_num = a0 + s*(a1 + sqrts*(a2 + sqrts*a3)) tf_den = b0 + s*s*sqrts*b3 tfreeze = tf_num/tf_den + (c1 + s*c2) if(T_prog(index_temp)%field(i,j,k,taup1) < tfreeze) then T_diag(index_frazil)%field(i,j,k) = & (tfreeze-T_prog(index_temp)%field(i,j,k,taup1)) & *Thickness%rho_dzt(i,j,k,taup1)*cp_ocean*frazil_factor T_prog(index_temp)%field(i,j,k,taup1) = tfreeze endif endif enddo enddo else do k=1,nk do j=jsc,jec do i=isc,iec T_diag(index_frazil)%field(i,j,k) = 0.0 if(Grd%tmask(i,j,k) > 0.0) then s = T_prog(index_salt)%field(i,j,k,taup1) press = pressure_at_depth(i,j,k) sqrts = sqrt(s) tf_num = a0 + s*(a1 + sqrts*(a2 + sqrts*a3)) + press*(a4 + press*(a5 + s*a6)) tf_den = b0 + press*(b1 + press*b2) + s*s*sqrts*b3 tfreeze = tf_num/tf_den + (c1 + s*c2) if(T_prog(index_temp)%field(i,j,k,taup1) < tfreeze) then T_diag(index_frazil)%field(i,j,k) = & (tfreeze-T_prog(index_temp)%field(i,j,k,taup1)) & *Thickness%rho_dzt(i,j,k,taup1)*cp_ocean*frazil_factor T_prog(index_temp)%field(i,j,k,taup1) = tfreeze endif endif enddo enddo enddo endif endif if (id_frazil_2d > 0) then used = send_data(id_frazil_2d, T_diag(index_frazil)%field(:,:,1)*dtimer, & Time%model_time, rmask=Grd%tmask(:,:,1), & is_in=isc, js_in=jsc, ie_in=iec, je_in=jec) endif if (id_frazil_3d > 0) then used = send_data(id_frazil_3d, T_diag(index_frazil)%field(:,:,:)*dtimer, & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif end subroutine compute_frazil_heating ! NAME="compute_frazil_heating"> end module ocean_frazil_mod