MOM6
MOM_ice_shelf.F90
1 !> Implements the thermodynamic aspects of ocean / ice-shelf interactions,
2 !! along with a crude placeholder for a later implementation of full
3 !! ice shelf dynamics, all using the MOM framework and coding style.
5 
6 ! This file is part of MOM6. See LICENSE.md for the license.
7 
8 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
9 use mom_cpu_clock, only : clock_component, clock_routine
10 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
11 use mom_diag_mediator, only : diag_mediator_init, set_diag_mediator_grid
12 use mom_diag_mediator, only : diag_ctrl, time_type, enable_averaging, disable_averaging
13 use mom_domains, only : mom_domains_init, clone_mom_domain
14 use mom_domains, only : pass_var, pass_vector, to_all, cgrid_ne, bgrid_ne, corner
15 use mom_dyn_horgrid, only : dyn_horgrid_type, create_dyn_horgrid, destroy_dyn_horgrid
16 use mom_dyn_horgrid, only : rescale_dyn_horgrid_bathymetry
17 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning, is_root_pe
19 use mom_grid, only : mom_grid_init, ocean_grid_type
20 use mom_grid_initialize, only : set_grid_metrics
21 use mom_fixed_initialization, only : mom_initialize_topography
22 use mom_fixed_initialization, only : mom_initialize_rotation
23 use user_initialization, only : user_initialize_topography
24 use mom_io, only : field_exists, file_exists, mom_read_data, write_version_number
25 use mom_io, only : slasher, fieldtype
26 use mom_io, only : write_field, close_file, single_file, multiple
27 use mom_restart, only : register_restart_field, query_initialized, save_restart
28 use mom_restart, only : restart_init, restore_state, mom_restart_cs
29 use mom_time_manager, only : time_type, time_type_to_real, time_type_to_real, real_to_time
30 use mom_transcribe_grid, only : copy_dyngrid_to_mom_grid, copy_mom_grid_to_dyngrid
31 use mom_unit_scaling, only : unit_scale_type, unit_scaling_init, fix_restart_unit_scaling
32 use mom_variables, only : surface
33 use mom_forcing_type, only : forcing, allocate_forcing_type, mom_forcing_chksum
34 use mom_forcing_type, only : mech_forcing, allocate_mech_forcing, mom_mech_forcing_chksum
35 use mom_forcing_type, only : copy_common_forcing_fields
36 use mom_get_input, only : directories, get_mom_input
38 use mom_eos, only : eos_type, eos_init
39 use mom_ice_shelf_dynamics, only : ice_shelf_dyn_cs, update_ice_shelf
40 use mom_ice_shelf_dynamics, only : register_ice_shelf_dyn_restarts, initialize_ice_shelf_dyn
41 use mom_ice_shelf_dynamics, only : ice_shelf_min_thickness_calve
42 use mom_ice_shelf_dynamics, only : ice_time_step_cfl, ice_shelf_dyn_end
43 use mom_ice_shelf_initialize, only : initialize_ice_thickness
44 !MJH use MOM_ice_shelf_initialize, only : initialize_ice_shelf_boundary
45 use mom_ice_shelf_state, only : ice_shelf_state, ice_shelf_state_end, ice_shelf_state_init
46 use user_shelf_init, only : user_initialize_shelf_mass, user_update_shelf_mass
48 use mom_coms, only : reproducing_sum, sum_across_pes
50 use time_interp_external_mod, only : init_external_field, time_interp_external
51 use time_interp_external_mod, only : time_interp_external_init
52 use time_manager_mod, only : print_time
53 implicit none ; private
54 
55 #include <MOM_memory.h>
56 #ifdef SYMMETRIC_LAND_ICE
57 # define GRID_SYM_ .true.
58 #else
59 # define GRID_SYM_ .false.
60 #endif
61 
62 public shelf_calc_flux, add_shelf_flux, initialize_ice_shelf, ice_shelf_end
63 public ice_shelf_save_restart, solo_time_step, add_shelf_forces
64 
65 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
66 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
67 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
68 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
69 
70 !> Control structure that contains ice shelf parameters and diagnostics handles
71 type, public :: ice_shelf_cs ; private
72  ! Parameters
73  type(mom_restart_cs), pointer :: restart_csp => null() !< A pointer to the restart control
74  !! structure for the ice shelves
75  type(ocean_grid_type) :: grid !< Grid for the ice-shelf model
76  type(unit_scale_type), pointer :: &
77  us => null() !< A structure containing various unit conversion factors
78  !type(dyn_horgrid_type), pointer :: dG !< Dynamic grid for the ice-shelf model
79  type(ocean_grid_type), pointer :: ocn_grid => null() !< A pointer to the ocean model grid
80  !! The rest is private
81  real :: flux_factor = 1.0 !< A factor that can be used to turn off ice shelf
82  !! melting (flux_factor = 0) [nondim].
83  character(len=128) :: restart_output_dir = ' ' !< The directory in which to write restart files
84  type(ice_shelf_state), pointer :: iss => null() !< A structure with elements that describe
85  !! the ice-shelf state
86  type(ice_shelf_dyn_cs), pointer :: dcs => null() !< The control structure for the ice-shelf dynamics.
87 
88  real, pointer, dimension(:,:) :: &
89  utide => null() !< tidal velocity [m s-1]
90 
91  real :: ustar_bg !< A minimum value for ustar under ice shelves [Z T-1 ~> m s-1].
92  real :: cdrag !< drag coefficient under ice shelves [nondim].
93  real :: g_earth !< The gravitational acceleration [m s-2]
94  real :: cp !< The heat capacity of sea water [J kg-1 degC-1].
95  real :: rho0 !< A reference ocean density [kg m-3].
96  real :: cp_ice !< The heat capacity of fresh ice [J kg-1 degC-1].
97  real :: gamma_t !< The (fixed) turbulent exchange velocity in the
98  !< 2-equation formulation [m s-1].
99  real :: salin_ice !< The salinity of shelf ice [ppt].
100  real :: temp_ice !< The core temperature of shelf ice [degC].
101  real :: kv_ice !< The viscosity of ice [m2 s-1].
102  real :: density_ice !< A typical density of ice [kg m-3].
103  real :: rho_ice !< Nominal ice density [kg m-2 Z-1 ~> kg m-3].
104  real :: kv_molec !< The molecular kinematic viscosity of sea water [m2 s-1].
105  real :: kd_molec_salt!< The molecular diffusivity of salt [m2 s-1].
106  real :: kd_molec_temp!< The molecular diffusivity of heat [m2 s-1].
107  real :: lat_fusion !< The latent heat of fusion [J kg-1].
108  real :: gamma_t_3eq !< Nondimensional heat-transfer coefficient, used in the 3Eq. formulation
109  !< This number should be specified by the user.
110  real :: col_thick_melt_threshold !< if the mixed layer is below this threshold, melt rate
111  logical :: mass_from_file !< Read the ice shelf mass from a file every dt
112 
113  !!!! PHYSICAL AND NUMERICAL PARAMETERS FOR ICE DYNAMICS !!!!!!
114 
115  real :: time_step !< this is the shortest timestep that the ice shelf sees, and
116  !! is equal to the forcing timestep (it is passed in when the shelf
117  !! is initialized - so need to reorganize MOM driver.
118  !! it will be the prognistic timestep ... maybe.
119 
120  logical :: solo_ice_sheet !< whether the ice model is running without being
121  !! coupled to the ocean
122  logical :: gl_regularize !< whether to regularize the floatation condition
123  !! at the grounding line a la Goldberg Holland Schoof 2009
124  logical :: gl_couple !< whether to let the floatation condition be
125  !!determined by ocean column thickness means update_OD_ffrac
126  !! will be called (note: GL_regularize and GL_couple
127  !! should be exclusive)
128  real :: density_ocean_avg !< this does not affect ocean circulation OR thermodynamics
129  !! it is to estimate the gravitational driving force at the
130  !! shelf front (until we think of a better way to do it,
131  !! but any difference will be negligible)
132  logical :: calve_to_mask !< If true, calve any ice that passes outside of a masked area
133  real :: min_thickness_simple_calve !< min. ice shelf thickness criteria for calving [Z ~> m].
134  real :: t0 !< temperature at ocean surface in the restoring region [degC]
135  real :: s0 !< Salinity at ocean surface in the restoring region [ppt].
136  real :: input_flux !< Ice volume flux at an upstream open boundary [m3 s-1].
137  real :: input_thickness !< Ice thickness at an upstream open boundary [m].
138 
139  type(time_type) :: time !< The component's time.
140  type(eos_type), pointer :: eqn_of_state => null() !< Type that indicates the
141  !! equation of state to use.
142  logical :: active_shelf_dynamics !< True if the ice shelf mass changes as a result
143  !! the dynamic ice-shelf model.
144  logical :: override_shelf_movement !< If true, user code specifies the shelf movement
145  !! instead of using the dynamic ice-shelf mode.
146  logical :: isthermo !< True if the ice shelf can exchange heat and
147  !! mass with the underlying ocean.
148  logical :: threeeq !< If true, the 3 equation consistency equations are
149  !! used to calculate the flux at the ocean-ice
150  !! interface.
151  logical :: insulator !< If true, ice shelf is a perfect insulator
152  logical :: const_gamma !< If true, gamma_T is specified by the user.
153  logical :: find_salt_root !< If true, if true find Sbdry using a quadratic eq.
154  logical :: constant_sea_level !< if true, apply an evaporative, heat and salt
155  !! fluxes. It will avoid large increase in sea level.
156  real :: cutoff_depth !< depth above which melt is set to zero (>= 0).
157  real :: lambda1 !< liquidus coeff., Needed if find_salt_root = true
158  real :: lambda2 !< liquidus coeff., Needed if find_salt_root = true
159  real :: lambda3 !< liquidus coeff., Needed if find_salt_root = true
160  !>@{ Diagnostic handles
161  integer :: id_melt = -1, id_exch_vel_s = -1, id_exch_vel_t = -1, &
162  id_tfreeze = -1, id_tfl_shelf = -1, &
163  id_thermal_driving = -1, id_haline_driving = -1, &
164  id_u_ml = -1, id_v_ml = -1, id_sbdry = -1, &
165  id_h_shelf = -1, id_h_mask = -1, &
166  id_surf_elev = -1, id_bathym = -1, &
167  id_area_shelf_h = -1, &
168  id_ustar_shelf = -1, id_shelf_mass = -1, id_mass_flux = -1
169  !>@}
170 
171  integer :: id_read_mass !< An integer handle used in time interpolation of
172  !! the ice shelf mass read from a file
173  integer :: id_read_area !< An integer handle used in time interpolation of
174  !! the ice shelf mass read from a file
175 
176  type(diag_ctrl), pointer :: diag => null() !< A structure that is used to control diagnostic output.
177  type(user_ice_shelf_cs), pointer :: user_cs => null() !< A pointer to the control structure for
178  !! user-supplied modifications to the ice shelf code.
179 
180  logical :: debug !< If true, write verbose checksums for debugging purposes
181  !! and use reproducible sums
182 end type ice_shelf_cs
183 
184 integer :: id_clock_shelf !< CPU Clock for the ice shelf code
185 integer :: id_clock_pass !< CPU Clock for group pass calls
186 
187 contains
188 
189 !> Calculates fluxes between the ocean and ice-shelf using the three-equations
190 !! formulation (optional to use just two equations).
191 !! See \ref section_ICE_SHELF_equations
192 subroutine shelf_calc_flux(state, fluxes, Time, time_step, CS, forces)
193  type(surface), intent(inout) :: state !< structure containing fields that
194  !!describe the surface state of the ocean
195  type(forcing), intent(inout) :: fluxes !< structure containing pointers to any possible
196  !! thermodynamic or mass-flux forcing fields.
197  type(time_type), intent(in) :: time !< Start time of the fluxes.
198  real, intent(in) :: time_step !< Length of time over which
199  !! these fluxes will be applied [s].
200  type(ice_shelf_cs), pointer :: cs !< A pointer to the control structure
201  !! returned by a previous call to
202  !! initialize_ice_shelf.
203  type(mech_forcing), optional, intent(inout) :: forces !< A structure with the driving mechanical forces
204 
205  type(ocean_grid_type), pointer :: g => null() ! The grid structure used by the ice shelf.
206  type(unit_scale_type), pointer :: us => null() ! Pointer to a structure containing
207  ! various unit conversion factors
208  type(ice_shelf_state), pointer :: iss => null() !< A structure with elements that describe
209  !! the ice-shelf state
210 
211  real, dimension(SZI_(CS%grid)) :: &
212  rhoml, & !< Ocean mixed layer density [kg m-3].
213  dr0_dt, & !< Partial derivative of the mixed layer density
214  !< with temperature [kg m-3 degC-1].
215  dr0_ds, & !< Partial derivative of the mixed layer density
216  !< with salinity [kg m-3 ppt-1].
217  p_int !< The pressure at the ice-ocean interface [Pa].
218 
219  real, dimension(SZI_(CS%grid),SZJ_(CS%grid)) :: &
220  exch_vel_t, & !< Sub-shelf thermal exchange velocity [m s-1]
221  exch_vel_s !< Sub-shelf salt exchange velocity [m s-1]
222 
223  real, dimension(SZDI_(CS%grid),SZDJ_(CS%grid)) :: &
224  mass_flux !< total mass flux of freshwater across
225  real, dimension(SZDI_(CS%grid),SZDJ_(CS%grid)) :: &
226  haline_driving !< (SSS - S_boundary) ice-ocean
227  !! interface, positive for melting and negative for freezing.
228  !! This is computed as part of the ISOMIP diagnostics.
229  real, parameter :: vk = 0.40 !< Von Karman's constant - dimensionless
230  real :: zeta_n = 0.052 !> The fraction of the boundary layer over which the
231  !! viscosity is linearly increasing. (Was 1/8. Why?)
232  real, parameter :: rc = 0.20 ! critical flux Richardson number.
233  real :: i_zeta_n !< The inverse of ZETA_N.
234  real :: lf, i_lf !< Latent Heat of fusion [J kg-1] and its inverse.
235  real :: i_vk !< The inverse of VK.
236  real :: pr, sc !< The Prandtl number and Schmidt number [nondim].
237 
238  ! 3 equations formulation variables
239  real, dimension(SZDI_(CS%grid),SZDJ_(CS%grid)) :: &
240  sbdry !< Salinities in the ocean at the interface with the ice shelf [ppt].
241  real :: sbdry_it
242  real :: sbdry1, sbdry2, s_a, s_b, s_c ! use to find salt roots
243  real :: ds_it !< The interface salinity change during an iteration [ppt].
244  real :: hbl_neut !< The neutral boundary layer thickness [m].
245  real :: hbl_neut_h_molec !< The ratio of the neutral boundary layer thickness
246  !! to the molecular boundary layer thickness [nondim].
247  !### THESE ARE CURRENTLY POSITIVE UPWARD.
248  real :: wt_flux !< The vertical flux of heat just inside the ocean [degC m s-1].
249  real :: wb_flux !< The vertical flux of heat just inside the ocean [m2 s-3].
250  real :: db_ds !< The derivative of buoyancy with salinity [m s-2 ppt-1].
251  real :: db_dt !< The derivative of buoyancy with temperature [m s-2 degC-1].
252  real :: i_n_star, n_star_term, absf
253  real :: dins_dwb !< The partial derivative of I_n_star with wB_flux, in ???.
254  real :: dt_ustar, ds_ustar
255  real :: ustar_h
256  real :: gam_turb
257  real :: gam_mol_t, gam_mol_s
258  real :: rhocp
259  real :: i_rholf
260  real :: ln_neut
261  real :: mass_exch
262  real :: sb_min, sb_max
263  real :: ds_min, ds_max
264  ! Variables used in iterating for wB_flux.
265  real :: wb_flux_new, dwb, ddwb_dwb_in
266  real :: i_gam_t, i_gam_s, dg_dwb, idens
267  real :: u_at_h, v_at_h, isqrt2
268  logical :: sb_min_set, sb_max_set
269  logical :: update_ice_vel ! If true, it is time to update the ice shelf velocities.
270  logical :: coupled_gl ! If true, the grouding line position is determined based on
271  ! coupled ice-ocean dynamics.
272 
273  real, parameter :: c2_3 = 2.0/3.0
274  character(len=160) :: mesg ! The text of an error message
275  integer :: i, j, is, ie, js, je, ied, jed, it1, it3
276  real, parameter :: rho_fw = 1000.0 ! fresh water density
277 
278  if (.not. associated(cs)) call mom_error(fatal, "shelf_calc_flux: "// &
279  "initialize_ice_shelf must be called before shelf_calc_flux.")
280  call cpu_clock_begin(id_clock_shelf)
281 
282  g => cs%grid ; us => cs%US
283  iss => cs%ISS
284 
285  ! useful parameters
286  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; ied = g%ied ; jed = g%jed
287  i_zeta_n = 1.0 / zeta_n
288  lf = cs%Lat_fusion
289  i_rholf = 1.0/(cs%Rho0*lf)
290  i_lf = 1.0 / lf
291  sc = cs%kv_molec/cs%kd_molec_salt
292  pr = cs%kv_molec/cs%kd_molec_temp
293  i_vk = 1.0/vk
294  rhocp = cs%Rho0 * cs%Cp
295  isqrt2 = 1.0/sqrt(2.0)
296 
297  !first calculate molecular component
298  gam_mol_t = 12.5 * (pr**c2_3) - 6
299  gam_mol_s = 12.5 * (sc**c2_3) - 6
300 
301  idens = 1.0/cs%density_ocean_avg
302 
303  ! GMM, zero some fields of the ice shelf structure (ice_shelf_CS)
304  ! these fields are already set to zero during initialization
305  ! However, they seem to be changed somewhere and, for diagnostic
306  ! reasons, it is better to set them to zero again.
307  exch_vel_t(:,:) = 0.0 ; exch_vel_s(:,:) = 0.0
308  iss%tflux_shelf(:,:) = 0.0 ; iss%water_flux(:,:) = 0.0
309  iss%salt_flux(:,:) = 0.0; iss%tflux_ocn(:,:) = 0.0
310  iss%tfreeze(:,:) = 0.0
311  ! define Sbdry to avoid Run-Time Check Failure, when melt is not computed.
312  haline_driving(:,:) = 0.0
313  sbdry(:,:) = state%sss(:,:)
314 
315  !update time
316  cs%Time = time
317 
318  if (cs%override_shelf_movement) then
319  cs%time_step = time_step
320  ! update shelf mass
321  if (cs%mass_from_file) call update_shelf_mass(g, cs, iss, time)
322  endif
323 
324  if (cs%debug) then
325  call hchksum(fluxes%frac_shelf_h, "frac_shelf_h before apply melting", g%HI, haloshift=0)
326  call hchksum(state%sst, "sst before apply melting", g%HI, haloshift=0)
327  call hchksum(state%sss, "sss before apply melting", g%HI, haloshift=0)
328  call hchksum(state%u, "u_ml before apply melting", g%HI, haloshift=0)
329  call hchksum(state%v, "v_ml before apply melting", g%HI, haloshift=0)
330  call hchksum(state%ocean_mass, "ocean_mass before apply melting", g%HI, haloshift=0)
331  endif
332 
333  do j=js,je
334  ! Find the pressure at the ice-ocean interface, averaged only over the
335  ! part of the cell covered by ice shelf.
336  do i=is,ie ; p_int(i) = cs%g_Earth * iss%mass_shelf(i,j) ; enddo
337 
338  ! Calculate insitu densities and expansion coefficients
339  call calculate_density(state%sst(:,j),state%sss(:,j), p_int, &
340  rhoml(:), is, ie-is+1, cs%eqn_of_state)
341  call calculate_density_derivs(state%sst(:,j), state%sss(:,j), p_int, &
342  dr0_dt, dr0_ds, is, ie-is+1, cs%eqn_of_state)
343 
344  do i=is,ie
345  ! set ustar_shelf to zero. This is necessary if shelf_mass_is_dynamic
346  ! but it won't make a difference otherwise.
347  fluxes%ustar_shelf(i,j)= 0.0
348 
349  ! DNG - to allow this everywhere Hml>0.0 allows for melting under grounded cells
350  ! propose instead to allow where Hml > [some threshold]
351 
352  if ((idens*state%ocean_mass(i,j) > cs%col_thick_melt_threshold) .and. &
353  (iss%area_shelf_h(i,j) > 0.0) .and. &
354  (cs%isthermo) .and. (state%Hml(i,j) > 0.0) ) then
355 
356  if (cs%threeeq) then
357  ! Iteratively determine a self-consistent set of fluxes, with the ocean
358  ! salinity just below the ice-shelf as the variable that is being
359  ! iterated for.
360  ! ### SHOULD I SET USTAR_SHELF YET?
361 
362  u_at_h = state%u(i,j)
363  v_at_h = state%v(i,j)
364 
365  !### I think that CS%utide**1 should be CS%utide**2
366  fluxes%ustar_shelf(i,j) = max(cs%ustar_bg, us%m_to_Z*us%T_to_s * &
367  sqrt(cs%cdrag*((u_at_h**2 + v_at_h**2) + cs%utide(i,j)**1)))
368 
369  ustar_h = us%Z_to_m*us%s_to_T*fluxes%ustar_shelf(i,j)
370 
371  if (associated(state%taux_shelf) .and. associated(state%tauy_shelf)) then
372  state%taux_shelf(i,j) = ustar_h*ustar_h*cs%Rho0*isqrt2
373  state%tauy_shelf(i,j) = state%taux_shelf(i,j)
374  endif
375 
376  ! Estimate the neutral ocean boundary layer thickness as the minimum of the
377  ! reported ocean mixed layer thickness and the neutral Ekman depth.
378  absf = 0.25*us%s_to_T*((abs(us%s_to_T*g%CoriolisBu(i,j)) + abs(us%s_to_T*g%CoriolisBu(i-1,j-1))) + &
379  (abs(us%s_to_T*g%CoriolisBu(i,j-1)) + abs(us%s_to_T*g%CoriolisBu(i-1,j))))
380  if (absf*state%Hml(i,j) <= vk*ustar_h) then ; hbl_neut = state%Hml(i,j)
381  else ; hbl_neut = (vk*ustar_h) / absf ; endif
382  hbl_neut_h_molec = zeta_n * ((hbl_neut * ustar_h) / (5.0 * cs%Kv_molec))
383 
384  ! Determine the mixed layer buoyancy flux, wB_flux.
385  db_ds = (cs%g_Earth / rhoml(i)) * dr0_ds(i)
386  db_dt = (cs%g_Earth / rhoml(i)) * dr0_dt(i)
387  ln_neut = 0.0 ; if (hbl_neut_h_molec > 1.0) ln_neut = log(hbl_neut_h_molec)
388 
389  if (cs%find_salt_root) then
390  ! read liquidus parameters
391 
392  s_a = cs%lambda1 * cs%Gamma_T_3EQ * cs%Cp
393 ! S_b = -CS%Gamma_T_3EQ*(CS%lambda2-CS%lambda3*p_int(i)-state%sst(i,j)) &
394 ! -LF*CS%Gamma_T_3EQ/35.0
395 
396  s_b = cs%Gamma_T_3EQ*cs%Cp*(cs%lambda2+cs%lambda3*p_int(i)- &
397  state%sst(i,j))-lf*cs%Gamma_T_3EQ/35.0
398  s_c = lf*(cs%Gamma_T_3EQ/35.0)*state%sss(i,j)
399 
400  !### Depending on the sign of S_b, one of these will be inaccurate!
401  sbdry1 = (-s_b + sqrt(s_b*s_b-4*s_a*s_c))/(2*s_a)
402  sbdry2 = (-s_b - sqrt(s_b*s_b-4*s_a*s_c))/(2*s_a)
403  sbdry(i,j) = max(sbdry1, sbdry2)
404  ! Safety check
405  if (sbdry(i,j) < 0.) then
406  write(mesg,*) 'state%sss(i,j) = ',state%sss(i,j), 'S_a, S_b, S_c', s_a, s_b, s_c
407  call mom_error(warning, mesg, .true.)
408  write(mesg,*) 'I,J,Sbdry1,Sbdry2',i,j,sbdry1,sbdry2
409  call mom_error(warning, mesg, .true.)
410  call mom_error(fatal, "shelf_calc_flux: Negative salinity (Sbdry).")
411  endif
412  else
413  ! Guess sss as the iteration starting point for the boundary salinity.
414  sbdry(i,j) = state%sss(i,j) ; sb_max_set = .false.
415  sb_min_set = .false.
416  endif !find_salt_root
417 
418  do it1 = 1,20
419  ! Determine the potential temperature at the ice-ocean interface.
420  call calculate_tfreeze(sbdry(i,j), p_int(i), iss%tfreeze(i,j), cs%eqn_of_state)
421 
422  dt_ustar = (state%sst(i,j) - iss%tfreeze(i,j)) * ustar_h
423  ds_ustar = (state%sss(i,j) - sbdry(i,j)) * ustar_h
424 
425  ! First, determine the buoyancy flux assuming no effects of stability
426  ! on the turbulence. Following H & J '99, this limit also applies
427  ! when the buoyancy flux is destabilizing.
428 
429  if (cs%const_gamma) then ! if using a constant gamma_T
430  ! note the different form, here I_Gam_T is NOT 1/Gam_T!
431  i_gam_t = cs%Gamma_T_3EQ
432  i_gam_s = cs%Gamma_T_3EQ/35.
433  else
434  gam_turb = i_vk * (ln_neut + (0.5 * i_zeta_n - 1.0))
435  i_gam_t = 1.0 / (gam_mol_t + gam_turb)
436  i_gam_s = 1.0 / (gam_mol_s + gam_turb)
437  endif
438 
439  wt_flux = dt_ustar * i_gam_t
440  wb_flux = db_ds * (ds_ustar * i_gam_s) + db_dt * wt_flux
441 
442  if (wb_flux > 0.0) then
443  ! The buoyancy flux is stabilizing and will reduce the tubulent
444  ! fluxes, and iteration is required.
445  n_star_term = (zeta_n/rc) * (hbl_neut * vk) / ustar_h**3
446  do it3 = 1,30
447  ! n_star <= 1.0 is the ratio of working boundary layer thickness
448  ! to the neutral thickness.
449  ! hBL = n_star*hBL_neut ; hSub = 1/8*n_star*hBL
450 
451  i_n_star = sqrt(1.0 + n_star_term * wb_flux)
452  dins_dwb = 0.5 * n_star_term / i_n_star
453  if (hbl_neut_h_molec > i_n_star**2) then
454  gam_turb = i_vk * ((ln_neut - 2.0*log(i_n_star)) + &
455  (0.5*i_zeta_n*i_n_star - 1.0))
456  dg_dwb = i_vk * ( -2.0 / i_n_star + (0.5 * i_zeta_n)) * dins_dwb
457  else
458  ! The layer dominated by molecular viscosity is smaller than
459  ! the assumed boundary layer. This should be rare!
460  gam_turb = i_vk * (0.5 * i_zeta_n*i_n_star - 1.0)
461  dg_dwb = i_vk * (0.5 * i_zeta_n) * dins_dwb
462  endif
463 
464  if (cs%const_gamma) then ! if using a constant gamma_T
465  ! note the different form, here I_Gam_T is NOT 1/Gam_T!
466  i_gam_t = cs%Gamma_T_3EQ
467  i_gam_s = cs%Gamma_T_3EQ/35.
468  else
469  i_gam_t = 1.0 / (gam_mol_t + gam_turb)
470  i_gam_s = 1.0 / (gam_mol_s + gam_turb)
471  endif
472 
473  wt_flux = dt_ustar * i_gam_t
474  wb_flux_new = db_ds * (ds_ustar * i_gam_s) + db_dt * wt_flux
475 
476  ! Find the root where dwB = 0.0
477  dwb = wb_flux_new - wb_flux
478  if (abs(wb_flux_new - wb_flux) < &
479  1e-4*(abs(wb_flux_new) + abs(wb_flux))) exit
480 
481  ddwb_dwb_in = -dg_dwb * (db_ds * (ds_ustar * i_gam_s**2) + &
482  db_dt * (dt_ustar * i_gam_t**2)) - 1.0
483  ! This is Newton's method without any bounds.
484  ! ### SHOULD BOUNDS BE NEEDED?
485  wb_flux_new = wb_flux - dwb / ddwb_dwb_in
486  enddo !it3
487  endif
488 
489  iss%tflux_ocn(i,j) = rhocp * wt_flux
490  exch_vel_t(i,j) = ustar_h * i_gam_t
491  exch_vel_s(i,j) = ustar_h * i_gam_s
492 
493  !Calculate the heat flux inside the ice shelf.
494 
495  !vertical adv/diff as in H+J 1999, eqns (26) & approx from (31).
496  ! Q_ice = rho_ice * CS%CP_Ice * K_ice * dT/dz (at interface)
497  !vertical adv/diff as in H+J 199, eqs (31) & (26)...
498  ! dT/dz ~= min( (lprec/(rho_ice*K_ice))*(CS%Temp_Ice-T_freeze) , 0.0 )
499  !If this approximation is not made, iterations are required... See H+J Fig 3.
500 
501  if (iss%tflux_ocn(i,j) <= 0.0) then ! Freezing occurs, so zero ice heat flux.
502  iss%water_flux(i,j) = i_lf * iss%tflux_ocn(i,j)
503  iss%tflux_shelf(i,j) = 0.0
504  else
505  if (cs%insulator) then
506  !no conduction/perfect insulator
507  iss%tflux_shelf(i,j) = 0.0
508  iss%water_flux(i,j) = i_lf * (- iss%tflux_shelf(i,j) + iss%tflux_ocn(i,j))
509 
510  else
511  ! With melting, from H&J 1999, eqs (31) & (26)...
512  ! Q_ice ~= cp_ice * (CS%Temp_Ice-T_freeze) * lprec
513  ! RhoLF*lprec = Q_ice + ISS%tflux_ocn(i,j)
514  ! lprec = (ISS%tflux_ocn(i,j)) / (LF + cp_ice * (T_freeze-CS%Temp_Ice))
515  iss%water_flux(i,j) = iss%tflux_ocn(i,j) / &
516  (lf + cs%CP_Ice * (iss%tfreeze(i,j) - cs%Temp_Ice))
517 
518  iss%tflux_shelf(i,j) = iss%tflux_ocn(i,j) - lf*iss%water_flux(i,j)
519  endif
520 
521  endif
522  !other options: dTi/dz linear through shelf
523  ! dTi_dz = (CS%Temp_Ice - ISS%tfreeze(i,j))/G%draft(i,j)
524  ! ISS%tflux_shelf(i,j) = - Rho_Ice * CS%CP_Ice * KTI * dTi_dz
525 
526 
527  if (cs%find_salt_root) then
528  exit ! no need to do interaction, so exit loop
529  else
530 
531  mass_exch = exch_vel_s(i,j) * cs%Rho0
532  sbdry_it = (state%sss(i,j) * mass_exch + cs%Salin_ice * &
533  iss%water_flux(i,j)) / (mass_exch + iss%water_flux(i,j))
534  ds_it = sbdry_it - sbdry(i,j)
535  if (abs(ds_it) < 1e-4*(0.5*(state%sss(i,j) + sbdry(i,j) + 1.e-10))) exit
536 
537 
538  if (ds_it < 0.0) then ! Sbdry is now the upper bound.
539  if (sb_max_set .and. (sbdry(i,j) > sb_max)) &
540  call mom_error(fatal,"shelf_calc_flux: Irregular iteration for Sbdry (max).")
541  sb_max = sbdry(i,j) ; ds_max = ds_it ; sb_max_set = .true.
542  else ! Sbdry is now the lower bound.
543  if (sb_min_set .and. (sbdry(i,j) < sb_min)) &
544  call mom_error(fatal, &
545  "shelf_calc_flux: Irregular iteration for Sbdry (min).")
546  sb_min = sbdry(i,j) ; ds_min = ds_it ; sb_min_set = .true.
547  endif ! dS_it < 0.0
548 
549  if (sb_min_set .and. sb_max_set) then
550  ! Use the false position method for the next iteration.
551  sbdry(i,j) = sb_min + (sb_max-sb_min) * &
552  (ds_min / (ds_min - ds_max))
553  else
554  sbdry(i,j) = sbdry_it
555  endif ! Sb_min_set
556 
557  sbdry(i,j) = sbdry_it
558  endif ! CS%find_salt_root
559 
560  enddo !it1
561  ! Check for non-convergence and/or non-boundedness?
562 
563  else
564  ! In the 2-equation form, the mixed layer turbulent exchange velocity
565  ! is specified and large enough that the ocean salinity at the interface
566  ! is about the same as the boundary layer salinity.
567 
568  call calculate_tfreeze(state%sss(i,j), p_int(i), iss%tfreeze(i,j), cs%eqn_of_state)
569 
570  exch_vel_t(i,j) = cs%gamma_t
571  iss%tflux_ocn(i,j) = rhocp * exch_vel_t(i,j) * (state%sst(i,j) - iss%tfreeze(i,j))
572  iss%tflux_shelf(i,j) = 0.0
573  iss%water_flux(i,j) = i_lf * iss%tflux_ocn(i,j)
574  sbdry(i,j) = 0.0
575  endif
576  else !not shelf
577  iss%tflux_ocn(i,j) = 0.0
578  endif
579 
580 ! haline_driving(:,:) = state%sss(i,j) - Sbdry(i,j)
581 
582  enddo ! i-loop
583  enddo ! j-loop
584 
585  ! ISS%water_flux = net liquid water into the ocean ( kg/(m^2 s) )
586  ! We want melt in m/year
587  if (cs%const_gamma) then ! use ISOMIP+ eq. with rho_fw
588  fluxes%iceshelf_melt = iss%water_flux * (86400.0*365.0/rho_fw) * cs%flux_factor
589  else ! use original eq.
590  fluxes%iceshelf_melt = iss%water_flux * (86400.0*365.0/cs%density_ice) * cs%flux_factor
591  endif
592 
593  do j=js,je ; do i=is,ie
594  if ((idens*state%ocean_mass(i,j) > cs%col_thick_melt_threshold) .and. &
595  (iss%area_shelf_h(i,j) > 0.0) .and. &
596  (cs%isthermo) .and. (state%Hml(i,j) > 0.0) ) then
597 
598  ! Set melt to zero above a cutoff pressure
599  ! (CS%Rho0*CS%cutoff_depth*CS%g_Earth) this is needed for the isomip
600  ! test case.
601  if ((cs%g_Earth * iss%mass_shelf(i,j)) < cs%Rho0*cs%cutoff_depth* &
602  cs%g_Earth) then
603  iss%water_flux(i,j) = 0.0
604  fluxes%iceshelf_melt(i,j) = 0.0
605  endif
606  ! Compute haline driving, which is one of the diags. used in ISOMIP
607  haline_driving(i,j) = (iss%water_flux(i,j) * sbdry(i,j)) / &
608  (cs%Rho0 * exch_vel_s(i,j))
609 
610  !!!!!!!!!!!!!!!!!!!!!!!!!!!!Safety checks !!!!!!!!!!!!!!!!!!!!!!!!!
611  !1)Check if haline_driving computed above is consistent with
612  ! haline_driving = state%sss - Sbdry
613  !if (fluxes%iceshelf_melt(i,j) /= 0.0) then
614  ! if (haline_driving(i,j) /= (state%sss(i,j) - Sbdry(i,j))) then
615  ! write(mesg,*) 'at i,j=',i,j,' haline_driving, sss-Sbdry',haline_driving(i,j), &
616  ! (state%sss(i,j) - Sbdry(i,j))
617  ! call MOM_error(FATAL, &
618  ! "shelf_calc_flux: Inconsistency in melt and haline_driving"//trim(mesg))
619  ! endif
620  !endif
621 
622  ! 2) check if |melt| > 0 when ustar_shelf = 0.
623  ! this should never happen
624  if ((abs(fluxes%iceshelf_melt(i,j))>0.0) .and. (fluxes%ustar_shelf(i,j) == 0.0)) then
625  write(mesg,*) "|melt| = ",fluxes%iceshelf_melt(i,j)," > 0 and ustar_shelf = 0. at i,j", i, j
626  call mom_error(fatal, "shelf_calc_flux: "//trim(mesg))
627  endif
628  endif ! area_shelf_h
629  !!!!!!!!!!!!!!!!!!!!!!!!!!!!End of safety checks !!!!!!!!!!!!!!!!!!!
630  enddo ; enddo ! i- and j-loops
631 
632  ! mass flux [kg s-1], part of ISOMIP diags.
633  mass_flux(:,:) = 0.0
634  mass_flux(:,:) = iss%water_flux(:,:) * iss%area_shelf_h(:,:)
635 
636  if (cs%active_shelf_dynamics .or. cs%override_shelf_movement) then
637  call cpu_clock_begin(id_clock_pass)
638  call pass_var(iss%area_shelf_h, g%domain, complete=.false.)
639  call pass_var(iss%mass_shelf, g%domain)
640  call cpu_clock_end(id_clock_pass)
641  endif
642 
643  ! Melting has been computed, now is time to update thickness and mass
644  if ( cs%override_shelf_movement .and. (.not.cs%mass_from_file)) then
645  call change_thickness_using_melt(iss, g, time_step, fluxes, cs%rho_ice, cs%debug)
646 
647  if (cs%debug) then
648  call hchksum(iss%h_shelf, "h_shelf after change thickness using melt", g%HI, haloshift=0, scale=us%Z_to_m)
649  call hchksum(iss%mass_shelf, "mass_shelf after change thickness using melt", g%HI, haloshift=0)
650  endif
651  endif
652 
653  if (cs%debug) call mom_forcing_chksum("Before add shelf flux", fluxes, g, cs%US, haloshift=0)
654 
655  call add_shelf_flux(g, cs, state, fluxes)
656 
657  ! now the thermodynamic data is passed on... time to update the ice dynamic quantities
658 
659  if (cs%active_shelf_dynamics) then
660  update_ice_vel = .false.
661  coupled_gl = (cs%GL_couple .and. .not.cs%solo_ice_sheet)
662 
663  ! advect the ice shelf, and advance the front. Calving will be in here somewhere as well..
664  ! when we decide on how to do it
665  call update_ice_shelf(cs%dCS, iss, g, us, time_step, time, state%ocean_mass, coupled_gl)
666 
667  endif
668 
669  call enable_averaging(time_step,time,cs%diag)
670  if (cs%id_shelf_mass > 0) call post_data(cs%id_shelf_mass, iss%mass_shelf, cs%diag)
671  if (cs%id_area_shelf_h > 0) call post_data(cs%id_area_shelf_h, iss%area_shelf_h, cs%diag)
672  if (cs%id_ustar_shelf > 0) call post_data(cs%id_ustar_shelf, fluxes%ustar_shelf, cs%diag)
673  if (cs%id_melt > 0) call post_data(cs%id_melt, fluxes%iceshelf_melt, cs%diag)
674  if (cs%id_thermal_driving > 0) call post_data(cs%id_thermal_driving, (state%sst-iss%tfreeze), cs%diag)
675  if (cs%id_Sbdry > 0) call post_data(cs%id_Sbdry, sbdry, cs%diag)
676  if (cs%id_haline_driving > 0) call post_data(cs%id_haline_driving, haline_driving, cs%diag)
677  if (cs%id_mass_flux > 0) call post_data(cs%id_mass_flux, mass_flux, cs%diag)
678  if (cs%id_u_ml > 0) call post_data(cs%id_u_ml, state%u, cs%diag)
679  if (cs%id_v_ml > 0) call post_data(cs%id_v_ml, state%v, cs%diag)
680  if (cs%id_tfreeze > 0) call post_data(cs%id_tfreeze, iss%tfreeze, cs%diag)
681  if (cs%id_tfl_shelf > 0) call post_data(cs%id_tfl_shelf, iss%tflux_shelf, cs%diag)
682  if (cs%id_exch_vel_t > 0) call post_data(cs%id_exch_vel_t, exch_vel_t, cs%diag)
683  if (cs%id_exch_vel_s > 0) call post_data(cs%id_exch_vel_s, exch_vel_s, cs%diag)
684  if (cs%id_h_shelf > 0) call post_data(cs%id_h_shelf,iss%h_shelf,cs%diag)
685  if (cs%id_h_mask > 0) call post_data(cs%id_h_mask,iss%hmask,cs%diag)
686  call disable_averaging(cs%diag)
687 
688  if (present(forces)) then
689  call add_shelf_forces(g, cs, forces, do_shelf_area=(cs%active_shelf_dynamics .or. &
690  cs%override_shelf_movement))
691  endif
692 
693  call cpu_clock_end(id_clock_shelf)
694 
695  if (cs%debug) call mom_forcing_chksum("End of shelf calc flux", fluxes, g, cs%US, haloshift=0)
696 
697 end subroutine shelf_calc_flux
698 
699 !> Changes the thickness (mass) of the ice shelf based on sub-ice-shelf melting
700 subroutine change_thickness_using_melt(ISS, G, time_step, fluxes, rho_ice, debug)
701  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
702  type(ice_shelf_state), intent(inout) :: ISS !< A structure with elements that describe
703  !! the ice-shelf state
704  real, intent(in) :: time_step !< The time step for this update [s].
705  type(forcing), intent(inout) :: fluxes !< structure containing pointers to any possible
706  !! thermodynamic or mass-flux forcing fields.
707  real, intent(in) :: rho_ice !< The density of ice-shelf ice [kg m-2 Z-1 ~> kg m-3].
708  logical, optional, intent(in) :: debug !< If present and true, write chksums
709 
710  ! locals
711  real :: I_rho_ice
712  integer :: i, j
713 
714  i_rho_ice = 1.0 / rho_ice
715 
716  do j=g%jsc,g%jec ; do i=g%isc,g%iec
717  if ((iss%hmask(i,j) == 1) .or. (iss%hmask(i,j) == 2)) then
718  ! first, zero out fluxes applied during previous time step
719  if (associated(fluxes%lprec)) fluxes%lprec(i,j) = 0.0
720  if (associated(fluxes%sens)) fluxes%sens(i,j) = 0.0
721  if (associated(fluxes%frac_shelf_h)) fluxes%frac_shelf_h(i,j) = 0.0
722  if (associated(fluxes%salt_flux)) fluxes%salt_flux(i,j) = 0.0
723 
724  if (iss%water_flux(i,j) / rho_ice * time_step < iss%h_shelf(i,j)) then
725  iss%h_shelf(i,j) = iss%h_shelf(i,j) - iss%water_flux(i,j) / rho_ice * time_step
726  else
727  ! the ice is about to melt away, so set thickness, area, and mask to zero
728  ! NOTE: this is not mass conservative should maybe scale salt & heat flux for this cell
729  iss%h_shelf(i,j) = 0.0
730  iss%hmask(i,j) = 0.0
731  iss%area_shelf_h(i,j) = 0.0
732  endif
733  endif
734  enddo ; enddo
735 
736  call pass_var(iss%area_shelf_h, g%domain)
737  call pass_var(iss%h_shelf, g%domain)
738  call pass_var(iss%hmask, g%domain)
739 
740  !### combine this with the loops above.
741  do j=g%jsd,g%jed ; do i=g%isd,g%ied
742  if ((iss%hmask(i,j) == 1) .or. (iss%hmask(i,j) == 2)) then
743  iss%mass_shelf(i,j) = iss%h_shelf(i,j)*rho_ice
744  endif
745  enddo ; enddo
746 
747  call pass_var(iss%mass_shelf, g%domain)
748 
749 end subroutine change_thickness_using_melt
750 
751 !> This subroutine adds the mechanical forcing fields and perhaps shelf areas, based on
752 !! the ice state in ice_shelf_CS.
753 subroutine add_shelf_forces(G, CS, forces, do_shelf_area)
754  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
755  type(ice_shelf_cs), pointer :: cs !< This module's control structure.
756  type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
757  logical, optional, intent(in) :: do_shelf_area !< If true find the shelf-covered areas.
758 
759  real :: kv_rho_ice ! The viscosity of ice divided by its density [m5 kg-1 s-1].
760  real :: press_ice ! The pressure of the ice shelf per unit area of ocean (not ice) [Pa].
761  logical :: find_area ! If true find the shelf areas at u & v points.
762  type(ice_shelf_state), pointer :: iss => null() ! A structure with elements that describe
763  ! the ice-shelf state
764 
765  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed
766  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
767  isd = g%isd ; jsd = g%jsd ; ied = g%ied ; jed = g%jed
768 
769  if ((cs%grid%isc /= g%isc) .or. (cs%grid%iec /= g%iec) .or. &
770  (cs%grid%jsc /= g%jsc) .or. (cs%grid%jec /= g%jec)) &
771  call mom_error(fatal,"add_shelf_forces: Incompatible ocean and ice shelf grids.")
772 
773  iss => cs%ISS
774 
775  find_area = .true. ; if (present(do_shelf_area)) find_area = do_shelf_area
776 
777  if (find_area) then
778  ! The frac_shelf is set over the widest possible area. Could it be smaller?
779  do j=jsd,jed ; do i=isd,ied-1
780  forces%frac_shelf_u(i,j) = 0.0
781  if ((g%areaT(i,j) + g%areaT(i+1,j) > 0.0)) & ! .and. (G%areaCu(I,j) > 0.0)) &
782  forces%frac_shelf_u(i,j) = ((iss%area_shelf_h(i,j) + iss%area_shelf_h(i+1,j)) / &
783  (g%areaT(i,j) + g%areaT(i+1,j)))
784  enddo ; enddo
785  do j=jsd,jed-1 ; do i=isd,ied
786  forces%frac_shelf_v(i,j) = 0.0
787  if ((g%areaT(i,j) + g%areaT(i,j+1) > 0.0)) & ! .and. (G%areaCv(i,J) > 0.0)) &
788  forces%frac_shelf_v(i,j) = ((iss%area_shelf_h(i,j) + iss%area_shelf_h(i,j+1)) / &
789  (g%areaT(i,j) + g%areaT(i,j+1)))
790  enddo ; enddo
791  call pass_vector(forces%frac_shelf_u, forces%frac_shelf_v, g%domain, to_all, cgrid_ne)
792  endif
793 
794  !### Consider working over a smaller array range.
795  do j=jsd,jed ; do i=isd,ied
796  press_ice = (iss%area_shelf_h(i,j) * g%IareaT(i,j)) * (cs%g_Earth * iss%mass_shelf(i,j))
797  if (associated(forces%p_surf)) then
798  if (.not.forces%accumulate_p_surf) forces%p_surf(i,j) = 0.0
799  forces%p_surf(i,j) = forces%p_surf(i,j) + press_ice
800  endif
801  if (associated(forces%p_surf_full)) then
802  if (.not.forces%accumulate_p_surf) forces%p_surf_full(i,j) = 0.0
803  forces%p_surf_full(i,j) = forces%p_surf_full(i,j) + press_ice
804  endif
805  enddo ; enddo
806 
807  ! For various reasons, forces%rigidity_ice_[uv] is always updated here. Note
808  ! that it may have been zeroed out where IOB is translated to forces and
809  ! contributions from icebergs and the sea-ice pack added subsequently.
810  !### THE RIGIDITY SHOULD ALSO INCORPORATE AREAL-COVERAGE INFORMATION.
811  kv_rho_ice = cs%kv_ice / cs%density_ice
812  do j=js,je ; do i=is-1,ie
813  if (.not.forces%accumulate_rigidity) forces%rigidity_ice_u(i,j) = 0.0
814  forces%rigidity_ice_u(i,j) = forces%rigidity_ice_u(i,j) + &
815  kv_rho_ice * min(iss%mass_shelf(i,j), iss%mass_shelf(i+1,j))
816  enddo ; enddo
817  do j=js-1,je ; do i=is,ie
818  if (.not.forces%accumulate_rigidity) forces%rigidity_ice_v(i,j) = 0.0
819  forces%rigidity_ice_v(i,j) = forces%rigidity_ice_v(i,j) + &
820  kv_rho_ice * min(iss%mass_shelf(i,j), iss%mass_shelf(i,j+1))
821  enddo ; enddo
822 
823  if (cs%debug) then
824  call uvchksum("rigidity_ice_[uv]", forces%rigidity_ice_u, forces%rigidity_ice_v, &
825  g%HI, symmetric=.true.)
826  call uvchksum("frac_shelf_[uv]", forces%frac_shelf_u, forces%frac_shelf_v, &
827  g%HI, symmetric=.true.)
828  endif
829 
830 end subroutine add_shelf_forces
831 
832 !> This subroutine adds the ice shelf pressure to the fluxes type.
833 subroutine add_shelf_pressure(G, CS, fluxes)
834  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
835  type(ice_shelf_cs), intent(in) :: CS !< This module's control structure.
836  type(forcing), intent(inout) :: fluxes !< A structure of surface fluxes that may be updated.
837 
838  real :: press_ice !< The pressure of the ice shelf per unit area of ocean (not ice) [Pa].
839  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed
840  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
841 
842  if ((cs%grid%isc /= g%isc) .or. (cs%grid%iec /= g%iec) .or. &
843  (cs%grid%jsc /= g%jsc) .or. (cs%grid%jec /= g%jec)) &
844  call mom_error(fatal,"add_shelf_pressure: Incompatible ocean and ice shelf grids.")
845 
846  do j=js,je ; do i=is,ie
847  press_ice = (cs%ISS%area_shelf_h(i,j) * g%IareaT(i,j)) * (cs%g_Earth * cs%ISS%mass_shelf(i,j))
848  if (associated(fluxes%p_surf)) then
849  if (.not.fluxes%accumulate_p_surf) fluxes%p_surf(i,j) = 0.0
850  fluxes%p_surf(i,j) = fluxes%p_surf(i,j) + press_ice
851  endif
852  if (associated(fluxes%p_surf_full)) then
853  if (.not.fluxes%accumulate_p_surf) fluxes%p_surf_full(i,j) = 0.0
854  fluxes%p_surf_full(i,j) = fluxes%p_surf_full(i,j) + press_ice
855  endif
856  enddo ; enddo
857 
858 end subroutine add_shelf_pressure
859 
860 !> Updates surface fluxes that are influenced by sub-ice-shelf melting
861 subroutine add_shelf_flux(G, CS, state, fluxes)
862  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
863  type(ice_shelf_cs), pointer :: cs !< This module's control structure.
864  type(surface), intent(inout) :: state!< Surface ocean state
865  type(forcing), intent(inout) :: fluxes !< A structure of surface fluxes that may be used/updated.
866 
867  ! local variables
868  real :: irho0 !< The inverse of the mean density [m3 kg-1].
869  real :: frac_area !< The fractional area covered by the ice shelf [nondim].
870  real :: shelf_mass0 !< Total ice shelf mass at previous time (Time-dt).
871  real :: shelf_mass1 !< Total ice shelf mass at current time (Time).
872  real :: delta_mass_shelf!< Change in ice shelf mass over one time step [kg s-1]
873  real :: taux2, tauy2 !< The squared surface stresses [Pa].
874  real :: press_ice !< The pressure of the ice shelf per unit area of ocean (not ice) [Pa].
875  real :: asu1, asu2 !< Ocean areas covered by ice shelves at neighboring u-
876  real :: asv1, asv2 !< and v-points [m2].
877  real :: fraz !< refreezing rate [kg m-2 s-1]
878  real :: mean_melt_flux !< spatial mean melt flux [kg s-1] or [kg m-2 s-1] at various points in the code.
879  real :: sponge_area !< total area of sponge region [m2]
880  real :: t0 !< The previous time (Time-dt) [s].
881  type(time_type) :: time0!< The previous time (Time-dt)
882  real, dimension(SZDI_(G),SZDJ_(G)) :: last_mass_shelf !< Ice shelf mass
883  !! at at previous time (Time-dt) [kg m-2]
884  real, dimension(SZDI_(G),SZDJ_(G)) :: last_h_shelf !< Ice shelf thickness [Z ~> m]
885  !! at at previous time (Time-dt)
886  real, dimension(SZDI_(G),SZDJ_(G)) :: last_hmask !< Ice shelf mask
887  !! at at previous time (Time-dt)
888  real, dimension(SZDI_(G),SZDJ_(G)) :: last_area_shelf_h !< Ice shelf area [m2]
889  !! at at previous time (Time-dt)
890  type(ice_shelf_state), pointer :: iss => null() !< A structure with elements that describe
891  !! the ice-shelf state
892 
893  real :: kv_rho_ice ! The viscosity of ice divided by its density [m5 kg-1 s-1]
894  real, parameter :: rho_fw = 1000.0 ! fresh water density
895  character(len=160) :: mesg ! The text of an error message
896  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed
897  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
898  isd = g%isd ; jsd = g%jsd ; ied = g%ied ; jed = g%jed
899 
900  if ((cs%grid%isc /= g%isc) .or. (cs%grid%iec /= g%iec) .or. &
901  (cs%grid%jsc /= g%jsc) .or. (cs%grid%jec /= g%jec)) &
902  call mom_error(fatal,"add_shelf_flux: Incompatible ocean and ice shelf grids.")
903 
904  iss => cs%ISS
905 
906  call add_shelf_pressure(g, cs, fluxes)
907 
908  ! Determine ustar and the square magnitude of the velocity in the
909  ! bottom boundary layer. Together these give the TKE source and
910  ! vertical decay scale.
911 
912  if (cs%debug) then
913  if (associated(state%taux_shelf) .and. associated(state%tauy_shelf)) then
914  call uvchksum("tau[xy]_shelf", state%taux_shelf, state%tauy_shelf, &
915  g%HI, haloshift=0)
916  endif
917  endif
918 
919  if (associated(state%taux_shelf) .and. associated(state%tauy_shelf)) then
920  call pass_vector(state%taux_shelf, state%tauy_shelf, g%domain, to_all, cgrid_ne)
921  endif
922  ! GMM: melting is computed using ustar_shelf (and not ustar), which has already
923  ! been passed, I so believe we do not need to update fluxes%ustar.
924 ! Irho0 = 1.0 / CS%Rho0
925 ! do j=js,je ; do i=is,ie ; if (fluxes%frac_shelf_h(i,j) > 0.0) then
926  ! ### THIS SHOULD BE AN AREA WEIGHTED AVERAGE OF THE ustar_shelf POINTS.
927  ! taux2 = 0.0 ; tauy2 = 0.0
928  ! asu1 = (ISS%area_shelf_h(i-1,j) + ISS%area_shelf_h(i,j))
929  ! asu2 = (ISS%area_shelf_h(i,j) + ISS%area_shelf_h(i+1,j))
930  ! asv1 = (ISS%area_shelf_h(i,j-1) + ISS%area_shelf_h(i,j))
931  ! asv2 = (ISS%area_shelf_h(i,j) + ISS%area_shelf_h(i,j+1))
932  ! if ((asu1 + asu2 > 0.0) .and. associated(state%taux_shelf)) &
933  ! taux2 = (asu1 * state%taux_shelf(I-1,j)**2 + &
934  ! asu2 * state%taux_shelf(I,j)**2 ) / (asu1 + asu2)
935  ! if ((asv1 + asv2 > 0.0) .and. associated(state%tauy_shelf)) &
936  ! tauy2 = (asv1 * state%tauy_shelf(i,J-1)**2 + &
937  ! asv2 * state%tauy_shelf(i,J)**2 ) / (asv1 + asv2)
938 
939  ! fluxes%ustar(i,j) = MAX(CS%ustar_bg, US%m_to_Z*US%T_to_s*sqrt(Irho0 * sqrt(taux2 + tauy2)))
940 ! endif ; enddo ; enddo
941 
942  if (cs%active_shelf_dynamics .or. cs%override_shelf_movement) then
943  do j=jsd,jed ; do i=isd,ied
944  if (g%areaT(i,j) > 0.0) &
945  fluxes%frac_shelf_h(i,j) = iss%area_shelf_h(i,j) * g%IareaT(i,j)
946  enddo ; enddo
947  endif
948 
949  do j=js,je ; do i=is,ie ; if (iss%area_shelf_h(i,j) > 0.0) then
950  frac_area = fluxes%frac_shelf_h(i,j) !### Should this be 1-frac_shelf_h?
951  if (associated(fluxes%sw)) fluxes%sw(i,j) = 0.0
952  if (associated(fluxes%sw_vis_dir)) fluxes%sw_vis_dir(i,j) = 0.0
953  if (associated(fluxes%sw_vis_dif)) fluxes%sw_vis_dif(i,j) = 0.0
954  if (associated(fluxes%sw_nir_dir)) fluxes%sw_nir_dir(i,j) = 0.0
955  if (associated(fluxes%sw_nir_dif)) fluxes%sw_nir_dif(i,j) = 0.0
956  if (associated(fluxes%lw)) fluxes%lw(i,j) = 0.0
957  if (associated(fluxes%latent)) fluxes%latent(i,j) = 0.0
958  if (associated(fluxes%evap)) fluxes%evap(i,j) = 0.0
959  if (associated(fluxes%lprec)) then
960  if (iss%water_flux(i,j) > 0.0) then
961  fluxes%lprec(i,j) = frac_area*iss%water_flux(i,j)*cs%flux_factor
962  else
963  fluxes%lprec(i,j) = 0.0
964  fluxes%evap(i,j) = frac_area*iss%water_flux(i,j)*cs%flux_factor
965  endif
966  endif
967 
968  if (associated(fluxes%sens)) &
969  fluxes%sens(i,j) = -frac_area*iss%tflux_ocn(i,j)*cs%flux_factor
970  if (associated(fluxes%salt_flux)) &
971  fluxes%salt_flux(i,j) = frac_area * iss%salt_flux(i,j)*cs%flux_factor
972  endif ; enddo ; enddo
973 
974  ! keep sea level constant by removing mass in the sponge
975  ! region (via virtual precip, vprec). Apply additional
976  ! salt/heat fluxes so that the resultant surface buoyancy
977  ! forcing is ~ 0.
978  ! This is needed for some of the ISOMIP+ experiments.
979 
980  if (cs%constant_sea_level) then
981  !### This code has lots of problems with hard coded constants and the use of
982  !### of non-reproducing sums. It needs to be refactored. -RWH
983 
984  if (.not. associated(fluxes%salt_flux)) allocate(fluxes%salt_flux(ie,je))
985  if (.not. associated(fluxes%vprec)) allocate(fluxes%vprec(ie,je))
986  fluxes%salt_flux(:,:) = 0.0 ; fluxes%vprec(:,:) = 0.0
987 
988  mean_melt_flux = 0.0; sponge_area = 0.0
989  do j=js,je ; do i=is,ie
990  frac_area = fluxes%frac_shelf_h(i,j)
991  if (frac_area > 0.0) &
992  mean_melt_flux = mean_melt_flux + (iss%water_flux(i,j)) * iss%area_shelf_h(i,j)
993 
994  !### These hard-coded limits need to be corrected. They are inappropriate here.
995  if (g%geoLonT(i,j) >= 790.0 .AND. g%geoLonT(i,j) <= 800.0) then
996  sponge_area = sponge_area + g%areaT(i,j)
997  endif
998  enddo ; enddo
999 
1000  ! take into account changes in mass (or thickness) when imposing ice shelf mass
1001  if (cs%override_shelf_movement .and. cs%mass_from_file) then
1002  t0 = time_type_to_real(cs%Time) - cs%time_step
1003 
1004  ! just compute changes in mass after first time step
1005  if (t0>0.0) then
1006  time0 = real_to_time(t0)
1007  last_hmask(:,:) = iss%hmask(:,:) ; last_area_shelf_h(:,:) = iss%area_shelf_h(:,:)
1008  call time_interp_external(cs%id_read_mass, time0, last_mass_shelf)
1009  last_h_shelf(:,:) = last_mass_shelf(:,:) / cs%rho_ice
1010 
1011  ! apply calving
1012  if (cs%min_thickness_simple_calve > 0.0) then
1013  call ice_shelf_min_thickness_calve(g, last_h_shelf, last_area_shelf_h, last_hmask, &
1014  cs%min_thickness_simple_calve)
1015  ! convert to mass again
1016  last_mass_shelf(:,:) = last_h_shelf(:,:) * cs%rho_ice
1017  endif
1018 
1019  shelf_mass0 = 0.0; shelf_mass1 = 0.0
1020  ! get total ice shelf mass at (Time-dt) and (Time), in kg
1021  do j=js,je ; do i=is,ie
1022  ! just floating shelf (0.1 is a threshold for min ocean thickness)
1023  if (((1.0/cs%density_ocean_avg)*state%ocean_mass(i,j) > 0.1) .and. &
1024  (iss%area_shelf_h(i,j) > 0.0)) then
1025  shelf_mass0 = shelf_mass0 + (last_mass_shelf(i,j) * iss%area_shelf_h(i,j))
1026  shelf_mass1 = shelf_mass1 + (iss%mass_shelf(i,j) * iss%area_shelf_h(i,j))
1027  endif
1028  enddo ; enddo
1029  call sum_across_pes(shelf_mass0); call sum_across_pes(shelf_mass1)
1030  delta_mass_shelf = (shelf_mass1 - shelf_mass0)/cs%time_step
1031 ! delta_mass_shelf = (shelf_mass1 - shelf_mass0)* &
1032 ! (rho_fw/CS%density_ice)/CS%time_step
1033 ! write(mesg,*)'delta_mass_shelf = ',delta_mass_shelf
1034 ! call MOM_mesg(mesg,5)
1035  else! first time step
1036  delta_mass_shelf = 0.0
1037  endif
1038  else ! ice shelf mass does not change
1039  delta_mass_shelf = 0.0
1040  endif
1041 
1042  call sum_across_pes(mean_melt_flux)
1043  call sum_across_pes(sponge_area)
1044 
1045  ! average total melt flux over sponge area
1046  mean_melt_flux = (mean_melt_flux+delta_mass_shelf) / sponge_area !kg/(m^2 s)
1047 
1048  ! apply fluxes
1049  do j=js,je ; do i=is,ie
1050  ! Note the following is hard coded for ISOMIP
1051  if (g%geoLonT(i,j) >= 790.0 .AND. g%geoLonT(i,j) <= 800.0) then
1052  fluxes%vprec(i,j) = -mean_melt_flux * cs%density_ice/1000. ! evap is negative
1053  fluxes%sens(i,j) = fluxes%vprec(i,j) * cs%Cp * cs%T0 ! W /m^2
1054  fluxes%salt_flux(i,j) = fluxes%vprec(i,j) * cs%S0*1.0e-3 ! kg (salt)/(m^2 s)
1055  endif
1056  enddo ; enddo
1057 
1058  if (cs%debug) then
1059  write(mesg,*) 'Mean melt flux (kg/(m^2 s)), dt = ', mean_melt_flux, cs%time_step
1060  call mom_mesg(mesg)
1061  call mom_forcing_chksum("After constant sea level", fluxes, g, cs%US, haloshift=0)
1062  endif
1063 
1064  endif !constant_sea_level
1065 
1066 end subroutine add_shelf_flux
1067 
1068 
1069 !> Initializes shelf model data, parameters and diagnostics
1070 subroutine initialize_ice_shelf(param_file, ocn_grid, Time, CS, diag, forces, fluxes, Time_in, solo_ice_sheet_in)
1071  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
1072  type(ocean_grid_type), pointer :: ocn_grid !< The calling ocean model's horizontal grid structure
1073  type(time_type), intent(inout) :: time !< The clock that that will indicate the model time
1074  type(ice_shelf_cs), pointer :: cs !< A pointer to the ice shelf control structure
1075  type(diag_ctrl), target, intent(in) :: diag !< A structure that is used to regulate the diagnostic output.
1076  type(forcing), optional, intent(inout) :: fluxes !< A structure containing pointers to any possible
1077  !! thermodynamic or mass-flux forcing fields.
1078  type(mech_forcing), optional, intent(inout) :: forces !< A structure with the driving mechanical forces
1079  type(time_type), optional, intent(in) :: time_in !< The time at initialization.
1080  logical, optional, intent(in) :: solo_ice_sheet_in !< If present, this indicates whether
1081  !! a solo ice-sheet driver.
1082 
1083  type(ocean_grid_type), pointer :: g => null(), og => null() ! Pointers to grids for convenience.
1084  type(unit_scale_type), pointer :: us => null() ! Pointer to a structure containing
1085  ! various unit conversion factors
1086  type(ice_shelf_state), pointer :: iss => null() !< A structure with elements that describe
1087  !! the ice-shelf state
1088  type(directories) :: dirs
1089  type(dyn_horgrid_type), pointer :: dg => null()
1090  real :: z_rescale ! A rescaling factor for heights from the representation in
1091  ! a reastart fole to the internal representation in this run.
1092  real :: cdrag, drag_bg_vel
1093  logical :: new_sim, save_ic, var_force
1094  !This include declares and sets the variable "version".
1095 #include "version_variable.h"
1096  character(len=200) :: config
1097  character(len=200) :: ic_file,filename,inputdir
1098  character(len=40) :: mdl = "MOM_ice_shelf" ! This module's name.
1099  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed, isdq, iedq, jsdq, jedq
1100  integer :: wd_halos(2)
1101  logical :: read_tideamp, shelf_mass_is_dynamic, debug
1102  character(len=240) :: tideamp_file
1103  real :: utide
1104  if (associated(cs)) then
1105  call mom_error(fatal, "MOM_ice_shelf.F90, initialize_ice_shelf: "// &
1106  "called with an associated control structure.")
1107  return
1108  endif
1109  allocate(cs)
1110 
1111  ! Go through all of the infrastructure initialization calls, since this is
1112  ! being treated as an independent component that just happens to use the
1113  ! MOM's grid and infrastructure.
1114  call get_mom_input(dirs=dirs)
1115 
1116  ! Determining the internal unit scaling factors for this run.
1117  call unit_scaling_init(param_file, cs%US)
1118 
1119  ! Set up the ice-shelf domain and grid
1120  wd_halos(:)=0
1121  call mom_domains_init(cs%grid%domain, param_file, min_halo=wd_halos, symmetric=grid_sym_)
1122  ! call diag_mediator_init(CS%grid,param_file,CS%diag)
1123  ! this needs to be fixed - will probably break when not using coupled driver 0
1124  call mom_grid_init(cs%grid, param_file)
1125 
1126  call create_dyn_horgrid(dg, cs%grid%HI)
1127  call clone_mom_domain(cs%grid%Domain, dg%Domain)
1128 
1129  call set_grid_metrics(dg, param_file)
1130  ! call set_diag_mediator_grid(CS%grid, CS%diag)
1131 
1132  ! The ocean grid possibly uses different symmetry.
1133  if (associated(ocn_grid)) then ; cs%ocn_grid => ocn_grid
1134  else ; cs%ocn_grid => cs%grid ; endif
1135 
1136  ! Convenience pointers
1137  g => cs%grid
1138  og => cs%ocn_grid
1139  us => cs%US
1140 
1141  if (is_root_pe()) then
1142  write(0,*) 'OG: ', og%isd, og%isc, og%iec, og%ied, og%jsd, og%jsc, og%jsd, og%jed
1143  write(0,*) 'IG: ', g%isd, g%isc, g%iec, g%ied, g%jsd, g%jsc, g%jsd, g%jed
1144  endif
1145 
1146  cs%Time = time ! ### This might not be in the right place?
1147  cs%diag => diag
1148 
1149  ! Are we being called from the solo ice-sheet driver? When called by the ocean
1150  ! model solo_ice_sheet_in is not preset.
1151  cs%solo_ice_sheet = .false.
1152  if (present(solo_ice_sheet_in)) cs%solo_ice_sheet = solo_ice_sheet_in
1153 
1154  if (present(time_in)) time = time_in
1155 
1156  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
1157  isd = g%isd ; jsd = g%jsd ; ied = g%ied ; jed = g%jed
1158  isdq = g%IsdB ; iedq = g%IedB ; jsdq = g%JsdB ; jedq = g%JedB
1159 
1160  cs%Lat_fusion = 3.34e5
1161  cs%override_shelf_movement = .false. ; cs%active_shelf_dynamics = .false.
1162 
1163  call log_version(param_file, mdl, version, "")
1164  call get_param(param_file, mdl, "DEBUG", debug, default=.false.)
1165  call get_param(param_file, mdl, "DEBUG_IS", cs%debug, &
1166  "If true, write verbose debugging messages for the ice shelf.", &
1167  default=debug)
1168  call get_param(param_file, mdl, "DYNAMIC_SHELF_MASS", shelf_mass_is_dynamic, &
1169  "If true, the ice sheet mass can evolve with time.", &
1170  default=.false.)
1171  if (shelf_mass_is_dynamic) then
1172  call get_param(param_file, mdl, "OVERRIDE_SHELF_MOVEMENT", cs%override_shelf_movement, &
1173  "If true, user provided code specifies the ice-shelf "//&
1174  "movement instead of the dynamic ice model.", default=.false.)
1175  cs%active_shelf_dynamics = .not.cs%override_shelf_movement
1176  call get_param(param_file, mdl, "GROUNDING_LINE_INTERPOLATE", cs%GL_regularize, &
1177  "If true, regularize the floatation condition at the "//&
1178  "grounding line as in Goldberg Holland Schoof 2009.", default=.false.)
1179  call get_param(param_file, mdl, "GROUNDING_LINE_COUPLE", cs%GL_couple, &
1180  "If true, let the floatation condition be determined by "//&
1181  "ocean column thickness. This means that update_OD_ffrac "//&
1182  "will be called. GL_REGULARIZE and GL_COUPLE are exclusive.", &
1183  default=.false., do_not_log=cs%GL_regularize)
1184  if (cs%GL_regularize) cs%GL_couple = .false.
1185  endif
1186 
1187  call get_param(param_file, mdl, "SHELF_THERMO", cs%isthermo, &
1188  "If true, use a thermodynamically interactive ice shelf.", &
1189  default=.false.)
1190  call get_param(param_file, mdl, "SHELF_THREE_EQN", cs%threeeq, &
1191  "If true, use the three equation expression of "//&
1192  "consistency to calculate the fluxes at the ice-ocean "//&
1193  "interface.", default=.true.)
1194  call get_param(param_file, mdl, "SHELF_INSULATOR", cs%insulator, &
1195  "If true, the ice shelf is a perfect insulatior "//&
1196  "(no conduction).", default=.false.)
1197  call get_param(param_file, mdl, "MELTING_CUTOFF_DEPTH", cs%cutoff_depth, &
1198  "Depth above which the melt is set to zero (it must be >= 0) "//&
1199  "Default value won't affect the solution.", default=0.0)
1200  if (cs%cutoff_depth < 0.) &
1201  call mom_error(warning,"Initialize_ice_shelf: MELTING_CUTOFF_DEPTH must be >= 0.")
1202 
1203  call get_param(param_file, mdl, "CONST_SEA_LEVEL", cs%constant_sea_level, &
1204  "If true, apply evaporative, heat and salt fluxes in "//&
1205  "the sponge region. This will avoid a large increase "//&
1206  "in sea level. This option is needed for some of the "//&
1207  "ISOMIP+ experiments (Ocean3 and Ocean4). "//&
1208  "IMPORTANT: it is not currently possible to do "//&
1209  "prefect restarts using this flag.", default=.false.)
1210 
1211  call get_param(param_file, mdl, "ISOMIP_S_SUR_SPONGE", &
1212  cs%S0, "Surface salinity in the resoring region.", &
1213  default=33.8, do_not_log=.true.)
1214 
1215  call get_param(param_file, mdl, "ISOMIP_T_SUR_SPONGE", &
1216  cs%T0, "Surface temperature in the resoring region.", &
1217  default=-1.9, do_not_log=.true.)
1218 
1219  call get_param(param_file, mdl, "SHELF_3EQ_GAMMA", cs%const_gamma, &
1220  "If true, user specifies a constant nondimensional heat-transfer coefficient "//&
1221  "(GAMMA_T_3EQ), from which the salt-transfer coefficient is then computed "//&
1222  " as GAMMA_T_3EQ/35. This is used with SHELF_THREE_EQN.", default=.false.)
1223  if (cs%const_gamma) call get_param(param_file, mdl, "SHELF_3EQ_GAMMA_T", cs%Gamma_T_3EQ, &
1224  "Nondimensional heat-transfer coefficient.",default=2.2e-2, &
1225  units="nondim.", fail_if_missing=.true.)
1226 
1227  call get_param(param_file, mdl, "ICE_SHELF_MASS_FROM_FILE", &
1228  cs%mass_from_file, "Read the mass of the "//&
1229  "ice shelf (every time step) from a file.", default=.false.)
1230 
1231  if (cs%threeeq) &
1232  call get_param(param_file, mdl, "SHELF_S_ROOT", cs%find_salt_root, &
1233  "If SHELF_S_ROOT = True, salinity at the ice/ocean interface (Sbdry) "//&
1234  "is computed from a quadratic equation. Otherwise, the previous "//&
1235  "interactive method to estimate Sbdry is used.", default=.false.)
1236  if (cs%find_salt_root) then ! read liquidus coeffs.
1237  call get_param(param_file, mdl, "TFREEZE_S0_P0",cs%lambda1, &
1238  "this is the freezing potential temperature at "//&
1239  "S=0, P=0.", units="degC", default=0.0, do_not_log=.true.)
1240  call get_param(param_file, mdl, "DTFREEZE_DS",cs%lambda1, &
1241  "this is the derivative of the freezing potential "//&
1242  "temperature with salinity.", &
1243  units="degC psu-1", default=-0.054, do_not_log=.true.)
1244  call get_param(param_file, mdl, "DTFREEZE_DP",cs%lambda3, &
1245  "this is the derivative of the freezing potential "//&
1246  "temperature with pressure.", &
1247  units="degC Pa-1", default=0.0, do_not_log=.true.)
1248 
1249  endif
1250 
1251  if (.not.cs%threeeq) &
1252  call get_param(param_file, mdl, "SHELF_2EQ_GAMMA_T", cs%gamma_t, &
1253  "If SHELF_THREE_EQN is false, this the fixed turbulent "//&
1254  "exchange velocity at the ice-ocean interface.", &
1255  units="m s-1", fail_if_missing=.true.)
1256 
1257  call get_param(param_file, mdl, "G_EARTH", cs%g_Earth, &
1258  "The gravitational acceleration of the Earth.", &
1259  units="m s-2", default = 9.80)
1260  call get_param(param_file, mdl, "C_P", cs%Cp, &
1261  "The heat capacity of sea water.", units="J kg-1 K-1", &
1262  fail_if_missing=.true.)
1263  call get_param(param_file, mdl, "RHO_0", cs%Rho0, &
1264  "The mean ocean density used with BOUSSINESQ true to "//&
1265  "calculate accelerations and the mass for conservation "//&
1266  "properties, or with BOUSSINSEQ false to convert some "//&
1267  "parameters from vertical units of m to kg m-2.", &
1268  units="kg m-3", default=1035.0) !### MAKE THIS A SEPARATE PARAMETER.
1269  call get_param(param_file, mdl, "C_P_ICE", cs%Cp_ice, &
1270  "The heat capacity of ice.", units="J kg-1 K-1", &
1271  default=2.10e3)
1272 
1273  call get_param(param_file, mdl, "ICE_SHELF_FLUX_FACTOR", cs%flux_factor, &
1274  "Non-dimensional factor applied to shelf thermodynamic "//&
1275  "fluxes.", units="none", default=1.0)
1276 
1277  call get_param(param_file, mdl, "KV_ICE", cs%kv_ice, &
1278  "The viscosity of the ice.", units="m2 s-1", default=1.0e10)
1279  call get_param(param_file, mdl, "KV_MOLECULAR", cs%kv_molec, &
1280  "The molecular kinimatic viscosity of sea water at the "//&
1281  "freezing temperature.", units="m2 s-1", default=1.95e-6)
1282  call get_param(param_file, mdl, "ICE_SHELF_SALINITY", cs%Salin_ice, &
1283  "The salinity of the ice inside the ice shelf.", units="psu", &
1284  default=0.0)
1285  call get_param(param_file, mdl, "ICE_SHELF_TEMPERATURE", cs%Temp_ice, &
1286  "The temperature at the center of the ice shelf.", &
1287  units = "degC", default=-15.0)
1288  call get_param(param_file, mdl, "KD_SALT_MOLECULAR", cs%kd_molec_salt, &
1289  "The molecular diffusivity of salt in sea water at the "//&
1290  "freezing point.", units="m2 s-1", default=8.02e-10)
1291  call get_param(param_file, mdl, "KD_TEMP_MOLECULAR", cs%kd_molec_temp, &
1292  "The molecular diffusivity of heat in sea water at the "//&
1293  "freezing point.", units="m2 s-1", default=1.41e-7)
1294  call get_param(param_file, mdl, "RHO_0", cs%density_ocean_avg, &
1295  "avg ocean density used in floatation cond", &
1296  units="kg m-3", default=1035.)
1297  call get_param(param_file, mdl, "DT_FORCING", cs%time_step, &
1298  "The time step for changing forcing, coupling with other "//&
1299  "components, or potentially writing certain diagnostics. "//&
1300  "The default value is given by DT.", units="s", default=0.0)
1301 
1302  call get_param(param_file, mdl, "COL_THICK_MELT_THRESHOLD", cs%col_thick_melt_threshold, &
1303  "The minimum ML thickness where melting is allowed.", units="m", &
1304  default=0.0)
1305 
1306  call get_param(param_file, mdl, "READ_TIDEAMP", read_tideamp, &
1307  "If true, read a file (given by TIDEAMP_FILE) containing "//&
1308  "the tidal amplitude with INT_TIDE_DISSIPATION.", default=.false.)
1309 
1310  call safe_alloc_ptr(cs%utide,isd,ied,jsd,jed) ; cs%utide(:,:) = 0.0
1311 
1312  if (read_tideamp) then
1313  call get_param(param_file, mdl, "TIDEAMP_FILE", tideamp_file, &
1314  "The path to the file containing the spatially varying "//&
1315  "tidal amplitudes.", &
1316  default="tideamp.nc")
1317  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
1318  inputdir = slasher(inputdir)
1319  tideamp_file = trim(inputdir) // trim(tideamp_file)
1320  call mom_read_data(tideamp_file,'tideamp',cs%utide,g%domain,timelevel=1)
1321  else
1322  call get_param(param_file, mdl, "UTIDE", utide, &
1323  "The constant tidal amplitude used with INT_TIDE_DISSIPATION.", &
1324  units="m s-1", default=0.0)
1325  cs%utide(:,:) = utide
1326  endif
1327 
1328  call eos_init(param_file, cs%eqn_of_state)
1329 
1330  !! new parameters that need to be in MOM_input
1331 
1332  if (cs%active_shelf_dynamics) then
1333 
1334  call get_param(param_file, mdl, "DENSITY_ICE", cs%density_ice, &
1335  "A typical density of ice.", units="kg m-3", default=917.0)
1336 
1337  call get_param(param_file, mdl, "INPUT_FLUX_ICE_SHELF", cs%input_flux, &
1338  "volume flux at upstream boundary", units="m2 s-1", default=0.)
1339  call get_param(param_file, mdl, "INPUT_THICK_ICE_SHELF", cs%input_thickness, &
1340  "flux thickness at upstream boundary", units="m", default=1000.)
1341  else
1342  ! This is here because of inconsistent defaults. I don't know why. RWH
1343  call get_param(param_file, mdl, "DENSITY_ICE", cs%density_ice, &
1344  "A typical density of ice.", units="kg m-3", default=900.0)
1345  endif
1346  cs%rho_ice = cs%density_ice*us%Z_to_m
1347  call get_param(param_file, mdl, "MIN_THICKNESS_SIMPLE_CALVE", &
1348  cs%min_thickness_simple_calve, &
1349  "Min thickness rule for the very simple calving law",&
1350  units="m", default=0.0, scale=us%m_to_Z)
1351 
1352  call get_param(param_file, mdl, "USTAR_SHELF_BG", cs%ustar_bg, &
1353  "The minimum value of ustar under ice sheves.", &
1354  units="m s-1", default=0.0, scale=us%m_to_Z*us%T_to_s)
1355  call get_param(param_file, mdl, "CDRAG_SHELF", cdrag, &
1356  "CDRAG is the drag coefficient relating the magnitude of "//&
1357  "the velocity field to the surface stress.", units="nondim", &
1358  default=0.003)
1359  cs%cdrag = cdrag
1360  if (cs%ustar_bg <= 0.0) then
1361  call get_param(param_file, mdl, "DRAG_BG_VEL_SHELF", drag_bg_vel, &
1362  "DRAG_BG_VEL is either the assumed bottom velocity (with "//&
1363  "LINEAR_DRAG) or an unresolved velocity that is "//&
1364  "combined with the resolved velocity to estimate the "//&
1365  "velocity magnitude.", units="m s-1", default=0.0, scale=us%m_to_Z*us%T_to_s)
1366  if (cs%cdrag*drag_bg_vel > 0.0) cs%ustar_bg = sqrt(cs%cdrag)*drag_bg_vel
1367  endif
1368 
1369  ! Allocate and initialize state variables to default values
1370  call ice_shelf_state_init(cs%ISS, cs%grid)
1371  iss => cs%ISS
1372 
1373  ! Allocate the arrays for passing ice-shelf data through the forcing type.
1374  if (.not. cs%solo_ice_sheet) then
1375  call mom_mesg("MOM_ice_shelf.F90, initialize_ice_shelf: allocating fluxes.")
1376  ! GMM: the following assures that water/heat fluxes are just allocated
1377  ! when SHELF_THERMO = True. These fluxes are necessary if one wants to
1378  ! use either ENERGETICS_SFC_PBL (ALE mode) or BULKMIXEDLAYER (layer mode).
1379  if (present(fluxes)) &
1380  call allocate_forcing_type(cs%ocn_grid, fluxes, ustar=.true., shelf=.true., &
1381  press=.true., water=cs%isthermo, heat=cs%isthermo)
1382  if (present(forces)) &
1383  call allocate_mech_forcing(cs%ocn_grid, forces, ustar=.true., shelf=.true., press=.true.)
1384  else
1385  call mom_mesg("MOM_ice_shelf.F90, initialize_ice_shelf: allocating fluxes in solo mode.")
1386  if (present(fluxes)) &
1387  call allocate_forcing_type(g, fluxes, ustar=.true., shelf=.true., press=.true.)
1388  if (present(forces)) &
1389  call allocate_mech_forcing(g, forces, ustar=.true., shelf=.true., press=.true.)
1390  endif
1391 
1392  ! Set up the bottom depth, G%D either analytically or from file
1393  call mom_initialize_topography(dg%bathyT, g%max_depth, dg, param_file)
1394  call rescale_dyn_horgrid_bathymetry(dg, us%Z_to_m)
1395 
1396  ! Set up the Coriolis parameter, G%f, usually analytically.
1397  call mom_initialize_rotation(dg%CoriolisBu, dg, param_file, us)
1398  ! This copies grid elements, including bathyT and CoriolisBu from dG to CS%grid.
1399  call copy_dyngrid_to_mom_grid(dg, cs%grid)
1400 
1401  call destroy_dyn_horgrid(dg)
1402 
1403  ! Set up the restarts.
1404  call restart_init(param_file, cs%restart_CSp, "Shelf.res")
1405  call register_restart_field(iss%mass_shelf, "shelf_mass", .true., cs%restart_CSp, &
1406  "Ice shelf mass", "kg m-2")
1407  call register_restart_field(iss%area_shelf_h, "shelf_area", .true., cs%restart_CSp, &
1408  "Ice shelf area in cell", "m2")
1409  call register_restart_field(iss%h_shelf, "h_shelf", .true., cs%restart_CSp, &
1410  "ice sheet/shelf thickness", "m")
1411  call register_restart_field(us%m_to_Z_restart, "m_to_Z", .false., cs%restart_CSp, &
1412  "Height unit conversion factor", "Z meter-1")
1413  if (cs%active_shelf_dynamics) then
1414  call register_restart_field(iss%hmask, "h_mask", .true., cs%restart_CSp, &
1415  "ice sheet/shelf thickness mask" ,"none")
1416  endif
1417 
1418  ! if (CS%active_shelf_dynamics) then !### Consider adding an ice shelf dynamics switch.
1419  ! Allocate CS%dCS and specify additional restarts for ice shelf dynamics
1420  call register_ice_shelf_dyn_restarts(g, param_file, cs%dCS, cs%restart_CSp)
1421  ! endif
1422 
1423  !GMM - I think we do not need to save ustar_shelf and iceshelf_melt in the restart file
1424  !if (.not. CS%solo_ice_sheet) then
1425  ! call register_restart_field(fluxes%ustar_shelf, "ustar_shelf", .false., CS%restart_CSp, &
1426  ! "Friction velocity under ice shelves", "m s-1")
1427  ! call register_restart_field(fluxes%iceshelf_melt, "iceshelf_melt", .false., CS%restart_CSp, &
1428  ! "Ice Shelf Melt Rate", "m year-1")
1429  !endif
1430 
1431  cs%restart_output_dir = dirs%restart_output_dir
1432 
1433  new_sim = .false.
1434  if ((dirs%input_filename(1:1) == 'n') .and. &
1435  (len_trim(dirs%input_filename) == 1)) new_sim = .true.
1436 
1437  if (cs%override_shelf_movement .and. cs%mass_from_file) then
1438 
1439  ! initialize the ids for reading shelf mass from a netCDF
1440  call initialize_shelf_mass(g, param_file, cs, iss)
1441 
1442  if (new_sim) then
1443  ! new simulation, initialize ice thickness as in the static case
1444  call initialize_ice_thickness(iss%h_shelf, iss%area_shelf_h, iss%hmask, g, us, param_file)
1445 
1446  ! next make sure mass is consistent with thickness
1447  do j=g%jsd,g%jed ; do i=g%isd,g%ied
1448  if ((iss%hmask(i,j) == 1) .or. (iss%hmask(i,j) == 2)) then
1449  iss%mass_shelf(i,j) = iss%h_shelf(i,j)*cs%rho_ice
1450  endif
1451  enddo ; enddo
1452 
1453  if (cs%min_thickness_simple_calve > 0.0) &
1454  call ice_shelf_min_thickness_calve(g, iss%h_shelf, iss%area_shelf_h, iss%hmask, &
1455  cs%min_thickness_simple_calve)
1456  endif
1457  endif
1458 
1459  if (cs%active_shelf_dynamics) then
1460  ! the only reason to initialize boundary conds is if the shelf is dynamic - MJH
1461 
1462  ! call initialize_ice_shelf_boundary ( CS%u_face_mask_bdry, CS%v_face_mask_bdry, &
1463  ! CS%u_flux_bdry_val, CS%v_flux_bdry_val, &
1464  ! CS%u_bdry_val, CS%v_bdry_val, CS%h_bdry_val, &
1465  ! ISS%hmask, G, param_file)
1466 
1467  endif
1468 
1469  if (new_sim .and. (.not. (cs%override_shelf_movement .and. cs%mass_from_file))) then
1470 
1471  ! This model is initialized internally or from a file.
1472  call initialize_ice_thickness(iss%h_shelf, iss%area_shelf_h, iss%hmask, g, us, param_file)
1473 
1474  ! next make sure mass is consistent with thickness
1475  do j=g%jsd,g%jed ; do i=g%isd,g%ied
1476  if ((iss%hmask(i,j) == 1) .or. (iss%hmask(i,j) == 2)) then
1477  iss%mass_shelf(i,j) = iss%h_shelf(i,j)*cs%rho_ice
1478  endif
1479  enddo ; enddo
1480 
1481  ! else ! Previous block for new_sim=.T., this block restores the state.
1482  elseif (.not.new_sim) then
1483  ! This line calls a subroutine that reads the initial conditions from a restart file.
1484  call mom_mesg("MOM_ice_shelf.F90, initialize_ice_shelf: Restoring ice shelf from file.")
1485  call restore_state(dirs%input_filename, dirs%restart_input_dir, time, &
1486  g, cs%restart_CSp)
1487 
1488  if ((us%m_to_Z_restart /= 0.0) .and. (us%m_to_Z_restart /= us%m_to_Z)) then
1489  z_rescale = us%m_to_Z / us%m_to_Z_restart
1490  do j=g%jsc,g%jec ; do i=g%isc,g%iec
1491  iss%h_shelf(i,j) = z_rescale * iss%h_shelf(i,j)
1492  enddo ; enddo
1493  endif
1494 
1495  endif ! .not. new_sim
1496 
1497  cs%Time = time
1498 
1499  call cpu_clock_begin(id_clock_pass)
1500  call pass_var(iss%area_shelf_h, g%domain)
1501  call pass_var(iss%h_shelf, g%domain)
1502  call pass_var(iss%mass_shelf, g%domain)
1503  call pass_var(iss%hmask, g%domain)
1504  call pass_var(g%bathyT, g%domain)
1505  call cpu_clock_end(id_clock_pass)
1506 
1507  do j=jsd,jed ; do i=isd,ied
1508  if (iss%area_shelf_h(i,j) > g%areaT(i,j)) then
1509  call mom_error(warning,"Initialize_ice_shelf: area_shelf_h exceeds G%areaT.")
1510  iss%area_shelf_h(i,j) = g%areaT(i,j)
1511  endif
1512  enddo ; enddo
1513  if (present(fluxes)) then ; do j=jsd,jed ; do i=isd,ied
1514  if (g%areaT(i,j) > 0.0) fluxes%frac_shelf_h(i,j) = iss%area_shelf_h(i,j) / g%areaT(i,j)
1515  enddo ; enddo ; endif
1516 
1517  if (cs%debug) then
1518  call hchksum(fluxes%frac_shelf_h, "IS init: frac_shelf_h", g%HI, haloshift=0)
1519  endif
1520 
1521  if (present(forces)) &
1522  call add_shelf_forces(g, cs, forces, do_shelf_area=.not.cs%solo_ice_sheet)
1523 
1524  if (present(fluxes)) call add_shelf_pressure(g, cs, fluxes)
1525 
1526  if (cs%active_shelf_dynamics .and. .not.cs%isthermo) then
1527  iss%water_flux(:,:) = 0.0
1528  endif
1529 
1530  if (shelf_mass_is_dynamic) &
1531  call initialize_ice_shelf_dyn(param_file, time, iss, cs%dCS, g, us, diag, new_sim, solo_ice_sheet_in)
1532 
1533  call fix_restart_unit_scaling(us)
1534 
1535  call get_param(param_file, mdl, "SAVE_INITIAL_CONDS", save_ic, &
1536  "If true, save the ice shelf initial conditions.", &
1537  default=.false.)
1538  if (save_ic) call get_param(param_file, mdl, "SHELF_IC_OUTPUT_FILE", ic_file,&
1539  "The name-root of the output file for the ice shelf "//&
1540  "initial conditions.", default="MOM_Shelf_IC")
1541 
1542  if (save_ic .and. .not.((dirs%input_filename(1:1) == 'r') .and. &
1543  (len_trim(dirs%input_filename) == 1))) then
1544  call save_restart(dirs%output_directory, cs%Time, g, &
1545  cs%restart_CSp, filename=ic_file)
1546  endif
1547 
1548 
1549  cs%id_area_shelf_h = register_diag_field('ocean_model', 'area_shelf_h', cs%diag%axesT1, cs%Time, &
1550  'Ice Shelf Area in cell', 'meter-2')
1551  cs%id_shelf_mass = register_diag_field('ocean_model', 'shelf_mass', cs%diag%axesT1, cs%Time, &
1552  'mass of shelf', 'kg/m^2')
1553  cs%id_h_shelf = register_diag_field('ocean_model', 'h_shelf', cs%diag%axesT1, cs%Time, &
1554  'ice shelf thickness', 'm', conversion=us%Z_to_m)
1555  cs%id_mass_flux = register_diag_field('ocean_model', 'mass_flux', cs%diag%axesT1,&
1556  cs%Time,'Total mass flux of freshwater across the ice-ocean interface.', 'kg/s')
1557  cs%id_melt = register_diag_field('ocean_model', 'melt', cs%diag%axesT1, cs%Time, &
1558  'Ice Shelf Melt Rate', 'm yr-1')
1559  cs%id_thermal_driving = register_diag_field('ocean_model', 'thermal_driving', cs%diag%axesT1, cs%Time, &
1560  'pot. temp. in the boundary layer minus freezing pot. temp. at the ice-ocean interface.', 'Celsius')
1561  cs%id_haline_driving = register_diag_field('ocean_model', 'haline_driving', cs%diag%axesT1, cs%Time, &
1562  'salinity in the boundary layer minus salinity at the ice-ocean interface.', 'psu')
1563  cs%id_Sbdry = register_diag_field('ocean_model', 'sbdry', cs%diag%axesT1, cs%Time, &
1564  'salinity at the ice-ocean interface.', 'psu')
1565  cs%id_u_ml = register_diag_field('ocean_model', 'u_ml', cs%diag%axesCu1, cs%Time, &
1566  'Eastward vel. in the boundary layer (used to compute ustar)', 'm s-1')
1567  cs%id_v_ml = register_diag_field('ocean_model', 'v_ml', cs%diag%axesCv1, cs%Time, &
1568  'Northward vel. in the boundary layer (used to compute ustar)', 'm s-1')
1569  cs%id_exch_vel_s = register_diag_field('ocean_model', 'exch_vel_s', cs%diag%axesT1, cs%Time, &
1570  'Sub-shelf salinity exchange velocity', 'm s-1')
1571  cs%id_exch_vel_t = register_diag_field('ocean_model', 'exch_vel_t', cs%diag%axesT1, cs%Time, &
1572  'Sub-shelf thermal exchange velocity', 'm s-1')
1573  cs%id_tfreeze = register_diag_field('ocean_model', 'tfreeze', cs%diag%axesT1, cs%Time, &
1574  'In Situ Freezing point at ice shelf interface', 'degC')
1575  cs%id_tfl_shelf = register_diag_field('ocean_model', 'tflux_shelf', cs%diag%axesT1, cs%Time, &
1576  'Heat conduction into ice shelf', 'W m-2')
1577  cs%id_ustar_shelf = register_diag_field('ocean_model', 'ustar_shelf', cs%diag%axesT1, cs%Time, &
1578  'Fric vel under shelf', 'm/s', conversion=us%Z_to_m*us%s_to_T)
1579  if (cs%active_shelf_dynamics) then
1580  cs%id_h_mask = register_diag_field('ocean_model', 'h_mask', cs%diag%axesT1, cs%Time, &
1581  'ice shelf thickness mask', 'none')
1582  endif
1583 
1584  id_clock_shelf = cpu_clock_id('Ice shelf', grain=clock_component)
1585  id_clock_pass = cpu_clock_id(' Ice shelf halo updates', grain=clock_routine)
1586 
1587 end subroutine initialize_ice_shelf
1588 
1589 !> Initializes shelf mass based on three options (file, zero and user)
1590 subroutine initialize_shelf_mass(G, param_file, CS, ISS, new_sim)
1592  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1593  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
1594  type(ice_shelf_cs), pointer :: CS !< A pointer to the ice shelf control structure
1595  type(ice_shelf_state), intent(inout) :: ISS !< The ice shelf state type that is being updated
1596  logical, optional, intent(in) :: new_sim !< If present and false, this run is being restarted
1597 
1598  integer :: i, j, is, ie, js, je
1599  logical :: read_shelf_area, new_sim_2
1600  character(len=240) :: config, inputdir, shelf_file, filename
1601  character(len=120) :: shelf_mass_var ! The name of shelf mass in the file.
1602  character(len=120) :: shelf_area_var ! The name of shelf area in the file.
1603  character(len=40) :: mdl = "MOM_ice_shelf"
1604  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
1605 
1606  new_sim_2 = .true. ; if (present(new_sim)) new_sim_2 = new_sim
1607 
1608  call get_param(param_file, mdl, "ICE_SHELF_CONFIG", config, &
1609  "A string that specifies how the ice shelf is "//&
1610  "initialized. Valid options include:\n"//&
1611  " \tfile\t Read from a file.\n"//&
1612  " \tzero\t Set shelf mass to 0 everywhere.\n"//&
1613  " \tUSER\t Call USER_initialize_shelf_mass.\n", &
1614  fail_if_missing=.true.)
1615 
1616  select case ( trim(config) )
1617  case ("file")
1618 
1619  call time_interp_external_init()
1620 
1621  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
1622  inputdir = slasher(inputdir)
1623 
1624  call get_param(param_file, mdl, "SHELF_FILE", shelf_file, &
1625  "If DYNAMIC_SHELF_MASS = True, OVERRIDE_SHELF_MOVEMENT = True "//&
1626  "and ICE_SHELF_MASS_FROM_FILE = True, this is the file from "//&
1627  "which to read the shelf mass and area.", &
1628  default="shelf_mass.nc")
1629  call get_param(param_file, mdl, "SHELF_MASS_VAR", shelf_mass_var, &
1630  "The variable in SHELF_FILE with the shelf mass.", &
1631  default="shelf_mass")
1632  call get_param(param_file, mdl, "READ_SHELF_AREA", read_shelf_area, &
1633  "If true, also read the area covered by ice-shelf from SHELF_FILE.", &
1634  default=.false.)
1635 
1636  filename = trim(slasher(inputdir))//trim(shelf_file)
1637  call log_param(param_file, mdl, "INPUTDIR/SHELF_FILE", filename)
1638 
1639  cs%id_read_mass = init_external_field(filename, shelf_mass_var, &
1640  domain=g%Domain%mpp_domain, verbose=cs%debug)
1641 
1642  if (read_shelf_area) then
1643  call get_param(param_file, mdl, "SHELF_AREA_VAR", shelf_area_var, &
1644  "The variable in SHELF_FILE with the shelf area.", &
1645  default="shelf_area")
1646 
1647  cs%id_read_area = init_external_field(filename,shelf_area_var, &
1648  domain=g%Domain%mpp_domain)
1649  endif
1650 
1651  if (.not.file_exists(filename, g%Domain)) call mom_error(fatal, &
1652  " initialize_shelf_mass: Unable to open "//trim(filename))
1653 
1654  case ("zero")
1655  do j=js,je ; do i=is,ie
1656  iss%mass_shelf(i,j) = 0.0
1657  iss%area_shelf_h(i,j) = 0.0
1658  enddo ; enddo
1659 
1660  case ("USER")
1661  call user_initialize_shelf_mass(iss%mass_shelf, iss%area_shelf_h, &
1662  iss%h_shelf, iss%hmask, g, cs%US, cs%user_CS, param_file, new_sim_2)
1663 
1664  case default ; call mom_error(fatal,"initialize_ice_shelf: "// &
1665  "Unrecognized ice shelf setup "//trim(config))
1666  end select
1667 
1668 end subroutine initialize_shelf_mass
1669 
1670 !> Updates the ice shelf mass using data from a file.
1671 subroutine update_shelf_mass(G, CS, ISS, Time)
1672  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
1673  type(ice_shelf_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
1674  type(ice_shelf_state), intent(inout) :: ISS !< The ice shelf state type that is being updated
1675  type(time_type), intent(in) :: Time !< The current model time
1676 
1677  ! local variables
1678  integer :: i, j, is, ie, js, je
1679  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
1680 
1681  call time_interp_external(cs%id_read_mass, time, iss%mass_shelf)
1682 
1683  do j=js,je ; do i=is,ie
1684  iss%area_shelf_h(i,j) = 0.0
1685  iss%hmask(i,j) = 0.
1686  if (iss%mass_shelf(i,j) > 0.0) then
1687  iss%area_shelf_h(i,j) = g%areaT(i,j)
1688  iss%h_shelf(i,j) = iss%mass_shelf(i,j) / cs%rho_ice
1689  iss%hmask(i,j) = 1.
1690  endif
1691  enddo ; enddo
1692 
1693  !call USER_update_shelf_mass(ISS%mass_shelf, ISS%area_shelf_h, ISS%h_shelf, &
1694  ! ISS%hmask, CS%grid, CS%user_CS, Time, .true.)
1695 
1696  if (cs%min_thickness_simple_calve > 0.0) then
1697  call ice_shelf_min_thickness_calve(g, iss%h_shelf, iss%area_shelf_h, iss%hmask, &
1698  cs%min_thickness_simple_calve)
1699  endif
1700 
1701  call pass_var(iss%area_shelf_h, g%domain)
1702  call pass_var(iss%h_shelf, g%domain)
1703  call pass_var(iss%hmask, g%domain)
1704  call pass_var(iss%mass_shelf, g%domain)
1705 
1706 end subroutine update_shelf_mass
1707 
1708 !> Save the ice shelf restart file
1709 subroutine ice_shelf_save_restart(CS, Time, directory, time_stamped, filename_suffix)
1710  type(ice_shelf_cs), pointer :: cs !< ice shelf control structure
1711  type(time_type), intent(in) :: time !< model time at this call
1712  character(len=*), optional, intent(in) :: directory !< An optional directory into which to write
1713  !! these restart files.
1714  logical, optional, intent(in) :: time_stamped !< f true, the restart file names include
1715  !! a unique time stamp. The default is false.
1716  character(len=*), optional, intent(in) :: filename_suffix !< An optional suffix (e.g., a
1717  !! time-stamp) to append to the restart file names.
1718  ! local variables
1719  type(ocean_grid_type), pointer :: g => null()
1720  character(len=200) :: restart_dir
1721 
1722  g => cs%grid
1723 
1724  if (present(directory)) then ; restart_dir = directory
1725  else ; restart_dir = cs%restart_output_dir ; endif
1726 
1727  call save_restart(restart_dir, time, cs%grid, cs%restart_CSp, time_stamped)
1728 
1729 end subroutine ice_shelf_save_restart
1730 
1731 !> Deallocates all memory associated with this module
1732 subroutine ice_shelf_end(CS)
1733  type(ice_shelf_cs), pointer :: cs !< A pointer to the ice shelf control structure
1734 
1735  if (.not.associated(cs)) return
1736 
1737  call ice_shelf_state_end(cs%ISS)
1738 
1739  if (cs%active_shelf_dynamics) call ice_shelf_dyn_end(cs%dCS)
1740 
1741  deallocate(cs)
1742 
1743 end subroutine ice_shelf_end
1744 
1745 !> This routine is for stepping a stand-alone ice shelf model without an ocean.
1746 subroutine solo_time_step(CS, time_step, nsteps, Time, min_time_step_in)
1747  type(ice_shelf_cs), pointer :: cs !< A pointer to the ice shelf control structure
1748  real, intent(in) :: time_step !< The time interval for this update [s].
1749  integer, intent(inout) :: nsteps !< The running number of ice shelf steps.
1750  type(time_type), intent(inout) :: time !< The current model time
1751  real, optional, intent(in) :: min_time_step_in !< The minimum permitted time step [s].
1752 
1753  type(ocean_grid_type), pointer :: g => null()
1754  type(unit_scale_type), pointer :: us => null() ! Pointer to a structure containing
1755  ! various unit conversion factors
1756  type(ice_shelf_state), pointer :: iss => null() !< A structure with elements that describe
1757  !! the ice-shelf state
1758  integer :: is, iec, js, jec, i, j
1759  real :: time_step_remain
1760  real :: time_step_int, min_time_step
1761  character(len=240) :: mesg
1762  logical :: update_ice_vel ! If true, it is time to update the ice shelf velocities.
1763  logical :: coupled_gl ! If true the grouding line position is determined based on
1764  ! coupled ice-ocean dynamics.
1765 
1766  g => cs%grid
1767  us => cs%US
1768  iss => cs%ISS
1769  is = g%isc ; iec = g%iec ; js = g%jsc ; jec = g%jec
1770 
1771  time_step_remain = time_step
1772  if (present (min_time_step_in)) then
1773  min_time_step = min_time_step_in
1774  else
1775  min_time_step = 1000.0 ! This is in seconds - at 1 km resolution it would imply ice is moving at ~1 meter per second
1776  endif
1777 
1778  write (mesg,*) "TIME in ice shelf call, yrs: ", time_type_to_real(time)/(365. * 86400.)
1779  call mom_mesg("solo_time_step: "//mesg)
1780 
1781  do while (time_step_remain > 0.0)
1782  nsteps = nsteps+1
1783 
1784  ! If time_step is not too long, this is unnecessary.
1785  time_step_int = min(ice_time_step_cfl(cs%dCS, iss, g), time_step)
1786 
1787  write (mesg,*) "Ice model timestep = ", time_step_int, " seconds"
1788  if (time_step_int < min_time_step) then
1789  call mom_error(fatal, "MOM_ice_shelf:solo_time_step: abnormally small timestep "//mesg)
1790  else
1791  call mom_mesg("solo_time_step: "//mesg)
1792  endif
1793 
1794  if (time_step_int >= time_step_remain) then
1795  time_step_int = time_step_remain
1796  time_step_remain = 0.0
1797  else
1798  time_step_remain = time_step_remain - time_step_int
1799  endif
1800 
1801  ! If the last mini-timestep is a day or less, we cannot expect velocities to change by much.
1802  ! Do not update the velocities if the last step is very short.
1803  update_ice_vel = ((time_step_int > min_time_step) .or. (time_step_int >= time_step))
1804  coupled_gl = .false.
1805 
1806  call update_ice_shelf(cs%dCS, iss, g, us, time_step_int, time, must_update_vel=update_ice_vel)
1807 
1808  call enable_averaging(time_step,time,cs%diag)
1809  if (cs%id_area_shelf_h > 0) call post_data(cs%id_area_shelf_h, iss%area_shelf_h, cs%diag)
1810  if (cs%id_h_shelf > 0) call post_data(cs%id_h_shelf, iss%h_shelf, cs%diag)
1811  if (cs%id_h_mask > 0) call post_data(cs%id_h_mask, iss%hmask, cs%diag)
1812  call disable_averaging(cs%diag)
1813 
1814  enddo
1815 
1816 end subroutine solo_time_step
1817 
1818 !> \namespace mom_ice_shelf
1819 !!
1820 !! \section section_ICE_SHELF
1821 !!
1822 !! This module implements the thermodynamic aspects of ocean/ice-shelf
1823 !! inter-actions using the MOM framework and coding style.
1824 !!
1825 !! Derived from code by Chris Little, early 2010.
1826 !!
1827 !! The ice-sheet dynamics subroutines do the following:
1828 !! initialize_shelf_mass - Initializes the ice shelf mass distribution.
1829 !! - Initializes h_shelf, h_mask, area_shelf_h
1830 !! - CURRENTLY: initializes mass_shelf as well, but this is unnecessary, as mass_shelf is initialized based on
1831 !! h_shelf and density_ice immediately afterwards. Possibly subroutine should be renamed
1832 !! update_shelf_mass - updates ice shelf mass via netCDF file
1833 !! USER_update_shelf_mass (TODO).
1834 !! solo_time_step - called only in ice-only mode.
1835 !! shelf_calc_flux - after melt rate & fluxes are calculated, ice dynamics are done. currently mass_shelf is
1836 !! updated immediately after ice_shelf_advect in fully dynamic mode.
1837 !!
1838 !! NOTES: be aware that hmask(:,:) has a number of functions; it is used for front advancement,
1839 !! for subroutines in the velocity solve, and for thickness boundary conditions (this last one may be removed).
1840 !! in other words, interfering with its updates will have implications you might not expect.
1841 !!
1842 !! Overall issues: Many variables need better documentation and units and the
1843 !! subgrid on which they are discretized.
1844 !!
1845 !! \subsection section_ICE_SHELF_equations ICE_SHELF equations
1846 !!
1847 !! The three fundamental equations are:
1848 !! Heat flux
1849 !! \f[ \qquad \rho_w C_{pw} \gamma_T (T_w - T_b) = \rho_i \dot{m} L_f \f]
1850 !! Salt flux
1851 !! \f[ \qquad \rho_w \gamma_s (S_w - S_b) = \rho_i \dot{m} S_b \f]
1852 !! Freezing temperature
1853 !! \f[ \qquad T_b = a S_b + b + c P \f]
1854 !!
1855 !! where ....
1856 !!
1857 !! \subsection section_ICE_SHELF_references References
1858 !!
1859 !! Asay-Davis, Xylar S., Stephen L. Cornford, Benjamin K. Galton-Fenzi, Rupert M. Gladstone, G. Hilmar Gudmundsson,
1860 !! David M. Holland, Paul R. Holland, and Daniel F. Martin. Experimental design for three interrelated marine ice sheet
1861 !! and ocean model intercomparison projects: MISMIP v. 3 (MISMIP+), ISOMIP v. 2 (ISOMIP+) and MISOMIP v. 1 (MISOMIP1).
1862 !! Geoscientific Model Development 9, no. 7 (2016): 2471.
1863 !!
1864 !! Goldberg, D. N., et al. Investigation of land ice-ocean interaction with a fully coupled ice-ocean model: 1.
1865 !! Model description and behavior. Journal of Geophysical Research: Earth Surface 117.F2 (2012).
1866 !!
1867 !! Goldberg, D. N., et al. Investigation of land ice-ocean interaction with a fully coupled ice-ocean model: 2.
1868 !! Sensitivity to external forcings. Journal of Geophysical Research: Earth Surface 117.F2 (2012).
1869 !!
1870 !! Holland, David M., and Adrian Jenkins. Modeling thermodynamic ice-ocean interactions at the base of an ice shelf.
1871 !! Journal of Physical Oceanography 29.8 (1999): 1787-1800.
1872 
1873 end module mom_ice_shelf
mom_time_manager
Wraps the FMS time manager functions.
Definition: MOM_time_manager.F90:2
mom_ice_shelf_dynamics
Implements a crude placeholder for a later implementation of full ice shelf dynamics.
Definition: MOM_ice_shelf_dynamics.F90:3
mom_forcing_type::mech_forcing
Structure that contains pointers to the mechanical forcing at the surface used to drive the liquid oc...
Definition: MOM_forcing_type.F90:185
mom_variables::surface
Pointers to various fields which may be used describe the surface state of MOM, and which will be ret...
Definition: MOM_variables.F90:38
mom_ice_shelf
Implements the thermodynamic aspects of ocean / ice-shelf interactions, along with a crude placeholde...
Definition: MOM_ice_shelf.F90:4
mom_checksums::vchksum
Checksums an array (2d or 3d) staggered at C-grid v points.
Definition: MOM_checksums.F90:38
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_checksums::qchksum
This is an older interface that has been renamed Bchksum.
Definition: MOM_checksums.F90:58
mom_diag_mediator
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Definition: MOM_diag_mediator.F90:3
mom_ice_shelf_initialize
Initialize ice shelf variables.
Definition: MOM_ice_shelf_initialize.F90:2
mom_get_input::directories
Container for paths and parameter file names.
Definition: MOM_get_input.F90:20
mom_dyn_horgrid
Contains a shareable dynamic type for describing horizontal grids and metric data and utilty routines...
Definition: MOM_dyn_horgrid.F90:3
mom_eos
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
mom_checksums::uvchksum
Checksums a pair velocity arrays (2d or 3d) staggered at C-grid locations.
Definition: MOM_checksums.F90:28
mom_domains::pass_var
Do a halo update on an array.
Definition: MOM_domains.F90:49
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_checksums::chksum
This is an older interface for 1-, 2-, or 3-D checksums.
Definition: MOM_checksums.F90:63
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_io
This module contains I/O framework code.
Definition: MOM_io.F90:2
mom_restart::mom_restart_cs
A restart registry and the control structure for restarts.
Definition: MOM_restart.F90:72
mom_get_input
Reads the only Fortran name list needed to boot-strap the model.
Definition: MOM_get_input.F90:6
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
mom_eos::calculate_tfreeze
Calculates the freezing point of sea water from T, S and P.
Definition: MOM_EOS.F90:81
mom_coms
Interfaces to non-domain-oriented communication subroutines, including the MOM6 reproducing sums faci...
Definition: MOM_coms.F90:3
mom_ice_shelf_dynamics::ice_shelf_dyn_cs
The control structure for the ice shelf dynamics.
Definition: MOM_ice_shelf_dynamics.F90:41
mom_diag_mediator::post_data
Make a diagnostic available for averaging or output.
Definition: MOM_diag_mediator.F90:70
mom_domains::pass_vector
Do a halo update on a pair of arrays representing the two components of a vector.
Definition: MOM_domains.F90:54
mom_transcribe_grid
Module with routines for copying information from a shared dynamic horizontal grid to an ocean-specif...
Definition: MOM_transcribe_grid.F90:3
mom_eos::eos_type
A control structure for the equation of state.
Definition: MOM_EOS.F90:86
mom_domains::clone_mom_domain
Copy one MOM_domain_type into another.
Definition: MOM_domains.F90:94
mom_forcing_type
This module implements boundary forcing for MOM6.
Definition: MOM_forcing_type.F90:2
mom_ice_shelf_state
Implements the thermodynamic aspects of ocean / ice-shelf interactions, along with a crude placeholde...
Definition: MOM_ice_shelf_state.F90:4
mom_ice_shelf::ice_shelf_cs
Control structure that contains ice shelf parameters and diagnostics handles.
Definition: MOM_ice_shelf.F90:71
mom_checksums
Routines to calculate checksums of various array and vector types.
Definition: MOM_checksums.F90:2
mom_restart
The MOM6 facility for reading and writing restart files, and querying what has been read.
Definition: MOM_restart.F90:2
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_variables
Provides transparent structures with groups of MOM6 variables and supporting routines.
Definition: MOM_variables.F90:2
mom_io::mom_read_data
Read a data field from a file.
Definition: MOM_io.F90:74
mom_ice_shelf_state::ice_shelf_state
Structure that describes the ice shelf state.
Definition: MOM_ice_shelf_state.F90:24
mom_fixed_initialization
Initializes fixed aspects of the model, such as horizontal grid metrics, topography and Coriolis.
Definition: MOM_fixed_initialization.F90:3
mom_cpu_clock
Wraps the MPP cpu clock functions.
Definition: MOM_cpu_clock.F90:2
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_eos::calculate_density_derivs
Calculate the derivatives of density with temperature and salinity from T, S, and P.
Definition: MOM_EOS.F90:70
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_restart::register_restart_field
Register fields for restarts.
Definition: MOM_restart.F90:107
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
mom_grid_initialize
Initializes horizontal grid.
Definition: MOM_grid_initialize.F90:2
mom_forcing_type::forcing
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Definition: MOM_forcing_type.F90:49
mom_io::file_exists
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
user_shelf_init
This module specifies the initial values and evolving properties of the MOM6 ice shelf,...
Definition: user_shelf_init.F90:3
mom_checksums::uchksum
Checksums an array (2d or 3d) staggered at C-grid u points.
Definition: MOM_checksums.F90:33
mom_coms::reproducing_sum
Find an accurate and order-invariant sum of distributed 2d or 3d fields.
Definition: MOM_coms.F90:54
mom_checksums::hchksum
Checksums an array (2d or 3d) staggered at tracer points.
Definition: MOM_checksums.F90:48
mom_file_parser::log_param
An overloaded interface to log the values of various types of parameters.
Definition: MOM_file_parser.F90:96
mom_restart::query_initialized
Indicate whether a field has been read from a restart file.
Definition: MOM_restart.F90:116
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_dyn_horgrid::dyn_horgrid_type
Describes the horizontal ocean grid with only dynamic memory arrays.
Definition: MOM_dyn_horgrid.F90:22
user_shelf_init::user_ice_shelf_cs
The control structure for the user_ice_shelf module.
Definition: user_shelf_init.F90:29
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:25
mom_diag_mediator::diag_ctrl
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Definition: MOM_diag_mediator.F90:239
user_initialization
A template of a user to code up customized initial conditions.
Definition: user_initialization.F90:2
mom_eos::calculate_density
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:60
mom_file_parser::read_param
An overloaded interface to read various types of parameters.
Definition: MOM_file_parser.F90:90