@@ -189,6 +189,61 @@ def set_rectangular_geom_points_and_edges(xmin, xmax, ymin, ymax):
189189 return geom_points , geom_edges
190190
191191
192+ def clip_mesh_to_bounding_box (mask_ds , base_ds , bounding_box ):
193+ """
194+ Set cells to culled if they lay outside the bounding box
195+
196+ Parameters
197+ ----------
198+ mask_ds: xr.Dataset
199+ mask dataset, generated by ``compute_mpas_region_mask``
200+ base_ds: xr.Dataset
201+ unculled mesh dataset
202+ bounding_box: list of 4 ints
203+ Bounding box [x_min, x_max, y_min, y_max] to cull mesh outside of
204+
205+ Returns
206+ -------
207+ mask_ds: xarray.Dataset
208+ mask dataset with updated masks based on bounding box
209+ """
210+
211+ if len (bounding_box ) != 4 :
212+ msg = f"bounding box must be len 4, instead is len { len (bounding_box )} "
213+ raise ValueError (msg )
214+
215+ x_min , x_max , y_min , y_max = bounding_box
216+
217+ if (x_max < x_min ) or (y_max < y_min ):
218+ msg = "Bounding box must be ordered: [x_min, x_max, y_min, y_max]"
219+ msg += (
220+ f"\n x_max < x_min ({ x_max :.2f} < { x_min :.2f} )"
221+ if x_max < x_min else ""
222+ )
223+ msg += (
224+ f"\n y_max < y_min ({ y_max :.2f} < { y_min :.2f} )"
225+ if y_max < y_min else ""
226+ )
227+ raise ValueError (msg )
228+
229+ for loc in ["Cell" , "Edge" , "Vertex" ]:
230+ mask_var = f"region{ loc } Masks"
231+
232+ if mask_var not in mask_ds :
233+ continue
234+
235+ mask = (
236+ (base_ds [f"x{ loc } " ] < x_min ) |
237+ (base_ds [f"x{ loc } " ] > x_max ) |
238+ (base_ds [f"y{ loc } " ] < y_min ) |
239+ (base_ds [f"y{ loc } " ] > y_max )
240+ )
241+
242+ mask_ds [mask_var ] = xarray .where (mask , 0 , mask_ds [mask_var ])
243+
244+ return mask_ds
245+
246+
192247def set_cell_width (self , section_name , thk , bed = None , vx = None , vy = None ,
193248 dist_to_edge = None , dist_to_grounding_line = None ,
194249 flood_fill_iStart = None , flood_fill_jStart = None ):
@@ -618,7 +673,7 @@ def build_cell_width(self, section_name, gridded_dataset,
618673def build_mali_mesh (self , cell_width , x1 , y1 , geom_points ,
619674 geom_edges , mesh_name , section_name ,
620675 gridded_dataset , projection , geojson_file = None ,
621- cores = 1 ):
676+ cores = 1 , bounding_box = None ):
622677 """
623678 Create the MALI mesh based on final cell widths determined by
624679 :py:func:`compass.landice.mesh.build_cell_width()`, using Jigsaw and
@@ -672,8 +727,18 @@ def build_mali_mesh(self, cell_width, x1, y1, geom_points,
672727
673728 cores : int, optional
674729 The number of cores to use for mask creation
730+
731+ bounding_box : array_like of float, shape (4,), optional
732+ Bounding box [x_min, x_max, y_min, y_max] to cull mesh outside of
675733 """
676734
735+ if bounding_box is not None and geojson_file is None :
736+ msg = (
737+ "Bounding box clipping can only be applied to an existing cull"
738+ "mask. You must provide a geojson file for this to work."
739+ )
740+ raise ValueError (msg )
741+
677742 logger = self .logger
678743 section = self .config [section_name ]
679744
@@ -735,6 +800,10 @@ def build_mali_mesh(self, cell_width, x1, y1, geom_points,
735800 dsMesh = xarray .open_dataset ('grid_preCull.nc' )
736801 if geojson_file is not None :
737802 mask = xarray .open_dataset ('mask.nc' )
803+
804+ if bounding_box is not None :
805+ mask = clip_mesh_to_bounding_box (mask , dsMesh , bounding_box )
806+
738807 else :
739808 mask = None
740809
0 commit comments