Source code for flopy.mf6.utils.lakpak_utils

import numpy as np


[docs]def get_lak_connections(modelgrid, lake_map, idomain=None, bedleak=None): """ Function to create lake package connection data from a zero-based integer array of lake numbers. If the shape of lake number array is equal to (nrow, ncol) or (ncpl) then the lakes are on top of the model and are vertically connected to cells at the top of the model. Otherwise the lakes are embedded in the grid. TODO: implement embedded lakes for VertexGrid TODO: add support for UnstructuredGrid Parameters ---------- modelgrid : StructuredGrid, VertexGrid model grid lake_map : MaskedArray, ndarray, list, tuple location and zero-based lake number for lakes in the model domain. If lake_map is of size (nrow, ncol) or (ncpl) lakes are located on top of the model and vertically connected to cells in model layer 1. If lake_map is of size (nlay, nrow, ncol) or (nlay, ncpl) lakes are embedded in the model domain and horizontal and vertical lake connections are defined. idomain : int or ndarray location of inactive cells, which are defined with a zero value. If a ndarray is passed it must be of size (nlay, nrow, ncol) or (nlay, ncpl). bedleak : ndarray, list, tuple, float bed leakance for lakes in the model domain. If bedleak is a float the same bed leakance is applied to each lake connection in the model. If bedleak is of size (nrow, ncol) or (ncpl) then all lake connections for the cellid are given the same bed leakance value. If bedleak is None, lake conductance is only a function of aquifer properties for all lakes. Can also pass mixed values as list or ndarray of size (nrow, ncol) or (ncpl) with floats and 'none' strings. Returns ------- idomain : ndarry idomain adjusted to inactivate cells with lakes connection_dict : dict dictionary with the zero-based lake number keys and number of connections in a lake values connectiondata : list of lists connectiondata block for the lake package """ if modelgrid.grid_type in ("unstructured",): raise ValueError( "unstructured grids not supported in get_lak_connections()" ) embedded = True shape3d = modelgrid.shape shape2d = shape3d[1:] # convert to numpy array if necessary if isinstance(lake_map, (list, tuple)): lake_map = np.array(lake_map, dtype=np.int32) elif isinstance(lake_map, (int, float)): raise TypeError( "lake_map must be a Masked Array, ndarray, list, or tuple" ) # evaluate lake_map shape shape_map = lake_map.shape if shape_map != shape3d: if shape_map != shape2d: raise ValueError( "lake_map shape ({}) must be equal to the grid shape for " "each layer ({})".format(shape_map, shape2d) ) else: embedded = False # process idomain if idomain is None: idomain = np.ones(shape3d, dtype=np.int32) elif isinstance(idomain, int): idomain = np.ones(shape3d, dtype=np.int32) * idomain elif isinstance(idomain, (float, bool)): raise ValueError("idomain must be a integer") # check dimensions of idomain if idomain.shape != shape3d: raise ValueError( f"shape of idomain ({idomain.shape}) not equal to {shape3d}" ) # convert bedleak to numpy array if necessary if bedleak is None: bedleak = np.chararray(shape2d, itemsize=4, unicode=True) bedleak[:] = "none" elif isinstance(bedleak, (float, int)): bedleak = np.ones(shape2d, dtype=float) * float(bedleak) elif isinstance(bedleak, (list, tuple)): bedleak = np.array(bedleak, dtype=object) # check the dimensions of the bedleak array if bedleak.shape != shape2d: raise ValueError( f"shape of bedleak ({bedleak.shape}) not equal to {shape2d}" ) # get the model grid elevations and reset lake_map using idomain # if lake is embedded and in an inactive cell if embedded: elevations = modelgrid.top_botm lake_map[idomain < 1] = -1 else: elevations = None # determine if masked array, in not convert to masked array if not np.ma.is_masked(lake_map): lake_map = np.ma.masked_where(lake_map < 0, lake_map) connection_dict = {} connectiondata = [] # find unique lake numbers unique = np.unique(lake_map) # exclude lakes with lake numbers less than 0 idx = np.where(unique > -1) unique = unique[idx] dx, dy = None, None # embedded lakes for lake_number in unique: iconn = 0 indices = np.argwhere(lake_map == lake_number) for index in indices: cell_index = tuple(index.tolist()) if embedded: leak_value = bedleak[cell_index[1:]] if modelgrid.grid_type == "structured": if dx is None: xv, yv = modelgrid.xvertices, modelgrid.yvertices dx = xv[0, 1:] - xv[0, :-1] dy = yv[:-1, 0] - yv[1:, 0] ( cellids, claktypes, belevs, televs, connlens, connwidths, ) = __structured_lake_connections( lake_map, idomain, cell_index, dx, dy, elevations ) elif modelgrid.grid_type == "vertex": raise NotImplementedError( "embedded lakes have not been implemented" ) else: cellid = (0,) + cell_index leak_value = bedleak[cell_index] if idomain[cellid] > 0: cellids = [cellid] claktypes = ["vertical"] belevs = [0.0] televs = [0.0] connlens = [0.0] connwidths = [0.0] else: cellids = [] claktypes = [] belevs = [] televs = [] connlens = [] connwidths = [] # iterate through each cellid for cellid, claktype, belev, telev, connlen, connwidth in zip( cellids, claktypes, belevs, televs, connlens, connwidths ): connectiondata.append( [ lake_number, iconn, cellid[:], claktype, leak_value, belev, telev, connlen, connwidth, ] ) iconn += 1 # set number of connections for lake connection_dict[lake_number] = iconn # reset idomain for lake if iconn > 0: idx = np.where((lake_map == lake_number) & (idomain > 0)) idomain[idx] = 0 return idomain, connection_dict, connectiondata
def __structured_lake_connections( lake_map, idomain, cell_index, dx, dy, elevations ): nlay, nrow, ncol = lake_map.shape cellids = [] claktypes = [] belevs = [] televs = [] connlens = [] connwidths = [] k, i, j = cell_index if idomain[cell_index] > 0: # back face if i > 0: ci = (k, i - 1, j) cit = (k + 1, i - 1, j) if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: cellids.append(ci) claktypes.append("horizontal") belevs.append(elevations[cit]) televs.append(elevations[ci]) connlens.append(0.5 * dy[i - 1]) connwidths.append(dx[j]) # left face if j > 0: ci = (k, i, j - 1) cit = (k + 1, i, j - 1) if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: cellids.append(ci) claktypes.append("horizontal") belevs.append(elevations[cit]) televs.append(elevations[ci]) connlens.append(0.5 * dx[j - 1]) connwidths.append(dy[i]) # right face if j < ncol - 1: ci = (k, i, j + 1) cit = (k + 1, i, j + 1) if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: cellids.append(ci) claktypes.append("horizontal") belevs.append(elevations[cit]) televs.append(elevations[ci]) connlens.append(0.5 * dx[j + 1]) connwidths.append(dy[i]) # front face if i < nrow - 1: ci = (k, i + 1, j) cit = (k + 1, i + 1, j) if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: cellids.append(ci) claktypes.append("horizontal") belevs.append(elevations[cit]) televs.append(elevations[ci]) connlens.append(0.5 * dy[i + 1]) connwidths.append(dx[j]) # lower face if k < nlay - 1: ci = (k + 1, i, j) if np.ma.is_masked(lake_map[ci]) and idomain[ci] > 0: cellids.append(ci) claktypes.append("vertical") belevs.append(0.0) televs.append(0.0) connlens.append(0.0) connwidths.append(0.0) return cellids, claktypes, belevs, televs, connlens, connwidths