def sample_size_f(a, axis=None, masked=False): """Return the sample size. :Parameters: axis: `int`, optional Axis along which to operate. By default, flattened input is used. :Returns: `numpy.ndarray` """ if masked: N = numpy_sum(~a.mask, axis=axis, dtype=float) if not numpy_ndim(N): N = numpy_asanyarray(N) else: if axis is None: N = numpy_array(a.size, dtype=float) else: shape = a.shape N = numpy_empty(shape[:axis] + shape[axis + 1 :], dtype=float) N[...] = shape[axis] # --- End: if return asanyarray(N)
def make_surface(array): """pygame.surfarray.make_surface (array): return Surface Copy an array to a new surface. Create a new Surface that best resembles the data and format on the array. The array can be 2D or 3D with any sized integer values. """ if isinstance(array, numpy_ndarray) and array.dtype in numpy_floats: array = numpy_rint(array, numpy_empty(array.shape, dtype=numpy_uint32)) return pix_make_surface (array)
def blit_array (surface, array): """pygame.surfarray.blit_array(Surface, array): return None Blit directly from a array values. Directly copy values from an array into a Surface. This is faster than converting the array into a Surface and blitting. The array must be the same dimensions as the Surface and will completely replace all pixel values. Only integer, ascii character and record arrays are accepted. This function will temporarily lock the Surface as the new values are copied. """ if isinstance(array, numpy_ndarray) and array.dtype in numpy_floats: array = numpy_rint(array, numpy_empty(array.shape, dtype=numpy_uint32)) return array_to_surface(surface, array)
def __getitem__(self, indices): """x.__getitem__(indices) <==> x[indices] Returns a numpy array. """ if indices is Ellipsis: array_shape = self.shape else: array_shape = [] for index in parse_indices(self.shape, indices): if isinstance(index, slice): step = index.step if step == 1: array_shape.append(index.stop - index.start) elif step == -1: stop = index.stop if stop is None: array_shape.append(index.start + 1) else: array_shape.append(index.start - index.stop) else: stop = index.stop if stop is None: stop = -1 a, b = divmod(stop - index.start, step) if b: a += 1 array_shape.append(a) else: array_shape.append(len(index)) # --- End: if if self.fill_value() is cf_masked: return numpy_ma_masked_all(array_shape, dtype=self.dtype) elif self.fill_value() is not None: return numpy_full(array_shape, fill_value=self.fill_value(), dtype=self.dtype) else: return numpy_empty(array_shape, dtype=self.dtype)
def map_array(surface, array): """pygame.numpyarray.map_array(Surface, array3d): return array2d map a 3d array into a 2d array Convert a 3D array into a 2D array. This will use the given Surface format to control the conversion. Note: arrays do not need to be 3D, as long as the minor axis has three elements giving the component colours, any array shape can be used (for example, a single colour can be mapped, or an array of colours). The array shape is limited to eleven dimensions maximum, including the three element minor axis. """ if array.ndim == 0: raise ValueError("array must have at least 1 dimension") shape = array.shape if shape[-1] != 3: raise ValueError("array must be a 3d array of 3-value color data") target = numpy_empty(shape[:-1], numpy.int32) pix_map_array(target, array, surface) return target
def sample_size_f(a, axis=None, masked=False): '''TODO :Parameters: axis: `int`, optional non-negative ''' if masked: N = numpy_sum(~a.mask, axis=axis, dtype=float) if not numpy_ndim(N): N = numpy_asanyarray(N) else: if axis is None: N = numpy_array(a.size, dtype=float) else: shape = a.shape N = numpy_empty(shape[:axis] + shape[axis + 1:], dtype=float) N[...] = shape[axis] # --- End: if return asanyarray(N)
def create_bounds(self, bound=None, cellsize=None, flt=0.5, max=None, min=None): """Create cell bounds. :Parameters: bound: optional If set to a value larger (smaller) than the largest (smallest) coordinate value then bounds are created which include this value and for which each coordinate is in the centre of its bounds. cellsize: optional Define the exact size of each cell that is created. Created cells are allowed to overlap do not have to be contigious. The *cellsize* parameter may be one of: * A data-like scalar (see below) that defines the cell size, either in the same units as the coordinates or in the units provided. Note that in this case, the position of each coordinate within the its cell is controlled by the *flt* parameter. *Parameter example:* To specify cellsizes of 10, in the same units as the coordinates: ``cellsize=10``. *Parameter example:* To specify cellsizes of 1 day: ``cellsize=cf.Data(1, 'day')`` (see `cf.Data` for details). *Parameter example:* For coordinates ``1, 2, 10``, setting ``cellsize=1`` will result in bounds of ``(0.5, 1.5), (1.5, 2.5), (9.5, 10.5)``. *Parameter example:* For coordinates ``1, 2, 10`` kilometres, setting ``cellsize=cf.Data(5000, 'm')`` will result in bounds of ``(-1.5, 3.5), (-0.5, 4.5), (7.5, 12.5)`` (see `cf.Data` for details). *Parameter example:* For decreasing coordinates ``2, 0, -12`` setting, ``cellsize=2`` will result in bounds of ``(3, 1), (1, -1), (-11, -13)``. * A `cf.TimeDuration` defining the cell size. Only applicable to reference time coordinates. It is possible to "anchor" the cell bounds via the `cf.TimeDuration` parameters. For example, to specify cell size of one calendar month, starting and ending on the 15th day: ``cellsize=cf.M(day=15)`` (see `cf.M` for details). Note that the *flt* parameter is ignored in this case. *Parameter example:* For coordinates ``1984-12-01 12:00, 1984-12-02 12:00, 2000-04-15 12:00`` setting, ``cellsize=cf.D()`` will result in bounds of ``(1984-12-01, 1984-12-02), (1984-12-02, 1984-12-03), (2000-05-15, 2000-04-16)`` (see `cf.D` for details). *Parameter example:* For coordinates ``1984-12-01, 1984-12-02, 2000-04-15`` setting, ``cellsize=cf.D()`` will result in bounds of ``(1984-12-01, 1984-12-02), (1984-12-02, 1984-12-03), (2000-05-15, 2000-04-16)`` (see `cf.D` for details). *Parameter example:* For coordinates ``1984-12-01, 1984-12-02, 2000-04-15`` setting, ``cellsize=cf.D(hour=12)`` will result in bounds of ``(1984-11:30 12:00, 1984-12-01 12:00), (1984-12-01 12:00, 1984-12-02 12:00), (2000-05-14 12:00, 2000-04-15 12:00)`` (see `cf.D` for details). *Parameter example:* For coordinates ``1984-12-16 12:00, 1985-01-16 12:00`` setting, ``cellsize=cf.M()`` will result in bounds of ``(1984-12-01, 1985-01-01), (1985-01-01, 1985-02-01)`` (see `cf.M` for details). *Parameter example:* For coordinates ``1984-12-01 12:00, 1985-01-01 12:00`` setting, ``cellsize=cf.M()`` will result in bounds of ``(1984-12-01, 1985-01-01), (1985-01-01, 1985-02-01)`` (see `cf.M` for details). *Parameter example:* For coordinates ``1984-12-01 12:00, 1985-01-01 12:00`` setting, ``cellsize=cf.M(day=20)`` will result in bounds of ``(1984-11-20, 1984-12-20), (1984-12-20, 1985-01-20)`` (see `cf.M` for details). *Parameter example:* For coordinates ``1984-03-01, 1984-06-01`` setting, ``cellsize=cf.Y()`` will result in bounds of ``(1984-01-01, 1985-01-01), (1984-01-01, 1985-01-01)`` (see `cf.Y` for details). Note that in this case each cell has the same bounds. This because ``cf.Y()`` is equivalent to ``cf.Y(month=1, day=1)`` and the closest 1st January to both coordinates is 1st January 1984. {+data-like-scalar} TODO flt: `float`, optional When creating cells with sizes specified by the *cellsize* parameter, define the fraction of the each cell which is less its coordinate value. By default *flt* is 0.5, so that each cell has its coordinate at it's centre. Ignored if *cellsize* is not set. *Parameter example:* For coordinates ``1, 2, 10``, setting ``cellsize=1, flt=0.5`` will result in bounds of ``(0.5, 1.5), (1.5, 2.5), (9.5, 10.5)``. *Parameter example:* For coordinates ``1, 2, 10``, setting ``cellsize=1, flt=0.25`` will result in bounds of ``(0.75, 1.75), (1.75, 2.75), (9.75, 10.75)``. *Parameter example:* For decreasing coordinates ``2, 0, -12``, setting ``cellsize=6, flt=0.9`` will result in bounds of ``(2.6, -3.4), (0.6, -5.4), (-11.4, -17.4)``. max: optional Limit the created bounds to be no more than this number. *Parameter example:* To ensure that all latitude bounds are at most 90: ``max=90``. min: optional Limit the created bounds to be no less than this number. *Parameter example:* To ensure that all latitude bounds are at least -90: ``min=-90``. :Returns: `Bounds` The newly-created coordinate cell bounds object. **Examples:** >>> c.create_bounds() >>> c.create_bounds(bound=-9000.0) """ array = self.array size = array.size if cellsize is not None: if bound: raise ValueError( "bound parameter can't be True when setting the " "cellsize parameter") if not isinstance(cellsize, TimeDuration): # ---------------------------------------------------- # Create bounds based on cell sizes defined by a # data-like object # # E.g. cellsize=10 # cellsize=cf.Data(1, 'day') # ---------------------------------------------------- cellsize = Data.asdata(abs(cellsize)) if cellsize.Units: if self.Units.isreftime: if not cellsize.Units.istime: raise ValueError("q123423423jhgsjhbd jh ") cellsize.Units = Units(self.Units._utime.units) else: if not cellsize.Units.equivalent(self.Units): raise ValueError("jhgsjhbd jh ") cellsize.Units = self.Units cellsize = cellsize.datum() cellsize0 = cellsize * flt cellsize1 = cellsize * (1 - flt) if not self.direction(): cellsize0, cellsize1 = -cellsize1, -cellsize0 bounds = numpy_empty((size, 2), dtype=array.dtype) bounds[:, 0] = array - cellsize0 bounds[:, 1] = array + cellsize1 else: # ---------------------------------------------------- # Create bounds based on cell sizes defined by a # TimeDuration object # # E.g. cellsize=cf.s() # cellsize=cf.m() # cellsize=cf.h() # cellsize=cf.D() # cellsize=cf.M() # cellsize=cf.Y() # cellsize=cf.D(hour=12) # cellsize=cf.M(day=16) # cellsize=cf.M(2) # cellsize=cf.M(2, day=15, hour=12) # ---------------------------------------------------- if not self.Units.isreftime: raise ValueError( "Can't create reference time bounds for " "non-reference time coordinates: {0!r}".format( self.Units)) bounds = numpy_empty((size, 2), dtype=object) cellsize_bounds = cellsize.bounds direction = bool(self.direction()) for c, b in zip(self.datetime_array, bounds): b[...] = cellsize_bounds(c, direction=direction) else: if bound is None: # ---------------------------------------------------- # Creat Voronoi bounds # ---------------------------------------------------- if size < 2: raise ValueError( "Can't create bounds for Voronoi cells from one value") bounds_1d = [array.item(0, ) * 1.5 - array.item(1, ) * 0.5] bounds_1d.extend((array[0:-1] + array[1:]) * 0.5) bounds_1d.append( array.item(-1, ) * 1.5 - array.item(-2, ) * 0.5) dtype = type(bounds_1d[0]) if max is not None: if self.direction(): bounds_1d[-1] = max else: bounds_1d[0] = max if min is not None: if self.direction(): bounds_1d[0] = min else: bounds_1d[-1] = min else: # ---------------------------------------------------- # Create # ---------------------------------------------------- direction = self.direction() if not direction and size > 1: array = array[::-1] bounds_1d = [bound] if bound <= array.item(0, ): for i in range(size): bound = (2.0 * array.item(i, ) - bound) bounds_1d.append(bound) elif bound >= array.item(-1, ): for i in range(size - 1, -1, -1): bound = (2.0 * array.item(i, ) - bound) bounds_1d.append(bound) bounds_1d = bounds_1d[::-1] else: raise ValueError("bad bound value") dtype = type(bounds_1d[-1]) if not direction: bounds_1d = bounds_1d[::-1] bounds = numpy_empty((size, 2), dtype=dtype) bounds[:, 0] = bounds_1d[:-1] bounds[:, 1] = bounds_1d[1:] # Create coordinate bounds object bounds = Bounds(data=Data(bounds, units=self.Units), copy=False) return bounds
def add_partitions(self, adimensions, master_flip, extra_boundaries, axis): '''Add partition boundaries. :Parameters: adimensions: `list` The ordered axis names of the master array. master_flip: `list` extra_boundaries: `list` of `int` The boundaries of the new partitions. axis: `str` The name of the axis to have the new partitions. ''' def _update_p(matrix, location, master_index, part, master_axis_to_position, master_flip): '''TODO :Parameters: matrix: numpy array of `Partition` objects location: `list` master_index: `int` part: `list` master_axis_to_position: `dict` master_flip: `list` :Returns: numpy array of `Partition` objects ''' for partition in matrix.flat: partition.location = partition.location[:] partition.shape = partition.shape[:] partition.location[master_index] = location partition.shape[master_index] = shape partition.new_part(part, master_axis_to_position, master_flip) # --- End: for return matrix # If no extra boundaries have been provided, just return # without doing anything if not extra_boundaries: return master_index = adimensions.index(axis) index = self.axes.index(axis) # Find the position of the extra-boundaries dimension in the # list of master array dimensions extra_boundaries = extra_boundaries[:] # Create the master_axis_to_position dictionary required by # Partition.new_part master_axis_to_position = {} for i, data_axis in enumerate(adimensions): master_axis_to_position[data_axis] = i matrix = self.matrix shape = matrix.shape # Initialize the new partition matrix new_shape = list(shape) new_shape[index] += len(extra_boundaries) new_matrix = numpy_empty(new_shape, dtype=object) part = [slice(None)] * len(adimensions) indices = [slice(None)] * matrix.ndim new_indices = indices[:] new_indices[index] = slice(0, 1) # 0 # Find the first extra boundary x = extra_boundaries.pop(0) for i in range(shape[index]): indices[index] = slice(i, i + 1) sub_matrix = matrix[tuple(indices)] # (r0, r1) = next(sub_matrix.flat).location[master_index] (r0, r1) = sub_matrix.item(0, ).location[master_index] # Could do better, perhaps, by assigning in blocks if not r0 < x < r1: # This new boundary is *not* within the span of this # sub-matrix. Therefore, just copy the sub-matrix # straight into the new matrix new_matrix[tuple(new_indices)] = sub_matrix # new_indices[index] += 1 new_indices[index] = slice(new_indices[index].start + 1, new_indices[index].stop + 1) continue # -------------------------------------------------------- # Still here? Then this new boundary *is* within the span # of this sub-matrix. # -------------------------------------------------------- # Find the new extent of the original partition(s) location = (r0, x) shape = x - r0 part[master_index] = slice(0, shape) # Create new partition(s) in place of the original ones(s) # and set the location, shape and part attributes new_matrix[tuple(new_indices)] = _update_p( deepcopy(sub_matrix), location, master_index, part, master_axis_to_position, master_flip) # new_indices[index] += 1 new_indices[index] = slice(new_indices[index].start + 1, new_indices[index].stop + 1) while x < r1: # Find the extent of the new partition(s) if not extra_boundaries: # There are no more new boundaries, so the new # partition(s) run to the end of the original # partition(s) in which they lie. location1 = r1 else: # There are more new boundaries, so this # new partition runs either to the next # new boundary or to the end of the # original partition, which comes first. location1 = min(extra_boundaries[0], r1) location = (x, location1) shape = location1 - x offset = x - r0 part[master_index] = slice(offset, offset + shape) # Create the new partition(s) and set the # location, shape and part attributes new_matrix[tuple(new_indices)] = _update_p( deepcopy(sub_matrix), location, master_index, part, master_axis_to_position, master_flip) new_indices[index] = slice(new_indices[index].start + 1, new_indices[index].stop + 1) # new_indices[index] += 1 if not extra_boundaries: # There are no more extra boundaries, so we can # return now. # new_indices[index] = slice(new_indices[index], # None) new_indices[index] = slice(new_indices[index].start, None) indices[index] = slice(i + 1, None) new_matrix[tuple(new_indices)] = matrix[tuple(indices)] self.matrix = new_matrix return # Still here? Then move on to the next new boundary x = extra_boundaries.pop(0) # --- End: while # --- End: for self.matrix = new_matrix
from numpy import ndenumerate as numpy_ndenumerate from numpy import empty as numpy_empty from numpy import expand_dims as numpy_expand_dims from numpy import squeeze as numpy_squeeze from copy import deepcopy from .partition import Partition from ..functions import (_DEPRECATION_WARNING_METHOD, _DEPRECATION_ERROR_METHOD) from ..decorators import (_inplace_enabled, _inplace_enabled_define_and_cleanup) _empty_matrix = numpy_empty((), dtype=object) class PartitionMatrix: ''' A hyperrectangular partition matrix of a master data array. Each of elements (called partitions) span all or part of exactly one sub-array of the master data array. Normal numpy basic and advanced indexing is supported, but size 1 dimensions are always removed from the output array, i.e. a partition rather than a partition matrix is returned if the output array has size 1.
def create_grid( coords, use_bounds, mask=None, cartesian=False, cyclic=False, coords_2D=False, coord_order=None, ): """Create an ESMPy grid given a sequence of coordinates for use as a source or destination grid in regridding. Optionally the grid may have an associated mask. :Parameters: coords: sequence The coordinates if not Cartesian it is assume that the first is longitude and the second is latitude. use_bounds: `bool` Whether to populate the grid corners with information from the bounds or not. mask: `numpy.ndarray`, optional An optional numpy array of booleans containing the grid points to mask. Where the elements of mask are True the output grid is masked. cartesian: `bool`, optional Whether to create a Cartesian grid or a spherical one, False by default. cyclic: `bool`, optional Whether or not the longitude (if present) is cyclic. If None the a check for cyclicity is made from the bounds. None by default. coords_2D: `bool`, optional Whether the coordinates are 2D or not. Presently only works for spherical coordinates. False by default. coord_order: sequence, optional Two tuples one indicating the order of the x and y axes for 2D longitude, one for 2D latitude. :Returns: `ESMF.Grid` The resulting ESMPy grid for use as a source or destination grid in regridding. """ if not cartesian: lon = coords[0] lat = coords[1] if not coords_2D: # Get the shape of the grid shape = [lon.size, lat.size] else: x_order = coord_order[0] y_order = coord_order[1] # Get the shape of the grid shape = lon.transpose(x_order).shape if lat.transpose(y_order).shape != shape: raise ValueError( "The longitude and latitude coordinates" " must have the same shape." ) # --- End: if if use_bounds: if not coords_2D: # Get the bounds x_bounds = lon.get_bounds() y_bounds = lat.get_bounds().clip(-90, 90, "degrees").array # If cyclic not set already, check for cyclicity if cyclic is None: cyclic = abs( x_bounds.datum(-1) - x_bounds.datum(0) ) == Data(360, "degrees") x_bounds = x_bounds.array else: # Get the bounds x_bounds = lon.get_bounds() y_bounds = lat.get_bounds().clip(-90, 90, "degrees") n = x_bounds.shape[0] m = x_bounds.shape[1] x_bounds = x_bounds.array y_bounds = y_bounds.array tmp_x = numpy_empty((n + 1, m + 1)) tmp_x[:n, :m] = x_bounds[:, :, 0] tmp_x[:n, m] = x_bounds[:, -1, 1] tmp_x[n, :m] = x_bounds[-1, :, 3] tmp_x[n, m] = x_bounds[-1, -1, 2] tmp_y = numpy_empty((n + 1, m + 1)) tmp_y[:n, :m] = y_bounds[:, :, 0] tmp_y[:n, m] = y_bounds[:, -1, 1] tmp_y[n, :m] = y_bounds[-1, :, 3] tmp_y[n, m] = y_bounds[-1, -1, 2] x_bounds = tmp_x y_bounds = tmp_y else: if not coords_2D: # If cyclicity not set already, check for cyclicity if cyclic is None: try: x_bounds = lon.get_bounds() cyclic = abs( x_bounds.datum(-1) - x_bounds.datum(0) ) == Data(360, "degrees") except ValueError: pass # --- End: if # Create empty grid max_index = numpy_array(shape, dtype="int32") if use_bounds: staggerLocs = [ESMF.StaggerLoc.CORNER, ESMF.StaggerLoc.CENTER] else: staggerLocs = [ESMF.StaggerLoc.CENTER] if cyclic: grid = ESMF.Grid( max_index, num_peri_dims=1, staggerloc=staggerLocs ) else: grid = ESMF.Grid(max_index, staggerloc=staggerLocs) # Populate grid centres x, y = 0, 1 gridXCentre = grid.get_coords(x, staggerloc=ESMF.StaggerLoc.CENTER) gridYCentre = grid.get_coords(y, staggerloc=ESMF.StaggerLoc.CENTER) if not coords_2D: gridXCentre[...] = lon.array.reshape((lon.size, 1)) gridYCentre[...] = lat.array.reshape((1, lat.size)) else: gridXCentre[...] = lon.transpose(x_order).array gridYCentre[...] = lat.transpose(y_order).array # Populate grid corners if there are bounds if use_bounds: gridCorner = grid.coords[ESMF.StaggerLoc.CORNER] if not coords_2D: if cyclic: gridCorner[x][...] = x_bounds[:, 0].reshape( lon.size, 1 ) else: n = x_bounds.shape[0] tmp_x = numpy_empty(n + 1) tmp_x[:n] = x_bounds[:, 0] tmp_x[n] = x_bounds[-1, 1] gridCorner[x][...] = tmp_x.reshape(lon.size + 1, 1) n = y_bounds.shape[0] tmp_y = numpy_empty(n + 1) tmp_y[:n] = y_bounds[:, 0] tmp_y[n] = y_bounds[-1, 1] gridCorner[y][...] = tmp_y.reshape(1, lat.size + 1) else: gridCorner = grid.coords[ESMF.StaggerLoc.CORNER] x_bounds = x_bounds.transpose(x_order) y_bounds = y_bounds.transpose(y_order) if cyclic: x_bounds = x_bounds[:-1, :] y_bounds = y_bounds[:-1, :] gridCorner[x][...] = x_bounds gridCorner[y][...] = y_bounds # --- End: if else: # Test the dimensionality of the list of coordinates ndim = len(coords) if ndim < 1 or ndim > 3: raise ValueError( "Cartesian grid must have between 1 and 3 dimensions." ) # For 1D conservative regridding add an extra dimension of size 1 if ndim == 1: if not use_bounds: # For 1D nonconservative regridding the extra dimension # should already have been added in cf.Field.regridc. raise ValueError( "Cannot create a Cartesian grid from " "one dimension coordinate with no bounds." ) coords = [ DimensionCoordinate( data=Data(0), bounds=Data( [ numpy_finfo("float32").epsneg, numpy_finfo("float32").eps, ] ), ) ] + coords if mask is not None: mask = mask[None, :] ndim = 2 shape = list() for coord in coords: shape.append(coord.size) # Initialise the grid max_index = numpy_array(shape, dtype="int32") if use_bounds: if ndim < 3: staggerLocs = [ ESMF.StaggerLoc.CORNER, ESMF.StaggerLoc.CENTER, ] else: staggerLocs = [ ESMF.StaggerLoc.CENTER_VCENTER, ESMF.StaggerLoc.CORNER_VFACE, ] else: if ndim < 3: staggerLocs = [ESMF.StaggerLoc.CENTER] else: staggerLocs = [ESMF.StaggerLoc.CENTER_VCENTER] # --- End: if grid = ESMF.Grid( max_index, coord_sys=ESMF.CoordSys.CART, staggerloc=staggerLocs ) # Populate the grid centres for d in range(0, ndim): if ndim < 3: gridCentre = grid.get_coords( d, staggerloc=ESMF.StaggerLoc.CENTER ) else: gridCentre = grid.get_coords( d, staggerloc=ESMF.StaggerLoc.CENTER_VCENTER ) gridCentre[...] = coords[d].array.reshape( [shape[d] if x == d else 1 for x in range(0, ndim)] ) # --- End: for # Populate grid corners if use_bounds: if ndim < 3: gridCorner = grid.coords[ESMF.StaggerLoc.CORNER] else: gridCorner = grid.coords[ESMF.StaggerLoc.CORNER_VFACE] for d in range(0, ndim): # boundsD = coords[d].get_bounds(create=True).array boundsD = coords[d].get_bounds(None) if boundsD is None: boundsD = coords[d].create_bounds() boundsD = boundsD.array if shape[d] > 1: tmp = numpy_empty(shape[d] + 1) tmp[0:-1] = boundsD[:, 0] tmp[-1] = boundsD[-1, 1] boundsD = tmp gridCorner[d][...] = boundsD.reshape( [shape[d] + 1 if x == d else 1 for x in range(0, ndim)] ) # --- End: if # --- End: if # Add the mask if appropriate if mask is not None: gmask = grid.add_item(ESMF.GridItem.MASK) gmask[...] = 1 gmask[mask] = 0 return grid