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