MOM6
MOM_ice_shelf_dynamics.F90
1 !> Implements a crude placeholder for a later implementation of full
2 !! ice shelf dynamics.
4 
5 ! This file is part of MOM6. See LICENSE.md for the license.
6 
7 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
8 use mom_cpu_clock, only : clock_component, clock_routine
9 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
10 use mom_diag_mediator, only : diag_mediator_init, set_diag_mediator_grid
11 use mom_diag_mediator, only : diag_ctrl, time_type, enable_averaging, disable_averaging
12 use mom_domains, only : mom_domains_init, clone_mom_domain
13 use mom_domains, only : pass_var, pass_vector, to_all, cgrid_ne, bgrid_ne, corner
14 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning, is_root_pe
16 use mom_grid, only : mom_grid_init, ocean_grid_type
17 use mom_io, only : file_exists, slasher, mom_read_data
19 use mom_restart, only : mom_restart_cs
20 use mom_time_manager, only : time_type, set_time
21 use mom_unit_scaling, only : unit_scale_type, unit_scaling_init
22 !MJH use MOM_ice_shelf_initialize, only : initialize_ice_shelf_boundary
24 use mom_coms, only : reproducing_sum, sum_across_pes, max_across_pes, min_across_pes
25 use mom_checksums, only : hchksum, qchksum
26 
27 implicit none ; private
28 
29 #include <MOM_memory.h>
30 
31 public register_ice_shelf_dyn_restarts, initialize_ice_shelf_dyn, update_ice_shelf
32 public ice_time_step_cfl, ice_shelf_dyn_end
33 public shelf_advance_front, ice_shelf_min_thickness_calve, calve_to_mask
34 
35 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
36 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
37 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
38 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
39 
40 !> The control structure for the ice shelf dynamics.
41 type, public :: ice_shelf_dyn_cs ; private
42  real, pointer, dimension(:,:) :: u_shelf => null() !< the zonal (?) velocity of the ice shelf/sheet
43  !! on q-points (B grid) [m s-1]??
44  real, pointer, dimension(:,:) :: v_shelf => null() !< the meridional velocity of the ice shelf/sheet
45  !! on q-points (B grid) [m s-1]??
46 
47  real, pointer, dimension(:,:) :: u_face_mask => null() !< mask for velocity boundary conditions on the C-grid
48  !! u-face - this is because the FEM cares about FACES THAT GET INTEGRATED OVER,
49  !! not vertices. Will represent boundary conditions on computational boundary
50  !! (or permanent boundary between fast-moving and near-stagnant ice
51  !! FOR NOW: 1=interior bdry, 0=no-flow boundary, 2=stress bdry condition,
52  !! 3=inhomogeneous dirichlet boundary, 4=flux boundary: at these faces a flux
53  !! will be specified which will override velocities; a homogeneous velocity
54  !! condition will be specified (this seems to give the solver less difficulty)
55  real, pointer, dimension(:,:) :: v_face_mask => null() !< A mask for velocity boundary conditions on the C-grid
56  !! v-face, with valued defined similarly to u_face_mask.
57  real, pointer, dimension(:,:) :: u_face_mask_bdry => null() !< A duplicate copy of u_face_mask?
58  real, pointer, dimension(:,:) :: v_face_mask_bdry => null() !< A duplicate copy of v_face_mask?
59  real, pointer, dimension(:,:) :: u_flux_bdry_val => null() !< The ice volume flux into the cell through open boundary
60  !! u-faces (where u_face_mask=4) [Z m2 s-1 ~> m3 s-1]??
61  real, pointer, dimension(:,:) :: v_flux_bdry_val => null() !< The ice volume flux into the cell through open boundary
62  !! v-faces (where v_face_mask=4) [Z m2 s-1 ~> m3 s-1]??
63  ! needed where u_face_mask is equal to 4, similary for v_face_mask
64  real, pointer, dimension(:,:) :: umask => null() !< u-mask on the actual degrees of freedom (B grid)
65  !! 1=normal node, 3=inhomogeneous boundary node,
66  !! 0 - no flow node (will also get ice-free nodes)
67  real, pointer, dimension(:,:) :: vmask => null() !< v-mask on the actual degrees of freedom (B grid)
68  !! 1=normal node, 3=inhomogeneous boundary node,
69  !! 0 - no flow node (will also get ice-free nodes)
70  real, pointer, dimension(:,:) :: calve_mask => null() !< a mask to prevent the ice shelf front from
71  !! advancing past its initial position (but it may retreat)
72  real, pointer, dimension(:,:) :: t_shelf => null() !< Veritcally integrated temperature in the ice shelf/stream,
73  !! on corner-points (B grid) [degC]
74  real, pointer, dimension(:,:) :: tmask => null() !< A mask on tracer points that is 1 where there is ice.
75  real, pointer, dimension(:,:) :: ice_visc => null() !< Glen's law ice viscosity, perhaps in [m].
76  real, pointer, dimension(:,:) :: thickness_bdry_val => null() !< The ice thickness at an inflowing boundary [Z ~> m].
77  real, pointer, dimension(:,:) :: u_bdry_val => null() !< The zonal ice velocity at inflowing boundaries [m s-1]??
78  real, pointer, dimension(:,:) :: v_bdry_val => null() !< The meridional ice velocity at inflowing boundaries [m s-1]??
79  real, pointer, dimension(:,:) :: h_bdry_val => null() !< The ice thickness at inflowing boundaries [m].
80  real, pointer, dimension(:,:) :: t_bdry_val => null() !< The ice temperature at inflowing boundaries [degC].
81 
82  real, pointer, dimension(:,:) :: taub_beta_eff => null() !< nonlinear part of "linearized" basal stress.
83  !! The exact form depends on basal law exponent and/or whether flow is "hybridized" a la Goldberg 2011
84 
85  real, pointer, dimension(:,:) :: od_rt => null() !< A running total for calculating OD_av.
86  real, pointer, dimension(:,:) :: float_frac_rt => null() !< A running total for calculating float_frac.
87  real, pointer, dimension(:,:) :: od_av => null() !< The time average open ocean depth [Z ~> m].
88  real, pointer, dimension(:,:) :: float_frac => null() !< Fraction of the time a cell is "exposed", i.e. the column
89  !! thickness is below a threshold.
90  !### [if float_frac = 1 ==> grounded; obviously counterintuitive; might fix]
91  integer :: od_rt_counter = 0 !< A counter of the number of contributions to OD_rt.
92 
93  real :: velocity_update_time_step !< The time interval over which to update the ice shelf velocity
94  !! using the nonlinear elliptic equation, or 0 to update every timestep [s].
95  ! DNGoldberg thinks this should be done no more often than about once a day
96  ! (maybe longer) because it will depend on ocean values that are averaged over
97  ! this time interval, and solving for the equiliabrated flow will begin to lose
98  ! meaning if it is done too frequently.
99  real :: elapsed_velocity_time !< The elapsed time since the ice velocies were last udated [s].
100 
101  real :: g_earth !< The gravitational acceleration [m s-2].
102  real :: density_ice !< A typical density of ice [kg m-3].
103 
104  logical :: gl_regularize !< Specifies whether to regularize the floatation condition
105  !! at the grounding line as in Goldberg Holland Schoof 2009
106  integer :: n_sub_regularize
107  !< partition of cell over which to integrate for
108  !! interpolated grounding line the (rectangular) is
109  !! divided into nxn equally-sized rectangles, over which
110  !! basal contribution is integrated (iterative quadrature)
111  logical :: gl_couple !< whether to let the floatation condition be
112  !! determined by ocean column thickness means update_OD_ffrac
113  !! will be called (note: GL_regularize and GL_couple
114  !! should be exclusive)
115 
116  real :: cfl_factor !< A factor used to limit subcycled advective timestep in uncoupled runs
117  !! i.e. dt <= CFL_factor * min(dx / u)
118 
119  real :: a_glen_isothermal !< Ice viscosity parameter in Glen's Lawa, [Pa-1/3 year].
120  real :: n_glen !< Nonlinearity exponent in Glen's Law
121  real :: eps_glen_min !< Min. strain rate to avoid infinite Glen's law viscosity, [year-1].
122  real :: c_basal_friction !< Ceofficient in sliding law tau_b = C u^(n_basal_friction), in
123  !! units="Pa (m-a)-(n_basal_friction)
124  real :: n_basal_friction !< Exponent in sliding law tau_b = C u^(m_slide)
125  real :: density_ocean_avg !< This does not affect ocean circulation or thermodynamics.
126  !! It is used to estimate the gravitational driving force at the
127  !! shelf front (until we think of a better way to do it,
128  !! but any difference will be negligible).
129  real :: thresh_float_col_depth !< The water column depth over which the shelf if considered to be floating
130  logical :: moving_shelf_front !< Specify whether to advance shelf front (and calve).
131  logical :: calve_to_mask !< If true, calve off the ice shelf when it passes the edge of a mask.
132  real :: min_thickness_simple_calve !< min. ice shelf thickness criteria for calving [Z ~> m].
133 
134  real :: cg_tolerance !< The tolerance in the CG solver, relative to initial residual, that
135  !! deterimnes when to stop the conguage gradient iterations.
136  real :: nonlinear_tolerance !< The fractional nonlinear tolerance, relative to the initial error,
137  !! that sets when to stop the iterative velocity solver
138  integer :: cg_max_iterations !< The maximum number of iterations that can be used in the CG solver
139  integer :: nonlin_solve_err_mode !< 1: exit vel solve based on nonlin residual
140  !! 2: exit based on "fixed point" metric (|u - u_last| / |u| < tol where | | is infty-norm
141  logical :: use_reproducing_sums !< Use reproducing global sums.
142 
143  ! ids for outputting intermediate thickness in advection subroutine (debugging)
144  !integer :: id_h_after_uflux = -1, id_h_after_vflux = -1, id_h_after_adv = -1
145 
146  logical :: debug !< If true, write verbose checksums for debugging purposes
147  !! and use reproducible sums
148  logical :: module_is_initialized = .false. !< True if this module has been initialized.
149 
150  !>@{ Diagnostic handles
151  integer :: id_u_shelf = -1, id_v_shelf = -1, id_t_shelf = -1, &
152  id_float_frac = -1, id_col_thick = -1, id_od_av = -1, &
153  id_u_mask = -1, id_v_mask = -1, id_t_mask = -1
154  !!@}
155  ! ids for outputting intermediate thickness in advection subroutine (debugging)
156  !integer :: id_h_after_uflux = -1, id_h_after_vflux = -1, id_h_after_adv = -1
157 
158  type(diag_ctrl), pointer :: diag => null() !< A structure that is used to control diagnostic output.
159 
160 end type ice_shelf_dyn_cs
161 
162 contains
163 
164 !> used for flux limiting in advective subroutines Van Leer limiter (source: Wikipedia)
165 function slope_limiter(num, denom)
166  real, intent(in) :: num !< The numerator of the ratio used in the Van Leer slope limiter
167  real, intent(in) :: denom !< The denominator of the ratio used in the Van Leer slope limiter
168  real :: slope_limiter
169  real :: r
170 
171  if (denom == 0) then
172  slope_limiter = 0
173  elseif (num*denom <= 0) then
174  slope_limiter = 0
175  else
176  r = num/denom
177  slope_limiter = (r+abs(r))/(1+abs(r))
178  endif
179 
180 end function slope_limiter
181 
182 !> Calculate area of quadrilateral.
183 function quad_area (X, Y)
184  real, dimension(4), intent(in) :: x !< The x-positions of the vertices of the quadrilateral.
185  real, dimension(4), intent(in) :: y !< The y-positions of the vertices of the quadrilateral.
186  real :: quad_area, p2, q2, a2, c2, b2, d2
187 
188 ! X and Y must be passed in the form
189  ! 3 - 4
190  ! | |
191  ! 1 - 2
192 
193  p2 = (x(4)-x(1))**2 + (y(4)-y(1))**2 ; q2 = (x(3)-x(2))**2 + (y(3)-y(2))**2
194  a2 = (x(3)-x(4))**2 + (y(3)-y(4))**2 ; c2 = (x(1)-x(2))**2 + (y(1)-y(2))**2
195  b2 = (x(2)-x(4))**2 + (y(2)-y(4))**2 ; d2 = (x(3)-x(1))**2 + (y(3)-y(1))**2
196  quad_area = .25 * sqrt(4*p2*q2-(b2+d2-a2-c2)**2)
197 
198 end function quad_area
199 
200 !> This subroutine is used to register any fields related to the ice shelf
201 !! dynamics that should be written to or read from the restart file.
202 subroutine register_ice_shelf_dyn_restarts(G, param_file, CS, restart_CS)
203  type(ocean_grid_type), intent(inout) :: g !< The grid type describing the ice shelf grid.
204  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
205  type(ice_shelf_dyn_cs), pointer :: cs !< A pointer to the ice shelf dynamics control structure
206  type(mom_restart_cs), pointer :: restart_cs !< A pointer to the restart control structure.
207 
208  logical :: shelf_mass_is_dynamic, override_shelf_movement, active_shelf_dynamics
209  character(len=40) :: mdl = "MOM_ice_shelf_dyn" ! This module's name.
210  integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
211 
212  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
213  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
214 
215  if (associated(cs)) then
216  call mom_error(fatal, "MOM_ice_shelf_dyn.F90, register_ice_shelf_dyn_restarts: "// &
217  "called with an associated control structure.")
218  return
219  endif
220  allocate(cs)
221 
222  override_shelf_movement = .false. ; active_shelf_dynamics = .false.
223  call get_param(param_file, mdl, "DYNAMIC_SHELF_MASS", shelf_mass_is_dynamic, &
224  "If true, the ice sheet mass can evolve with time.", &
225  default=.false., do_not_log=.true.)
226  if (shelf_mass_is_dynamic) then
227  call get_param(param_file, mdl, "OVERRIDE_SHELF_MOVEMENT", override_shelf_movement, &
228  "If true, user provided code specifies the ice-shelf "//&
229  "movement instead of the dynamic ice model.", default=.false., do_not_log=.true.)
230  active_shelf_dynamics = .not.override_shelf_movement
231  endif
232 
233  if (active_shelf_dynamics) then
234  allocate( cs%u_shelf(isdb:iedb,jsdb:jedb) ) ; cs%u_shelf(:,:) = 0.0
235  allocate( cs%v_shelf(isdb:iedb,jsdb:jedb) ) ; cs%v_shelf(:,:) = 0.0
236  allocate( cs%t_shelf(isd:ied,jsd:jed) ) ; cs%t_shelf(:,:) = -10.0
237  allocate( cs%ice_visc(isd:ied,jsd:jed) ) ; cs%ice_visc(:,:) = 0.0
238  allocate( cs%taub_beta_eff(isd:ied,jsd:jed) ) ; cs%taub_beta_eff(:,:) = 0.0
239  allocate( cs%OD_av(isd:ied,jsd:jed) ) ; cs%OD_av(:,:) = 0.0
240  allocate( cs%float_frac(isd:ied,jsd:jed) ) ; cs%float_frac(:,:) = 0.0
241 
242  ! additional restarts for ice shelf state
243  call register_restart_field(cs%u_shelf, "u_shelf", .false., restart_cs, &
244  "ice sheet/shelf u-velocity", "m s-1", hor_grid='Bu')
245  call register_restart_field(cs%v_shelf, "v_shelf", .false., restart_cs, &
246  "ice sheet/shelf v-velocity", "m s-1", hor_grid='Bu')
247  call register_restart_field(cs%t_shelf, "t_shelf", .true., restart_cs, &
248  "ice sheet/shelf vertically averaged temperature", "deg C")
249  call register_restart_field(cs%OD_av, "OD_av", .true., restart_cs, &
250  "Average open ocean depth in a cell","m")
251  call register_restart_field(cs%float_frac, "float_frac", .true., restart_cs, &
252  "fractional degree of grounding", "nondim")
253  call register_restart_field(cs%ice_visc, "viscosity", .true., restart_cs, &
254  "Glens law ice viscosity", "m (seems wrong)")
255  call register_restart_field(cs%taub_beta_eff, "tau_b_beta", .true., restart_cs, &
256  "Coefficient of basal traction", "m (seems wrong)")
257  endif
258 
259 end subroutine register_ice_shelf_dyn_restarts
260 
261 !> Initializes shelf model data, parameters and diagnostics
262 subroutine initialize_ice_shelf_dyn(param_file, Time, ISS, CS, G, US, diag, new_sim, solo_ice_sheet_in)
263  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
264  type(ocean_grid_type), pointer :: ocn_grid !< The calling ocean model's horizontal grid structure
265  type(time_type), intent(inout) :: time !< The clock that that will indicate the model time
266  type(ice_shelf_state), intent(in) :: iss !< A structure with elements that describe
267  !! the ice-shelf state
268  type(ice_shelf_dyn_cs), pointer :: cs !< A pointer to the ice shelf dynamics control structure
269  type(ocean_grid_type), intent(inout) :: g !< The grid type describing the ice shelf grid.
270  type(unit_scale_type), intent(in) :: us !< Pointer to a structure containing unit conversion factors
271  type(diag_ctrl), target, intent(in) :: diag !< A structure that is used to regulate the diagnostic output.
272  logical, intent(in) :: new_sim !< If true this is a new simulation, otherwise
273  !! has been started from a restart file.
274  logical, optional, intent(in) :: solo_ice_sheet_in !< If present, this indicates whether
275  !! a solo ice-sheet driver.
276 
277  ! Local variables
278  real :: z_rescale ! A rescaling factor for heights from the representation in
279  ! a reastart fole to the internal representation in this run.
280  !This include declares and sets the variable "version".
281 # include "version_variable.h"
282  character(len=200) :: config
283  character(len=200) :: ic_file,filename,inputdir
284  character(len=40) :: var_name
285  character(len=40) :: mdl = "MOM_ice_shelf_dyn" ! This module's name.
286  logical :: shelf_mass_is_dynamic, override_shelf_movement, active_shelf_dynamics
287  logical :: debug
288  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed, isdq, iedq, jsdq, jedq, iters
289 
290  if (.not.associated(cs)) then
291  call mom_error(fatal, "MOM_ice_shelf_dyn.F90, initialize_ice_shelf_dyn: "// &
292  "called with an associated control structure.")
293  return
294  endif
295  if (cs%module_is_initialized) then
296  call mom_error(warning, "MOM_ice_shelf_dyn.F90, initialize_ice_shelf_dyn was "//&
297  "called with a control structure that has already been initialized.")
298  endif
299  cs%module_is_initialized = .true.
300 
301  cs%diag => diag ! ; CS%Time => Time
302 
303  ! Read all relevant parameters and write them to the model log.
304  call log_version(param_file, mdl, version, "")
305  call get_param(param_file, mdl, "DEBUG", debug, default=.false.)
306  call get_param(param_file, mdl, "DEBUG_IS", cs%debug, &
307  "If true, write verbose debugging messages for the ice shelf.", &
308  default=debug)
309  call get_param(param_file, mdl, "DYNAMIC_SHELF_MASS", shelf_mass_is_dynamic, &
310  "If true, the ice sheet mass can evolve with time.", &
311  default=.false.)
312  override_shelf_movement = .false. ; active_shelf_dynamics = .false.
313  if (shelf_mass_is_dynamic) then
314  call get_param(param_file, mdl, "OVERRIDE_SHELF_MOVEMENT", override_shelf_movement, &
315  "If true, user provided code specifies the ice-shelf "//&
316  "movement instead of the dynamic ice model.", default=.false., do_not_log=.true.)
317  active_shelf_dynamics = .not.override_shelf_movement
318 
319  call get_param(param_file, mdl, "GROUNDING_LINE_INTERPOLATE", cs%GL_regularize, &
320  "If true, regularize the floatation condition at the "//&
321  "grounding line as in Goldberg Holland Schoof 2009.", default=.false.)
322  call get_param(param_file, mdl, "GROUNDING_LINE_INTERP_SUBGRID_N", cs%n_sub_regularize, &
323  "The number of sub-partitions of each cell over which to "//&
324  "integrate for the interpolated grounding line. Each cell "//&
325  "is divided into NxN equally-sized rectangles, over which the "//&
326  "basal contribution is integrated by iterative quadrature.", &
327  default=0)
328  call get_param(param_file, mdl, "GROUNDING_LINE_COUPLE", cs%GL_couple, &
329  "If true, let the floatation condition be determined by "//&
330  "ocean column thickness. This means that update_OD_ffrac "//&
331  "will be called. GL_REGULARIZE and GL_COUPLE are exclusive.", &
332  default=.false., do_not_log=cs%GL_regularize)
333  if (cs%GL_regularize) cs%GL_couple = .false.
334  if (cs%GL_regularize .and. (cs%n_sub_regularize == 0)) call mom_error (fatal, &
335  "GROUNDING_LINE_INTERP_SUBGRID_N must be a positive integer if GL regularization is used")
336  call get_param(param_file, mdl, "ICE_SHELF_CFL_FACTOR", cs%CFL_factor, &
337  "A factor used to limit timestep as CFL_FACTOR * min (\Delta x / u). "//&
338  "This is only used with an ice-only model.", default=0.25)
339  endif
340  call get_param(param_file, mdl, "RHO_0", cs%density_ocean_avg, &
341  "avg ocean density used in floatation cond", &
342  units="kg m-3", default=1035.)
343  if (active_shelf_dynamics) then
344  call get_param(param_file, mdl, "ICE_VELOCITY_TIMESTEP", cs%velocity_update_time_step, &
345  "seconds between ice velocity calcs", units="s", &
346  fail_if_missing=.true.)
347  call get_param(param_file, mdl, "G_EARTH", cs%g_Earth, &
348  "The gravitational acceleration of the Earth.", &
349  units="m s-2", default = 9.80)
350 
351  call get_param(param_file, mdl, "A_GLEN_ISOTHERM", cs%A_glen_isothermal, &
352  "Ice viscosity parameter in Glen's Law", &
353  units="Pa -1/3 a", default=9.461e-18)
354  call get_param(param_file, mdl, "GLEN_EXPONENT", cs%n_glen, &
355  "nonlinearity exponent in Glen's Law", &
356  units="none", default=3.)
357  call get_param(param_file, mdl, "MIN_STRAIN_RATE_GLEN", cs%eps_glen_min, &
358  "min. strain rate to avoid infinite Glen's law viscosity", &
359  units="a-1", default=1.e-12)
360  call get_param(param_file, mdl, "BASAL_FRICTION_COEFF", cs%C_basal_friction, &
361  "ceofficient in sliding law \tau_b = C u^(n_basal_friction)", &
362  units="Pa (m-a)-(n_basal_friction)", fail_if_missing=.true.)
363  call get_param(param_file, mdl, "BASAL_FRICTION_EXP", cs%n_basal_friction, &
364  "exponent in sliding law \tau_b = C u^(m_slide)", &
365  units="none", fail_if_missing=.true.)
366  call get_param(param_file, mdl, "DENSITY_ICE", cs%density_ice, &
367  "A typical density of ice.", units="kg m-3", default=917.0)
368  call get_param(param_file, mdl, "CONJUGATE_GRADIENT_TOLERANCE", cs%cg_tolerance, &
369  "tolerance in CG solver, relative to initial residual", default=1.e-6)
370  call get_param(param_file, mdl, "ICE_NONLINEAR_TOLERANCE", cs%nonlinear_tolerance, &
371  "nonlin tolerance in iterative velocity solve",default=1.e-6)
372  call get_param(param_file, mdl, "CONJUGATE_GRADIENT_MAXIT", cs%cg_max_iterations, &
373  "max iteratiions in CG solver", default=2000)
374  call get_param(param_file, mdl, "THRESH_FLOAT_COL_DEPTH", cs%thresh_float_col_depth, &
375  "min ocean thickness to consider ice *floating*; "//&
376  "will only be important with use of tides", &
377  units="m", default=1.e-3, scale=us%m_to_Z)
378  call get_param(param_file, mdl, "NONLIN_SOLVE_ERR_MODE", cs%nonlin_solve_err_mode, &
379  "Choose whether nonlin error in vel solve is based on nonlinear "//&
380  "residual (1) or relative change since last iteration (2)", default=1)
381  call get_param(param_file, mdl, "SHELF_DYN_REPRODUCING_SUMS", cs%use_reproducing_sums, &
382  "If true, use the reproducing extended-fixed-point sums in "//&
383  "the ice shelf dynamics solvers.", default=.true.)
384 
385  call get_param(param_file, mdl, "SHELF_MOVING_FRONT", cs%moving_shelf_front, &
386  "Specify whether to advance shelf front (and calve).", &
387  default=.true.)
388  call get_param(param_file, mdl, "CALVE_TO_MASK", cs%calve_to_mask, &
389  "If true, do not allow an ice shelf where prohibited by a mask.", &
390  default=.false.)
391  endif
392  call get_param(param_file, mdl, "MIN_THICKNESS_SIMPLE_CALVE", &
393  cs%min_thickness_simple_calve, &
394  "Min thickness rule for the VERY simple calving law",&
395  units="m", default=0.0, scale=us%m_to_Z)
396 
397  ! Allocate memory in the ice shelf dynamics control structure that was not
398  ! previously allocated for registration for restarts.
399  ! OVS vertically integrated Temperature
400 
401  if (active_shelf_dynamics) then
402  ! DNG
403  allocate( cs%u_bdry_val(isdq:iedq,jsdq:jedq) ) ; cs%u_bdry_val(:,:) = 0.0
404  allocate( cs%v_bdry_val(isdq:iedq,jsdq:jedq) ) ; cs%v_bdry_val(:,:) = 0.0
405  allocate( cs%t_bdry_val(isd:ied,jsd:jed) ) ; cs%t_bdry_val(:,:) = -15.0
406  allocate( cs%h_bdry_val(isd:ied,jsd:jed) ) ; cs%h_bdry_val(:,:) = 0.0
407  allocate( cs%thickness_bdry_val(isd:ied,jsd:jed) ) ; cs%thickness_bdry_val(:,:) = 0.0
408  allocate( cs%u_face_mask(isdq:iedq,jsd:jed) ) ; cs%u_face_mask(:,:) = 0.0
409  allocate( cs%v_face_mask(isd:ied,jsdq:jedq) ) ; cs%v_face_mask(:,:) = 0.0
410  allocate( cs%u_face_mask_bdry(isdq:iedq,jsd:jed) ) ; cs%u_face_mask_bdry(:,:) = -2.0
411  allocate( cs%v_face_mask_bdry(isd:ied,jsdq:jedq) ) ; cs%v_face_mask_bdry(:,:) = -2.0
412  allocate( cs%u_flux_bdry_val(isdq:iedq,jsd:jed) ) ; cs%u_flux_bdry_val(:,:) = 0.0
413  allocate( cs%v_flux_bdry_val(isd:ied,jsdq:jedq) ) ; cs%v_flux_bdry_val(:,:) = 0.0
414  allocate( cs%umask(isdq:iedq,jsdq:jedq) ) ; cs%umask(:,:) = -1.0
415  allocate( cs%vmask(isdq:iedq,jsdq:jedq) ) ; cs%vmask(:,:) = -1.0
416  allocate( cs%tmask(isdq:iedq,jsdq:jedq) ) ; cs%tmask(:,:) = -1.0
417 
418  cs%OD_rt_counter = 0
419  allocate( cs%OD_rt(isd:ied,jsd:jed) ) ; cs%OD_rt(:,:) = 0.0
420  allocate( cs%float_frac_rt(isd:ied,jsd:jed) ) ; cs%float_frac_rt(:,:) = 0.0
421 
422  if (cs%calve_to_mask) then
423  allocate( cs%calve_mask(isd:ied,jsd:jed) ) ; cs%calve_mask(:,:) = 0.0
424  endif
425 
426  cs%elapsed_velocity_time = 0.0
427 
428  call update_velocity_masks(cs, g, iss%hmask, cs%umask, cs%vmask, cs%u_face_mask, cs%v_face_mask)
429  endif
430 
431  ! Take additional initialization steps, for example of dependent variables.
432  if (active_shelf_dynamics .and. .not.new_sim) then
433  if ((us%m_to_Z_restart /= 0.0) .and. (us%m_to_Z_restart /= us%m_to_Z)) then
434  z_rescale = us%m_to_Z / us%m_to_Z_restart
435  do j=g%jsc,g%jec ; do i=g%isc,g%iec
436  cs%OD_av(i,j) = z_rescale * cs%OD_av(i,j)
437  enddo ; enddo
438  endif
439 
440  ! this is unfortunately necessary; if grid is not symmetric the boundary values
441  ! of u and v are otherwise not set till the end of the first linear solve, and so
442  ! viscosity is not calculated correctly.
443  ! This has to occur after init_boundary_values or some of the arrays on the
444  ! right hand side have not been set up yet.
445  if (.not. g%symmetric) then
446  do j=g%jsd,g%jed ; do i=g%isd,g%ied
447  if (((i+g%idg_offset) == (g%domain%nihalo+1)).and.(cs%u_face_mask(i-1,j) == 3)) then
448  cs%u_shelf(i-1,j-1) = cs%u_bdry_val(i-1,j-1)
449  cs%u_shelf(i-1,j) = cs%u_bdry_val(i-1,j)
450  endif
451  if (((j+g%jdg_offset) == (g%domain%njhalo+1)).and.(cs%v_face_mask(i,j-1) == 3)) then
452  cs%u_shelf(i-1,j-1) = cs%u_bdry_val(i-1,j-1)
453  cs%u_shelf(i,j-1) = cs%u_bdry_val(i,j-1)
454  endif
455  enddo ; enddo
456  endif
457 
458  call pass_var(cs%OD_av,g%domain)
459  call pass_var(cs%float_frac,g%domain)
460  call pass_var(cs%ice_visc,g%domain)
461  call pass_var(cs%taub_beta_eff,g%domain)
462  call pass_vector(cs%u_shelf, cs%v_shelf, g%domain, to_all, bgrid_ne)
463  endif
464 
465  if (active_shelf_dynamics) then
466  ! If we are calving to a mask, i.e. if a mask exists where a shelf cannot, read the mask from a file.
467  if (cs%calve_to_mask) then
468  call mom_mesg(" MOM_ice_shelf.F90, initialize_ice_shelf: reading calving_mask")
469 
470  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
471  inputdir = slasher(inputdir)
472  call get_param(param_file, mdl, "CALVING_MASK_FILE", ic_file, &
473  "The file with a mask for where calving might occur.", &
474  default="ice_shelf_h.nc")
475  call get_param(param_file, mdl, "CALVING_MASK_VARNAME", var_name, &
476  "The variable to use in masking calving.", &
477  default="area_shelf_h")
478 
479  filename = trim(inputdir)//trim(ic_file)
480  call log_param(param_file, mdl, "INPUTDIR/CALVING_MASK_FILE", filename)
481  if (.not.file_exists(filename, g%Domain)) call mom_error(fatal, &
482  " calving mask file: Unable to open "//trim(filename))
483 
484  call mom_read_data(filename,trim(var_name),cs%calve_mask,g%Domain)
485  do j=g%jsc,g%jec ; do i=g%isc,g%iec
486  if (cs%calve_mask(i,j) > 0.0) cs%calve_mask(i,j) = 1.0
487  enddo ; enddo
488  call pass_var(cs%calve_mask,g%domain)
489  endif
490 
491 ! call init_boundary_values(CS, G, time, ISS%hmask, CS%input_flux, CS%input_thickness, new_sim)
492 
493  if (new_sim) then
494  call mom_mesg("MOM_ice_shelf.F90, initialize_ice_shelf: initialize ice velocity.")
495  call update_od_ffrac_uncoupled(cs, g, iss%h_shelf(:,:))
496  call ice_shelf_solve_outer(cs, iss, g, us, cs%u_shelf, cs%v_shelf, iters, time)
497 
498  if (cs%id_u_shelf > 0) call post_data(cs%id_u_shelf,cs%u_shelf,cs%diag)
499  if (cs%id_v_shelf > 0) call post_data(cs%id_v_shelf,cs%v_shelf,cs%diag)
500  endif
501 
502  ! Register diagnostics.
503  cs%id_u_shelf = register_diag_field('ocean_model','u_shelf',cs%diag%axesCu1, time, &
504  'x-velocity of ice', 'm yr-1')
505  cs%id_v_shelf = register_diag_field('ocean_model','v_shelf',cs%diag%axesCv1, time, &
506  'y-velocity of ice', 'm yr-1')
507  cs%id_u_mask = register_diag_field('ocean_model','u_mask',cs%diag%axesCu1, time, &
508  'mask for u-nodes', 'none')
509  cs%id_v_mask = register_diag_field('ocean_model','v_mask',cs%diag%axesCv1, time, &
510  'mask for v-nodes', 'none')
511 ! CS%id_surf_elev = register_diag_field('ocean_model','ice_surf',CS%diag%axesT1, Time, &
512 ! 'ice surf elev', 'm')
513  cs%id_float_frac = register_diag_field('ocean_model','ice_float_frac',cs%diag%axesT1, time, &
514  'fraction of cell that is floating (sort of)', 'none')
515  cs%id_col_thick = register_diag_field('ocean_model','col_thick',cs%diag%axesT1, time, &
516  'ocean column thickness passed to ice model', 'm', conversion=us%Z_to_m)
517  cs%id_OD_av = register_diag_field('ocean_model','OD_av',cs%diag%axesT1, time, &
518  'intermediate ocean column thickness passed to ice model', 'm', conversion=us%Z_to_m)
519  !CS%id_h_after_uflux = register_diag_field('ocean_model','h_after_uflux',CS%diag%axesh1, Time, &
520  ! 'thickness after u flux ', 'none')
521  !CS%id_h_after_vflux = register_diag_field('ocean_model','h_after_vflux',CS%diag%axesh1, Time, &
522  ! 'thickness after v flux ', 'none')
523  !CS%id_h_after_adv = register_diag_field('ocean_model','h_after_adv',CS%diag%axesh1, Time, &
524  ! 'thickness after front adv ', 'none')
525 
526 !!! OVS vertically integrated temperature
527  cs%id_t_shelf = register_diag_field('ocean_model','t_shelf',cs%diag%axesT1, time, &
528  'T of ice', 'oC')
529  cs%id_t_mask = register_diag_field('ocean_model','tmask',cs%diag%axesT1, time, &
530  'mask for T-nodes', 'none')
531  endif
532 
533 end subroutine initialize_ice_shelf_dyn
534 
535 
536 subroutine initialize_diagnostic_fields(CS, ISS, G, US, Time)
537  type(ice_shelf_dyn_cs), intent(inout) :: CS !< A pointer to the ice shelf control structure
538  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
539  !! the ice-shelf state
540  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
541  type(unit_scale_type), intent(in) :: US !< Pointer to a structure containing unit conversion factors
542  type(time_type), intent(in) :: Time !< The current model time
543 
544  integer :: i, j, iters, isd, ied, jsd, jed
545  real :: rhoi_rhow, OD
546  type(time_type) :: dummy_time
547 
548  rhoi_rhow = cs%density_ice / cs%density_ocean_avg
549  dummy_time = set_time(0,0)
550  isd=g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
551 
552  do j=jsd,jed
553  do i=isd,ied
554  od = g%bathyT(i,j) - rhoi_rhow * iss%h_shelf(i,j)
555  if (od >= 0) then
556  ! ice thickness does not take up whole ocean column -> floating
557  cs%OD_av(i,j) = od
558  cs%float_frac(i,j) = 0.
559  else
560  cs%OD_av(i,j) = 0.
561  cs%float_frac(i,j) = 1.
562  endif
563  enddo
564  enddo
565 
566  call ice_shelf_solve_outer(cs, iss, g, us, cs%u_shelf, cs%v_shelf, iters, dummy_time)
567 
568 end subroutine initialize_diagnostic_fields
569 
570 !> This function returns the global maximum timestep that can be taken based on the current
571 !! ice velocities. Because it involves finding a global minimum, it can be suprisingly expensive.
572 function ice_time_step_cfl(CS, ISS, G)
573  type(ice_shelf_dyn_cs), intent(inout) :: cs !< The ice shelf dynamics control structure
574  type(ice_shelf_state), intent(inout) :: iss !< A structure with elements that describe
575  !! the ice-shelf state
576  type(ocean_grid_type), intent(inout) :: g !< The grid structure used by the ice shelf.
577  real :: ice_time_step_cfl !< The maximum permitted timestep based on the ice velocities [s].
578 
579  real :: ratio, min_ratio
580  real :: local_u_max, local_v_max
581  integer :: i, j
582 
583  min_ratio = 1.0e16 ! This is just an arbitrary large value.
584  do j=g%jsc,g%jec ; do i=g%isc,g%iec ; if (iss%hmask(i,j) == 1.0) then
585  local_u_max = max(abs(cs%u_shelf(i,j)), abs(cs%u_shelf(i+1,j+1)), &
586  abs(cs%u_shelf(i+1,j)), abs(cs%u_shelf(i,j+1)))
587  local_v_max = max(abs(cs%v_shelf(i,j)), abs(cs%v_shelf(i+1,j+1)), &
588  abs(cs%v_shelf(i+1,j)), abs(cs%v_shelf(i,j+1)))
589 
590  ratio = min(g%areaT(i,j) / (local_u_max+1.0e-12), g%areaT(i,j) / (local_v_max+1.0e-12))
591  min_ratio = min(min_ratio, ratio)
592  endif ; enddo ; enddo ! i- and j- loops
593 
594  call min_across_pes(min_ratio)
595 
596  ! solved velocities are in m/yr; we want time_step_int in seconds
597  ice_time_step_cfl = cs%CFL_factor * min_ratio * (365*86400)
598 
599 end function ice_time_step_cfl
600 
601 !> This subroutine updates the ice shelf velocities, mass, stresses and properties due to the
602 !! ice shelf dynamics.
603 subroutine update_ice_shelf(CS, ISS, G, US, time_step, Time, ocean_mass, coupled_grounding, must_update_vel)
604  type(ice_shelf_dyn_cs), intent(inout) :: cs !< The ice shelf dynamics control structure
605  type(ice_shelf_state), intent(inout) :: iss !< A structure with elements that describe
606  !! the ice-shelf state
607  type(ocean_grid_type), intent(inout) :: g !< The grid structure used by the ice shelf.
608  type(unit_scale_type), intent(in) :: us !< Pointer to a structure containing unit conversion factors
609  real, intent(in) :: time_step !< time step [s]
610  type(time_type), intent(in) :: time !< The current model time
611  real, dimension(SZDI_(G),SZDJ_(G)), &
612  optional, intent(in) :: ocean_mass !< If present this is the mass per unit area
613  !! of the ocean [kg m-2].
614  logical, optional, intent(in) :: coupled_grounding !< If true, the grounding line is
615  !! determined by coupled ice-ocean dynamics
616  logical, optional, intent(in) :: must_update_vel !< Always update the ice velocities if true.
617 
618  integer :: iters
619  logical :: update_ice_vel, coupled_gl
620 
621  update_ice_vel = .false.
622  if (present(must_update_vel)) update_ice_vel = must_update_vel
623 
624  coupled_gl = .false.
625  if (present(ocean_mass) .and. present(coupled_grounding)) coupled_gl = coupled_grounding
626 
627  call ice_shelf_advect(cs, iss, g, time_step, time)
628  cs%elapsed_velocity_time = cs%elapsed_velocity_time + time_step
629  if (cs%elapsed_velocity_time >= cs%velocity_update_time_step) update_ice_vel = .true.
630 
631  if (coupled_gl) then
632  call update_od_ffrac(cs, g, us, ocean_mass, update_ice_vel)
633  elseif (update_ice_vel) then
634  call update_od_ffrac_uncoupled(cs, g, iss%h_shelf(:,:))
635  endif
636 
637  if (update_ice_vel) then
638  call ice_shelf_solve_outer(cs, iss, g, us, cs%u_shelf, cs%v_shelf, iters, time)
639  endif
640 
641  call ice_shelf_temp(cs, iss, g, us, time_step, iss%water_flux, time)
642 
643  if (update_ice_vel) then
644  call enable_averaging(cs%elapsed_velocity_time, time, cs%diag)
645  if (cs%id_col_thick > 0) call post_data(cs%id_col_thick, cs%OD_av, cs%diag)
646  if (cs%id_u_shelf > 0) call post_data(cs%id_u_shelf,cs%u_shelf,cs%diag)
647  if (cs%id_v_shelf > 0) call post_data(cs%id_v_shelf,cs%v_shelf,cs%diag)
648  if (cs%id_t_shelf > 0) call post_data(cs%id_t_shelf,cs%t_shelf,cs%diag)
649  if (cs%id_float_frac > 0) call post_data(cs%id_float_frac,cs%float_frac,cs%diag)
650  if (cs%id_OD_av >0) call post_data(cs%id_OD_av, cs%OD_av,cs%diag)
651 
652  if (cs%id_u_mask > 0) call post_data(cs%id_u_mask,cs%umask,cs%diag)
653  if (cs%id_v_mask > 0) call post_data(cs%id_v_mask,cs%vmask,cs%diag)
654  if (cs%id_t_mask > 0) call post_data(cs%id_t_mask,cs%tmask,cs%diag)
655 
656  call disable_averaging(cs%diag)
657 
658  cs%elapsed_velocity_time = 0.0
659  endif
660 
661 end subroutine update_ice_shelf
662 
663 !> This subroutine takes the velocity (on the Bgrid) and timesteps h_t = - div (uh) once.
664 !! Additionally, it will update the volume of ice in partially-filled cells, and update
665 !! hmask accordingly
666 subroutine ice_shelf_advect(CS, ISS, G, time_step, Time)
667  type(ice_shelf_dyn_cs), intent(inout) :: CS !< The ice shelf dynamics control structure
668  type(ice_shelf_state), intent(inout) :: ISS !< A structure with elements that describe
669  !! the ice-shelf state
670  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
671  real, intent(in) :: time_step !< time step [s]
672  type(time_type), intent(in) :: Time !< The current model time
673 
674 
675 ! 3/8/11 DNG
676 !
677 ! This subroutine takes the velocity (on the Bgrid) and timesteps h_t = - div (uh) once.
678 ! ADDITIONALLY, it will update the volume of ice in partially-filled cells, and update
679 ! hmask accordingly
680 !
681 ! The flux overflows are included here. That is because they will be used to advect 3D scalars
682 ! into partial cells
683 
684  !
685  ! flux_enter: this is to capture flow into partially covered cells; it gives the mass flux into a given
686  ! cell across its boundaries.
687  ! ###Perhaps flux_enter should be changed into u-face and v-face
688  ! ###fluxes, which can then be used in halo updates, etc.
689  !
690  ! from left neighbor: flux_enter(:,:,1)
691  ! from right neighbor: flux_enter(:,:,2)
692  ! from bottom neighbor: flux_enter(:,:,3)
693  ! from top neighbor: flux_enter(:,:,4)
694  !
695  ! THESE ARE NOT CONSISTENT ==> FIND OUT WHAT YOU IMPLEMENTED
696 
697  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
698  !
699  ! o--- (4) ---o
700  ! | |
701  ! (1) (2)
702  ! | |
703  ! o--- (3) ---o
704  !
705 
706  real, dimension(SZDI_(G),SZDJ_(G)) :: h_after_uflux, h_after_vflux ! Ice thicknesses [Z ~> m].
707  real, dimension(SZDI_(G),SZDJ_(G),4) :: flux_enter
708  integer :: isd, ied, jsd, jed, i, j, isc, iec, jsc, jec
709  real :: rho, spy
710 
711  rho = cs%density_ice
712  spy = 365 * 86400 ! seconds per year; is there a global constant for this? No - it is dependent upon a calendar.
713 
714  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
715  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec
716  flux_enter(:,:,:) = 0.0
717 
718  h_after_uflux(:,:) = 0.0
719  h_after_vflux(:,:) = 0.0
720  ! call MOM_mesg("MOM_ice_shelf.F90: ice_shelf_advect called")
721 
722  do j=jsd,jed ; do i=isd,ied ; if (cs%thickness_bdry_val(i,j) /= 0.0) then
723  iss%h_shelf(i,j) = cs%thickness_bdry_val(i,j)
724  endif ; enddo ; enddo
725 
726  call ice_shelf_advect_thickness_x(cs, g, time_step/spy, iss%hmask, iss%h_shelf, h_after_uflux, flux_enter)
727 
728 ! call enable_averaging(time_step,Time,CS%diag)
729  ! call pass_var(h_after_uflux, G%domain)
730 ! if (CS%id_h_after_uflux > 0) call post_data(CS%id_h_after_uflux, h_after_uflux, CS%diag)
731 ! call disable_averaging(CS%diag)
732 
733  call ice_shelf_advect_thickness_y(cs, g, time_step/spy, iss%hmask, h_after_uflux, h_after_vflux, flux_enter)
734 
735 ! call enable_averaging(time_step,Time,CS%diag)
736 ! call pass_var(h_after_vflux, G%domain)
737 ! if (CS%id_h_after_vflux > 0) call post_data(CS%id_h_after_vflux, h_after_vflux, CS%diag)
738 ! call disable_averaging(CS%diag)
739 
740  do j=jsd,jed
741  do i=isd,ied
742  if (iss%hmask(i,j) == 1) iss%h_shelf(i,j) = h_after_vflux(i,j)
743  enddo
744  enddo
745 
746  if (cs%moving_shelf_front) then
747  call shelf_advance_front(cs, iss, g, flux_enter)
748  if (cs%min_thickness_simple_calve > 0.0) then
749  call ice_shelf_min_thickness_calve(g, iss%h_shelf, iss%area_shelf_h, iss%hmask, &
750  cs%min_thickness_simple_calve)
751  endif
752  if (cs%calve_to_mask) then
753  call calve_to_mask(g, iss%h_shelf, iss%area_shelf_h, iss%hmask, cs%calve_mask)
754  endif
755  endif
756 
757  !call enable_averaging(time_step,Time,CS%diag)
758  !if (CS%id_h_after_adv > 0) call post_data(CS%id_h_after_adv, ISS%h_shelf, CS%diag)
759  !call disable_averaging(CS%diag)
760 
761  !call change_thickness_using_melt(ISS, G, time_step, fluxes, CS%density_ice)
762 
763  call update_velocity_masks(cs, g, iss%hmask, cs%umask, cs%vmask, cs%u_face_mask, cs%v_face_mask)
764 
765 end subroutine ice_shelf_advect
766 
767 subroutine ice_shelf_solve_outer(CS, ISS, G, US, u, v, iters, time)
768  type(ice_shelf_dyn_cs), intent(inout) :: CS !< The ice shelf dynamics control structure
769  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
770  !! the ice-shelf state
771  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
772  type(unit_scale_type), intent(in) :: US !< Pointer to a structure containing unit conversion factors
773  real, dimension(SZDIB_(G),SZDJB_(G)), &
774  intent(inout) :: u !< The zonal ice shelf velocity at vertices [m year-1]
775  real, dimension(SZDIB_(G),SZDJB_(G)), &
776  intent(inout) :: v !< The meridional ice shelf velocity at vertices [m year-1]
777  integer, intent(out) :: iters !< The number of iterations used in the solver.
778  type(time_type), intent(in) :: Time !< The current model time
779 
780  real, dimension(SZDIB_(G),SZDJB_(G)) :: TAUDX, TAUDY, u_prev_iterate, v_prev_iterate, &
781  u_bdry_cont, v_bdry_cont, Au, Av, err_u, err_v, &
782  u_last, v_last
783  real, dimension(SZDIB_(G),SZDJB_(G)) :: H_node ! Ice shelf thickness at corners [Z ~> m].
784  real, dimension(SZDI_(G),SZDJ_(G)) :: float_cond ! An array indicating where the ice
785  ! shelf is floating: 0 if floating, 1 if not.
786  character(len=160) :: mesg ! The text of an error message
787  integer :: conv_flag, i, j, k,l, iter
788  integer :: isdq, iedq, jsdq, jedq, isd, ied, jsd, jed, isumstart, jsumstart, nodefloat, nsub
789  real :: err_max, err_tempu, err_tempv, err_init, area, max_vel, tempu, tempv, rhoi_rhow
790  real, pointer, dimension(:,:,:,:) :: Phi => null()
791  real, pointer, dimension(:,:,:,:,:,:) :: Phisub => null()
792  real, dimension(8,4) :: Phi_temp
793  real, dimension(2,2) :: X,Y
794  character(2) :: iternum
795  character(2) :: numproc
796 
797  ! for GL interpolation - need to make this a readable parameter
798  nsub = cs%n_sub_regularize
799 
800  isdq = g%isdB ; iedq = g%iedB ; jsdq = g%jsdB ; jedq = g%jedB
801  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
802  rhoi_rhow = cs%density_ice / cs%density_ocean_avg
803 
804  taudx(:,:) = 0.0 ; taudy(:,:) = 0.0
805  u_bdry_cont(:,:) = 0.0 ; v_bdry_cont(:,:) = 0.0
806  au(:,:) = 0.0 ; av(:,:) = 0.0
807 
808  ! need to make these conditional on GL interpolation
809  float_cond(:,:) = 0.0 ; h_node(:,:)=0
810  allocate(phisub(nsub,nsub,2,2,2,2)) ; phisub = 0.0
811 
812  isumstart = g%isc
813  ! Include the edge if tile is at the western bdry; Should add a test to avoid this if reentrant.
814  if (g%isc+g%idg_offset==g%isg) isumstart = g%iscB
815 
816  jsumstart = g%jsc
817  ! Include the edge if tile is at the southern bdry; Should add a test to avoid this if reentrant.
818  if (g%jsc+g%jdg_offset==g%jsg) jsumstart = g%jscB
819 
820  call calc_shelf_driving_stress(cs, iss, g, us, taudx, taudy, cs%OD_av)
821 
822  ! this is to determine which cells contain the grounding line,
823  ! the criterion being that the cell is ice-covered, with some nodes
824  ! floating and some grounded
825  ! floatation condition is estimated by assuming topography is cellwise constant
826  ! and H is bilinear in a cell; floating where rho_i/rho_w * H_node + D is nonpositive
827 
828  ! need to make this conditional on GL interp
829 
830  if (cs%GL_regularize) then
831 
832  call interpolate_h_to_b(g, iss%h_shelf, iss%hmask, h_node)
833 
834  do j=g%jsc,g%jec
835  do i=g%isc,g%iec
836  nodefloat = 0
837  do k=0,1
838  do l=0,1
839  if ((iss%hmask(i,j) == 1) .and. &
840  (rhoi_rhow * h_node(i-1+k,j-1+l) - g%bathyT(i,j) <= 0)) then
841  nodefloat = nodefloat + 1
842  endif
843  enddo
844  enddo
845  if ((nodefloat > 0) .and. (nodefloat < 4)) then
846  float_cond(i,j) = 1.0
847  cs%float_frac(i,j) = 1.0
848  endif
849  enddo
850  enddo
851 
852  call pass_var(float_cond, g%Domain)
853 
854  call bilinear_shape_functions_subgrid(phisub, nsub)
855 
856  endif
857 
858  ! make above conditional
859 
860  u_prev_iterate(:,:) = u(:,:)
861  v_prev_iterate(:,:) = v(:,:)
862 
863  ! must prepare phi
864  allocate(phi(isd:ied,jsd:jed,1:8,1:4)) ; phi(:,:,:,:) = 0.0
865 
866  do j=jsd,jed ; do i=isd,ied
867  if (((i > isd) .and. (j > jsd))) then
868  x(:,:) = g%geoLonBu(i-1:i,j-1:j)*1000
869  y(:,:) = g%geoLatBu(i-1:i,j-1:j)*1000
870  else
871  x(2,:) = g%geoLonBu(i,j)*1000
872  x(1,:) = g%geoLonBu(i,j)*1000-g%dxT(i,j)
873  y(:,2) = g%geoLatBu(i,j)*1000
874  y(:,1) = g%geoLatBu(i,j)*1000-g%dyT(i,j)
875  endif
876 
877  call bilinear_shape_functions(x, y, phi_temp, area)
878  phi(i,j,:,:) = phi_temp
879  enddo ; enddo
880 
881  call calc_shelf_visc(cs, iss, g, us, u, v)
882 
883  call pass_var(cs%ice_visc, g%domain)
884  call pass_var(cs%taub_beta_eff, g%domain)
885 
886  ! makes sure basal stress is only applied when it is supposed to be
887 
888  do j=g%jsd,g%jed ; do i=g%isd,g%ied
889  cs%taub_beta_eff(i,j) = cs%taub_beta_eff(i,j) * cs%float_frac(i,j)
890  enddo ; enddo
891 
892  call apply_boundary_values(cs, iss, g, time, phisub, h_node, cs%ice_visc, &
893  cs%taub_beta_eff, float_cond, &
894  rhoi_rhow, u_bdry_cont, v_bdry_cont)
895 
896  au(:,:) = 0.0 ; av(:,:) = 0.0
897 
898  call cg_action(au, av, u, v, phi, phisub, cs%umask, cs%vmask, iss%hmask, h_node, &
899  cs%ice_visc, float_cond, g%bathyT(:,:), cs%taub_beta_eff, g%areaT, &
900  g, g%isc-1, g%iec+1, g%jsc-1, g%jec+1, rhoi_rhow)
901 
902  err_init = 0 ; err_tempu = 0; err_tempv = 0
903  do j=jsumstart,g%jecB
904  do i=isumstart,g%iecB
905  if (cs%umask(i,j) == 1) then
906  err_tempu = abs(au(i,j) + u_bdry_cont(i,j) - taudx(i,j))
907  endif
908  if (cs%vmask(i,j) == 1) then
909  err_tempv = max(abs(av(i,j) + v_bdry_cont(i,j) - taudy(i,j)), err_tempu)
910  endif
911  if (err_tempv >= err_init) then
912  err_init = err_tempv
913  endif
914  enddo
915  enddo
916 
917  call max_across_pes(err_init)
918 
919  write(mesg,*) "ice_shelf_solve_outer: INITIAL nonlinear residual = ",err_init
920  call mom_mesg(mesg, 5)
921 
922  u_last(:,:) = u(:,:) ; v_last(:,:) = v(:,:)
923 
924  !! begin loop
925 
926  do iter=1,100
927 
928  call ice_shelf_solve_inner(cs, iss, g, u, v, taudx, taudy, h_node, float_cond, &
929  iss%hmask, conv_flag, iters, time, phi, phisub)
930 
931  if (cs%debug) then
932  call qchksum(u, "u shelf", g%HI, haloshift=2)
933  call qchksum(v, "v shelf", g%HI, haloshift=2)
934  endif
935 
936  write(mesg,*) "ice_shelf_solve_outer: linear solve done in ",iters," iterations"
937  call mom_mesg(mesg, 5)
938 
939  call calc_shelf_visc(cs, iss, g, us, u, v)
940  call pass_var(cs%ice_visc, g%domain)
941  call pass_var(cs%taub_beta_eff, g%domain)
942 
943  ! makes sure basal stress is only applied when it is supposed to be
944 
945  do j=g%jsd,g%jed ; do i=g%isd,g%ied
946  cs%taub_beta_eff(i,j) = cs%taub_beta_eff(i,j) * cs%float_frac(i,j)
947  enddo ; enddo
948 
949  u_bdry_cont(:,:) = 0 ; v_bdry_cont(:,:) = 0
950 
951  call apply_boundary_values(cs, iss, g, time, phisub, h_node, cs%ice_visc, &
952  cs%taub_beta_eff, float_cond, &
953  rhoi_rhow, u_bdry_cont, v_bdry_cont)
954 
955  au(:,:) = 0 ; av(:,:) = 0
956 
957  call cg_action(au, av, u, v, phi, phisub, cs%umask, cs%vmask, iss%hmask, h_node, &
958  cs%ice_visc, float_cond, g%bathyT(:,:), cs%taub_beta_eff, g%areaT, &
959  g, g%isc-1, g%iec+1, g%jsc-1, g%jec+1, rhoi_rhow)
960 
961  err_max = 0
962 
963  if (cs%nonlin_solve_err_mode == 1) then
964 
965  do j=jsumstart,g%jecB
966  do i=isumstart,g%iecB
967  if (cs%umask(i,j) == 1) then
968  err_tempu = abs(au(i,j) + u_bdry_cont(i,j) - taudx(i,j))
969  endif
970  if (cs%vmask(i,j) == 1) then
971  err_tempv = max(abs(av(i,j) + v_bdry_cont(i,j) - taudy(i,j)), err_tempu)
972  endif
973  if (err_tempv >= err_max) then
974  err_max = err_tempv
975  endif
976  enddo
977  enddo
978 
979  call max_across_pes(err_max)
980 
981  elseif (cs%nonlin_solve_err_mode == 2) then
982 
983  max_vel = 0 ; tempu = 0 ; tempv = 0
984 
985  do j=jsumstart,g%jecB
986  do i=isumstart,g%iecB
987  if (cs%umask(i,j) == 1) then
988  err_tempu = abs(u_last(i,j)-u(i,j))
989  tempu = u(i,j)
990  endif
991  if (cs%vmask(i,j) == 1) then
992  err_tempv = max(abs(v_last(i,j)- v(i,j)), err_tempu)
993  tempv = sqrt(v(i,j)**2+tempu**2)
994  endif
995  if (err_tempv >= err_max) then
996  err_max = err_tempv
997  endif
998  if (tempv >= max_vel) then
999  max_vel = tempv
1000  endif
1001  enddo
1002  enddo
1003 
1004  u_last(:,:) = u(:,:)
1005  v_last(:,:) = v(:,:)
1006 
1007  call max_across_pes(max_vel)
1008  call max_across_pes(err_max)
1009  err_init = max_vel
1010 
1011  endif
1012 
1013  write(mesg,*) "ice_shelf_solve_outer: nonlinear residual = ",err_max/err_init
1014  call mom_mesg(mesg, 5)
1015 
1016  if (err_max <= cs%nonlinear_tolerance * err_init) then
1017  write(mesg,*) "ice_shelf_solve_outer: exiting nonlinear solve after ",iter," iterations"
1018  call mom_mesg(mesg, 5)
1019  exit
1020  endif
1021 
1022  enddo
1023 
1024  deallocate(phi)
1025  deallocate(phisub)
1026 
1027 end subroutine ice_shelf_solve_outer
1028 
1029 subroutine ice_shelf_solve_inner(CS, ISS, G, u, v, taudx, taudy, H_node, float_cond, &
1030  hmask, conv_flag, iters, time, Phi, Phisub)
1031  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
1032  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
1033  !! the ice-shelf state
1034  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
1035  real, dimension(SZDIB_(G),SZDJB_(G)), &
1036  intent(inout) :: u !< The zonal ice shelf velocity at vertices [m year-1]
1037  real, dimension(SZDIB_(G),SZDJB_(G)), &
1038  intent(inout) :: v !< The meridional ice shelf velocity at vertices [m year-1]
1039  real, dimension(SZDIB_(G),SZDJB_(G)), &
1040  intent(in) :: taudx !< The x-direction driving stress, in ???
1041  real, dimension(SZDIB_(G),SZDJB_(G)), &
1042  intent(in) :: taudy !< The y-direction driving stress, in ???
1043  real, dimension(SZDIB_(G),SZDJB_(G)), &
1044  intent(in) :: H_node !< The ice shelf thickness at nodal (corner)
1045  !! points [Z ~> m].
1046  real, dimension(SZDI_(G),SZDJ_(G)), &
1047  intent(in) :: float_cond !< An array indicating where the ice
1048  !! shelf is floating: 0 if floating, 1 if not.
1049  real, dimension(SZDI_(G),SZDJ_(G)), &
1050  intent(in) :: hmask !< A mask indicating which tracer points are
1051  !! partly or fully covered by an ice-shelf
1052  integer, intent(out) :: conv_flag !< A flag indicating whether (1) or not (0) the
1053  !! iterations have converged to the specified tolerence
1054  integer, intent(out) :: iters !< The number of iterations used in the solver.
1055  type(time_type), intent(in) :: Time !< The current model time
1056  real, dimension(SZDI_(G),SZDJ_(G),8,4), &
1057  intent(in) :: Phi !< The gradients of bilinear basis elements at Gaussian
1058  !! quadrature points surrounding the cell verticies.
1059  real, dimension(:,:,:,:,:,:), &
1060  intent(in) :: Phisub !< Quadrature structure weights at subgridscale
1061  !! locations for finite element calculations
1062 ! one linear solve (nonlinear iteration) of the solution for velocity
1063 
1064 ! in this subroutine:
1065 ! boundary contributions are added to taud to get the RHS
1066 ! diagonal of matrix is found (for Jacobi precondition)
1067 ! CG iteration is carried out for max. iterations or until convergence
1068 
1069 ! assumed - u, v, taud, visc, beta_eff are valid on the halo
1070 
1071  real, dimension(SZDIB_(G),SZDJB_(G)) :: &
1072  Ru, Rv, Zu, Zv, DIAGu, DIAGv, RHSu, RHSv, &
1073  ubd, vbd, Au, Av, Du, Dv, &
1074  Zu_old, Zv_old, Ru_old, Rv_old, &
1075  sum_vec, sum_vec_2
1076  integer :: iter, i, j, isd, ied, jsd, jed, &
1077  isc, iec, jsc, jec, is, js, ie, je, isumstart, jsumstart, &
1078  isdq, iedq, jsdq, jedq, iscq, iecq, jscq, jecq, nx_halo, ny_halo
1079  real :: tol, beta_k, alpha_k, area, dot_p1, dot_p2, resid0, cg_halo, dot_p1a, dot_p2a
1080  character(2) :: gridsize
1081 
1082  real, dimension(8,4) :: Phi_temp
1083  real, dimension(2,2) :: X,Y
1084 
1085  isdq = g%isdB ; iedq = g%iedB ; jsdq = g%jsdB ; jedq = g%jedB
1086  iscq = g%iscB ; iecq = g%iecB ; jscq = g%jscB ; jecq = g%jecB
1087  ny_halo = g%domain%njhalo ; nx_halo = g%domain%nihalo
1088  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1089  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec
1090 
1091  zu(:,:) = 0 ; zv(:,:) = 0 ; diagu(:,:) = 0 ; diagv(:,:) = 0
1092  ru(:,:) = 0 ; rv(:,:) = 0 ; au(:,:) = 0 ; av(:,:) = 0
1093  du(:,:) = 0 ; dv(:,:) = 0 ; ubd(:,:) = 0 ; vbd(:,:) = 0
1094  dot_p1 = 0 ; dot_p2 = 0
1095 
1096  isumstart = g%isc
1097  ! Include the edge if tile is at the western bdry; Should add a test to avoid this if reentrant.
1098  if (g%isc+g%idg_offset==g%isg) isumstart = g%iscB
1099 
1100  jsumstart = g%jsc
1101  ! Include the edge if tile is at the southern bdry; Should add a test to avoid this if reentrant.
1102  if (g%jsc+g%jdg_offset==g%jsg) jsumstart = g%jscB
1103 
1104  call apply_boundary_values(cs, iss, g, time, phisub, h_node, cs%ice_visc, &
1105  cs%taub_beta_eff, float_cond, &
1106  cs%density_ice/cs%density_ocean_avg, ubd, vbd)
1107 
1108  rhsu(:,:) = taudx(:,:) - ubd(:,:)
1109  rhsv(:,:) = taudy(:,:) - vbd(:,:)
1110 
1111 
1112  call pass_vector(rhsu, rhsv, g%domain, to_all, bgrid_ne)
1113 
1114  call matrix_diagonal(cs, g, float_cond, h_node, cs%ice_visc, &
1115  cs%taub_beta_eff, hmask, &
1116  cs%density_ice/cs%density_ocean_avg, phisub, diagu, diagv)
1117 ! DIAGu(:,:) = 1 ; DIAGv(:,:) = 1
1118 
1119  call pass_vector(diagu, diagv, g%domain, to_all, bgrid_ne)
1120 
1121  call cg_action(au, av, u, v, phi, phisub, cs%umask, cs%vmask, hmask, &
1122  h_node, cs%ice_visc, float_cond, g%bathyT(:,:), cs%taub_beta_eff, &
1123  g%areaT, g, isc-1, iec+1, jsc-1, jec+1, cs%density_ice/cs%density_ocean_avg)
1124 
1125  call pass_vector(au, av, g%domain, to_all, bgrid_ne)
1126 
1127  ru(:,:) = rhsu(:,:) - au(:,:) ; rv(:,:) = rhsv(:,:) - av(:,:)
1128 
1129  if (.not. cs%use_reproducing_sums) then
1130 
1131  do j=jsumstart,jecq
1132  do i=isumstart,iecq
1133  if (cs%umask(i,j) == 1) dot_p1 = dot_p1 + ru(i,j)**2
1134  if (cs%vmask(i,j) == 1) dot_p1 = dot_p1 + rv(i,j)**2
1135  enddo
1136  enddo
1137 
1138  call sum_across_pes(dot_p1)
1139 
1140  else
1141 
1142  sum_vec(:,:) = 0.0
1143 
1144  do j=jsumstart,jecq
1145  do i=isumstart,iecq
1146  if (cs%umask(i,j) == 1) sum_vec(i,j) = ru(i,j)**2
1147  if (cs%vmask(i,j) == 1) sum_vec(i,j) = sum_vec(i,j) + rv(i,j)**2
1148  enddo
1149  enddo
1150 
1151  dot_p1 = reproducing_sum( sum_vec, isumstart+(1-g%IsdB), iecq+(1-g%IsdB), &
1152  jsumstart+(1-g%JsdB), jecq+(1-g%JsdB) )
1153 
1154  endif
1155 
1156  resid0 = sqrt(dot_p1)
1157 
1158  do j=jsdq,jedq
1159  do i=isdq,iedq
1160  if (cs%umask(i,j) == 1) zu(i,j) = ru(i,j) / diagu(i,j)
1161  if (cs%vmask(i,j) == 1) zv(i,j) = rv(i,j) / diagv(i,j)
1162  enddo
1163  enddo
1164 
1165  du(:,:) = zu(:,:) ; dv(:,:) = zv(:,:)
1166 
1167  cg_halo = 3
1168  conv_flag = 0
1169 
1170  !!!!!!!!!!!!!!!!!!
1171  !! !!
1172  !! MAIN CG LOOP !!
1173  !! !!
1174  !!!!!!!!!!!!!!!!!!
1175 
1176 
1177 
1178  ! initially, c-grid data is valid up to 3 halo nodes out
1179 
1180  do iter = 1,cs%cg_max_iterations
1181 
1182  ! assume asymmetry
1183  ! thus we can never assume that any arrays are legit more than 3 vertices past
1184  ! the computational domain - this is their state in the initial iteration
1185 
1186 
1187  is = isc - cg_halo ; ie = iecq + cg_halo
1188  js = jscq - cg_halo ; je = jecq + cg_halo
1189 
1190  au(:,:) = 0 ; av(:,:) = 0
1191 
1192  call cg_action(au, av, du, dv, phi, phisub, cs%umask, cs%vmask, hmask, &
1193  h_node, cs%ice_visc, float_cond, g%bathyT(:,:), cs%taub_beta_eff, &
1194  g%areaT, g, is, ie, js, je, cs%density_ice/cs%density_ocean_avg)
1195 
1196  ! Au, Av valid region moves in by 1
1197 
1198  if ( .not. cs%use_reproducing_sums) then
1199 
1200 
1201  ! alpha_k = (Z \dot R) / (D \dot AD}
1202  dot_p1 = 0 ; dot_p2 = 0
1203  do j=jsumstart,jecq
1204  do i=isumstart,iecq
1205  if (cs%umask(i,j) == 1) then
1206  dot_p1 = dot_p1 + zu(i,j)*ru(i,j)
1207  dot_p2 = dot_p2 + du(i,j)*au(i,j)
1208  endif
1209  if (cs%vmask(i,j) == 1) then
1210  dot_p1 = dot_p1 + zv(i,j)*rv(i,j)
1211  dot_p2 = dot_p2 + dv(i,j)*av(i,j)
1212  endif
1213  enddo
1214  enddo
1215  call sum_across_pes(dot_p1) ; call sum_across_pes(dot_p2)
1216  else
1217 
1218  sum_vec(:,:) = 0.0 ; sum_vec_2(:,:) = 0.0
1219 
1220  do j=jscq,jecq
1221  do i=iscq,iecq
1222  if (cs%umask(i,j) == 1) sum_vec(i,j) = zu(i,j) * ru(i,j)
1223  if (cs%vmask(i,j) == 1) sum_vec(i,j) = sum_vec(i,j) + zv(i,j) * rv(i,j)
1224 
1225  if (cs%umask(i,j) == 1) sum_vec_2(i,j) = du(i,j) * au(i,j)
1226  if (cs%vmask(i,j) == 1) sum_vec_2(i,j) = sum_vec_2(i,j) + dv(i,j) * av(i,j)
1227  enddo
1228  enddo
1229 
1230  dot_p1 = reproducing_sum( sum_vec, isumstart+(1-g%IsdB), iecq+(1-g%IsdB), &
1231  jsumstart+(1-g%JsdB), jecq+(1-g%JsdB) )
1232 
1233  dot_p2 = reproducing_sum( sum_vec_2, isumstart+(1-g%IsdB), iecq+(1-g%IsdB), &
1234  jsumstart+(1-g%JsdB), jecq+(1-g%JsdB) )
1235  endif
1236 
1237  alpha_k = dot_p1/dot_p2
1238 
1239  do j=jsd,jed
1240  do i=isd,ied
1241  if (cs%umask(i,j) == 1) u(i,j) = u(i,j) + alpha_k * du(i,j)
1242  if (cs%vmask(i,j) == 1) v(i,j) = v(i,j) + alpha_k * dv(i,j)
1243  enddo
1244  enddo
1245 
1246  do j=jsd,jed
1247  do i=isd,ied
1248  if (cs%umask(i,j) == 1) then
1249  ru_old(i,j) = ru(i,j) ; zu_old(i,j) = zu(i,j)
1250  endif
1251  if (cs%vmask(i,j) == 1) then
1252  rv_old(i,j) = rv(i,j) ; zv_old(i,j) = zv(i,j)
1253  endif
1254  enddo
1255  enddo
1256 
1257 ! Ru(:,:) = Ru(:,:) - alpha_k * Au(:,:)
1258 ! Rv(:,:) = Rv(:,:) - alpha_k * Av(:,:)
1259 
1260  do j=jsd,jed
1261  do i=isd,ied
1262  if (cs%umask(i,j) == 1) ru(i,j) = ru(i,j) - alpha_k * au(i,j)
1263  if (cs%vmask(i,j) == 1) rv(i,j) = rv(i,j) - alpha_k * av(i,j)
1264  enddo
1265  enddo
1266 
1267 
1268  do j=jsdq,jedq
1269  do i=isdq,iedq
1270  if (cs%umask(i,j) == 1) then
1271  zu(i,j) = ru(i,j) / diagu(i,j)
1272  endif
1273  if (cs%vmask(i,j) == 1) then
1274  zv(i,j) = rv(i,j) / diagv(i,j)
1275  endif
1276  enddo
1277  enddo
1278 
1279  ! R,u,v,Z valid region moves in by 1
1280 
1281  if (.not. cs%use_reproducing_sums) then
1282 
1283  ! beta_k = (Z \dot R) / (Zold \dot Rold}
1284  dot_p1 = 0 ; dot_p2 = 0
1285  do j=jsumstart,jecq
1286  do i=isumstart,iecq
1287  if (cs%umask(i,j) == 1) then
1288  dot_p1 = dot_p1 + zu(i,j)*ru(i,j)
1289  dot_p2 = dot_p2 + zu_old(i,j)*ru_old(i,j)
1290  endif
1291  if (cs%vmask(i,j) == 1) then
1292  dot_p1 = dot_p1 + zv(i,j)*rv(i,j)
1293  dot_p2 = dot_p2 + zv_old(i,j)*rv_old(i,j)
1294  endif
1295  enddo
1296  enddo
1297  call sum_across_pes(dot_p1) ; call sum_across_pes(dot_p2)
1298 
1299 
1300  else
1301 
1302  sum_vec(:,:) = 0.0 ; sum_vec_2(:,:) = 0.0
1303 
1304  do j=jsumstart,jecq
1305  do i=isumstart,iecq
1306  if (cs%umask(i,j) == 1) sum_vec(i,j) = zu(i,j) * ru(i,j)
1307  if (cs%vmask(i,j) == 1) sum_vec(i,j) = sum_vec(i,j) + &
1308  zv(i,j) * rv(i,j)
1309 
1310  if (cs%umask(i,j) == 1) sum_vec_2(i,j) = zu_old(i,j) * ru_old(i,j)
1311  if (cs%vmask(i,j) == 1) sum_vec_2(i,j) = sum_vec_2(i,j) + &
1312  zv_old(i,j) * rv_old(i,j)
1313  enddo
1314  enddo
1315 
1316 
1317  dot_p1 = reproducing_sum(sum_vec, isumstart+(1-g%IsdB), iecq+(1-g%IsdB), &
1318  jsumstart+(1-g%JsdB), jecq+(1-g%JsdB) )
1319 
1320  dot_p2 = reproducing_sum(sum_vec_2, isumstart+(1-g%IsdB), iecq+(1-g%IsdB), &
1321  jsumstart+(1-g%JsdB), jecq+(1-g%JsdB) )
1322 
1323  endif
1324 
1325  beta_k = dot_p1/dot_p2
1326 
1327 
1328 ! Du(:,:) = Zu(:,:) + beta_k * Du(:,:)
1329 ! Dv(:,:) = Zv(:,:) + beta_k * Dv(:,:)
1330 
1331  do j=jsd,jed
1332  do i=isd,ied
1333  if (cs%umask(i,j) == 1) du(i,j) = zu(i,j) + beta_k * du(i,j)
1334  if (cs%vmask(i,j) == 1) dv(i,j) = zv(i,j) + beta_k * dv(i,j)
1335  enddo
1336  enddo
1337 
1338  ! D valid region moves in by 1
1339 
1340  dot_p1 = 0
1341 
1342  if (.not. cs%use_reproducing_sums) then
1343 
1344  do j=jsumstart,jecq
1345  do i=isumstart,iecq
1346  if (cs%umask(i,j) == 1) then
1347  dot_p1 = dot_p1 + ru(i,j)**2
1348  endif
1349  if (cs%vmask(i,j) == 1) then
1350  dot_p1 = dot_p1 + rv(i,j)**2
1351  endif
1352  enddo
1353  enddo
1354  call sum_across_pes(dot_p1)
1355 
1356  else
1357 
1358  sum_vec(:,:) = 0.0
1359 
1360  do j=jsumstart,jecq
1361  do i=isumstart,iecq
1362  if (cs%umask(i,j) == 1) sum_vec(i,j) = ru(i,j)**2
1363  if (cs%vmask(i,j) == 1) sum_vec(i,j) = sum_vec(i,j) + rv(i,j)**2
1364  enddo
1365  enddo
1366 
1367  dot_p1 = reproducing_sum( sum_vec, isumstart+(1-g%IsdB), iecq+(1-g%IsdB), &
1368  jsumstart+(1-g%JsdB), jecq+(1-g%JsdB) )
1369  endif
1370 
1371  dot_p1 = sqrt(dot_p1)
1372 
1373  if (dot_p1 <= cs%cg_tolerance * resid0) then
1374  iters = iter
1375  conv_flag = 1
1376  exit
1377  endif
1378 
1379  cg_halo = cg_halo - 1
1380 
1381  if (cg_halo == 0) then
1382  ! pass vectors
1383  call pass_vector(du, dv, g%domain, to_all, bgrid_ne)
1384  call pass_vector(u, v, g%domain, to_all, bgrid_ne)
1385  call pass_vector(ru, rv, g%domain, to_all, bgrid_ne)
1386  cg_halo = 3
1387  endif
1388 
1389  enddo ! end of CG loop
1390 
1391  do j=jsdq,jedq
1392  do i=isdq,iedq
1393  if (cs%umask(i,j) == 3) then
1394  u(i,j) = cs%u_bdry_val(i,j)
1395  elseif (cs%umask(i,j) == 0) then
1396  u(i,j) = 0
1397  endif
1398 
1399  if (cs%vmask(i,j) == 3) then
1400  v(i,j) = cs%v_bdry_val(i,j)
1401  elseif (cs%vmask(i,j) == 0) then
1402  v(i,j) = 0
1403  endif
1404  enddo
1405  enddo
1406 
1407  call pass_vector(u,v, g%domain, to_all, bgrid_ne)
1408 
1409  if (conv_flag == 0) then
1410  iters = cs%cg_max_iterations
1411  endif
1412 
1413 end subroutine ice_shelf_solve_inner
1414 
1415 subroutine ice_shelf_advect_thickness_x(CS, G, time_step, hmask, h0, h_after_uflux, flux_enter)
1416  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
1417  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
1418  real, intent(in) :: time_step !< The time step for this update [s].
1419  real, dimension(SZDI_(G),SZDJ_(G)), &
1420  intent(inout) :: hmask !< A mask indicating which tracer points are
1421  !! partly or fully covered by an ice-shelf
1422  real, dimension(SZDI_(G),SZDJ_(G)), &
1423  intent(in) :: h0 !< The initial ice shelf thicknesses [Z ~> m].
1424  real, dimension(SZDI_(G),SZDJ_(G)), &
1425  intent(inout) :: h_after_uflux !< The ice shelf thicknesses after
1426  !! the zonal mass fluxes [Z ~> m].
1427  real, dimension(SZDI_(G),SZDJ_(G),4), &
1428  intent(inout) :: flux_enter !< The ice volume flux into the cell
1429  !! through the 4 cell boundaries [Z m2 ~> m3].
1430 
1431  ! use will be made of ISS%hmask here - its value at the boundary will be zero, just like uncovered cells
1432 
1433  ! if there is an input bdry condition, the thickness there will be set in initialization
1434 
1435  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
1436  !
1437  ! from left neighbor: flux_enter(:,:,1)
1438  ! from right neighbor: flux_enter(:,:,2)
1439  ! from bottom neighbor: flux_enter(:,:,3)
1440  ! from top neighbor: flux_enter(:,:,4)
1441  !
1442  ! o--- (4) ---o
1443  ! | |
1444  ! (1) (2)
1445  ! | |
1446  ! o--- (3) ---o
1447  !
1448 
1449  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed, gjed, gied
1450  integer :: i_off, j_off
1451  logical :: at_east_bdry, at_west_bdry, one_off_west_bdry, one_off_east_bdry
1452  real, dimension(-2:2) :: stencil ! Thicknesses [Z ~> m].
1453  real :: u_face, & ! positive if out
1454  flux_diff_cell, phi, dxh, dyh, dxdyh
1455  character (len=1) :: debug_str
1456 
1457  is = g%isc-2 ; ie = g%iec+2 ; js = g%jsc ; je = g%jec
1458  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1459  i_off = g%idg_offset ; j_off = g%jdg_offset
1460 
1461  do j=jsd+1,jed-1
1462  if (((j+j_off) <= g%domain%njglobal+g%domain%njhalo) .AND. &
1463  ((j+j_off) >= g%domain%njhalo+1)) then ! based on mehmet's code - only if btw north & south boundaries
1464 
1465  stencil(:) = -1.
1466 ! if (i+i_off == G%domain%nihalo+G%domain%nihalo)
1467  do i=is,ie
1468 
1469  if (((i+i_off) <= g%domain%niglobal+g%domain%nihalo) .AND. &
1470  ((i+i_off) >= g%domain%nihalo+1)) then
1471 
1472  if (i+i_off == g%domain%nihalo+1) then
1473  at_west_bdry=.true.
1474  else
1475  at_west_bdry=.false.
1476  endif
1477 
1478  if (i+i_off == g%domain%niglobal+g%domain%nihalo) then
1479  at_east_bdry=.true.
1480  else
1481  at_east_bdry=.false.
1482  endif
1483 
1484  if (hmask(i,j) == 1) then
1485 
1486  dxh = g%dxT(i,j) ; dyh = g%dyT(i,j) ; dxdyh = g%areaT(i,j)
1487 
1488  h_after_uflux(i,j) = h0(i,j)
1489 
1490  stencil(:) = h0(i-2:i+2,j) ! fine as long has nx_halo >= 2
1491 
1492  flux_diff_cell = 0
1493 
1494  ! 1ST DO LEFT FACE
1495 
1496  if (cs%u_face_mask(i-1,j) == 4.) then
1497 
1498  flux_diff_cell = flux_diff_cell + dyh * time_step * cs%u_flux_bdry_val(i-1,j) / dxdyh
1499 
1500  else
1501 
1502  ! get u-velocity at center of left face
1503  u_face = 0.5 * (cs%u_shelf(i-1,j-1) + cs%u_shelf(i-1,j))
1504 
1505  if (u_face > 0) then !flux is into cell - we need info from h(i-2), h(i-1) if available
1506 
1507  ! i may not cover all the cases.. but i cover the realistic ones
1508 
1509  if (at_west_bdry .AND. (hmask(i-1,j) == 3)) then ! at western bdry but there is a
1510  ! thickness bdry condition, and the stencil contains it
1511  stencil(-1) = cs%thickness_bdry_val(i-1,j)
1512  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step * stencil(-1) / dxdyh
1513 
1514  elseif (hmask(i-1,j) * hmask(i-2,j) == 1) then ! h(i-2) and h(i-1) are valid
1515  phi = slope_limiter(stencil(-1)-stencil(-2), stencil(0)-stencil(-1))
1516  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh* time_step / dxdyh * &
1517  (stencil(-1) - phi * (stencil(-1)-stencil(0))/2)
1518 
1519  else ! h(i-1) is valid
1520  ! (o.w. flux would most likely be out of cell)
1521  ! but h(i-2) is not
1522 
1523  flux_diff_cell = flux_diff_cell + abs(u_face) * (dyh * time_step / dxdyh) * stencil(-1)
1524 
1525  endif
1526 
1527  elseif (u_face < 0) then !flux is out of cell - we need info from h(i-1), h(i+1) if available
1528  if (hmask(i-1,j) * hmask(i+1,j) == 1) then ! h(i-1) and h(i+1) are both valid
1529  phi = slope_limiter(stencil(0)-stencil(1), stencil(-1)-stencil(0))
1530  flux_diff_cell = flux_diff_cell - abs(u_face) * dyh * time_step / dxdyh * &
1531  (stencil(0) - phi * (stencil(0)-stencil(-1))/2)
1532 
1533  else
1534  flux_diff_cell = flux_diff_cell - abs(u_face) * (dyh * time_step / dxdyh) * stencil(0)
1535 
1536  if ((hmask(i-1,j) == 0) .OR. (hmask(i-1,j) == 2)) then
1537  flux_enter(i-1,j,2) = abs(u_face) * dyh * time_step * stencil(0)
1538  endif
1539  endif
1540  endif
1541  endif
1542 
1543  ! NEXT DO RIGHT FACE
1544 
1545  ! get u-velocity at center of right face
1546 
1547  if (cs%u_face_mask(i+1,j) == 4.) then
1548 
1549  flux_diff_cell = flux_diff_cell + dyh * time_step * cs%u_flux_bdry_val(i+1,j) / dxdyh
1550 
1551  else
1552 
1553  u_face = 0.5 * (cs%u_shelf(i,j-1) + cs%u_shelf(i,j))
1554 
1555  if (u_face < 0) then !flux is into cell - we need info from h(i+2), h(i+1) if available
1556 
1557  if (at_east_bdry .AND. (hmask(i+1,j) == 3)) then ! at eastern bdry but there is a
1558  ! thickness bdry condition, and the stencil contains it
1559 
1560  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step * stencil(1) / dxdyh
1561 
1562  elseif (hmask(i+1,j) * hmask(i+2,j) == 1) then ! h(i+2) and h(i+1) are valid
1563 
1564  phi = slope_limiter(stencil(1)-stencil(2), stencil(0)-stencil(1))
1565  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step / dxdyh * &
1566  (stencil(1) - phi * (stencil(1)-stencil(0))/2)
1567 
1568  else ! h(i+1) is valid
1569  ! (o.w. flux would most likely be out of cell)
1570  ! but h(i+2) is not
1571 
1572  flux_diff_cell = flux_diff_cell + abs(u_face) * (dyh * time_step / dxdyh) * stencil(1)
1573 
1574  endif
1575 
1576  elseif (u_face > 0) then !flux is out of cell - we need info from h(i-1), h(i+1) if available
1577 
1578  if (hmask(i-1,j) * hmask(i+1,j) == 1) then ! h(i-1) and h(i+1) are both valid
1579 
1580  phi = slope_limiter(stencil(0)-stencil(-1), stencil(1)-stencil(0))
1581  flux_diff_cell = flux_diff_cell - abs(u_face) * dyh * time_step / dxdyh * &
1582  (stencil(0) - phi * (stencil(0)-stencil(1))/2)
1583 
1584  else ! h(i+1) is valid
1585  ! (o.w. flux would most likely be out of cell)
1586  ! but h(i+2) is not
1587 
1588  flux_diff_cell = flux_diff_cell - abs(u_face) * (dyh * time_step / dxdyh) * stencil(0)
1589 
1590  if ((hmask(i+1,j) == 0) .OR. (hmask(i+1,j) == 2)) then
1591  flux_enter(i+1,j,1) = abs(u_face) * dyh * time_step * stencil(0)
1592  endif
1593 
1594  endif
1595 
1596  endif
1597 
1598  h_after_uflux(i,j) = h_after_uflux(i,j) + flux_diff_cell
1599 
1600  endif
1601 
1602  elseif ((hmask(i,j) == 0) .OR. (hmask(i,j) == 2)) then
1603 
1604  if (at_west_bdry .AND. (hmask(i-1,j) == 3)) then
1605  u_face = 0.5 * (cs%u_shelf(i-1,j-1) + cs%u_shelf(i-1,j))
1606  flux_enter(i,j,1) = abs(u_face) * g%dyT(i,j) * time_step * cs%thickness_bdry_val(i-1,j)
1607  elseif (cs%u_face_mask(i-1,j) == 4.) then
1608  flux_enter(i,j,1) = g%dyT(i,j) * time_step * cs%u_flux_bdry_val(i-1,j)
1609  endif
1610 
1611  if (at_east_bdry .AND. (hmask(i+1,j) == 3)) then
1612  u_face = 0.5 * (cs%u_shelf(i,j-1) + cs%u_shelf(i,j))
1613  flux_enter(i,j,2) = abs(u_face) * g%dyT(i,j) * time_step * cs%thickness_bdry_val(i+1,j)
1614  elseif (cs%u_face_mask(i+1,j) == 4.) then
1615  flux_enter(i,j,2) = g%dyT(i,j) * time_step * cs%u_flux_bdry_val(i+1,j)
1616  endif
1617 
1618  if ((i == is) .AND. (hmask(i,j) == 0) .AND. (hmask(i-1,j) == 1)) then
1619  ! this is solely for the purposes of keeping the mask consistent while advancing
1620  ! the front without having to call pass_var - if cell is empty and cell to left
1621  ! is ice-covered then this cell will become partly covered
1622 
1623  hmask(i,j) = 2
1624  elseif ((i == ie) .AND. (hmask(i,j) == 0) .AND. (hmask(i+1,j) == 1)) then
1625  ! this is solely for the purposes of keeping the mask consistent while advancing
1626  ! the front without having to call pass_var - if cell is empty and cell to left
1627  ! is ice-covered then this cell will become partly covered
1628 
1629  hmask(i,j) = 2
1630 
1631  endif
1632 
1633  endif
1634 
1635  endif
1636 
1637  enddo ! i loop
1638 
1639  endif
1640 
1641  enddo ! j loop
1642 
1643 end subroutine ice_shelf_advect_thickness_x
1644 
1645 subroutine ice_shelf_advect_thickness_y(CS, G, time_step, hmask, h_after_uflux, h_after_vflux, flux_enter)
1646  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
1647  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
1648  real, intent(in) :: time_step !< The time step for this update [s].
1649  real, dimension(SZDI_(G),SZDJ_(G)), &
1650  intent(inout) :: hmask !< A mask indicating which tracer points are
1651  !! partly or fully covered by an ice-shelf
1652  real, dimension(SZDI_(G),SZDJ_(G)), &
1653  intent(in) :: h_after_uflux !< The ice shelf thicknesses after
1654  !! the zonal mass fluxes [Z ~> m].
1655  real, dimension(SZDI_(G),SZDJ_(G)), &
1656  intent(inout) :: h_after_vflux !< The ice shelf thicknesses after
1657  !! the meridional mass fluxes [Z ~> m].
1658  real, dimension(SZDI_(G),SZDJ_(G),4), &
1659  intent(inout) :: flux_enter !< The ice volume flux into the cell
1660  !! through the 4 cell boundaries [Z m2 ~> m3].
1661 
1662  ! use will be made of ISS%hmask here - its value at the boundary will be zero, just like uncovered cells
1663 
1664  ! if there is an input bdry condition, the thickness there will be set in initialization
1665 
1666  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
1667  !
1668  ! from left neighbor: flux_enter(:,:,1)
1669  ! from right neighbor: flux_enter(:,:,2)
1670  ! from bottom neighbor: flux_enter(:,:,3)
1671  ! from top neighbor: flux_enter(:,:,4)
1672  !
1673  ! o--- (4) ---o
1674  ! | |
1675  ! (1) (2)
1676  ! | |
1677  ! o--- (3) ---o
1678  !
1679 
1680  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed, gjed, gied
1681  integer :: i_off, j_off
1682  logical :: at_north_bdry, at_south_bdry, one_off_west_bdry, one_off_east_bdry
1683  real, dimension(-2:2) :: stencil ! Thicknesses [Z ~> m].
1684  real :: v_face, & ! positive if out
1685  flux_diff_cell, phi, dxh, dyh, dxdyh
1686  character(len=1) :: debug_str
1687 
1688  is = g%isc ; ie = g%iec ; js = g%jsc-1 ; je = g%jec+1 ; isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1689  i_off = g%idg_offset ; j_off = g%jdg_offset
1690 
1691  do i=isd+2,ied-2
1692  if (((i+i_off) <= g%domain%niglobal+g%domain%nihalo) .AND. &
1693  ((i+i_off) >= g%domain%nihalo+1)) then ! based on Mehmet's code - only if btw east & west boundaries
1694 
1695  stencil(:) = -1
1696 
1697  do j=js,je
1698 
1699  if (((j+j_off) <= g%domain%njglobal+g%domain%njhalo) .AND. &
1700  ((j+j_off) >= g%domain%njhalo+1)) then
1701 
1702  if (j+j_off == g%domain%njhalo+1) then
1703  at_south_bdry=.true.
1704  else
1705  at_south_bdry=.false.
1706  endif
1707 
1708  if (j+j_off == g%domain%njglobal+g%domain%njhalo) then
1709  at_north_bdry=.true.
1710  else
1711  at_north_bdry=.false.
1712  endif
1713 
1714  if (hmask(i,j) == 1) then
1715  dxh = g%dxT(i,j) ; dyh = g%dyT(i,j) ; dxdyh = g%areaT(i,j)
1716  h_after_vflux(i,j) = h_after_uflux(i,j)
1717 
1718  stencil(:) = h_after_uflux(i,j-2:j+2) ! fine as long has ny_halo >= 2
1719  flux_diff_cell = 0
1720 
1721  ! 1ST DO south FACE
1722 
1723  if (cs%v_face_mask(i,j-1) == 4.) then
1724 
1725  flux_diff_cell = flux_diff_cell + dxh * time_step * cs%v_flux_bdry_val(i,j-1) / dxdyh
1726 
1727  else
1728 
1729  ! get u-velocity at center of left face
1730  v_face = 0.5 * (cs%v_shelf(i-1,j-1) + cs%v_shelf(i,j-1))
1731 
1732  if (v_face > 0) then !flux is into cell - we need info from h(j-2), h(j-1) if available
1733 
1734  ! i may not cover all the cases.. but i cover the realistic ones
1735 
1736  if (at_south_bdry .AND. (hmask(i,j-1) == 3)) then ! at western bdry but there is a
1737  ! thickness bdry condition, and the stencil contains it
1738  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step * stencil(-1) / dxdyh
1739 
1740  elseif (hmask(i,j-1) * hmask(i,j-2) == 1) then ! h(j-2) and h(j-1) are valid
1741 
1742  phi = slope_limiter(stencil(-1)-stencil(-2), stencil(0)-stencil(-1))
1743  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * &
1744  (stencil(-1) - phi * (stencil(-1)-stencil(0))/2)
1745 
1746  else ! h(j-1) is valid
1747  ! (o.w. flux would most likely be out of cell)
1748  ! but h(j-2) is not
1749  flux_diff_cell = flux_diff_cell + abs(v_face) * (dxh * time_step / dxdyh) * stencil(-1)
1750  endif
1751 
1752  elseif (v_face < 0) then !flux is out of cell - we need info from h(j-1), h(j+1) if available
1753 
1754  if (hmask(i,j-1) * hmask(i,j+1) == 1) then ! h(j-1) and h(j+1) are both valid
1755  phi = slope_limiter(stencil(0)-stencil(1), stencil(-1)-stencil(0))
1756  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * &
1757  (stencil(0) - phi * (stencil(0)-stencil(-1))/2)
1758  else
1759  flux_diff_cell = flux_diff_cell - abs(v_face) * (dxh * time_step / dxdyh) * stencil(0)
1760 
1761  if ((hmask(i,j-1) == 0) .OR. (hmask(i,j-1) == 2)) then
1762  flux_enter(i,j-1,4) = abs(v_face) * dyh * time_step * stencil(0)
1763  endif
1764 
1765  endif
1766 
1767  endif
1768 
1769  endif
1770 
1771  ! NEXT DO north FACE
1772 
1773  if (cs%v_face_mask(i,j+1) == 4.) then
1774 
1775  flux_diff_cell = flux_diff_cell + dxh * time_step * cs%v_flux_bdry_val(i,j+1) / dxdyh
1776 
1777  else
1778 
1779  ! get u-velocity at center of right face
1780  v_face = 0.5 * (cs%v_shelf(i-1,j) + cs%v_shelf(i,j))
1781 
1782  if (v_face < 0) then !flux is into cell - we need info from h(j+2), h(j+1) if available
1783 
1784  if (at_north_bdry .AND. (hmask(i,j+1) == 3)) then ! at eastern bdry but there is a
1785  ! thickness bdry condition, and the stencil contains it
1786  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step * stencil(1) / dxdyh
1787  elseif (hmask(i,j+1) * hmask(i,j+2) == 1) then ! h(j+2) and h(j+1) are valid
1788  phi = slope_limiter(stencil(1)-stencil(2), stencil(0)-stencil(1))
1789  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * &
1790  (stencil(1) - phi * (stencil(1)-stencil(0))/2)
1791  else ! h(j+1) is valid
1792  ! (o.w. flux would most likely be out of cell)
1793  ! but h(j+2) is not
1794  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * stencil(1)
1795  endif
1796 
1797  elseif (v_face > 0) then !flux is out of cell - we need info from h(j-1), h(j+1) if available
1798 
1799  if (hmask(i,j-1) * hmask(i,j+1) == 1) then ! h(j-1) and h(j+1) are both valid
1800  phi = slope_limiter(stencil(0)-stencil(-1), stencil(1)-stencil(0))
1801  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * &
1802  (stencil(0) - phi * (stencil(0)-stencil(1))/2)
1803  else ! h(j+1) is valid
1804  ! (o.w. flux would most likely be out of cell)
1805  ! but h(j+2) is not
1806  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * stencil(0)
1807  if ((hmask(i,j+1) == 0) .OR. (hmask(i,j+1) == 2)) then
1808  flux_enter(i,j+1,3) = abs(v_face) * dxh * time_step * stencil(0)
1809  endif
1810  endif
1811 
1812  endif
1813 
1814  endif
1815 
1816  h_after_vflux(i,j) = h_after_vflux(i,j) + flux_diff_cell
1817 
1818  elseif ((hmask(i,j) == 0) .OR. (hmask(i,j) == 2)) then
1819 
1820  if (at_south_bdry .AND. (hmask(i,j-1) == 3)) then
1821  v_face = 0.5 * (cs%u_shelf(i-1,j-1) + cs%u_shelf(i,j-1))
1822  flux_enter(i,j,3) = abs(v_face) * g%dxT(i,j) * time_step * cs%thickness_bdry_val(i,j-1)
1823  elseif (cs%v_face_mask(i,j-1) == 4.) then
1824  flux_enter(i,j,3) = g%dxT(i,j) * time_step * cs%v_flux_bdry_val(i,j-1)
1825  endif
1826 
1827  if (at_north_bdry .AND. (hmask(i,j+1) == 3)) then
1828  v_face = 0.5 * (cs%u_shelf(i-1,j) + cs%u_shelf(i,j))
1829  flux_enter(i,j,4) = abs(v_face) * g%dxT(i,j) * time_step * cs%thickness_bdry_val(i,j+1)
1830  elseif (cs%v_face_mask(i,j+1) == 4.) then
1831  flux_enter(i,j,4) = g%dxT(i,j) * time_step * cs%v_flux_bdry_val(i,j+1)
1832  endif
1833 
1834  if ((j == js) .AND. (hmask(i,j) == 0) .AND. (hmask(i,j-1) == 1)) then
1835  ! this is solely for the purposes of keeping the mask consistent while advancing
1836  ! the front without having to call pass_var - if cell is empty and cell to left
1837  ! is ice-covered then this cell will become partly covered
1838  hmask(i,j) = 2
1839  elseif ((j == je) .AND. (hmask(i,j) == 0) .AND. (hmask(i,j+1) == 1)) then
1840  ! this is solely for the purposes of keeping the mask consistent while advancing
1841  ! the front without having to call pass_var - if cell is empty and cell to left
1842  ! is ice-covered then this cell will become partly covered
1843  hmask(i,j) = 2
1844  endif
1845 
1846  endif
1847  endif
1848  enddo ! j loop
1849  endif
1850  enddo ! i loop
1851 
1852 end subroutine ice_shelf_advect_thickness_y
1853 
1854 subroutine shelf_advance_front(CS, ISS, G, flux_enter)
1855  type(ice_shelf_dyn_cs), intent(in) :: cs !< A pointer to the ice shelf control structure
1856  type(ice_shelf_state), intent(inout) :: iss !< A structure with elements that describe
1857  !! the ice-shelf state
1858  type(ocean_grid_type), intent(in) :: g !< The grid structure used by the ice shelf.
1859  real, dimension(SZDI_(G),SZDJ_(G),4), &
1860  intent(inout) :: flux_enter !< The ice volume flux into the cell
1861  !! through the 4 cell boundaries [Z m2 ~> m3].
1862 
1863  ! in this subroutine we go through the computational cells only and, if they are empty or partial cells,
1864  ! we find the reference thickness and update the shelf mass and partial area fraction and the hmask if necessary
1865 
1866  ! if any cells go from partial to complete, we then must set the thickness, update hmask accordingly,
1867  ! and divide the overflow across the adjacent EMPTY (not partly-covered) cells.
1868  ! (it is highly unlikely there will not be any; in which case this will need to be rethought.)
1869 
1870  ! most likely there will only be one "overflow". if not, though, a pass_var of all relevant variables
1871  ! is done; there will therefore be a loop which, in practice, will hopefully not have to go through
1872  ! many iterations
1873 
1874  ! when 3d advected scalars are introduced, they will be impacted by what is done here
1875 
1876  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
1877  !
1878  ! from left neighbor: flux_enter(:,:,1)
1879  ! from right neighbor: flux_enter(:,:,2)
1880  ! from bottom neighbor: flux_enter(:,:,3)
1881  ! from top neighbor: flux_enter(:,:,4)
1882  !
1883  ! o--- (4) ---o
1884  ! | |
1885  ! (1) (2)
1886  ! | |
1887  ! o--- (3) ---o
1888  !
1889 
1890  integer :: i, j, isc, iec, jsc, jec, n_flux, k, l, iter_count
1891  integer :: i_off, j_off
1892  integer :: iter_flag
1893 
1894  real :: h_reference, dxh, dyh, dxdyh, rho, partial_vol, tot_flux
1895  character(len=160) :: mesg ! The text of an error message
1896  integer, dimension(4) :: mapi, mapj, new_partial
1897 ! real, dimension(size(flux_enter,1),size(flux_enter,2),size(flux_enter,2)) :: flux_enter_replace
1898  real, dimension(SZDI_(G),SZDJ_(G),4) :: flux_enter_replace
1899 
1900  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec
1901  i_off = g%idg_offset ; j_off = g%jdg_offset
1902  rho = cs%density_ice
1903  iter_count = 0 ; iter_flag = 1
1904 
1905 
1906  mapi(1) = -1 ; mapi(2) = 1 ; mapi(3:4) = 0
1907  mapj(3) = -1 ; mapj(4) = 1 ; mapj(1:2) = 0
1908 
1909  do while (iter_flag == 1)
1910 
1911  iter_flag = 0
1912 
1913  if (iter_count > 0) then
1914  flux_enter(:,:,:) = flux_enter_replace(:,:,:)
1915  endif
1916  flux_enter_replace(:,:,:) = 0.0
1917 
1918  iter_count = iter_count + 1
1919 
1920  ! if iter_count >= 3 then some halo updates need to be done...
1921 
1922  do j=jsc-1,jec+1
1923 
1924  if (((j+j_off) <= g%domain%njglobal+g%domain%njhalo) .AND. &
1925  ((j+j_off) >= g%domain%njhalo+1)) then
1926 
1927  do i=isc-1,iec+1
1928 
1929  if (((i+i_off) <= g%domain%niglobal+g%domain%nihalo) .AND. &
1930  ((i+i_off) >= g%domain%nihalo+1)) then
1931  ! first get reference thickness by averaging over cells that are fluxing into this cell
1932  n_flux = 0
1933  h_reference = 0.0
1934  tot_flux = 0.0
1935 
1936  do k=1,2
1937  if (flux_enter(i,j,k) > 0) then
1938  n_flux = n_flux + 1
1939  h_reference = h_reference + iss%h_shelf(i+2*k-3,j)
1940  tot_flux = tot_flux + flux_enter(i,j,k)
1941  flux_enter(i,j,k) = 0.0
1942  endif
1943  enddo
1944 
1945  do k=1,2
1946  if (flux_enter(i,j,k+2) > 0) then
1947  n_flux = n_flux + 1
1948  h_reference = h_reference + iss%h_shelf(i,j+2*k-3)
1949  tot_flux = tot_flux + flux_enter(i,j,k+2)
1950  flux_enter(i,j,k+2) = 0.0
1951  endif
1952  enddo
1953 
1954  if (n_flux > 0) then
1955  dxdyh = g%areaT(i,j)
1956  h_reference = h_reference / real(n_flux)
1957  partial_vol = iss%h_shelf(i,j) * iss%area_shelf_h(i,j) + tot_flux
1958 
1959  if ((partial_vol / dxdyh) == h_reference) then ! cell is exactly covered, no overflow
1960  iss%hmask(i,j) = 1
1961  iss%h_shelf(i,j) = h_reference
1962  iss%area_shelf_h(i,j) = dxdyh
1963  elseif ((partial_vol / dxdyh) < h_reference) then
1964  iss%hmask(i,j) = 2
1965  ! ISS%mass_shelf(i,j) = partial_vol * rho
1966  iss%area_shelf_h(i,j) = partial_vol / h_reference
1967  iss%h_shelf(i,j) = h_reference
1968  else
1969 
1970  iss%hmask(i,j) = 1
1971  iss%area_shelf_h(i,j) = dxdyh
1972  !h_temp(i,j) = h_reference
1973  partial_vol = partial_vol - h_reference * dxdyh
1974 
1975  iter_flag = 1
1976 
1977  n_flux = 0 ; new_partial(:) = 0
1978 
1979  do k=1,2
1980  if (cs%u_face_mask(i-2+k,j) == 2) then
1981  n_flux = n_flux + 1
1982  elseif (iss%hmask(i+2*k-3,j) == 0) then
1983  n_flux = n_flux + 1
1984  new_partial(k) = 1
1985  endif
1986  enddo
1987  do k=1,2
1988  if (cs%v_face_mask(i,j-2+k) == 2) then
1989  n_flux = n_flux + 1
1990  elseif (iss%hmask(i,j+2*k-3) == 0) then
1991  n_flux = n_flux + 1
1992  new_partial(k+2) = 1
1993  endif
1994  enddo
1995 
1996  if (n_flux == 0) then ! there is nowhere to put the extra ice!
1997  iss%h_shelf(i,j) = h_reference + partial_vol / dxdyh
1998  else
1999  iss%h_shelf(i,j) = h_reference
2000 
2001  do k=1,2
2002  if (new_partial(k) == 1) &
2003  flux_enter_replace(i+2*k-3,j,3-k) = partial_vol / real(n_flux)
2004  enddo
2005  do k=1,2 ! ### Combine these two loops?
2006  if (new_partial(k+2) == 1) &
2007  flux_enter_replace(i,j+2*k-3,5-k) = partial_vol / real(n_flux)
2008  enddo
2009  endif
2010 
2011  endif ! Parital_vol test.
2012  endif ! n_flux gt 0 test.
2013 
2014  endif
2015  enddo ! j-loop
2016  endif
2017  enddo
2018 
2019  ! call max_across_PEs(iter_flag)
2020 
2021  enddo ! End of do while(iter_flag) loop
2022 
2023  call max_across_pes(iter_count)
2024 
2025  if (is_root_pe() .and. (iter_count > 1)) then
2026  write(mesg,*) "shelf_advance_front: ", iter_count, " max iterations"
2027  call mom_mesg(mesg, 5)
2028  endif
2029 
2030 end subroutine shelf_advance_front
2031 
2032 !> Apply a very simple calving law using a minimum thickness rule
2033 subroutine ice_shelf_min_thickness_calve(G, h_shelf, area_shelf_h, hmask, thickness_calve)
2034  type(ocean_grid_type), intent(in) :: g !< The grid structure used by the ice shelf.
2035  real, dimension(SZDI_(G),SZDJ_(G)), &
2036  intent(inout) :: h_shelf !< The ice shelf thickness [Z ~> m].
2037  real, dimension(SZDI_(G),SZDJ_(G)), &
2038  intent(inout) :: area_shelf_h !< The area per cell covered by the ice shelf [m2].
2039  real, dimension(SZDI_(G),SZDJ_(G)), &
2040  intent(inout) :: hmask !< A mask indicating which tracer points are
2041  !! partly or fully covered by an ice-shelf
2042  real, intent(in) :: thickness_calve !< The thickness at which to trigger calving [Z ~> m].
2043 
2044  integer :: i,j
2045 
2046  do j=g%jsd,g%jed
2047  do i=g%isd,g%ied
2048 ! if ((h_shelf(i,j) < CS%thickness_calve) .and. (hmask(i,j) == 1) .and. &
2049 ! (CS%float_frac(i,j) == 0.0)) then
2050  if ((h_shelf(i,j) < thickness_calve) .and. (area_shelf_h(i,j) > 0.)) then
2051  h_shelf(i,j) = 0.0
2052  area_shelf_h(i,j) = 0.0
2053  hmask(i,j) = 0.0
2054  endif
2055  enddo
2056  enddo
2057 
2058 end subroutine ice_shelf_min_thickness_calve
2059 
2060 subroutine calve_to_mask(G, h_shelf, area_shelf_h, hmask, calve_mask)
2061  type(ocean_grid_type), intent(in) :: g !< The grid structure used by the ice shelf.
2062  real, dimension(SZDI_(G),SZDJ_(G)), &
2063  intent(inout) :: h_shelf !< The ice shelf thickness [Z ~> m].
2064  real, dimension(SZDI_(G),SZDJ_(G)), &
2065  intent(inout) :: area_shelf_h !< The area per cell covered by the ice shelf [m2].
2066  real, dimension(SZDI_(G),SZDJ_(G)), &
2067  intent(inout) :: hmask !< A mask indicating which tracer points are
2068  !! partly or fully covered by an ice-shelf
2069  real, dimension(SZDI_(G),SZDJ_(G)), &
2070  intent(in) :: calve_mask !< A mask that indicates where the ice shelf
2071  !! can exist, and where it will calve.
2072 
2073  integer :: i,j
2074 
2075  do j=g%jsc,g%jec ; do i=g%isc,g%iec
2076  if ((calve_mask(i,j) == 0.0) .and. (hmask(i,j) /= 0.0)) then
2077  h_shelf(i,j) = 0.0
2078  area_shelf_h(i,j) = 0.0
2079  hmask(i,j) = 0.0
2080  endif
2081  enddo ; enddo
2082 
2083 end subroutine calve_to_mask
2084 
2085 subroutine calc_shelf_driving_stress(CS, ISS, G, US, TAUD_X, TAUD_Y, OD)
2086  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
2087  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
2088  !! the ice-shelf state
2089  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
2090  type(unit_scale_type), intent(in) :: US !< Pointer to a structure containing unit conversion factors
2091  real, dimension(SZDI_(G),SZDJ_(G)), &
2092  intent(in) :: OD !< ocean floor depth at tracer points [Z ~> m].
2093  real, dimension(SZDIB_(G),SZDJB_(G)), &
2094  intent(inout) :: TAUD_X !< X-direction driving stress at q-points
2095  real, dimension(SZDIB_(G),SZDJB_(G)), &
2096  intent(inout) :: TAUD_Y !< Y-direction driving stress at q-points
2097 
2098 ! driving stress!
2099 
2100 ! ! TAUD_X and TAUD_Y will hold driving stress in the x- and y- directions when done.
2101 ! they will sit on the BGrid, and so their size depends on whether the grid is symmetric
2102 !
2103 ! Since this is a finite element solve, they will actually have the form \int \phi_i rho g h \nabla s
2104 !
2105 ! OD -this is important and we do not yet know where (in MOM) it will come from. It represents
2106 ! "average" ocean depth -- and is needed to find surface elevation
2107 ! (it is assumed that base_ice = bed + OD)
2108 
2109  real, dimension(SIZE(OD,1),SIZE(OD,2)) :: S, & ! surface elevation [Z ~> m].
2110  BASE ! basal elevation of shelf/stream [Z ~> m].
2111 
2112 
2113  real :: rho, rhow, sx, sy, neumann_val, dxh, dyh, dxdyh, grav
2114 
2115  integer :: i, j, iscq, iecq, jscq, jecq, isd, jsd, is, js, iegq, jegq
2116  integer :: giec, gjec, gisc, gjsc, cnt, isc, jsc, iec, jec
2117  integer :: i_off, j_off
2118 
2119  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
2120  iscq = g%iscB ; iecq = g%iecB ; jscq = g%jscB ; jecq = g%jecB
2121  isd = g%isd ; jsd = g%jsd
2122  iegq = g%iegB ; jegq = g%jegB
2123  gisc = g%domain%nihalo+1 ; gjsc = g%domain%njhalo+1
2124  giec = g%domain%niglobal+g%domain%nihalo ; gjec = g%domain%njglobal+g%domain%njhalo
2125  is = iscq - 1; js = jscq - 1
2126  i_off = g%idg_offset ; j_off = g%jdg_offset
2127 
2128  rho = cs%density_ice
2129  rhow = cs%density_ocean_avg
2130  grav = us%Z_to_m**2 * cs%g_Earth
2131 
2132  ! prelim - go through and calculate S
2133 
2134  ! or is this faster?
2135  base(:,:) = -g%bathyT(:,:) + od(:,:)
2136  s(:,:) = base(:,:) + iss%h_shelf(:,:)
2137 
2138  do j=jsc-1,jec+1
2139  do i=isc-1,iec+1
2140  cnt = 0
2141  sx = 0
2142  sy = 0
2143  dxh = g%dxT(i,j)
2144  dyh = g%dyT(i,j)
2145  dxdyh = g%areaT(i,j)
2146 
2147  if (iss%hmask(i,j) == 1) then ! we are inside the global computational bdry, at an ice-filled cell
2148 
2149  ! calculate sx
2150  if ((i+i_off) == gisc) then ! at left computational bdry
2151  if (iss%hmask(i+1,j) == 1) then
2152  sx = (s(i+1,j)-s(i,j))/dxh
2153  else
2154  sx = 0
2155  endif
2156  elseif ((i+i_off) == giec) then ! at right computational bdry
2157  if (iss%hmask(i-1,j) == 1) then
2158  sx = (s(i,j)-s(i-1,j))/dxh
2159  else
2160  sx = 0
2161  endif
2162  else ! interior
2163  if (iss%hmask(i+1,j) == 1) then
2164  cnt = cnt+1
2165  sx = s(i+1,j)
2166  else
2167  sx = s(i,j)
2168  endif
2169  if (iss%hmask(i-1,j) == 1) then
2170  cnt = cnt+1
2171  sx = sx - s(i-1,j)
2172  else
2173  sx = sx - s(i,j)
2174  endif
2175  if (cnt == 0) then
2176  sx = 0
2177  else
2178  sx = sx / (cnt * dxh)
2179  endif
2180  endif
2181 
2182  cnt = 0
2183 
2184  ! calculate sy, similarly
2185  if ((j+j_off) == gjsc) then ! at south computational bdry
2186  if (iss%hmask(i,j+1) == 1) then
2187  sy = (s(i,j+1)-s(i,j))/dyh
2188  else
2189  sy = 0
2190  endif
2191  elseif ((j+j_off) == gjec) then ! at nprth computational bdry
2192  if (iss%hmask(i,j-1) == 1) then
2193  sy = (s(i,j)-s(i,j-1))/dyh
2194  else
2195  sy = 0
2196  endif
2197  else ! interior
2198  if (iss%hmask(i,j+1) == 1) then
2199  cnt = cnt+1
2200  sy = s(i,j+1)
2201  else
2202  sy = s(i,j)
2203  endif
2204  if (iss%hmask(i,j-1) == 1) then
2205  cnt = cnt+1
2206  sy = sy - s(i,j-1)
2207  else
2208  sy = sy - s(i,j)
2209  endif
2210  if (cnt == 0) then
2211  sy = 0
2212  else
2213  sy = sy / (cnt * dyh)
2214  endif
2215  endif
2216 
2217  ! SW vertex
2218  taud_x(i-1,j-1) = taud_x(i-1,j-1) - .25 * rho * grav * iss%h_shelf(i,j) * sx * dxdyh
2219  taud_y(i-1,j-1) = taud_y(i-1,j-1) - .25 * rho * grav * iss%h_shelf(i,j) * sy * dxdyh
2220 
2221  ! SE vertex
2222  taud_x(i,j-1) = taud_x(i,j-1) - .25 * rho * grav * iss%h_shelf(i,j) * sx * dxdyh
2223  taud_y(i,j-1) = taud_y(i,j-1) - .25 * rho * grav * iss%h_shelf(i,j) * sy * dxdyh
2224 
2225  ! NW vertex
2226  taud_x(i-1,j) = taud_x(i-1,j) - .25 * rho * grav * iss%h_shelf(i,j) * sx * dxdyh
2227  taud_y(i-1,j) = taud_y(i-1,j) - .25 * rho * grav * iss%h_shelf(i,j) * sy * dxdyh
2228 
2229  ! NE vertex
2230  taud_x(i,j) = taud_x(i,j) - .25 * rho * grav * iss%h_shelf(i,j) * sx * dxdyh
2231  taud_y(i,j) = taud_y(i,j) - .25 * rho * grav * iss%h_shelf(i,j) * sy * dxdyh
2232 
2233  if (cs%float_frac(i,j) == 1) then
2234  neumann_val = .5 * grav * (rho * iss%h_shelf(i,j)**2 - rhow * g%bathyT(i,j)**2)
2235  else
2236  neumann_val = .5 * grav * (1-rho/rhow) * rho * iss%h_shelf(i,j)**2
2237  endif
2238 
2239 
2240  if ((cs%u_face_mask(i-1,j) == 2) .OR. (iss%hmask(i-1,j) == 0) .OR. (iss%hmask(i-1,j) == 2) ) then
2241  ! left face of the cell is at a stress boundary
2242  ! the depth-integrated longitudinal stress is equal to the difference of depth-integrated
2243  ! pressure on either side of the face
2244  ! on the ice side, it is rho g h^2 / 2
2245  ! on the ocean side, it is rhow g (delta OD)^2 / 2
2246  ! OD can be zero under the ice; but it is ASSUMED on the ice-free side of the face, topography elevation
2247  ! is not above the base of the ice in the current cell
2248 
2249  ! note negative sign due to direction of normal vector
2250  taud_x(i-1,j-1) = taud_x(i-1,j-1) - .5 * dyh * neumann_val
2251  taud_x(i-1,j) = taud_x(i-1,j) - .5 * dyh * neumann_val
2252  endif
2253 
2254  if ((cs%u_face_mask(i,j) == 2) .OR. (iss%hmask(i+1,j) == 0) .OR. (iss%hmask(i+1,j) == 2) ) then
2255  ! right face of the cell is at a stress boundary
2256  taud_x(i,j-1) = taud_x(i,j-1) + .5 * dyh * neumann_val
2257  taud_x(i,j) = taud_x(i,j) + .5 * dyh * neumann_val
2258  endif
2259 
2260  if ((cs%v_face_mask(i,j-1) == 2) .OR. (iss%hmask(i,j-1) == 0) .OR. (iss%hmask(i,j-1) == 2) ) then
2261  ! south face of the cell is at a stress boundary
2262  taud_y(i-1,j-1) = taud_y(i-1,j-1) - .5 * dxh * neumann_val
2263  taud_y(i,j-1) = taud_y(i,j-1) - .5 * dxh * neumann_val
2264  endif
2265 
2266  if ((cs%v_face_mask(i,j) == 2) .OR. (iss%hmask(i,j+1) == 0) .OR. (iss%hmask(i,j+1) == 2) ) then
2267  ! north face of the cell is at a stress boundary
2268  taud_y(i-1,j) = taud_y(i-1,j) + .5 * dxh * neumann_val ! note negative sign due to direction of normal vector
2269  taud_y(i,j) = taud_y(i,j) + .5 * dxh * neumann_val
2270  endif
2271 
2272  endif
2273  enddo
2274  enddo
2275 
2276 end subroutine calc_shelf_driving_stress
2277 
2278 subroutine init_boundary_values(CS, G, time, hmask, input_flux, input_thick, new_sim)
2279  type(ice_shelf_dyn_cs),intent(inout) :: CS !< A pointer to the ice shelf control structure
2280  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
2281  type(time_type), intent(in) :: Time !< The current model time
2282  real, dimension(SZDI_(G),SZDJ_(G)), &
2283  intent(in) :: hmask !< A mask indicating which tracer points are
2284  !! partly or fully covered by an ice-shelf
2285  real, intent(in) :: input_flux !< The integrated inward ice thickness flux [Z m2 s-1 ~> m3 s-1]
2286  real, intent(in) :: input_thick !< The ice thickness at boundaries [Z ~> m].
2287  logical, optional, intent(in) :: new_sim !< If present and false, this run is being restarted
2288 
2289 ! this will be a per-setup function. the boundary values of thickness and velocity
2290 ! (and possibly other variables) will be updated in this function
2291 
2292 ! FOR RESTARTING PURPOSES: if grid is not symmetric and the model is restarted, we will
2293 ! need to update those velocity points not *technically* in any
2294 ! computational domain -- if this function gets moves to another module,
2295 ! DO NOT TAKE THE RESTARTING BIT WITH IT
2296  integer :: i, j, iscq, iecq, jscq, jecq, isd, jsd, ied, jed, iegq, jegq
2297  integer :: gjec, gisc, gjsc, cnt, isc, jsc, iec, jec
2298  integer :: i_off, j_off
2299  real :: A, n, ux, uy, vx, vy, eps_min, domain_width
2300 
2301 
2302  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
2303 ! iscq = G%iscq ; iecq = G%iecq ; jscq = G%jscq ; jecq = G%jecq
2304  isd = g%isd ; jsd = g%jsd ; ied = g%ied ; jed = g%jed
2305 ! iegq = G%iegq ; jegq = G%jegq
2306  i_off = g%idg_offset ; j_off = g%jdg_offset
2307 
2308  domain_width = g%len_lat
2309 
2310  ! this loop results in some values being set twice but... eh.
2311 
2312  do j=jsd,jed
2313  do i=isd,ied
2314 
2315  if (hmask(i,j) == 3) then
2316  cs%thickness_bdry_val(i,j) = input_thick
2317  endif
2318 
2319  if ((hmask(i,j) == 0) .or. (hmask(i,j) == 1) .or. (hmask(i,j) == 2)) then
2320  if ((i <= iec).and.(i >= isc)) then
2321  if (cs%u_face_mask(i-1,j) == 3) then
2322  cs%u_bdry_val(i-1,j-1) = (1 - ((g%geoLatBu(i-1,j-1) - 0.5*g%len_lat)*2./g%len_lat)**2) * &
2323  1.5 * input_flux / input_thick
2324  cs%u_bdry_val(i-1,j) = (1 - ((g%geoLatBu(i-1,j) - 0.5*g%len_lat)*2./g%len_lat)**2) * &
2325  1.5 * input_flux / input_thick
2326  endif
2327  endif
2328  endif
2329 
2330  if (.not.(new_sim)) then
2331  if (.not. g%symmetric) then
2332  if (((i+i_off) == (g%domain%nihalo+1)).and.(cs%u_face_mask(i-1,j) == 3)) then
2333  cs%u_shelf(i-1,j-1) = cs%u_bdry_val(i-1,j-1)
2334  cs%u_shelf(i-1,j) = cs%u_bdry_val(i-1,j)
2335  endif
2336  if (((j+j_off) == (g%domain%njhalo+1)).and.(cs%v_face_mask(i,j-1) == 3)) then
2337  cs%u_shelf(i-1,j-1) = cs%u_bdry_val(i-1,j-1)
2338  cs%u_shelf(i,j-1) = cs%u_bdry_val(i,j-1)
2339  endif
2340  endif
2341  endif
2342  enddo
2343  enddo
2344 
2345 end subroutine init_boundary_values
2346 
2347 
2348 subroutine cg_action(uret, vret, u, v, Phi, Phisub, umask, vmask, hmask, H_node, &
2349  nu, float_cond, bathyT, beta, dxdyh, G, is, ie, js, je, dens_ratio)
2351  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
2352  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), &
2353  intent(inout) :: uret !< The retarding stresses working at u-points.
2354  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), &
2355  intent(inout) :: vret !< The retarding stresses working at v-points.
2356  real, dimension(SZDI_(G),SZDJ_(G),8,4), &
2357  intent(in) :: Phi !< The gradients of bilinear basis elements at Gaussian
2358  !! quadrature points surrounding the cell verticies.
2359  real, dimension(:,:,:,:,:,:), &
2360  intent(in) :: Phisub !< Quadrature structure weights at subgridscale
2361  !! locations for finite element calculations
2362  real, dimension(SZDIB_(G),SZDJB_(G)), &
2363  intent(in) :: u !< The zonal ice shelf velocity at vertices [m year-1]
2364  real, dimension(SZDIB_(G),SZDJB_(G)), &
2365  intent(in) :: v !< The meridional ice shelf velocity at vertices [m year-1]
2366  real, dimension(SZDIB_(G),SZDJB_(G)), &
2367  intent(in) :: umask !< A coded mask indicating the nature of the
2368  !! zonal flow at the corner point
2369  real, dimension(SZDIB_(G),SZDJB_(G)), &
2370  intent(in) :: vmask !< A coded mask indicating the nature of the
2371  !! meridional flow at the corner point
2372  real, dimension(SZDIB_(G),SZDJB_(G)), &
2373  intent(in) :: H_node !< The ice shelf thickness at nodal (corner)
2374  !! points [Z ~> m].
2375  real, dimension(SZDI_(G),SZDJ_(G)), &
2376  intent(in) :: hmask !< A mask indicating which tracer points are
2377  !! partly or fully covered by an ice-shelf
2378  real, dimension(SZDIB_(G),SZDJB_(G)), &
2379  intent(in) :: nu !< A field related to the ice viscosity from Glen's
2380  !! flow law. The exact form and units depend on the
2381  !! basal law exponent.
2382  real, dimension(SZDI_(G),SZDJ_(G)), &
2383  intent(in) :: float_cond !< An array indicating where the ice
2384  !! shelf is floating: 0 if floating, 1 if not.
2385  real, dimension(SZDI_(G),SZDJ_(G)), &
2386  intent(in) :: bathyT !< The depth of ocean bathymetry at tracer points [Z ~> m].
2387  real, dimension(SZDIB_(G),SZDJB_(G)), &
2388  intent(in) :: beta !< A field related to the nonlinear part of the
2389  !! "linearized" basal stress. The exact form and
2390  !! units depend on the basal law exponent.
2391  ! and/or whether flow is "hybridized"
2392  real, dimension(SZDI_(G),SZDJ_(G)), &
2393  intent(in) :: dxdyh !< The tracer cell area [m2]
2394  real, intent(in) :: dens_ratio !< The density of ice divided by the density
2395  !! of seawater, nondimensional
2396  integer, intent(in) :: is !< The starting i-index to work on
2397  integer, intent(in) :: ie !< The ending i-index to work on
2398  integer, intent(in) :: js !< The starting j-index to work on
2399  integer, intent(in) :: je !< The ending j-index to work on
2400 
2401 ! the linear action of the matrix on (u,v) with bilinear finite elements
2402 ! as of now everything is passed in so no grid pointers or anything of the sort have to be dereferenced,
2403 ! but this may change pursuant to conversations with others
2404 !
2405 ! is & ie are the cells over which the iteration is done; this may change between calls to this subroutine
2406 ! in order to make less frequent halo updates
2407 
2408 ! the linear action of the matrix on (u,v) with bilinear finite elements
2409 ! Phi has the form
2410 ! Phi(i,j,k,q) - applies to cell i,j
2411 
2412  ! 3 - 4
2413  ! | |
2414  ! 1 - 2
2415 
2416 ! Phi(i,j,2*k-1,q) gives d(Phi_k)/dx at quadrature point q
2417 ! Phi(i,j,2*k,q) gives d(Phi_k)/dy at quadrature point q
2418 ! Phi_k is equal to 1 at vertex k, and 0 at vertex l /= k, and bilinear
2419 
2420  real :: ux, vx, uy, vy, uq, vq, area, basel
2421  integer :: iq, jq, iphi, jphi, i, j, ilq, jlq
2422  real, dimension(2) :: xquad
2423  real, dimension(2,2) :: Ucell,Vcell,Hcell,Usubcontr,Vsubcontr,Ucontr
2424 
2425  xquad(1) = .5 * (1-sqrt(1./3)) ; xquad(2) = .5 * (1+sqrt(1./3))
2426 
2427  do j=js,je
2428  do i=is,ie ; if (hmask(i,j) == 1) then
2429 ! dxh = G%dxh(i,j)
2430 ! dyh = G%dyh(i,j)
2431 !
2432 ! X(:,:) = G%geoLonBu(i-1:i,j-1:j)
2433 ! Y(:,:) = G%geoLatBu(i-1:i,j-1:j)
2434 !
2435 ! call bilinear_shape_functions (X, Y, Phi, area)
2436 
2437  ! X and Y must be passed in the form
2438  ! 3 - 4
2439  ! | |
2440  ! 1 - 2
2441  ! Phi (2*i-1,j) gives d(Phi_i)/dx at quadrature point j
2442  ! Phi (2*i,j) gives d(Phi_i)/dy at quadrature point j
2443 
2444  area = dxdyh(i,j)
2445 
2446  ucontr=0
2447  do iq=1,2 ; do jq=1,2
2448 
2449 
2450  if (iq == 2) then
2451  ilq = 2
2452  else
2453  ilq = 1
2454  endif
2455 
2456  if (jq == 2) then
2457  jlq = 2
2458  else
2459  jlq = 1
2460  endif
2461 
2462  uq = u(i-1,j-1) * xquad(3-iq) * xquad(3-jq) + &
2463  u(i,j-1) * xquad(iq) * xquad(3-jq) + &
2464  u(i-1,j) * xquad(3-iq) * xquad(jq) + &
2465  u(i,j) * xquad(iq) * xquad(jq)
2466 
2467  vq = v(i-1,j-1) * xquad(3-iq) * xquad(3-jq) + &
2468  v(i,j-1) * xquad(iq) * xquad(3-jq) + &
2469  v(i-1,j) * xquad(3-iq) * xquad(jq) + &
2470  v(i,j) * xquad(iq) * xquad(jq)
2471 
2472  ux = u(i-1,j-1) * phi(i,j,1,2*(jq-1)+iq) + &
2473  u(i,j-1) * phi(i,j,3,2*(jq-1)+iq) + &
2474  u(i-1,j) * phi(i,j,5,2*(jq-1)+iq) + &
2475  u(i,j) * phi(i,j,7,2*(jq-1)+iq)
2476 
2477  vx = v(i-1,j-1) * phi(i,j,1,2*(jq-1)+iq) + &
2478  v(i,j-1) * phi(i,j,3,2*(jq-1)+iq) + &
2479  v(i-1,j) * phi(i,j,5,2*(jq-1)+iq) + &
2480  v(i,j) * phi(i,j,7,2*(jq-1)+iq)
2481 
2482  uy = u(i-1,j-1) * phi(i,j,2,2*(jq-1)+iq) + &
2483  u(i,j-1) * phi(i,j,4,2*(jq-1)+iq) + &
2484  u(i-1,j) * phi(i,j,6,2*(jq-1)+iq) + &
2485  u(i,j) * phi(i,j,8,2*(jq-1)+iq)
2486 
2487  vy = v(i-1,j-1) * phi(i,j,2,2*(jq-1)+iq) + &
2488  v(i,j-1) * phi(i,j,4,2*(jq-1)+iq) + &
2489  v(i-1,j) * phi(i,j,6,2*(jq-1)+iq) + &
2490  v(i,j) * phi(i,j,8,2*(jq-1)+iq)
2491 
2492  do iphi=1,2 ; do jphi=1,2
2493  if (umask(i-2+iphi,j-2+jphi) == 1) then
2494 
2495  uret(i-2+iphi,j-2+jphi) = uret(i-2+iphi,j-2+jphi) + &
2496  .25 * area * nu(i,j) * ((4*ux+2*vy) * phi(i,j,2*(2*(jphi-1)+iphi)-1,2*(jq-1)+iq) + &
2497  (uy+vx) * phi(i,j,2*(2*(jphi-1)+iphi),2*(jq-1)+iq))
2498  endif
2499  if (vmask(i-2+iphi,j-2+jphi) == 1) then
2500 
2501  vret(i-2+iphi,j-2+jphi) = vret(i-2+iphi,j-2+jphi) + &
2502  .25 * area * nu(i,j) * ((uy+vx) * phi(i,j,2*(2*(jphi-1)+iphi)-1,2*(jq-1)+iq) + &
2503  (4*vy+2*ux) * phi(i,j,2*(2*(jphi-1)+iphi),2*(jq-1)+iq))
2504  endif
2505 
2506  if (iq == iphi) then
2507  ilq = 2
2508  else
2509  ilq = 1
2510  endif
2511 
2512  if (jq == jphi) then
2513  jlq = 2
2514  else
2515  jlq = 1
2516  endif
2517 
2518  if (float_cond(i,j) == 0) then
2519 
2520  if (umask(i-2+iphi,j-2+jphi) == 1) then
2521 
2522  uret(i-2+iphi,j-2+jphi) = uret(i-2+iphi,j-2+jphi) + &
2523  .25 * beta(i,j) * area * uq * xquad(ilq) * xquad(jlq)
2524 
2525  endif
2526 
2527  if (vmask(i-2+iphi,j-2+jphi) == 1) then
2528 
2529  vret(i-2+iphi,j-2+jphi) = vret(i-2+iphi,j-2+jphi) + &
2530  .25 * beta(i,j) * area * vq * xquad(ilq) * xquad(jlq)
2531 
2532  endif
2533 
2534  endif
2535  ucontr(iphi,jphi) = ucontr(iphi,jphi) + .25 * area * uq * xquad(ilq) * xquad(jlq) * beta(i,j)
2536  enddo ; enddo
2537  enddo ; enddo
2538 
2539  if (float_cond(i,j) == 1) then
2540  usubcontr = 0.0 ; vsubcontr = 0.0 ; basel = bathyt(i,j)
2541  ucell(:,:) = u(i-1:i,j-1:j) ; vcell(:,:) = v(i-1:i,j-1:j) ; hcell(:,:) = h_node(i-1:i,j-1:j)
2542  call cg_action_subgrid_basal(phisub, hcell, ucell, vcell, area, basel, &
2543  dens_ratio, usubcontr, vsubcontr)
2544  do iphi=1,2 ; do jphi=1,2
2545  if (umask(i-2+iphi,j-2+jphi) == 1) then
2546  uret(i-2+iphi,j-2+jphi) = uret(i-2+iphi,j-2+jphi) + usubcontr(iphi,jphi) * beta(i,j)
2547  endif
2548  if (vmask(i-2+iphi,j-2+jphi) == 1) then
2549  vret(i-2+iphi,j-2+jphi) = vret(i-2+iphi,j-2+jphi) + vsubcontr(iphi,jphi) * beta(i,j)
2550  endif
2551  enddo ; enddo
2552  endif
2553 
2554  endif
2555  enddo ; enddo
2556 
2557 end subroutine cg_action
2558 
2559 subroutine cg_action_subgrid_basal(Phisub, H, U, V, DXDYH, bathyT, dens_ratio, Ucontr, Vcontr)
2560  real, dimension(:,:,:,:,:,:), &
2561  intent(in) :: Phisub !< Quadrature structure weights at subgridscale
2562  !! locations for finite element calculations
2563  real, dimension(2,2), intent(in) :: H !< The ice shelf thickness at nodal (corner) points [Z ~> m].
2564  real, dimension(2,2), intent(in) :: U !< The zonal ice shelf velocity at vertices [m year-1]
2565  real, dimension(2,2), intent(in) :: V !< The meridional ice shelf velocity at vertices [m year-1]
2566  real, intent(in) :: DXDYH !< The tracer cell area [m2]
2567  real, intent(in) :: bathyT !< The depth of ocean bathymetry at tracer points [Z ~> m].
2568  real, intent(in) :: dens_ratio !< The density of ice divided by the density
2569  !! of seawater, nondimensional
2570  real, dimension(2,2), intent(inout) :: Ucontr !< A field related to the subgridscale contributions to
2571  !! the u-direction basal stress.
2572  real, dimension(2,2), intent(inout) :: Vcontr !< A field related to the subgridscale contributions to
2573  !! the v-direction basal stress.
2574 
2575  integer :: nsub, i, j, k, l, qx, qy, m, n
2576  real :: subarea, hloc, uq, vq
2577 
2578  nsub = size(phisub,1)
2579  subarea = dxdyh / (nsub**2)
2580 
2581  do m=1,2
2582  do n=1,2
2583  do j=1,nsub
2584  do i=1,nsub
2585  do qx=1,2
2586  do qy = 1,2
2587 
2588  hloc = phisub(i,j,1,1,qx,qy)*h(1,1) + phisub(i,j,1,2,qx,qy)*h(1,2) + &
2589  phisub(i,j,2,1,qx,qy)*h(2,1) + phisub(i,j,2,2,qx,qy)*h(2,2)
2590 
2591  if (dens_ratio * hloc - bathyt > 0) then
2592  !if (.true.) then
2593  uq = 0 ; vq = 0
2594  do k=1,2
2595  do l=1,2
2596  !Ucontr(m,n) = Ucontr(m,n) + subarea * 0.25 * Phisub(i,j,m,n,qx,qy) * Phisub(i,j,k,l,qx,qy) * U(k,l)
2597  !Vcontr(m,n) = Vcontr(m,n) + subarea * 0.25 * Phisub(i,j,m,n,qx,qy) * Phisub(i,j,k,l,qx,qy) * V(k,l)
2598  uq = uq + phisub(i,j,k,l,qx,qy) * u(k,l) ; vq = vq + phisub(i,j,k,l,qx,qy) * v(k,l)
2599  enddo
2600  enddo
2601 
2602  ucontr(m,n) = ucontr(m,n) + subarea * 0.25 * phisub(i,j,m,n,qx,qy) * uq
2603  vcontr(m,n) = vcontr(m,n) + subarea * 0.25 * phisub(i,j,m,n,qx,qy) * vq
2604 
2605  endif
2606 
2607  enddo
2608  enddo
2609  enddo
2610  enddo
2611  enddo
2612  enddo
2613 
2614 end subroutine cg_action_subgrid_basal
2615 
2616 !> returns the diagonal entries of the matrix for a Jacobi preconditioning
2617 subroutine matrix_diagonal(CS, G, float_cond, H_node, nu, beta, hmask, dens_ratio, &
2618  Phisub, u_diagonal, v_diagonal)
2620  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
2621  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
2622  real, dimension(SZDI_(G),SZDJ_(G)), &
2623  intent(in) :: float_cond !< An array indicating where the ice
2624  !! shelf is floating: 0 if floating, 1 if not.
2625  real, dimension(SZDIB_(G),SZDJB_(G)), &
2626  intent(in) :: H_node !< The ice shelf thickness at nodal
2627  !! (corner) points [Z ~> m].
2628  real, dimension(SZDIB_(G),SZDJB_(G)), &
2629  intent(in) :: nu !< A field related to the ice viscosity from Glen's
2630  !! flow law. The exact form and units depend on the
2631  !! basal law exponent.
2632  real, dimension(SZDIB_(G),SZDJB_(G)), &
2633  intent(in) :: beta !< A field related to the nonlinear part of the
2634  !! "linearized" basal stress. The exact form and
2635  !! units depend on the basal law exponent
2636  real, dimension(SZDI_(G),SZDJ_(G)), &
2637  intent(in) :: hmask !< A mask indicating which tracer points are
2638  !! partly or fully covered by an ice-shelf
2639  real, intent(in) :: dens_ratio !< The density of ice divided by the density
2640  !! of seawater, nondimensional
2641  real, dimension(:,:,:,:,:,:), intent(in) :: Phisub !< Quadrature structure weights at subgridscale
2642  !! locations for finite element calculations
2643  real, dimension(SZDIB_(G),SZDJB_(G)), &
2644  intent(inout) :: u_diagonal !< The diagonal elements of the u-velocity
2645  !! matrix from the left-hand side of the solver.
2646  real, dimension(SZDIB_(G),SZDJB_(G)), &
2647  intent(inout) :: v_diagonal !< The diagonal elements of the v-velocity
2648  !! matrix from the left-hand side of the solver.
2649 
2650 
2651 ! returns the diagonal entries of the matrix for a Jacobi preconditioning
2652 
2653  integer :: i, j, is, js, cnt, isc, jsc, iec, jec, iphi, jphi, iq, jq, ilq, jlq
2654  real :: A, n, ux, uy, vx, vy, eps_min, domain_width, dxh, dyh, dxdyh, area, uq, vq, basel
2655  real, dimension(8,4) :: Phi
2656  real, dimension(4) :: X, Y
2657  real, dimension(2) :: xquad
2658  real, dimension(2,2) :: Hcell,Usubcontr,Vsubcontr
2659 
2660 
2661  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
2662 
2663  xquad(1) = .5 * (1-sqrt(1./3)) ; xquad(2) = .5 * (1+sqrt(1./3))
2664 
2665 ! X and Y must be passed in the form
2666  ! 3 - 4
2667  ! | |
2668  ! 1 - 2
2669 ! Phi (2*i-1,j) gives d(Phi_i)/dx at quadrature point j
2670 ! Phi (2*i,j) gives d(Phi_i)/dy at quadrature point j
2671 
2672  do j=jsc-1,jec+1 ; do i=isc-1,iec+1 ; if (hmask(i,j) == 1) then
2673 
2674  dxh = g%dxT(i,j)
2675  dyh = g%dyT(i,j)
2676  dxdyh = g%areaT(i,j)
2677 
2678  x(1:2) = g%geoLonBu(i-1:i,j-1)*1000
2679  x(3:4) = g%geoLonBu(i-1:i,j) *1000
2680  y(1:2) = g%geoLatBu(i-1:i,j-1) *1000
2681  y(3:4) = g%geoLatBu(i-1:i,j)*1000
2682 
2683  call bilinear_shape_functions(x, y, phi, area)
2684 
2685  ! X and Y must be passed in the form
2686  ! 3 - 4
2687  ! | |
2688  ! 1 - 2
2689  ! Phi (2*i-1,j) gives d(Phi_i)/dx at quadrature point j
2690  ! Phi (2*i,j) gives d(Phi_i)/dy at quadrature point j
2691 
2692  do iq=1,2 ; do jq=1,2
2693 
2694  do iphi=1,2 ; do jphi=1,2
2695 
2696  if (iq == iphi) then
2697  ilq = 2
2698  else
2699  ilq = 1
2700  endif
2701 
2702  if (jq == jphi) then
2703  jlq = 2
2704  else
2705  jlq = 1
2706  endif
2707 
2708  if (cs%umask(i-2+iphi,j-2+jphi) == 1) then
2709 
2710  ux = phi(2*(2*(jphi-1)+iphi)-1, 2*(jq-1)+iq)
2711  uy = phi(2*(2*(jphi-1)+iphi), 2*(jq-1)+iq)
2712  vx = 0.
2713  vy = 0.
2714 
2715  u_diagonal(i-2+iphi,j-2+jphi) = u_diagonal(i-2+iphi,j-2+jphi) + &
2716  .25 * dxdyh * nu(i,j) * ((4*ux+2*vy) * phi(2*(2*(jphi-1)+iphi)-1,2*(jq-1)+iq) + &
2717  (uy+vy) * phi(2*(2*(jphi-1)+iphi),2*(jq-1)+iq))
2718 
2719  uq = xquad(ilq) * xquad(jlq)
2720 
2721  if (float_cond(i,j) == 0) then
2722  u_diagonal(i-2+iphi,j-2+jphi) = u_diagonal(i-2+iphi,j-2+jphi) + &
2723  .25 * beta(i,j) * dxdyh * uq * xquad(ilq) * xquad(jlq)
2724  endif
2725 
2726  endif
2727 
2728  if (cs%vmask(i-2+iphi,j-2+jphi) == 1) then
2729 
2730  vx = phi(2*(2*(jphi-1)+iphi)-1, 2*(jq-1)+iq)
2731  vy = phi(2*(2*(jphi-1)+iphi), 2*(jq-1)+iq)
2732  ux = 0.
2733  uy = 0.
2734 
2735  v_diagonal(i-2+iphi,j-2+jphi) = v_diagonal(i-2+iphi,j-2+jphi) + &
2736  .25 * dxdyh * nu(i,j) * ((uy+vx) * phi(2*(2*(jphi-1)+iphi)-1,2*(jq-1)+iq) + &
2737  (4*vy+2*ux) * phi(2*(2*(jphi-1)+iphi),2*(jq-1)+iq))
2738 
2739  vq = xquad(ilq) * xquad(jlq)
2740 
2741  if (float_cond(i,j) == 0) then
2742  v_diagonal(i-2+iphi,j-2+jphi) = v_diagonal(i-2+iphi,j-2+jphi) + &
2743  .25 * beta(i,j) * dxdyh * vq * xquad(ilq) * xquad(jlq)
2744  endif
2745 
2746  endif
2747  enddo ; enddo
2748  enddo ; enddo
2749  if (float_cond(i,j) == 1) then
2750  usubcontr = 0.0 ; vsubcontr = 0.0 ; basel = g%bathyT(i,j)
2751  hcell(:,:) = h_node(i-1:i,j-1:j)
2752  call cg_diagonal_subgrid_basal(phisub, hcell, dxdyh, basel, dens_ratio, usubcontr, vsubcontr)
2753  do iphi=1,2 ; do jphi=1,2
2754  if (cs%umask(i-2+iphi,j-2+jphi) == 1) then
2755  u_diagonal(i-2+iphi,j-2+jphi) = u_diagonal(i-2+iphi,j-2+jphi) + usubcontr(iphi,jphi) * beta(i,j)
2756  v_diagonal(i-2+iphi,j-2+jphi) = v_diagonal(i-2+iphi,j-2+jphi) + vsubcontr(iphi,jphi) * beta(i,j)
2757  endif
2758  enddo ; enddo
2759  endif
2760  endif ; enddo ; enddo
2761 
2762 end subroutine matrix_diagonal
2763 
2764 subroutine cg_diagonal_subgrid_basal (Phisub, H_node, DXDYH, bathyT, dens_ratio, Ucontr, Vcontr)
2765  real, dimension(:,:,:,:,:,:), &
2766  intent(in) :: Phisub !< Quadrature structure weights at subgridscale
2767  !! locations for finite element calculations
2768  real, dimension(2,2), intent(in) :: H_node !< The ice shelf thickness at nodal (corner)
2769  !! points [Z ~> m].
2770  real, intent(in) :: DXDYH !< The tracer cell area [m2]
2771  real, intent(in) :: bathyT !< The depth of ocean bathymetry at tracer points [Z ~> m].
2772  real, intent(in) :: dens_ratio !< The density of ice divided by the density
2773  !! of seawater, nondimensional
2774  real, dimension(2,2), intent(inout) :: Ucontr !< A field related to the subgridscale contributions to
2775  !! the u-direction diagonal elements from basal stress.
2776  real, dimension(2,2), intent(inout) :: Vcontr !< A field related to the subgridscale contributions to
2777  !! the v-direction diagonal elements from basal stress.
2778 
2779  ! bathyT = cellwise-constant bed elevation
2780 
2781  integer :: nsub, i, j, k, l, qx, qy, m, n
2782  real :: subarea, hloc
2783 
2784  nsub = size(phisub,1)
2785  subarea = dxdyh / (nsub**2)
2786 
2787  do m=1,2 ; do n=1,2 ; do j=1,nsub ; do i=1,nsub ; do qx=1,2 ; do qy = 1,2
2788 
2789  hloc = phisub(i,j,1,1,qx,qy)*h_node(1,1) + phisub(i,j,1,2,qx,qy)*h_node(1,2) + &
2790  phisub(i,j,2,1,qx,qy)*h_node(2,1) + phisub(i,j,2,2,qx,qy)*h_node(2,2)
2791 
2792  if (dens_ratio * hloc - bathyt > 0) then
2793  ucontr(m,n) = ucontr(m,n) + subarea * 0.25 * phisub(i,j,m,n,qx,qy)**2
2794  vcontr(m,n) = vcontr(m,n) + subarea * 0.25 * phisub(i,j,m,n,qx,qy)**2
2795  endif
2796 
2797  enddo ; enddo ; enddo ; enddo ; enddo ; enddo
2798 
2799 end subroutine cg_diagonal_subgrid_basal
2800 
2801 
2802 subroutine apply_boundary_values(CS, ISS, G, time, Phisub, H_node, nu, beta, float_cond, &
2803  dens_ratio, u_bdry_contr, v_bdry_contr)
2805  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
2806  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
2807  !! the ice-shelf state
2808  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
2809  type(time_type), intent(in) :: Time !< The current model time
2810  real, dimension(:,:,:,:,:,:), &
2811  intent(in) :: Phisub !< Quadrature structure weights at subgridscale
2812  !! locations for finite element calculations
2813  real, dimension(SZDIB_(G),SZDJB_(G)), &
2814  intent(in) :: H_node !< The ice shelf thickness at nodal
2815  !! (corner) points [Z ~> m].
2816  real, dimension(SZDIB_(G),SZDJB_(G)), &
2817  intent(in) :: nu !< A field related to the ice viscosity from Glen's
2818  !! flow law. The exact form and units depend on the
2819  !! basal law exponent.
2820  real, dimension(SZDIB_(G),SZDJB_(G)), &
2821  intent(in) :: beta !< A field related to the nonlinear part of the
2822  !! "linearized" basal stress. The exact form and
2823  !! units depend on the basal law exponent
2824  real, dimension(SZDI_(G),SZDJ_(G)), &
2825  intent(in) :: float_cond !< An array indicating where the ice
2826  !! shelf is floating: 0 if floating, 1 if not.
2827  real, intent(in) :: dens_ratio !< The density of ice divided by the density
2828  !! of seawater, nondimensional
2829  real, dimension(SZDIB_(G),SZDJB_(G)), &
2830  intent(inout) :: u_bdry_contr !< Contributions to the zonal ice
2831  !! velocities due to the open boundaries
2832  real, dimension(SZDIB_(G),SZDJB_(G)), &
2833  intent(inout) :: v_bdry_contr !< Contributions to the zonal ice
2834  !! velocities due to the open boundaries
2835 
2836 ! this will be a per-setup function. the boundary values of thickness and velocity
2837 ! (and possibly other variables) will be updated in this function
2838 
2839  real, dimension(8,4) :: Phi
2840  real, dimension(4) :: X, Y
2841  real, dimension(2) :: xquad
2842  integer :: i, j, isc, jsc, iec, jec, iq, jq, iphi, jphi, ilq, jlq
2843  real :: A, n, ux, uy, vx, vy, eps_min, domain_width, dxh, dyh, dxdyh, uq, vq, area, basel
2844  real, dimension(2,2) :: Ucell,Vcell,Hcell,Usubcontr,Vsubcontr
2845 
2846 
2847  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
2848 
2849  xquad(1) = .5 * (1-sqrt(1./3)) ; xquad(2) = .5 * (1+sqrt(1./3))
2850 
2851 ! X and Y must be passed in the form
2852  ! 3 - 4
2853  ! | |
2854  ! 1 - 2
2855 ! Phi (2*i-1,j) gives d(Phi_i)/dx at quadrature point j
2856 ! Phi (2*i,j) gives d(Phi_i)/dy at quadrature point j
2857 
2858  do j=jsc-1,jec+1 ; do i=isc-1,iec+1 ; if (iss%hmask(i,j) == 1) then
2859 
2860  ! process this cell if any corners have umask set to non-dirichlet bdry.
2861  ! NOTE: vmask not considered, probably should be
2862 
2863  if ((cs%umask(i-1,j-1) == 3) .OR. (cs%umask(i,j-1) == 3) .OR. &
2864  (cs%umask(i-1,j) == 3) .OR. (cs%umask(i,j) == 3)) then
2865 
2866 
2867  dxh = g%dxT(i,j)
2868  dyh = g%dyT(i,j)
2869  dxdyh = g%areaT(i,j)
2870 
2871  x(1:2) = g%geoLonBu(i-1:i,j-1)*1000
2872  x(3:4) = g%geoLonBu(i-1:i,j)*1000
2873  y(1:2) = g%geoLatBu(i-1:i,j-1)*1000
2874  y(3:4) = g%geoLatBu(i-1:i,j)*1000
2875 
2876  call bilinear_shape_functions(x, y, phi, area)
2877 
2878  ! X and Y must be passed in the form
2879  ! 3 - 4
2880  ! | |
2881  ! 1 - 2
2882  ! Phi (2*i-1,j) gives d(Phi_i)/dx at quadrature point j
2883  ! Phi (2*i,j) gives d(Phi_i)/dy at quadrature point j
2884 
2885 
2886 
2887  do iq=1,2 ; do jq=1,2
2888 
2889  uq = cs%u_bdry_val(i-1,j-1) * xquad(3-iq) * xquad(3-jq) + &
2890  cs%u_bdry_val(i,j-1) * xquad(iq) * xquad(3-jq) + &
2891  cs%u_bdry_val(i-1,j) * xquad(3-iq) * xquad(jq) + &
2892  cs%u_bdry_val(i,j) * xquad(iq) * xquad(jq)
2893 
2894  vq = cs%v_bdry_val(i-1,j-1) * xquad(3-iq) * xquad(3-jq) + &
2895  cs%v_bdry_val(i,j-1) * xquad(iq) * xquad(3-jq) + &
2896  cs%v_bdry_val(i-1,j) * xquad(3-iq) * xquad(jq) + &
2897  cs%v_bdry_val(i,j) * xquad(iq) * xquad(jq)
2898 
2899  ux = cs%u_bdry_val(i-1,j-1) * phi(1,2*(jq-1)+iq) + &
2900  cs%u_bdry_val(i,j-1) * phi(3,2*(jq-1)+iq) + &
2901  cs%u_bdry_val(i-1,j) * phi(5,2*(jq-1)+iq) + &
2902  cs%u_bdry_val(i,j) * phi(7,2*(jq-1)+iq)
2903 
2904  vx = cs%v_bdry_val(i-1,j-1) * phi(1,2*(jq-1)+iq) + &
2905  cs%v_bdry_val(i,j-1) * phi(3,2*(jq-1)+iq) + &
2906  cs%v_bdry_val(i-1,j) * phi(5,2*(jq-1)+iq) + &
2907  cs%v_bdry_val(i,j) * phi(7,2*(jq-1)+iq)
2908 
2909  uy = cs%u_bdry_val(i-1,j-1) * phi(2,2*(jq-1)+iq) + &
2910  cs%u_bdry_val(i,j-1) * phi(4,2*(jq-1)+iq) + &
2911  cs%u_bdry_val(i-1,j) * phi(6,2*(jq-1)+iq) + &
2912  cs%u_bdry_val(i,j) * phi(8,2*(jq-1)+iq)
2913 
2914  vy = cs%v_bdry_val(i-1,j-1) * phi(2,2*(jq-1)+iq) + &
2915  cs%v_bdry_val(i,j-1) * phi(4,2*(jq-1)+iq) + &
2916  cs%v_bdry_val(i-1,j) * phi(6,2*(jq-1)+iq) + &
2917  cs%v_bdry_val(i,j) * phi(8,2*(jq-1)+iq)
2918 
2919  do iphi=1,2 ; do jphi=1,2
2920 
2921  if (iq == iphi) then
2922  ilq = 2
2923  else
2924  ilq = 1
2925  endif
2926 
2927  if (jq == jphi) then
2928  jlq = 2
2929  else
2930  jlq = 1
2931  endif
2932 
2933  if (cs%umask(i-2+iphi,j-2+jphi) == 1) then
2934 
2935 
2936  u_bdry_contr(i-2+iphi,j-2+jphi) = u_bdry_contr(i-2+iphi,j-2+jphi) + &
2937  .25 * dxdyh * nu(i,j) * ( (4*ux+2*vy) * phi(2*(2*(jphi-1)+iphi)-1,2*(jq-1)+iq) + &
2938  (uy+vx) * phi(2*(2*(jphi-1)+iphi),2*(jq-1)+iq) )
2939 
2940  if (float_cond(i,j) == 0) then
2941  u_bdry_contr(i-2+iphi,j-2+jphi) = u_bdry_contr(i-2+iphi,j-2+jphi) + &
2942  .25 * beta(i,j) * dxdyh * uq * xquad(ilq) * xquad(jlq)
2943  endif
2944 
2945  endif
2946 
2947  if (cs%vmask(i-2+iphi,j-2+jphi) == 1) then
2948 
2949 
2950  v_bdry_contr(i-2+iphi,j-2+jphi) = v_bdry_contr(i-2+iphi,j-2+jphi) + &
2951  .25 * dxdyh * nu(i,j) * ( (uy+vx) * phi(2*(2*(jphi-1)+iphi)-1,2*(jq-1)+iq) + &
2952  (4*vy+2*ux) * phi(2*(2*(jphi-1)+iphi),2*(jq-1)+iq))
2953 
2954  if (float_cond(i,j) == 0) then
2955  v_bdry_contr(i-2+iphi,j-2+jphi) = v_bdry_contr(i-2+iphi,j-2+jphi) + &
2956  .25 * beta(i,j) * dxdyh * vq * xquad(ilq) * xquad(jlq)
2957  endif
2958 
2959  endif
2960  enddo ; enddo
2961  enddo ; enddo
2962 
2963  if (float_cond(i,j) == 1) then
2964  usubcontr = 0.0 ; vsubcontr = 0.0 ; basel = g%bathyT(i,j)
2965  ucell(:,:) = cs%u_bdry_val(i-1:i,j-1:j) ; vcell(:,:) = cs%v_bdry_val(i-1:i,j-1:j)
2966  hcell(:,:) = h_node(i-1:i,j-1:j)
2967  call cg_action_subgrid_basal(phisub, hcell, ucell, vcell, dxdyh, basel, &
2968  dens_ratio, usubcontr, vsubcontr)
2969  do iphi=1,2 ; do jphi = 1,2
2970  if (cs%umask(i-2+iphi,j-2+jphi) == 1) then
2971  u_bdry_contr(i-2+iphi,j-2+jphi) = u_bdry_contr(i-2+iphi,j-2+jphi) + &
2972  usubcontr(iphi,jphi) * beta(i,j)
2973  endif
2974  if (cs%vmask(i-2+iphi,j-2+jphi) == 1) then
2975  v_bdry_contr(i-2+iphi,j-2+jphi) = v_bdry_contr(i-2+iphi,j-2+jphi) + &
2976  vsubcontr(iphi,jphi) * beta(i,j)
2977  endif
2978  enddo ; enddo
2979  endif
2980  endif
2981  endif ; enddo ; enddo
2982 
2983 end subroutine apply_boundary_values
2984 
2985 !> Update depth integrated viscosity, based on horizontal strain rates, and also update the
2986 !! nonlinear part of the basal traction.
2987 subroutine calc_shelf_visc(CS, ISS, G, US, u, v)
2988  type(ice_shelf_dyn_cs), intent(inout) :: CS !< A pointer to the ice shelf control structure
2989  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
2990  !! the ice-shelf state
2991  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
2992  type(unit_scale_type), intent(in) :: US !< Pointer to a structure containing unit conversion factors
2993  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), &
2994  intent(inout) :: u !< The zonal ice shelf velocity [m year-1].
2995  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), &
2996  intent(inout) :: v !< The meridional ice shelf velocity [m year-1].
2997 
2998 ! update DEPTH_INTEGRATED viscosity, based on horizontal strain rates - this is for bilinear FEM solve
2999 ! so there is an "upper" and "lower" bilinear viscosity
3000 
3001 ! also this subroutine updates the nonlinear part of the basal traction
3002 
3003 ! this may be subject to change later... to make it "hybrid"
3004 
3005  integer :: i, j, iscq, iecq, jscq, jecq, isd, jsd, ied, jed, iegq, jegq
3006  integer :: giec, gjec, gisc, gjsc, cnt, isc, jsc, iec, jec, is, js
3007  real :: A, n, ux, uy, vx, vy, eps_min, umid, vmid, unorm, C_basal_friction, n_basal_friction, dxh, dyh, dxdyh
3008 
3009  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
3010  iscq = g%iscB ; iecq = g%iecB ; jscq = g%jscB ; jecq = g%jecB
3011  isd = g%isd ; jsd = g%jsd ; ied = g%ied ; jed = g%jed
3012  iegq = g%iegB ; jegq = g%jegB
3013  gisc = g%domain%nihalo+1 ; gjsc = g%domain%njhalo+1
3014  giec = g%domain%niglobal+gisc ; gjec = g%domain%njglobal+gjsc
3015  is = iscq - 1; js = jscq - 1
3016 
3017  a = cs%A_glen_isothermal ; n = cs%n_glen; eps_min = cs%eps_glen_min
3018  c_basal_friction = cs%C_basal_friction ; n_basal_friction = cs%n_basal_friction
3019 
3020  do j=jsd+1,jed-1
3021  do i=isd+1,ied-1
3022 
3023  dxh = g%dxT(i,j)
3024  dyh = g%dyT(i,j)
3025  dxdyh = g%areaT(i,j)
3026 
3027  if (iss%hmask(i,j) == 1) then
3028  ux = (u(i,j) + u(i,j-1) - u(i-1,j) - u(i-1,j-1)) / (2*dxh)
3029  vx = (v(i,j) + v(i,j-1) - v(i-1,j) - v(i-1,j-1)) / (2*dxh)
3030  uy = (u(i,j) - u(i,j-1) + u(i-1,j) - u(i-1,j-1)) / (2*dyh)
3031  vy = (v(i,j) - v(i,j-1) + v(i-1,j) - v(i-1,j-1)) / (2*dyh)
3032 
3033  cs%ice_visc(i,j) = .5 * a**(-1/n) * &
3034  (ux**2+vy**2+ux*vy+0.25*(uy+vx)**2+eps_min**2) ** ((1-n)/(2*n)) * &
3035  us%Z_to_m*iss%h_shelf(i,j)
3036 
3037  umid = (u(i,j) + u(i,j-1) + u(i-1,j) + u(i-1,j-1))/4
3038  vmid = (v(i,j) + v(i,j-1) + v(i-1,j) + v(i-1,j-1))/4
3039  unorm = sqrt(umid**2+vmid**2+(eps_min*dxh)**2)
3040  cs%taub_beta_eff(i,j) = c_basal_friction * unorm ** (n_basal_friction-1)
3041  endif
3042  enddo
3043  enddo
3044 
3045 end subroutine calc_shelf_visc
3046 
3047 subroutine update_od_ffrac(CS, G, US, ocean_mass, find_avg)
3048  type(ice_shelf_dyn_cs), intent(inout) :: CS !< A pointer to the ice shelf control structure
3049  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
3050  type(unit_scale_type), intent(in) :: US !< Pointer to a structure containing unit conversion factors
3051  real, dimension(SZDI_(G),SZDJ_(G)), &
3052  intent(in) :: ocean_mass !< The mass per unit area of the ocean [kg m-2].
3053  logical, intent(in) :: find_avg !< If true, find the average of OD and ffrac, and
3054  !! reset the underlying running sums to 0.
3055 
3056  integer :: isc, iec, jsc, jec, i, j
3057  real :: I_rho_ocean
3058  real :: I_counter
3059 
3060  i_rho_ocean = 1.0 / (us%Z_to_m*cs%density_ocean_avg)
3061 
3062  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
3063 
3064  do j=jsc,jec ; do i=isc,iec
3065  cs%OD_rt(i,j) = cs%OD_rt(i,j) + ocean_mass(i,j)*i_rho_ocean
3066  if (ocean_mass(i,j)*i_rho_ocean > cs%thresh_float_col_depth) then
3067  cs%float_frac_rt(i,j) = cs%float_frac_rt(i,j) + 1.0
3068  endif
3069  enddo ; enddo
3070  cs%OD_rt_counter = cs%OD_rt_counter + 1
3071 
3072  if (find_avg) then
3073  i_counter = 1.0 / real(cs%OD_rt_counter)
3074  do j=jsc,jec ; do i=isc,iec
3075  cs%float_frac(i,j) = 1.0 - (cs%float_frac_rt(i,j) * i_counter)
3076  cs%OD_av(i,j) = cs%OD_rt(i,j) * i_counter
3077 
3078  cs%OD_rt(i,j) = 0.0 ; cs%float_frac_rt(i,j) = 0.0
3079  enddo ; enddo
3080 
3081  call pass_var(cs%float_frac, g%domain)
3082  call pass_var(cs%OD_av, g%domain)
3083  endif
3084 
3085 end subroutine update_od_ffrac
3086 
3087 subroutine update_od_ffrac_uncoupled(CS, G, h_shelf)
3088  type(ice_shelf_dyn_cs), intent(inout) :: CS !< A pointer to the ice shelf control structure
3089  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
3090  real, dimension(SZDI_(G),SZDJ_(G)), &
3091  intent(in) :: h_shelf !< the thickness of the ice shelf [Z ~> m].
3092 
3093  integer :: i, j, iters, isd, ied, jsd, jed
3094  real :: rhoi_rhow, OD
3095 
3096  rhoi_rhow = cs%density_ice / cs%density_ocean_avg
3097  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
3098 
3099  do j=jsd,jed
3100  do i=isd,ied
3101  od = g%bathyT(i,j) - rhoi_rhow * h_shelf(i,j)
3102  if (od >= 0) then
3103  ! ice thickness does not take up whole ocean column -> floating
3104  cs%OD_av(i,j) = od
3105  cs%float_frac(i,j) = 0.
3106  else
3107  cs%OD_av(i,j) = 0.
3108  cs%float_frac(i,j) = 1.
3109  endif
3110  enddo
3111  enddo
3112 
3113 end subroutine update_od_ffrac_uncoupled
3114 
3115 !> This subroutine calculates the gradients of bilinear basis elements that
3116 !! that are centered at the vertices of the cell. values are calculated at
3117 !! points of gaussian quadrature.
3118 subroutine bilinear_shape_functions (X, Y, Phi, area)
3119  real, dimension(4), intent(in) :: X !< The x-positions of the vertices of the quadrilateral.
3120  real, dimension(4), intent(in) :: Y !< The y-positions of the vertices of the quadrilateral.
3121  real, dimension(8,4), intent(inout) :: Phi !< The gradients of bilinear basis elements at Gaussian
3122  !! quadrature points surrounding the cell verticies.
3123  real, intent(out) :: area !< The quadrilateral cell area [m2].
3124 
3125 ! X and Y must be passed in the form
3126  ! 3 - 4
3127  ! | |
3128  ! 1 - 2
3129 
3130 ! this subroutine calculates the gradients of bilinear basis elements that
3131 ! that are centered at the vertices of the cell. values are calculated at
3132 ! points of gaussian quadrature. (in 1D: .5 * (1 +/- sqrt(1/3)) for [0,1])
3133 ! (ordered in same way as vertices)
3134 !
3135 ! Phi (2*i-1,j) gives d(Phi_i)/dx at quadrature point j
3136 ! Phi (2*i,j) gives d(Phi_i)/dy at quadrature point j
3137 ! Phi_i is equal to 1 at vertex i, and 0 at vertex k /= i, and bilinear
3138 !
3139 ! This should be a one-off; once per nonlinear solve? once per lifetime?
3140 ! ... will all cells have the same shape and dimension?
3141 
3142  real, dimension(4) :: xquad, yquad
3143  integer :: node, qpoint, xnode, xq, ynode, yq
3144  real :: a,b,c,d,e,f,xexp,yexp
3145 
3146  xquad(1:3:2) = .5 * (1-sqrt(1./3)) ; yquad(1:2) = .5 * (1-sqrt(1./3))
3147  xquad(2:4:2) = .5 * (1+sqrt(1./3)) ; yquad(3:4) = .5 * (1+sqrt(1./3))
3148 
3149  do qpoint=1,4
3150 
3151  a = -x(1)*(1-yquad(qpoint)) + x(2)*(1-yquad(qpoint)) - x(3)*yquad(qpoint) + x(4)*yquad(qpoint) ! d(x)/d(x*)
3152  b = -y(1)*(1-yquad(qpoint)) + y(2)*(1-yquad(qpoint)) - y(3)*yquad(qpoint) + y(4)*yquad(qpoint) ! d(y)/d(x*)
3153  c = -x(1)*(1-xquad(qpoint)) - x(2)*(xquad(qpoint)) + x(3)*(1-xquad(qpoint)) + x(4)*(xquad(qpoint)) ! d(x)/d(y*)
3154  d = -y(1)*(1-xquad(qpoint)) - y(2)*(xquad(qpoint)) + y(3)*(1-xquad(qpoint)) + y(4)*(xquad(qpoint)) ! d(y)/d(y*)
3155 
3156  do node=1,4
3157 
3158  xnode = 2-mod(node,2) ; ynode = ceiling(real(node)/2)
3159 
3160  if (ynode == 1) then
3161  yexp = 1-yquad(qpoint)
3162  else
3163  yexp = yquad(qpoint)
3164  endif
3165 
3166  if (1 == xnode) then
3167  xexp = 1-xquad(qpoint)
3168  else
3169  xexp = xquad(qpoint)
3170  endif
3171 
3172  phi(2*node-1,qpoint) = ( d * (2 * xnode - 3) * yexp - b * (2 * ynode - 3) * xexp) / (a*d-b*c)
3173  phi(2*node,qpoint) = ( -c * (2 * xnode - 3) * yexp + a * (2 * ynode - 3) * xexp) / (a*d-b*c)
3174 
3175  enddo
3176  enddo
3177 
3178  area = quad_area(x, y)
3179 
3180 end subroutine bilinear_shape_functions
3181 
3182 
3183 subroutine bilinear_shape_functions_subgrid(Phisub, nsub)
3184  real, dimension(nsub,nsub,2,2,2,2), &
3185  intent(inout) :: Phisub !< Quadrature structure weights at subgridscale
3186  !! locations for finite element calculations
3187  integer, intent(in) :: nsub !< The nubmer of subgridscale quadrature locations in each direction
3188 
3189  ! this subroutine is a helper for interpolation of floatation condition
3190  ! for the purposes of evaluating the terms \int (u,v) \phi_i dx dy in a cell that is
3191  ! in partial floatation
3192  ! the array Phisub contains the values of \phi_i (where i is a node of the cell)
3193  ! at quad point j
3194  ! i think this general approach may not work for nonrectangular elements...
3195  !
3196 
3197  ! Phisub(i,j,k,l,q1,q2)
3198  ! i: subgrid index in x-direction
3199  ! j: subgrid index in y-direction
3200  ! k: basis function x-index
3201  ! l: basis function y-index
3202  ! q1: quad point x-index
3203  ! q2: quad point y-index
3204 
3205  ! e.g. k=1,l=1 => node 1
3206  ! q1=2,q2=1 => quad point 2
3207 
3208  ! 3 - 4
3209  ! | |
3210  ! 1 - 2
3211 
3212  integer :: i, j, k, l, qx, qy, indx, indy
3213  real,dimension(2) :: xquad
3214  real :: x0, y0, x, y, val, fracx
3215 
3216  xquad(1) = .5 * (1-sqrt(1./3)) ; xquad(2) = .5 * (1+sqrt(1./3))
3217  fracx = 1.0/real(nsub)
3218 
3219  do j=1,nsub
3220  do i=1,nsub
3221  x0 = (i-1) * fracx ; y0 = (j-1) * fracx
3222  do qx=1,2
3223  do qy=1,2
3224  x = x0 + fracx*xquad(qx)
3225  y = y0 + fracx*xquad(qy)
3226  do k=1,2
3227  do l=1,2
3228  val = 1.0
3229  if (k == 1) then
3230  val = val * (1.0-x)
3231  else
3232  val = val * x
3233  endif
3234  if (l == 1) then
3235  val = val * (1.0-y)
3236  else
3237  val = val * y
3238  endif
3239  phisub(i,j,k,l,qx,qy) = val
3240  enddo
3241  enddo
3242  enddo
3243  enddo
3244  enddo
3245  enddo
3246 
3247 end subroutine bilinear_shape_functions_subgrid
3248 
3249 
3250 subroutine update_velocity_masks(CS, G, hmask, umask, vmask, u_face_mask, v_face_mask)
3251  type(ice_shelf_dyn_cs),intent(in) :: CS !< A pointer to the ice shelf dynamics control structure
3252  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
3253  real, dimension(SZDI_(G),SZDJ_(G)), &
3254  intent(in) :: hmask !< A mask indicating which tracer points are
3255  !! partly or fully covered by an ice-shelf
3256  real, dimension(SZDIB_(G),SZDJB_(G)), &
3257  intent(out) :: umask !< A coded mask indicating the nature of the
3258  !! zonal flow at the corner point
3259  real, dimension(SZDIB_(G),SZDJB_(G)), &
3260  intent(out) :: vmask !< A coded mask indicating the nature of the
3261  !! meridional flow at the corner point
3262  real, dimension(SZDIB_(G),SZDJ_(G)), &
3263  intent(out) :: u_face_mask !< A coded mask for velocities at the C-grid u-face
3264  real, dimension(SZDI_(G),SZDJB_(G)), &
3265  intent(out) :: v_face_mask !< A coded mask for velocities at the C-grid v-face
3266  ! sets masks for velocity solve
3267  ! ignores the fact that their might be ice-free cells - this only considers the computational boundary
3268 
3269  ! !!!IMPORTANT!!! relies on thickness mask - assumed that this is called after hmask has been updated & halo-updated
3270 
3271  integer :: i, j, k, iscq, iecq, jscq, jecq, isd, jsd, is, js, iegq, jegq
3272  integer :: giec, gjec, gisc, gjsc, isc, jsc, iec, jec
3273  integer :: i_off, j_off
3274 
3275  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
3276  iscq = g%iscB ; iecq = g%iecB ; jscq = g%jscB ; jecq = g%jecB
3277  i_off = g%idg_offset ; j_off = g%jdg_offset
3278  isd = g%isd ; jsd = g%jsd
3279  iegq = g%iegB ; jegq = g%jegB
3280  gisc = g%Domain%nihalo ; gjsc = g%Domain%njhalo
3281  giec = g%Domain%niglobal+gisc ; gjec = g%Domain%njglobal+gjsc
3282 
3283  umask(:,:) = 0 ; vmask(:,:) = 0
3284  u_face_mask(:,:) = 0 ; v_face_mask(:,:) = 0
3285 
3286  if (g%symmetric) then
3287  is = isd ; js = jsd
3288  else
3289  is = isd+1 ; js = jsd+1
3290  endif
3291 
3292  do j=js,g%jed
3293  do i=is,g%ied
3294 
3295  if (hmask(i,j) == 1) then
3296 
3297  umask(i-1:i,j-1:j) = 1.
3298  vmask(i-1:i,j-1:j) = 1.
3299 
3300  do k=0,1
3301 
3302  select case (int(cs%u_face_mask_bdry(i-1+k,j)))
3303  case (3)
3304  umask(i-1+k,j-1:j)=3.
3305  vmask(i-1+k,j-1:j)=0.
3306  u_face_mask(i-1+k,j)=3.
3307  case (2)
3308  u_face_mask(i-1+k,j)=2.
3309  case (4)
3310  umask(i-1+k,j-1:j)=0.
3311  vmask(i-1+k,j-1:j)=0.
3312  u_face_mask(i-1+k,j)=4.
3313  case (0)
3314  umask(i-1+k,j-1:j)=0.
3315  vmask(i-1+k,j-1:j)=0.
3316  u_face_mask(i-1+k,j)=0.
3317  case (1) ! stress free x-boundary
3318  umask(i-1+k,j-1:j)=0.
3319  case default
3320  end select
3321  enddo
3322 
3323  do k=0,1
3324 
3325  select case (int(cs%v_face_mask_bdry(i,j-1+k)))
3326  case (3)
3327  vmask(i-1:i,j-1+k)=3.
3328  umask(i-1:i,j-1+k)=0.
3329  v_face_mask(i,j-1+k)=3.
3330  case (2)
3331  v_face_mask(i,j-1+k)=2.
3332  case (4)
3333  umask(i-1:i,j-1+k)=0.
3334  vmask(i-1:i,j-1+k)=0.
3335  v_face_mask(i,j-1+k)=4.
3336  case (0)
3337  umask(i-1:i,j-1+k)=0.
3338  vmask(i-1:i,j-1+k)=0.
3339  u_face_mask(i,j-1+k)=0.
3340  case (1) ! stress free y-boundary
3341  vmask(i-1:i,j-1+k)=0.
3342  case default
3343  end select
3344  enddo
3345 
3346  !if (CS%u_face_mask_bdry(i-1,j) >= 0) then !left boundary
3347  ! u_face_mask(i-1,j) = CS%u_face_mask_bdry(i-1,j)
3348  ! umask(i-1,j-1:j) = 3.
3349  ! vmask(i-1,j-1:j) = 0.
3350  !endif
3351 
3352  !if (j_off+j == gjsc+1) then !bot boundary
3353  ! v_face_mask(i,j-1) = 0.
3354  ! umask (i-1:i,j-1) = 0.
3355  ! vmask (i-1:i,j-1) = 0.
3356  !elseif (j_off+j == gjec) then !top boundary
3357  ! v_face_mask(i,j) = 0.
3358  ! umask (i-1:i,j) = 0.
3359  ! vmask (i-1:i,j) = 0.
3360  !endif
3361 
3362  if (i < g%ied) then
3363  if ((hmask(i+1,j) == 0) &
3364  .OR. (hmask(i+1,j) == 2)) then
3365  !right boundary or adjacent to unfilled cell
3366  u_face_mask(i,j) = 2.
3367  endif
3368  endif
3369 
3370  if (i > g%isd) then
3371  if ((hmask(i-1,j) == 0) .OR. (hmask(i-1,j) == 2)) then
3372  !adjacent to unfilled cell
3373  u_face_mask(i-1,j) = 2.
3374  endif
3375  endif
3376 
3377  if (j > g%jsd) then
3378  if ((hmask(i,j-1) == 0) .OR. (hmask(i,j-1) == 2)) then
3379  !adjacent to unfilled cell
3380  v_face_mask(i,j-1) = 2.
3381  endif
3382  endif
3383 
3384  if (j < g%jed) then
3385  if ((hmask(i,j+1) == 0) .OR. (hmask(i,j+1) == 2)) then
3386  !adjacent to unfilled cell
3387  v_face_mask(i,j) = 2.
3388  endif
3389  endif
3390 
3391 
3392  endif
3393 
3394  enddo
3395  enddo
3396 
3397  ! note: if the grid is nonsymmetric, there is a part that will not be transferred with a halo update
3398  ! so this subroutine must update its own symmetric part of the halo
3399 
3400  call pass_vector(u_face_mask, v_face_mask, g%domain, to_all, cgrid_ne)
3401  call pass_vector(umask, vmask, g%domain, to_all, bgrid_ne)
3402 
3403 end subroutine update_velocity_masks
3404 
3405 !> Interpolate the ice shelf thickness from tracer point to nodal points,
3406 !! subject to a mask.
3407 subroutine interpolate_h_to_b(G, h_shelf, hmask, H_node)
3408  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
3409  real, dimension(SZDI_(G),SZDJ_(G)), &
3410  intent(in) :: h_shelf !< The ice shelf thickness at tracer points [Z ~> m].
3411  real, dimension(SZDI_(G),SZDJ_(G)), &
3412  intent(in) :: hmask !< A mask indicating which tracer points are
3413  !! partly or fully covered by an ice-shelf
3414  real, dimension(SZDIB_(G),SZDJB_(G)), &
3415  intent(inout) :: H_node !< The ice shelf thickness at nodal (corner)
3416  !! points [Z ~> m].
3417 
3418  integer :: i, j, isc, iec, jsc, jec, num_h, k, l
3419  real :: summ
3420 
3421  isc = g%isc ; jsc = g%jsc ; iec = g%iec ; jec = g%jec
3422 
3423  h_node(:,:) = 0.0
3424 
3425  ! H_node is node-centered; average over all cells that share that node
3426  ! if no (active) cells share the node then its value there is irrelevant
3427 
3428  do j=jsc-1,jec
3429  do i=isc-1,iec
3430  summ = 0.0
3431  num_h = 0
3432  do k=0,1
3433  do l=0,1
3434  if (hmask(i+k,j+l) == 1.0) then
3435  summ = summ + h_shelf(i+k,j+l)
3436  num_h = num_h + 1
3437  endif
3438  enddo
3439  enddo
3440  if (num_h > 0) then
3441  h_node(i,j) = summ / num_h
3442  endif
3443  enddo
3444  enddo
3445 
3446  call pass_var(h_node, g%domain, position=corner)
3447 
3448 end subroutine interpolate_h_to_b
3449 
3450 !> Deallocates all memory associated with the ice shelf dynamics module
3451 subroutine ice_shelf_dyn_end(CS)
3452  type(ice_shelf_dyn_cs), pointer :: cs !< A pointer to the ice shelf dynamics control structure
3453 
3454  if (.not.associated(cs)) return
3455 
3456  deallocate(cs%u_shelf, cs%v_shelf)
3457  deallocate(cs%t_shelf, cs%tmask)
3458  deallocate(cs%u_bdry_val, cs%v_bdry_val, cs%t_bdry_val)
3459  deallocate(cs%u_face_mask, cs%v_face_mask)
3460  deallocate(cs%umask, cs%vmask)
3461 
3462  deallocate(cs%ice_visc, cs%taub_beta_eff)
3463  deallocate(cs%OD_rt, cs%OD_av)
3464  deallocate(cs%float_frac, cs%float_frac_rt)
3465 
3466  deallocate(cs)
3467 
3468 end subroutine ice_shelf_dyn_end
3469 
3470 
3471 !> This subroutine updates the vertically averaged ice shelf temperature.
3472 subroutine ice_shelf_temp(CS, ISS, G, US, time_step, melt_rate, Time)
3473  type(ice_shelf_dyn_cs), intent(inout) :: CS !< A pointer to the ice shelf control structure
3474  type(ice_shelf_state), intent(in) :: ISS !< A structure with elements that describe
3475  !! the ice-shelf state
3476  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
3477  type(unit_scale_type), intent(in) :: US !< Pointer to a structure containing unit conversion factors
3478  real, intent(in) :: time_step !< The time step for this update [s].
3479  real, dimension(SZDI_(G),SZDJ_(G)), &
3480  intent(in) :: melt_rate !< basal melt rate [kg m-2 s-1]
3481  type(time_type), intent(in) :: Time !< The current model time
3482 
3483 ! 5/23/12 OVS
3484 ! This subroutine takes the velocity (on the Bgrid) and timesteps
3485 ! (HT)_t = - div (uHT) + (adot Tsurf -bdot Tbot) once and then calculates T=HT/H
3486 !
3487 ! The flux overflows are included here. That is because they will be used to advect 3D scalars
3488 ! into partial cells
3489 
3490  !
3491  ! flux_enter: this is to capture flow into partially covered cells; it gives the mass flux into a given
3492  ! cell across its boundaries.
3493  ! ###Perhaps flux_enter should be changed into u-face and v-face
3494  ! ###fluxes, which can then be used in halo updates, etc.
3495  !
3496  ! from left neighbor: flux_enter(:,:,1)
3497  ! from right neighbor: flux_enter(:,:,2)
3498  ! from bottom neighbor: flux_enter(:,:,3)
3499  ! from top neighbor: flux_enter(:,:,4)
3500  !
3501  ! THESE ARE NOT CONSISTENT ==> FIND OUT WHAT YOU IMPLEMENTED
3502 
3503  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
3504  !
3505  ! o--- (4) ---o
3506  ! | |
3507  ! (1) (2)
3508  ! | |
3509  ! o--- (3) ---o
3510  !
3511 
3512  real, dimension(SZDI_(G),SZDJ_(G)) :: th_after_uflux, th_after_vflux, TH
3513  real, dimension(SZDI_(G),SZDJ_(G),4) :: flux_enter
3514  integer :: isd, ied, jsd, jed, i, j, isc, iec, jsc, jec
3515  real :: rho, spy, t_bd, Tsurf, adot
3516 
3517  rho = cs%density_ice
3518  spy = 365 * 86400 ! seconds per year; is there a global constant for this? No - it is dependent upon a calendar.
3519 
3520  adot = 0.1*us%m_to_Z/spy ! for now adot and Tsurf are defined here adot=surf acc 0.1m/yr, Tsurf=-20oC, vary them later
3521  tsurf = -20.0
3522 
3523  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
3524  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec
3525  flux_enter(:,:,:) = 0.0
3526 
3527  th_after_uflux(:,:) = 0.0
3528  th_after_vflux(:,:) = 0.0
3529 
3530  do j=jsd,jed
3531  do i=isd,ied
3532  t_bd = cs%t_bdry_val(i,j)
3533 ! if (ISS%hmask(i,j) > 1) then
3534  if ((iss%hmask(i,j) == 3) .or. (iss%hmask(i,j) == -2)) then
3535  cs%t_shelf(i,j) = cs%t_bdry_val(i,j)
3536  endif
3537  enddo
3538  enddo
3539 
3540  do j=jsd,jed
3541  do i=isd,ied
3542  th(i,j) = cs%t_shelf(i,j)*iss%h_shelf(i,j)
3543  enddo
3544  enddo
3545 
3546 
3547 ! call enable_averaging(time_step,Time,CS%diag)
3548 ! call pass_var(h_after_uflux, G%domain)
3549 ! call pass_var(h_after_vflux, G%domain)
3550 ! if (CS%id_h_after_uflux > 0) call post_data(CS%id_h_after_uflux, h_after_uflux, CS%diag)
3551 ! if (CS%id_h_after_vflux > 0) call post_data(CS%id_h_after_vflux, h_after_vflux, CS%diag)
3552 ! call disable_averaging(CS%diag)
3553 
3554  call ice_shelf_advect_temp_x(cs, g, time_step/spy, iss%hmask, th, th_after_uflux, flux_enter)
3555  call ice_shelf_advect_temp_y(cs, g, time_step/spy, iss%hmask, th_after_uflux, th_after_vflux, flux_enter)
3556 
3557  do j=jsd,jed
3558  do i=isd,ied
3559 ! if (ISS%hmask(i,j) == 1) then
3560  if (iss%h_shelf(i,j) > 0.0) then
3561  cs%t_shelf(i,j) = th_after_vflux(i,j)/(iss%h_shelf(i,j))
3562  else
3563  cs%t_shelf(i,j) = -10.0
3564  endif
3565  enddo
3566  enddo
3567 
3568  do j=jsd,jed
3569  do i=isd,ied
3570  t_bd = cs%t_bdry_val(i,j)
3571 ! if (ISS%hmask(i,j) > 1) then
3572  if ((iss%hmask(i,j) == 3) .or. (iss%hmask(i,j) == -2)) then
3573  cs%t_shelf(i,j) = t_bd
3574 ! CS%t_shelf(i,j) = -15.0
3575  endif
3576  enddo
3577  enddo
3578 
3579  do j=jsc,jec
3580  do i=isc,iec
3581  if ((iss%hmask(i,j) == 1) .or. (iss%hmask(i,j) == 2)) then
3582  if (iss%h_shelf(i,j) > 0.0) then
3583 ! CS%t_shelf(i,j) = CS%t_shelf(i,j) + &
3584 ! time_step*(adot*Tsurf - US%m_to_Z*melt_rate(i,j)*ISS%tfreeze(i,j))/(ISS%h_shelf(i,j))
3585  cs%t_shelf(i,j) = cs%t_shelf(i,j) + &
3586  time_step*(adot*tsurf - (3.0*us%m_to_Z/spy)*iss%tfreeze(i,j)) / iss%h_shelf(i,j)
3587  else
3588  ! the ice is about to melt away
3589  ! in this case set thickness, area, and mask to zero
3590  ! NOTE: not mass conservative
3591  ! should maybe scale salt & heat flux for this cell
3592 
3593  cs%t_shelf(i,j) = -10.0
3594  cs%tmask(i,j) = 0.0
3595  endif
3596  endif
3597  enddo
3598  enddo
3599 
3600  call pass_var(cs%t_shelf, g%domain)
3601  call pass_var(cs%tmask, g%domain)
3602 
3603  if (cs%debug) then
3604  call hchksum(cs%t_shelf, "temp after front", g%HI, haloshift=3)
3605  endif
3606 
3607 end subroutine ice_shelf_temp
3608 
3609 
3610 subroutine ice_shelf_advect_temp_x(CS, G, time_step, hmask, h0, h_after_uflux, flux_enter)
3611  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
3612  type(ocean_grid_type), intent(inout) :: G !< The grid structure used by the ice shelf.
3613  real, intent(in) :: time_step !< The time step for this update [s].
3614  real, dimension(SZDI_(G),SZDJ_(G)), &
3615  intent(in) :: hmask !< A mask indicating which tracer points are
3616  !! partly or fully covered by an ice-shelf
3617  real, dimension(SZDI_(G),SZDJ_(G)), &
3618  intent(in) :: h0 !< The initial ice shelf thicknesses [Z ~> m].
3619  real, dimension(SZDI_(G),SZDJ_(G)), &
3620  intent(inout) :: h_after_uflux !< The ice shelf thicknesses after
3621  !! the zonal mass fluxes [Z ~> m].
3622  real, dimension(SZDI_(G),SZDJ_(G),4), &
3623  intent(inout) :: flux_enter !< The integrated temperature flux into
3624  !! the cell through the 4 cell boundaries [degC Z m2 ~> degC m3]
3625 
3626  ! use will be made of ISS%hmask here - its value at the boundary will be zero, just like uncovered cells
3627 
3628  ! if there is an input bdry condition, the thickness there will be set in initialization
3629 
3630  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
3631  !
3632  ! from left neighbor: flux_enter(:,:,1)
3633  ! from right neighbor: flux_enter(:,:,2)
3634  ! from bottom neighbor: flux_enter(:,:,3)
3635  ! from top neighbor: flux_enter(:,:,4)
3636  !
3637  ! o--- (4) ---o
3638  ! | |
3639  ! (1) (2)
3640  ! | |
3641  ! o--- (3) ---o
3642  !
3643 
3644  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed, gjed, gied
3645  integer :: i_off, j_off
3646  logical :: at_east_bdry, at_west_bdry, one_off_west_bdry, one_off_east_bdry
3647  real, dimension(-2:2) :: stencil
3648  real :: u_face, & ! positive if out
3649  flux_diff_cell, phi, dxh, dyh, dxdyh
3650 
3651  character (len=1) :: debug_str
3652 
3653 
3654  is = g%isc-2 ; ie = g%iec+2 ; js = g%jsc ; je = g%jec ; isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
3655  i_off = g%idg_offset ; j_off = g%jdg_offset
3656 
3657  do j=jsd+1,jed-1
3658  if (((j+j_off) <= g%domain%njglobal+g%domain%njhalo) .AND. &
3659  ((j+j_off) >= g%domain%njhalo+1)) then ! based on mehmet's code - only if btw north & south boundaries
3660 
3661  stencil(:) = -1
3662 ! if (i+i_off == G%domain%nihalo+G%domain%nihalo)
3663  do i=is,ie
3664 
3665  if (((i+i_off) <= g%domain%niglobal+g%domain%nihalo) .AND. &
3666  ((i+i_off) >= g%domain%nihalo+1)) then
3667 
3668  if (i+i_off == g%domain%nihalo+1) then
3669  at_west_bdry=.true.
3670  else
3671  at_west_bdry=.false.
3672  endif
3673 
3674  if (i+i_off == g%domain%niglobal+g%domain%nihalo) then
3675  at_east_bdry=.true.
3676  else
3677  at_east_bdry=.false.
3678  endif
3679 
3680  if (hmask(i,j) == 1) then
3681 
3682  dxh = g%dxT(i,j) ; dyh = g%dyT(i,j) ; dxdyh = g%areaT(i,j)
3683 
3684  h_after_uflux(i,j) = h0(i,j)
3685 
3686  stencil(:) = h0(i-2:i+2,j) ! fine as long has nx_halo >= 2
3687 
3688  flux_diff_cell = 0
3689 
3690  ! 1ST DO LEFT FACE
3691 
3692  if (cs%u_face_mask(i-1,j) == 4.) then
3693 
3694  flux_diff_cell = flux_diff_cell + dyh * time_step * cs%u_flux_bdry_val(i-1,j) * &
3695  cs%t_bdry_val(i-1,j) / dxdyh
3696  else
3697 
3698  ! get u-velocity at center of left face
3699  u_face = 0.5 * (cs%u_shelf(i-1,j-1) + cs%u_shelf(i-1,j))
3700 
3701  if (u_face > 0) then !flux is into cell - we need info from h(i-2), h(i-1) if available
3702 
3703  ! i may not cover all the cases.. but i cover the realistic ones
3704 
3705  if (at_west_bdry .AND. (hmask(i-1,j) == 3)) then ! at western bdry but there is a
3706  ! thickness bdry condition, and the stencil contains it
3707  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step * stencil(-1) / dxdyh
3708 
3709  elseif (hmask(i-1,j) * hmask(i-2,j) == 1) then ! h(i-2) and h(i-1) are valid
3710  phi = slope_limiter(stencil(-1)-stencil(-2), stencil(0)-stencil(-1))
3711  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh* time_step / dxdyh * &
3712  (stencil(-1) - phi * (stencil(-1)-stencil(0))/2)
3713 
3714  else ! h(i-1) is valid
3715  ! (o.w. flux would most likely be out of cell)
3716  ! but h(i-2) is not
3717 
3718  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step / dxdyh * stencil(-1)
3719 
3720  endif
3721 
3722  elseif (u_face < 0) then !flux is out of cell - we need info from h(i-1), h(i+1) if available
3723  if (hmask(i-1,j) * hmask(i+1,j) == 1) then ! h(i-1) and h(i+1) are both valid
3724  phi = slope_limiter(stencil(0)-stencil(1), stencil(-1)-stencil(0))
3725  flux_diff_cell = flux_diff_cell - abs(u_face) * dyh * time_step / dxdyh * &
3726  (stencil(0) - phi * (stencil(0)-stencil(-1))/2)
3727 
3728  else
3729  flux_diff_cell = flux_diff_cell - abs(u_face) * dyh * time_step / dxdyh * stencil(0)
3730 
3731  if ((hmask(i-1,j) == 0) .OR. (hmask(i-1,j) == 2)) then
3732  flux_enter(i-1,j,2) = abs(u_face) * dyh * time_step * stencil(0)
3733  endif
3734  endif
3735  endif
3736  endif
3737 
3738  ! NEXT DO RIGHT FACE
3739 
3740  ! get u-velocity at center of right face
3741 
3742  if (cs%u_face_mask(i+1,j) == 4.) then
3743 
3744  flux_diff_cell = flux_diff_cell + dyh * time_step * cs%u_flux_bdry_val(i+1,j) *&
3745  cs%t_bdry_val(i+1,j)/ dxdyh
3746  else
3747 
3748  u_face = 0.5 * (cs%u_shelf(i,j-1) + cs%u_shelf(i,j))
3749 
3750  if (u_face < 0) then !flux is into cell - we need info from h(i+2), h(i+1) if available
3751 
3752  if (at_east_bdry .AND. (hmask(i+1,j) == 3)) then ! at eastern bdry but there is a
3753  ! thickness bdry condition, and the stencil contains it
3754 
3755  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step * stencil(1) / dxdyh
3756 
3757  elseif (hmask(i+1,j) * hmask(i+2,j) == 1) then ! h(i+2) and h(i+1) are valid
3758 
3759  phi = slope_limiter(stencil(1)-stencil(2), stencil(0)-stencil(1))
3760  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step / dxdyh * &
3761  (stencil(1) - phi * (stencil(1)-stencil(0))/2)
3762 
3763  else ! h(i+1) is valid
3764  ! (o.w. flux would most likely be out of cell)
3765  ! but h(i+2) is not
3766 
3767  flux_diff_cell = flux_diff_cell + abs(u_face) * dyh * time_step / dxdyh * stencil(1)
3768 
3769  endif
3770 
3771  elseif (u_face > 0) then !flux is out of cell - we need info from h(i-1), h(i+1) if available
3772 
3773  if (hmask(i-1,j) * hmask(i+1,j) == 1) then ! h(i-1) and h(i+1) are both valid
3774 
3775  phi = slope_limiter(stencil(0)-stencil(-1), stencil(1)-stencil(0))
3776  flux_diff_cell = flux_diff_cell - abs(u_face) * dyh * time_step / dxdyh * &
3777  (stencil(0) - phi * (stencil(0)-stencil(1))/2)
3778 
3779  else ! h(i+1) is valid
3780  ! (o.w. flux would most likely be out of cell)
3781  ! but h(i+2) is not
3782 
3783  flux_diff_cell = flux_diff_cell - abs(u_face) * dyh * time_step / dxdyh * stencil(0)
3784 
3785  if ((hmask(i+1,j) == 0) .OR. (hmask(i+1,j) == 2)) then
3786 
3787  flux_enter(i+1,j,1) = abs(u_face) * dyh * time_step * stencil(0)
3788  endif
3789 
3790  endif
3791 
3792  endif
3793 
3794  h_after_uflux(i,j) = h_after_uflux(i,j) + flux_diff_cell
3795 
3796  endif
3797 
3798  elseif ((hmask(i,j) == 0) .OR. (hmask(i,j) == 2)) then
3799 
3800  if (at_west_bdry .AND. (hmask(i-1,j) == 3)) then
3801  u_face = 0.5 * (cs%u_shelf(i-1,j-1) + cs%u_shelf(i-1,j))
3802  flux_enter(i,j,1) = abs(u_face) * g%dyT(i,j) * time_step * cs%t_bdry_val(i-1,j)* &
3803  cs%thickness_bdry_val(i+1,j)
3804  elseif (cs%u_face_mask(i-1,j) == 4.) then
3805  flux_enter(i,j,1) = g%dyT(i,j) * time_step * cs%u_flux_bdry_val(i-1,j)*cs%t_bdry_val(i-1,j)
3806  endif
3807 
3808  if (at_east_bdry .AND. (hmask(i+1,j) == 3)) then
3809  u_face = 0.5 * (cs%u_shelf(i,j-1) + cs%u_shelf(i,j))
3810  flux_enter(i,j,2) = abs(u_face) * g%dyT(i,j) * time_step * cs%t_bdry_val(i+1,j)* &
3811  cs%thickness_bdry_val(i+1,j)
3812  elseif (cs%u_face_mask(i+1,j) == 4.) then
3813  flux_enter(i,j,2) = g%dyT(i,j) * time_step * cs%u_flux_bdry_val(i+1,j) * cs%t_bdry_val(i+1,j)
3814  endif
3815 
3816 ! if ((i == is) .AND. (hmask(i,j) == 0) .AND. (hmask(i-1,j) == 1)) then
3817  ! this is solely for the purposes of keeping the mask consistent while advancing
3818  ! the front without having to call pass_var - if cell is empty and cell to left
3819  ! is ice-covered then this cell will become partly covered
3820 ! hmask(i,j) = 2
3821 ! elseif ((i == ie) .AND. (hmask(i,j) == 0) .AND. (hmask(i+1,j) == 1)) then
3822  ! this is solely for the purposes of keeping the mask consistent while advancing
3823  ! the front without having to call pass_var - if cell is empty and cell to left
3824  ! is ice-covered then this cell will become partly covered
3825 ! hmask(i,j) = 2
3826 
3827 ! endif
3828 
3829  endif
3830 
3831  endif
3832 
3833  enddo ! i loop
3834 
3835  endif
3836 
3837  enddo ! j loop
3838 
3839 end subroutine ice_shelf_advect_temp_x
3840 
3841 subroutine ice_shelf_advect_temp_y(CS, G, time_step, hmask, h_after_uflux, h_after_vflux, flux_enter)
3842  type(ice_shelf_dyn_cs), intent(in) :: CS !< A pointer to the ice shelf control structure
3843  type(ocean_grid_type), intent(in) :: G !< The grid structure used by the ice shelf.
3844  real, intent(in) :: time_step !< The time step for this update [s].
3845  real, dimension(SZDI_(G),SZDJ_(G)), &
3846  intent(in) :: hmask !< A mask indicating which tracer points are
3847  !! partly or fully covered by an ice-shelf
3848  real, dimension(SZDI_(G),SZDJ_(G)), &
3849  intent(in) :: h_after_uflux !< The ice shelf thicknesses after
3850  !! the zonal mass fluxes [Z ~> m].
3851  real, dimension(SZDI_(G),SZDJ_(G)), &
3852  intent(inout) :: h_after_vflux !< The ice shelf thicknesses after
3853  !! the meridional mass fluxes [Z ~> m].
3854  real, dimension(SZDI_(G),SZDJ_(G),4), &
3855  intent(inout) :: flux_enter !< The integrated temperature flux into
3856  !! the cell through the 4 cell boundaries [degC Z m2 ~> degC m3]
3857 
3858  ! use will be made of ISS%hmask here - its value at the boundary will be zero, just like uncovered cells
3859 
3860  ! if there is an input bdry condition, the thickness there will be set in initialization
3861 
3862  ! flux_enter(isd:ied,jsd:jed,1:4): if cell is not ice-covered, gives flux of ice into cell from kth boundary
3863  !
3864  ! from left neighbor: flux_enter(:,:,1)
3865  ! from right neighbor: flux_enter(:,:,2)
3866  ! from bottom neighbor: flux_enter(:,:,3)
3867  ! from top neighbor: flux_enter(:,:,4)
3868  !
3869  ! o--- (4) ---o
3870  ! | |
3871  ! (1) (2)
3872  ! | |
3873  ! o--- (3) ---o
3874  !
3875 
3876  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed, gjed, gied
3877  integer :: i_off, j_off
3878  logical :: at_north_bdry, at_south_bdry, one_off_west_bdry, one_off_east_bdry
3879  real, dimension(-2:2) :: stencil
3880  real :: v_face, & ! positive if out
3881  flux_diff_cell, phi, dxh, dyh, dxdyh
3882  character(len=1) :: debug_str
3883 
3884  is = g%isc ; ie = g%iec ; js = g%jsc-1 ; je = g%jec+1 ; isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
3885  i_off = g%idg_offset ; j_off = g%jdg_offset
3886 
3887  do i=isd+2,ied-2
3888  if (((i+i_off) <= g%domain%niglobal+g%domain%nihalo) .AND. &
3889  ((i+i_off) >= g%domain%nihalo+1)) then ! based on mehmet's code - only if btw east & west boundaries
3890 
3891  stencil(:) = -1
3892 
3893  do j=js,je
3894 
3895  if (((j+j_off) <= g%domain%njglobal+g%domain%njhalo) .AND. &
3896  ((j+j_off) >= g%domain%njhalo+1)) then
3897 
3898  if (j+j_off == g%domain%njhalo+1) then
3899  at_south_bdry=.true.
3900  else
3901  at_south_bdry=.false.
3902  endif
3903  if (j+j_off == g%domain%njglobal+g%domain%njhalo) then
3904  at_north_bdry=.true.
3905  else
3906  at_north_bdry=.false.
3907  endif
3908 
3909  if (hmask(i,j) == 1) then
3910  dxh = g%dxT(i,j) ; dyh = g%dyT(i,j) ; dxdyh = g%areaT(i,j)
3911  h_after_vflux(i,j) = h_after_uflux(i,j)
3912 
3913  stencil(:) = h_after_uflux(i,j-2:j+2) ! fine as long has ny_halo >= 2
3914  flux_diff_cell = 0
3915 
3916  ! 1ST DO south FACE
3917 
3918  if (cs%v_face_mask(i,j-1) == 4.) then
3919 
3920  flux_diff_cell = flux_diff_cell + dxh * time_step * cs%v_flux_bdry_val(i,j-1) * &
3921  cs%t_bdry_val(i,j-1)/ dxdyh
3922  else
3923 
3924  ! get u-velocity at center of left face
3925  v_face = 0.5 * (cs%v_shelf(i-1,j-1) + cs%v_shelf(i,j-1))
3926 
3927  if (v_face > 0) then !flux is into cell - we need info from h(j-2), h(j-1) if available
3928 
3929  ! i may not cover all the cases.. but i cover the realistic ones
3930 
3931  if (at_south_bdry .AND. (hmask(i,j-1) == 3)) then ! at western bdry but there is a
3932  ! thickness bdry condition, and the stencil contains it
3933  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step * stencil(-1) / dxdyh
3934 
3935  elseif (hmask(i,j-1) * hmask(i,j-2) == 1) then ! h(j-2) and h(j-1) are valid
3936 
3937  phi = slope_limiter(stencil(-1)-stencil(-2), stencil(0)-stencil(-1))
3938  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * &
3939  (stencil(-1) - phi * (stencil(-1)-stencil(0))/2)
3940 
3941  else ! h(j-1) is valid
3942  ! (o.w. flux would most likely be out of cell)
3943  ! but h(j-2) is not
3944  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * stencil(-1)
3945  endif
3946 
3947  elseif (v_face < 0) then !flux is out of cell - we need info from h(j-1), h(j+1) if available
3948 
3949  if (hmask(i,j-1) * hmask(i,j+1) == 1) then ! h(j-1) and h(j+1) are both valid
3950  phi = slope_limiter(stencil(0)-stencil(1), stencil(-1)-stencil(0))
3951  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * &
3952  (stencil(0) - phi * (stencil(0)-stencil(-1))/2)
3953  else
3954  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * stencil(0)
3955 
3956  if ((hmask(i,j-1) == 0) .OR. (hmask(i,j-1) == 2)) then
3957  flux_enter(i,j-1,4) = abs(v_face) * dyh * time_step * stencil(0)
3958  endif
3959 
3960  endif
3961 
3962  endif
3963 
3964  endif
3965 
3966  ! NEXT DO north FACE
3967 
3968  if (cs%v_face_mask(i,j+1) == 4.) then
3969 
3970  flux_diff_cell = flux_diff_cell + dxh * time_step * cs%v_flux_bdry_val(i,j+1) *&
3971  cs%t_bdry_val(i,j+1)/ dxdyh
3972  else
3973 
3974  ! get u-velocity at center of right face
3975  v_face = 0.5 * (cs%v_shelf(i-1,j) + cs%v_shelf(i,j))
3976 
3977  if (v_face < 0) then !flux is into cell - we need info from h(j+2), h(j+1) if available
3978 
3979  if (at_north_bdry .AND. (hmask(i,j+1) == 3)) then ! at eastern bdry but there is a
3980  ! thickness bdry condition, and the stencil contains it
3981  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step * stencil(1) / dxdyh
3982  elseif (hmask(i,j+1) * hmask(i,j+2) == 1) then ! h(j+2) and h(j+1) are valid
3983  phi = slope_limiter(stencil(1)-stencil(2), stencil(0)-stencil(1))
3984  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * &
3985  (stencil(1) - phi * (stencil(1)-stencil(0))/2)
3986  else ! h(j+1) is valid
3987  ! (o.w. flux would most likely be out of cell)
3988  ! but h(j+2) is not
3989  flux_diff_cell = flux_diff_cell + abs(v_face) * dxh * time_step / dxdyh * stencil(1)
3990  endif
3991 
3992  elseif (v_face > 0) then !flux is out of cell - we need info from h(j-1), h(j+1) if available
3993 
3994  if (hmask(i,j-1) * hmask(i,j+1) == 1) then ! h(j-1) and h(j+1) are both valid
3995  phi = slope_limiter(stencil(0)-stencil(-1), stencil(1)-stencil(0))
3996  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * &
3997  (stencil(0) - phi * (stencil(0)-stencil(1))/2)
3998  else ! h(j+1) is valid
3999  ! (o.w. flux would most likely be out of cell)
4000  ! but h(j+2) is not
4001  flux_diff_cell = flux_diff_cell - abs(v_face) * dxh * time_step / dxdyh * stencil(0)
4002  if ((hmask(i,j+1) == 0) .OR. (hmask(i,j+1) == 2)) then
4003  flux_enter(i,j+1,3) = abs(v_face) * dxh * time_step * stencil(0)
4004  endif
4005  endif
4006 
4007  endif
4008 
4009  endif
4010 
4011  h_after_vflux(i,j) = h_after_vflux(i,j) + flux_diff_cell
4012 
4013  elseif ((hmask(i,j) == 0) .OR. (hmask(i,j) == 2)) then
4014 
4015  if (at_south_bdry .AND. (hmask(i,j-1) == 3)) then
4016  v_face = 0.5 * (cs%v_shelf(i-1,j-1) + cs%v_shelf(i,j-1))
4017  flux_enter(i,j,3) = abs(v_face) * g%dxT(i,j) * time_step * cs%t_bdry_val(i,j-1)* &
4018  cs%thickness_bdry_val(i,j-1)
4019  elseif (cs%v_face_mask(i,j-1) == 4.) then
4020  flux_enter(i,j,3) = g%dxT(i,j) * time_step * cs%v_flux_bdry_val(i,j-1)*cs%t_bdry_val(i,j-1)
4021  endif
4022 
4023  if (at_north_bdry .AND. (hmask(i,j+1) == 3)) then
4024  v_face = 0.5 * (cs%v_shelf(i-1,j) + cs%v_shelf(i,j))
4025  flux_enter(i,j,4) = abs(v_face) * g%dxT(i,j) * time_step * cs%t_bdry_val(i,j+1)* &
4026  cs%thickness_bdry_val(i,j+1)
4027  elseif (cs%v_face_mask(i,j+1) == 4.) then
4028  flux_enter(i,j,4) = g%dxT(i,j) * time_step * cs%v_flux_bdry_val(i,j+1)*cs%t_bdry_val(i,j+1)
4029  endif
4030 
4031 ! if ((j == js) .AND. (hmask(i,j) == 0) .AND. (hmask(i,j-1) == 1)) then
4032  ! this is solely for the purposes of keeping the mask consistent while advancing
4033  ! the front without having to call pass_var - if cell is empty and cell to left
4034  ! is ice-covered then this cell will become partly covered
4035  ! hmask(i,j) = 2
4036  ! elseif ((j == je) .AND. (hmask(i,j) == 0) .AND. (hmask(i,j+1) == 1)) then
4037  ! this is solely for the purposes of keeping the mask consistent while advancing the
4038  ! front without having to call pass_var - if cell is empty and cell to left is
4039  ! ice-covered then this cell will become partly covered
4040 ! hmask(i,j) = 2
4041 ! endif
4042 
4043  endif
4044  endif
4045  enddo ! j loop
4046  endif
4047  enddo ! i loop
4048 
4049 end subroutine ice_shelf_advect_temp_y
4050 
4051 end module mom_ice_shelf_dynamics
mom_time_manager
Wraps the FMS time manager functions.
Definition: MOM_time_manager.F90:2
mom_ice_shelf_dynamics
Implements a crude placeholder for a later implementation of full ice shelf dynamics.
Definition: MOM_ice_shelf_dynamics.F90:3
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_checksums::qchksum
This is an older interface that has been renamed Bchksum.
Definition: MOM_checksums.F90:58
mom_diag_mediator
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Definition: MOM_diag_mediator.F90:3
mom_domains::pass_var
Do a halo update on an array.
Definition: MOM_domains.F90:49
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_io
This module contains I/O framework code.
Definition: MOM_io.F90:2
mom_restart::mom_restart_cs
A restart registry and the control structure for restarts.
Definition: MOM_restart.F90:72
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
mom_coms
Interfaces to non-domain-oriented communication subroutines, including the MOM6 reproducing sums faci...
Definition: MOM_coms.F90:3
mom_ice_shelf_dynamics::ice_shelf_dyn_cs
The control structure for the ice shelf dynamics.
Definition: MOM_ice_shelf_dynamics.F90:41
mom_diag_mediator::post_data
Make a diagnostic available for averaging or output.
Definition: MOM_diag_mediator.F90:70
mom_domains::pass_vector
Do a halo update on a pair of arrays representing the two components of a vector.
Definition: MOM_domains.F90:54
mom_domains::clone_mom_domain
Copy one MOM_domain_type into another.
Definition: MOM_domains.F90:94
mom_ice_shelf_state
Implements the thermodynamic aspects of ocean / ice-shelf interactions, along with a crude placeholde...
Definition: MOM_ice_shelf_state.F90:4
mom_checksums
Routines to calculate checksums of various array and vector types.
Definition: MOM_checksums.F90:2
mom_restart
The MOM6 facility for reading and writing restart files, and querying what has been read.
Definition: MOM_restart.F90:2
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_io::mom_read_data
Read a data field from a file.
Definition: MOM_io.F90:74
mom_ice_shelf_state::ice_shelf_state
Structure that describes the ice shelf state.
Definition: MOM_ice_shelf_state.F90:24
mom_cpu_clock
Wraps the MPP cpu clock functions.
Definition: MOM_cpu_clock.F90:2
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_restart::register_restart_field
Register fields for restarts.
Definition: MOM_restart.F90:107
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
mom_io::file_exists
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
mom_coms::reproducing_sum
Find an accurate and order-invariant sum of distributed 2d or 3d fields.
Definition: MOM_coms.F90:54
mom_checksums::hchksum
Checksums an array (2d or 3d) staggered at tracer points.
Definition: MOM_checksums.F90:48
mom_file_parser::log_param
An overloaded interface to log the values of various types of parameters.
Definition: MOM_file_parser.F90:96
mom_restart::query_initialized
Indicate whether a field has been read from a restart file.
Definition: MOM_restart.F90:116
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:25
mom_diag_mediator::diag_ctrl
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Definition: MOM_diag_mediator.F90:239
mom_file_parser::read_param
An overloaded interface to read various types of parameters.
Definition: MOM_file_parser.F90:90