@@ -224,8 +224,9 @@ def clip_mesh_to_bounding_box(mask_ds, base_ds, bounding_box):
224224 return mask_ds
225225
226226
227- def set_cell_width (self , section_name , thk , bed = None , vx = None , vy = None ,
227+ def set_cell_width (self , section_name , thk , bed , vx = None , vy = None ,
228228 dist_to_edge = None , dist_to_grounding_line = None ,
229+ dist_to_coast = None ,
229230 flood_fill_iStart = None , flood_fill_jStart = None ):
230231 """
231232 Set cell widths based on settings in config file to pass to
@@ -238,9 +239,10 @@ def set_cell_width(self, section_name, thk, bed=None, vx=None, vy=None,
238239 following options to be set in the given config section:
239240 ``levels``, ``x_min``, ``x_max``, ``y_min``, ``y_max``,
240241 ``min_spac``, ``max_spac``, ``high_log_speed``, ``low_log_speed``,
241- ``high_dist``, ``low_dist``, ``high_dist_bed``, ``low_dist_bed``,
242- ``high_bed``, ``low_bed``, ``cull_distance``, ``use_speed``,
243- ``use_dist_to_edge``, ``use_dist_to_grounding_line``, and ``use_bed``.
242+ ``high_dist``, ``low_dist``, ``high_dist_coast``, ``low_dist_coast``,
243+ ``high_dist_bed``, ``low_dist_bed``, ``high_bed``, ``low_bed``,
244+ ``cull_distance``, ``use_speed``, ``use_dist_to_edge``,
245+ ``use_dist_to_grounding_line``, ``use_dist_to_coast``, and ``use_bed``.
244246 See the Land-Ice Framework section of the Users or Developers guide
245247 for more information about these options and their uses.
246248
@@ -272,6 +274,11 @@ def set_cell_width(self, section_name, thk, bed=None, vx=None, vy=None,
272274 function. Can be set to ``None`` if
273275 ``use_dist_to_grounding_line == False`` in config file.
274276
277+ dist_to_coast : numpy.ndarray, optional
278+ Distance from each cell to coast, calculated in separate
279+ function. Can be set to ``None`` if
280+ ``use_dist_to_coast == False`` in config file.
281+
275282 flood_fill_iStart : int, optional
276283 x-index location to start flood-fill when using bed topography
277284
@@ -291,21 +298,19 @@ def set_cell_width(self, section_name, thk, bed=None, vx=None, vy=None,
291298 # Get config inputs for cell spacing functions
292299 min_spac = section .getfloat ('min_spac' )
293300 max_spac = section .getfloat ('max_spac' )
294- high_log_speed = section .getfloat ('high_log_speed' )
295- low_log_speed = section .getfloat ('low_log_speed' )
296- high_dist = section .getfloat ('high_dist' )
297- low_dist = section .getfloat ('low_dist' )
298- high_dist_bed = section .getfloat ('high_dist_bed' )
299- low_dist_bed = section .getfloat ('low_dist_bed' )
300- low_bed = section .getfloat ('low_bed' )
301- high_bed = section .getfloat ('high_bed' )
302-
303301 # convert km to m
304302 cull_distance = section .getfloat ('cull_distance' ) * 1.e3
305303
304+ land_mask = np .logical_and (thk == 0.0 , bed >= 0. )
305+ ocean_mask = np .logical_and (thk == 0.0 , bed < 0. )
306+
306307 # Cell spacing function based on union of masks
307308 if section .get ('use_bed' ) == 'True' :
308309 logger .info ('Using bed elevation for spacing.' )
310+ high_dist_bed = section .getfloat ('high_dist_bed' )
311+ low_dist_bed = section .getfloat ('low_dist_bed' )
312+ low_bed = section .getfloat ('low_bed' )
313+ high_bed = section .getfloat ('high_bed' )
309314 if flood_fill_iStart is not None and flood_fill_jStart is not None :
310315 logger .info ('calling gridded_flood_fill to find ' +
311316 'bedTopography <= low_bed connected to the ocean.' )
@@ -355,6 +360,8 @@ def set_cell_width(self, section_name, thk, bed=None, vx=None, vy=None,
355360 # Make cell spacing function mapping from log speed to cell spacing
356361 if section .get ('use_speed' ) == 'True' :
357362 logger .info ('Using speed for cell spacing' )
363+ high_log_speed = section .getfloat ('high_log_speed' )
364+ low_log_speed = section .getfloat ('low_log_speed' )
358365 speed = (vx ** 2 + vy ** 2 ) ** 0.5
359366 lspd = np .log10 (speed )
360367 spacing_speed = np .interp (lspd , [low_log_speed , high_log_speed ],
@@ -372,33 +379,53 @@ def set_cell_width(self, section_name, thk, bed=None, vx=None, vy=None,
372379 f'dataset with missing velocity values. Setting '
373380 f'velocity-based spacing to maximum value.' )
374381
375- spacing_speed [thk == 0.0 ] = min_spac
376382 else :
377383 spacing_speed = max_spac * np .ones_like (thk )
378384
379385 # Make cell spacing function mapping from distance to ice edge
380386 if section .get ('use_dist_to_edge' ) == 'True' :
381387 logger .info ('Using distance to ice edge for cell spacing' )
388+ high_dist = section .getfloat ('high_dist' )
389+ low_dist = section .getfloat ('low_dist' )
382390 spacing_edge = np .interp (dist_to_edge , [low_dist , high_dist ],
383391 [min_spac , max_spac ], left = min_spac ,
384392 right = max_spac )
385- spacing_edge [thk == 0.0 ] = min_spac
386393 else :
387394 spacing_edge = max_spac * np .ones_like (thk )
388395
389396 # Make cell spacing function mapping from distance to grounding line
390397 if section .get ('use_dist_to_grounding_line' ) == 'True' :
391398 logger .info ('Using distance to grounding line for cell spacing' )
399+ high_dist = section .getfloat ('high_dist' )
400+ low_dist = section .getfloat ('low_dist' )
392401 spacing_gl = np .interp (dist_to_grounding_line , [low_dist , high_dist ],
393402 [min_spac , max_spac ], left = min_spac ,
394403 right = max_spac )
395- spacing_gl [thk == 0.0 ] = min_spac
396404 else :
397405 spacing_gl = max_spac * np .ones_like (thk )
398406
407+ # Make cell spacing function mapping from distance to coast
408+ if section .get ('use_dist_to_coast' ) == 'True' :
409+ logger .info ('Using distance to coast for cell spacing' )
410+ high_dist_coast = section .getfloat ('high_dist_coast' )
411+ low_dist_coast = section .getfloat ('low_dist_coast' )
412+ spacing_coast = np .interp (dist_to_coast ,
413+ [low_dist_coast , high_dist_coast ],
414+ [min_spac , max_spac ], left = min_spac ,
415+ right = max_spac )
416+ # distance from coast is only used to set spacing in ocean
417+ spacing_coast [bed > 0. ] = max_spac
418+ else :
419+ spacing_coast = max_spac * np .ones_like (thk )
420+ # If not using distance from coast, use finest spacing
421+ # in the ocean as well as ice-free land.
422+ spacing_coast [land_mask ] = min_spac
423+ spacing_coast [ocean_mask ] = min_spac
424+
399425 # Merge cell spacing methods
400426 cell_width = max_spac * np .ones_like (thk )
401- for width in [spacing_bed , spacing_speed , spacing_edge , spacing_gl ]:
427+ for width in [spacing_bed , spacing_speed , spacing_edge ,
428+ spacing_gl , spacing_coast ]:
402429 cell_width = np .minimum (cell_width , width )
403430
404431 # Set large cell_width in areas we are going to cull anyway (speeds up
@@ -420,8 +447,7 @@ def get_dist_to_edge_and_gl(self, thk, topg, x, y, section_name,
420447 """
421448 Calculate distance from each point to ice edge and grounding line,
422449 to be used in mesh density functions in
423- :py:func:`compass.landice.mesh.set_cell_width()`. In future development,
424- this should be updated to use a faster package such as ``scikit-fmm``.
450+ :py:func:`compass.landice.mesh.set_cell_width()`.
425451
426452 Parameters
427453 ----------
@@ -465,6 +491,11 @@ def get_dist_to_edge_and_gl(self, thk, topg, x, y, section_name,
465491
466492 dist_to_grounding_line : numpy.ndarray
467493 Distance from each cell to the grounding line
494+
495+ dist_to_coast : numpy.ndarray
496+ Distance from each cell to the coast, defined as the last cell
497+ adjacent to ocean (ice free with bed < 0) whether ice-filled
498+ or ice-free.
468499 """
469500
470501 logger = self .logger
@@ -495,12 +526,14 @@ def get_dist_to_edge_and_gl(self, thk, topg, x, y, section_name,
495526 ])
496527
497528 ice_mask = thk > 0.0
529+ ocean_mask = np .logical_and (thk == 0. , topg < 0. )
498530 grounded_mask = np .logical_and (thk > (- 1028.0 / 910.0 * topg ),
499531 ice_mask )
500532 float_mask = np .logical_and (thk < (- 1028.0 / 910.0 * topg ),
501533 ice_mask )
502534 margin_mask = np .zeros (thk .shape , dtype = bool )
503535 grounding_line_mask = np .zeros (thk .shape , dtype = bool )
536+ coast_mask = np .zeros (thk .shape , dtype = bool )
504537
505538 for n in neighbors :
506539 shifted_ice = np .roll (ice_mask , n , axis = [0 , 1 ])
@@ -512,17 +545,24 @@ def get_dist_to_edge_and_gl(self, thk, topg, x, y, section_name,
512545 grounding_line_mask = np .logical_or (grounding_line_mask ,
513546 not_grounded_mask )
514547
548+ shifted_ocean = np .roll (ocean_mask , n , axis = [0 , 1 ])
549+ coast_mask = np .logical_or (coast_mask , shifted_ocean )
550+
515551 # where ice exists and neighbors non-ice locations
516552 margin_mask = np .logical_and (margin_mask , ice_mask )
517553 # where grounded ice exists and neighbors floating ice
518554 grounding_line_mask = np .logical_and (grounding_line_mask , grounded_mask )
555+ # where non-ocean exists and neighbors ocean locations
556+ coast_mask = np .logical_and (coast_mask , np .logical_not (ocean_mask ))
519557
520- fig , ax = plt .subplots (1 , 2 , sharex = True , sharey = True , figsize = (6 , 3 ))
558+ fig , ax = plt .subplots (1 , 3 , sharex = True , sharey = True , figsize = (9 , 3 ))
521559 margin_plot = ax [0 ].pcolor (margin_mask )
522560 gl_plot = ax [1 ].pcolor (grounding_line_mask ) # noqa F841
561+ coast_plot = ax [2 ].pcolor (coast_mask ) # noqa F841
523562 ax [0 ].set_title ("margin mask" )
524563 ax [1 ].set_title ("grounding line mask" )
525- plt .colorbar (margin_plot , ax = [ax [0 ], ax [1 ]], shrink = 0.7 )
564+ ax [2 ].set_title ("coast mask" )
565+ plt .colorbar (margin_plot , ax = ax , shrink = 0.7 )
526566 [ax .set_aspect ('equal' ) for ax in ax ]
527567 fig .savefig ("masks.png" , dpi = 400 )
528568
@@ -534,19 +574,23 @@ def get_dist_to_edge_and_gl(self, thk, topg, x, y, section_name,
534574 dist_to_grounding_line = distance_transform_edt (
535575 ~ grounding_line_mask , sampling = (dy , dx )
536576 )
577+ dist_to_coast = distance_transform_edt (
578+ ~ coast_mask , sampling = (dy , dx )
579+ )
537580
538581 # Limit maximum distance
539582 max_dist = float (np .ceil (window_size / max (dx , dy ))) * max (dx , dy )
540583 dist_to_edge = np .minimum (dist_to_edge , max_dist )
541584 dist_to_grounding_line = np .minimum (dist_to_grounding_line , max_dist )
585+ dist_to_coast = np .minimum (dist_to_coast , max_dist )
542586
543587 toc = time .time ()
544588 logger .info (
545589 'compass.landice.mesh.get_dist_to_edge_and_gl() took '
546590 f'{ toc - tic :0.2f} seconds'
547591 )
548592
549- return dist_to_edge , dist_to_grounding_line
593+ return dist_to_edge , dist_to_grounding_line , dist_to_coast
550594
551595
552596def build_cell_width (self , section_name , gridded_dataset ,
@@ -628,7 +672,7 @@ def build_cell_width(self, section_name, gridded_dataset,
628672
629673 # Calculate distance from each grid point to ice edge
630674 # and grounding line, for use in cell spacing functions.
631- distToEdge , distToGL = get_dist_to_edge_and_gl (
675+ distToEdge , distToGL , distToCoast = get_dist_to_edge_and_gl (
632676 self , thk , topg , x1 ,
633677 y1 , section_name = section_name )
634678
@@ -637,6 +681,7 @@ def build_cell_width(self, section_name, gridded_dataset,
637681 thk = thk , bed = topg , vx = vx , vy = vy ,
638682 dist_to_edge = distToEdge ,
639683 dist_to_grounding_line = distToGL ,
684+ dist_to_coast = distToCoast ,
640685 flood_fill_iStart = flood_fill_start [0 ],
641686 flood_fill_jStart = flood_fill_start [1 ])
642687
@@ -683,9 +728,10 @@ def build_mali_mesh(self, cell_width, x1, y1, geom_points,
683728 following options to be set in the given config section:
684729 ``levels``, ``x_min``, ``x_max``, ``y_min``, ``y_max``,
685730 ``min_spac``, ``max_spac``, ``high_log_speed``, ``low_log_speed``,
686- ``high_dist``, ``low_dist``, ``high_dist_bed``, ``low_dist_bed``,
687- ``high_bed``, ``low_bed``, ``cull_distance``, ``use_speed``,
688- ``use_dist_to_edge``, ``use_dist_to_grounding_line``, and ``use_bed``.
731+ ``high_dist``, ``low_dist``, ``high_dist_coast``, ``low_dist_coast``,
732+ ``high_dist_bed``, ``low_dist_bed``, ``high_bed``, ``low_bed``,
733+ ``cull_distance``, ``use_speed``, ``use_dist_to_edge``,
734+ ``use_dist_to_grounding_line``, ``use_dist_to_coast``, and ``use_bed``.
689735 See the Land-Ice Framework section of the Users or Developers guide
690736 for more information about these options and their uses.
691737
0 commit comments