def get_cstrt(nlay, ncol, length, x1, x2, a1, a2, b, c1, c2, c3): cstrt = c1 * np.ones((nlay, ncol), dtype=float) from flopy.utils.gridintersect import GridIntersect from shapely.geometry import Polygon p3 = Polygon([(0, b), (x2 - a2, b), (x2 + a2, 0), (0, 0)]) p2 = Polygon([(x2 - a2, b), (x1 - a1, b), (x1 + a1, 0), (x1 - a1, 0)]) delc = b / nlay * np.ones(nlay) delr = length / ncol * np.ones(ncol) sgr = flopy.discretization.StructuredGrid(delc, delr) ix = GridIntersect(sgr, method="structured") for ival, p in [(c2, p2), (c3, p3)]: result = ix.intersect(p) for i, j in list(result["cellids"]): cstrt[i, j] = ival return cstrt
def test_tri_grid_linestring_on_inner_boundary(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) result = ix.intersect(LineString([(5.0, 10.0), (15.0, 10.0)])) assert len(result) == 2 assert result.lengths.sum() == 10.0 assert result.cellids[0] == 0 assert result.cellids[1] == 1 return result
def test_rect_grid_polygon_with_hole_shapely(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_rect_grid() ix = GridIntersect(gr, method="vertex", rtree=rtree) p = Polygon( [(5.0, 5.0), (5.0, 15.0), (25.0, 15.0), (25.0, -5.0), (5.0, -5.0)], holes=[[(9.0, -1), (9, 11), (21, 11), (21, -1)]], ) result = ix.intersect(p) assert len(result) == 3 assert result.areas.sum() == 104.0 return result
def test_rect_grid_linestring_in_and_out_of_cell2(): # avoid test fail when shapely not available try: import shapely except: return gr = get_rect_grid() ix = GridIntersect(gr, method="structured") result = ix.intersect( LineString([(5, 15), (5.0, 9), (15.0, 5.0), (5.0, 1.0)]) ) assert len(result) == 3 # assert result.cellids[0] == (1, 0) # assert result.cellids[1] == (1, 1) # assert np.allclose(result.lengths.sum(), 21.540659228538015) return result
def test_tri_grid_polygon_with_hole(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) p = Polygon([(5., 5.), (5., 15.), (25., 15.), (25., -5.), (5., -5.)], holes=[[(9., -1), (9, 11), (21, 11), (21, -1)]]) result = ix.intersect(p) assert len(result) == 6 assert result.areas.sum() == 104. return result
def test_tri_grid_linestring_in_2cells(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) result = ix.intersect(LineString([(5., 5.), (5., 15.)])) assert len(result) == 2 assert result.lengths.sum() == 10. assert result.cellids[0] == 1 assert result.cellids[1] == 3 return result
def test_tri_grid_linestring_on_inner_boundary(): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid(triangle_exe=triangle_exe) if gr == -1: return ix = GridIntersect(gr) result = ix.intersect_linestring(LineString([(5., 10.), (15., 10.)])) assert len(result) == 2 assert result.lengths.sum() == 10. assert result.cellids[0] == 0 assert result.cellids[1] == 1 return result
def test_tri_grid_polygon_in_2cells(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) result = ix.intersect( Polygon([(2.5, 5.0), (5.0, 5.0), (5.0, 15.0), (2.5, 15.0)]) ) assert len(result) == 2 assert result.areas.sum() == 25.0 return result
def test_rect_grid_multilinestring_in_one_cell_shapely(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_rect_grid() ix = GridIntersect(gr, method='vertex', rtree=rtree) result = ix.intersect( MultiLineString([ LineString([(1., 1), (9., 1.)]), LineString([(1., 9.), (9., 9.)]) ])) assert len(result) == 1 assert result.lengths == 16. assert result.cellids[0] == (1, 0) return result
def test_tri_grid_multipolygon_in_multiple_cells(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) p1 = Polygon([(1., 1.), (19., 1.), (19., 3.), (1., 3.)]) p2 = Polygon([(1., 9.), (19., 9.), (19., 7.), (1., 7.)]) p = MultiPolygon([p1, p2]) result = ix.intersect(p) assert len(result) == 4 assert result.areas.sum() == 72. return result
def test_tri_grid_multipolygon_in_one_cell(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) p1 = Polygon([(1.0, 1.0), (8.0, 1.0), (8.0, 3.0), (3.0, 3.0)]) p2 = Polygon([(5.0, 5.0), (8.0, 5.0), (8.0, 8.0)]) p = MultiPolygon([p1, p2]) result = ix.intersect(p) assert len(result) == 1 assert result.areas.sum() == 16.5 return result
def test_tri_grid_multipolygon_in_one_cell(): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid(triangle_exe=triangle_exe) if gr == -1: return ix = GridIntersect(gr) p1 = Polygon([(1., 1.), (8., 1.), (8., 3.), (3., 3.)]) p2 = Polygon([(5., 5.), (8., 5.), (8., 8.)]) p = MultiPolygon([p1, p2]) result = ix.intersect_polygon(p) assert len(result) == 1 assert result.areas.sum() == 16.5 return result
def test_polygon_offset_rot_structured_grid_shapely(rtree=True): # avoid test fail when shapely not available try: import shapely except: return sgr = get_rect_grid(angrot=45.0, xyoffset=10.0) p = Polygon( [ (5, 10.0 + np.sqrt(200.0)), (15, 10.0 + np.sqrt(200.0)), (15, 10.0 + 1.5 * np.sqrt(200.0)), (5, 10.0 + 1.5 * np.sqrt(200.0)), ] ) ix = GridIntersect(sgr, method="vertex", rtree=rtree) result = ix.intersect(p) # assert len(result) == 3. return result
def test_tri_grid_multilinestring_in_one_cell(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_tri_grid() if gr == -1: return ix = GridIntersect(gr, rtree=rtree) result = ix.intersect( MultiLineString([ LineString([(1., 1), (9., 1.)]), LineString([(2., 2.), (9., 2.)]) ])) assert len(result) == 1 assert result.lengths == 15. assert result.cellids[0] == 4 return result
def test_rect_grid_multilinestring_in_one_cell(): # avoid test fail when shapely not available try: import shapely except: return gr = get_rect_grid() ix = GridIntersect(gr, method="structured") result = ix.intersect( MultiLineString( [ LineString([(1.0, 1), (9.0, 1.0)]), LineString([(1.0, 9.0), (9.0, 9.0)]), ] ) ) assert len(result) == 1 assert result.lengths == 16.0 assert result.cellids[0] == (1, 0) return result
def gp2cellids(grid, gp, idomain, idomain_active=True, type="polygon", layer=0, areas=3): """ this function extract the cellids of the intersection between a geopandas object and a grid grid : modelgrid gp : geopandas object (polygon, linestring only) idomain : the idomain array to update it idomain_active : bool, if true the idomain is update (cells intersect by the gp will be noted as active), prevents some issues type : str, features type (polygon or line) layer : int, the layer on which is the gp areas : factor that determine if a cell is accounted intersected or not based on the total area intersected in this cell (a value of 3, for example, mean only cells which have 1/3 of their area intersected by the polygon will be taken into account) """ ix = GridIntersect(grid) if type == "polygon": result = ix.intersect_polygon(gp.geometry[0]) result = result[result.areas > ( np.max(result.areas) / 3 )] # only take into account cells that have a least 1/3 intersected result = result[result.areas != 0] # fix bug if type == "boundary": result = ix.intersect_linestring(gp.geometry[0].boundary) if type == "line": result = ix.intersect_linestring(gp.geometry[0]) lst = [] for irow, icol in result.cellids: lst.append(((layer, irow, icol))) if idomain_active: idomain[irow * grid.ncol + icol] = 1 return lst
def test_rect_grid_polygon_in_edge_in_cell(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_rect_grid() ix = GridIntersect(gr, method="vertex", rtree=rtree) p = Polygon( [ (0.0, 5.0), (3.0, 0.0), (7.0, 0.0), (10.0, 5.0), (10.0, -1.0), (0.0, -1.0), ] ) result = ix.intersect(p) assert len(result) == 1 assert result.areas.sum() == 15.0 return result
def gp2cellids (grid, gp, idomain, idomain_active=True, type = "polygon",layer=0,areas=3): """ this function extract the cellids of the intersection between a geopandas object and a grid """ ix = GridIntersect(grid) if type == "polygon": result = ix.intersect_polygon(gp.geometry[0]) result = result[result.areas>(np.max(result.areas)/3)] # only take into account cells that have a least 1/3 intersected by the polygon if type == "boundary" : result = ix.intersect_linestring(gp.geometry[0].boundary) if type == "line" : result = ix.intersect_linestring(gp.geometry[0]) lst=[]; for irow, icol in result.cellids: lst.append(((layer,irow,icol))) if idomain_active: idomain[irow*grid.ncol+icol] = 1 return lst
def importWells3D(path, grid, lst_domain, fac=1 / 365 / 86400, V_col="V Bancaris", geol_col="NAPPE_CAPT", geol_layer=["PLIOCENE", "QUATERNAIRE"], layer_num=[1, 0]): """ extract the infos about the amount of water uptake by wells path : path to the shp (multi points required) grid : the modelgrid fac : the factor to transform volume units to get m3/s (depends of original units) V_col : the column name containing info about Volume geol_col = the column name containing geol infos geol_layer : the name of the differents lithology encountered layer_num : the num layer corresponding to the lithology in geol_layer """ ix = GridIntersect(grid) BD_prlvm = gp.read_file(path) stress_data_well = [] for ilayer in range(len(geol_layer)): # iterate through layers BD = BD_prlvm[BD_prlvm[geol_col] == geol_layer[ ilayer]] # only keep layers with the right geol for o in BD.index: #iterate through each well Vw = BD.loc[o, V_col] if not (np.isnan(Vw)) | (Vw == 0): #keep productive well cellidx = ix.intersect_point(BD.geometry[o]).cellids[0][0] cellidy = ix.intersect_point(BD.geometry[o]).cellids[0][1] cellid = (layer_num[ilayer], cellidx, cellidy ) #cell on which the well is active if cellid in lst_domain: # check if the well is in the domain stress_data_well.append((cellid, -fac * Vw)) return stress_data_well
def test_rect_vertex_grid_point_in_one_cell_shapely(rtree=True): # avoid test fail when shapely not available try: import shapely except: return gr = get_rect_vertex_grid() ix = GridIntersect(gr, method='vertex', rtree=rtree) result = ix.intersect(Point(4., 4.)) assert len(result) == 1 assert result.cellids[0] == 0 result = ix.intersect(Point(4., 6.)) assert len(result) == 1 assert result.cellids[0] == 0 result = ix.intersect(Point(6., 6.)) assert len(result) == 1 assert result.cellids[0] == 0 result = ix.intersect(Point(6., 4.)) assert len(result) == 1 assert result.cellids[0] == 0 return result
def gp2idomain(gp, grid, idomain, area=0, layer=0, method="none"): ''' This function attribute active values to cells given a certain geopandas object and a grid (flopy.discretization) with idomain the area is a value that determine at which level a cell will be counted as intersected by the polygon (3 for example mean that only cells that have 1/3 of their area intersected by the polygon will be accounted) ''' if method == "none": ix = GridIntersect(grid) if method == "structured": ix = GridIntersect(grid, method=method) if area == 0: result = ix.intersect_polygon(gp.geometry[0]) if area >= 1: result = ix.intersect_polygon(gp.geometry[0]) result = result[result.areas > (np.max(result.areas) / area)] lst = [] for irow, icol in result.cellids: idomain[irow * grid.ncol + icol] = 1 lst.append(((layer, irow, icol))) return lst
ss_4="ss_roc.txt" # we are including the qbg hydraulic conductivity by using shapes gravoso=sf.Reader(path_sh+"/Superficies/Cont_Qbg2.shp") gravoso1=gravoso.shapeRecords()[0] firstkg=gravoso1.shape.__geo_interface__ # print(firstd) shp_geomkg=shape(firstkg) # now we use shapely to instersect # plt.figure() gwf.modelgrid.plot() ix = GridIntersect(gwf.modelgrid, method="structured", rtree=False) resultkg= ix.intersect(shp_geomkg) gravoso_cells=[] for i in range(resultkg.shape[0]): gravoso_cells.append([*resultkg["cellids"][i]])#hay que revisar si la tupla quedó mal # creating the idomain matrix domin_grav=np.zeros((nrows,ncols)) # print(nlay,nrows,ncols) for i, value in enumerate(gravoso_cells): # print(i) # print(value) k_qd_qbg[tuple(value)]=1e-5 ss_qd_qbg[tuple(value)]=1e-4 sy_qd_qbg[tuple(value)]=1e-1
def import_riv(grid, gp): """ This function extract infos about a river (geopandas object, LINESTRING),cellids + lengths of in each cells in the right order. Format : import_riv (Grid (from the gwf model, gwf.modelgrid for ex.), gp (a geopandas object containing a unique Linestring)) Return a dataframe containing these datas, post-processing necessary to remove cells that are already counted as BC in the model """ ix = GridIntersect(grid) coord_riv = [] for x, y in zip(gp.geometry[0].xy[0], gp.geometry[0].xy[1]): coord_riv.append((x, y)) verti = [] df_tot_ord = pd.DataFrame() # empty DF for i in range(len(coord_riv)): if i < len(coord_riv) - 1: lsi = LineString([coord_riv[i], coord_riv[i + 1] ]) # create the linestring btw point i and i+1 res = ix.intersect_linestring(lsi) # do the intersection cellids = res.cellids # extract cellids if len( cellids ) > 1: # if more than one cells is intersected --> we need to order them dirx = coord_riv[i + 1][0] - coord_riv[i][ 0] # Xdirection of the linestring for x, y in res.vertices: # extract the 1st vertice of the intersections in order to organize verti.append(x) vertix = np.array(verti)[:, 0] df = pd.DataFrame({ "cellids": cellids, "vertix": vertix, "lengths": res.lengths }) # create a DF to order verti = [] #organize the cells given the direction if dirx > 0: df.sort_values(by=["vertix"], ascending=True, inplace=True) if dirx < 0: df.sort_values(by=["vertix"], ascending=False, inplace=True) # append these data in a big DF df_tot_ord = df_tot_ord.append(df).drop(["vertix"], axis=1) else: # if only one cell is intersected by the linestring df_tot_ord = df_tot_ord.append( pd.DataFrame({ "cellids": cellids, "lengths": res.lengths })) df_riv = df_tot_ord.groupby(["cellids"], sort=False).sum() # retrieve data lst_len_Riv = df_riv["lengths"].values cellids_Riv = [] # list of all the cells intersected by the river cellids = df_riv.index for irow, icol in cellids: cell = (0, irow, icol) if cell not in cellids_Riv: cellids_Riv.append(cell) df_riv = pd.DataFrame({"cellids": cellids_Riv, "lengths": lst_len_Riv}) return df_riv
def build_model(): if config.buildModel: sim_ws = os.path.join(ws, sim_name) sim = flopy.mf6.MFSimulation( sim_name=sim_name, sim_ws=sim_ws, exe_name=config.mf6_exe ) flopy.mf6.ModflowTdis( sim, nper=nper, perioddata=tdis_ds, time_units=time_units ) flopy.mf6.ModflowIms( sim, outer_maximum=nouter, outer_dvclose=hclose, inner_maximum=ninner, inner_dvclose=hclose, rcloserecord=[rclose, "strict"], ) gwf = flopy.mf6.ModflowGwf(sim, modelname=sim_name, save_flows=True) flopy.mf6.ModflowGwfdis( gwf, length_units=length_units, nlay=nlay, nrow=nrow, ncol=ncol, delr=delr, delc=delc, top=top, botm=botm, ) flopy.mf6.ModflowGwfnpf( gwf, cvoptions="perched", perched=True, icelltype=icelltype, k=k11, k33=k33, save_specific_discharge=True, ) flopy.mf6.ModflowGwfic(gwf, strt=strt) flopy.mf6.ModflowGwfsto( gwf, iconvert=1, ss=1.0e-6, sy=sy, steady_state={0: True}, transient={1: True}, ) ghb_spd = [] ghb_spd += [ [1, i, 9, "tides", 15.0, "ESTUARY-L2"] for i in range(nrow) ] ghb_spd += [ [2, i, 9, "tides", 1500.0, "ESTUARY-L3"] for i in range(nrow) ] ghb_spd = {0: ghb_spd} fname = os.path.join(config.data_ws, sim_name, "tides.csv") tsdict = get_timeseries(fname, "tides", "linear") ghbobs_dict = {} ghbobs_dict["{}.ghb.obs.csv".format(sim_name)] = [ ("ghb_2_6_10", "ghb", (1, 5, 9)), ("ghb_3_6_10", "ghb", (2, 5, 9)), ("estuary2", "ghb", "ESTUARY-L2"), ("estuary3", "ghb", "ESTUARY-L3"), ] flopy.mf6.ModflowGwfghb( gwf, stress_period_data=ghb_spd, boundnames=True, timeseries=tsdict, observations=ghbobs_dict, pname="GHB-TIDAL", ) wel_spd = {} wel_spd[1] = [ [0, 11, 2, -50, ""], [2, 4, 7, "well_1_rate", "well_1"], [2, 3, 2, "well_2_rate", "well_2"], ] wel_spd[2] = [ [2, 3, 2, "well_2_rate", "well_2"], [2, 4, 7, "well_1_rate", "well_1"], ] wel_spd[3] = [ [2, 4, 7, "well_1_rate", "well_1"], [2, 3, 2, "well_2_rate", "well_2"], [0, 11, 2, -10, ""], [0, 2, 4, -20, ""], [0, 13, 5, -40, ""], ] fname = os.path.join(config.data_ws, sim_name, "wellrates.csv") tsdict = get_timeseries( fname, ["well_1_rate", "well_2_rate", "well_6_rate"], 3 * ["stepwise"], ) flopy.mf6.ModflowGwfwel( gwf, stress_period_data=wel_spd, boundnames=True, timeseries=tsdict, pname="WEL", ) rivlay = 20 * [0] rivrow = [2, 3, 4, 4, 5, 5, 5, 4, 4, 4, 9, 8, 7, 6, 6, 5, 5, 6, 6, 6] rivcol = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] rivstg = 10 * ["river_stage_1"] + 10 * ["river_stage_2"] rivcnd = 2 * [1000 + f + 1 for f in range(10)] rivrbt = list(np.linspace(35.9, 35.0, 10)) + list( np.linspace(36.9, 36.0, 10) ) rivbnd = ( 5 * [""] + ["riv1_c6", "riv1_c7"] + 3 * [""] + 3 * ["riv2_upper"] + 2 * [""] + ["riv2_c6", "riv2_c7"] + 3 * [""] ) riv_spd = list( zip(rivlay, rivrow, rivcol, rivstg, rivcnd, rivrbt, rivbnd) ) fname = os.path.join(config.data_ws, sim_name, "riverstage.csv") tsdict = get_timeseries( fname, ["river_stage_1", "river_stage_2"], ["linear", "stepwise"], ) flopy.mf6.ModflowGwfriv( gwf, stress_period_data=riv_spd, boundnames=True, timeseries=tsdict, pname="RIV", ) for ipak, p in enumerate( [recharge_zone_1, recharge_zone_2, recharge_zone_3] ): ix = GridIntersect(gwf.modelgrid, method="vertex", rtree=True) result = ix.intersect(p) rch_spd = [] for i in range(result.shape[0]): rch_spd.append( [ 0, *result["cellids"][i], "rch_{}".format(ipak + 1), result["areas"][i] / delr / delc, ] ) fname = os.path.join( config.data_ws, sim_name, "recharge{}.csv".format(ipak + 1) ) tsdict = get_timeseries( fname, ["rch_{}".format(ipak + 1)], ["stepwise"], filename="{}.rch{}.ts".format(sim_name, ipak + 1), ) flopy.mf6.ModflowGwfrch( gwf, stress_period_data=rch_spd, boundnames=True, timeseries=tsdict, fixed_cell=True, print_input=True, print_flows=True, save_flows=True, auxiliary=["MULTIPLIER"], auxmultname="MULTIPLIER", pname="RCH-ZONE_{}".format(ipak + 1), filename="{}.rch{}".format(sim_name, ipak + 1), ) nseg = 3 etsurf = 50 etrate = 0.0004 depth = 10.0 pxdp = [0.2, 0.5] petm = [0.3, 0.1] row, col = np.where(np.zeros((nrow, ncol)) == 0) cellids = list(zip(nrow * ncol * [0], row, col)) evt_spd = [ [k, i, j, etsurf, etrate, depth, *pxdp, *petm] for k, i, j in cellids ] flopy.mf6.ModflowGwfevt( gwf, nseg=nseg, stress_period_data=evt_spd, pname="EVT" ) head_filerecord = "{}.hds".format(sim_name) budget_filerecord = "{}.cbc".format(sim_name) flopy.mf6.ModflowGwfoc( gwf, head_filerecord=head_filerecord, budget_filerecord=budget_filerecord, saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], ) obsdict = {} obslist = [["h1_13_8", "head", (2, 12, 7)]] obsdict["{}.obs.head.csv".format(sim_name)] = obslist obslist = [["icf1", "flow-ja-face", (0, 4, 5), (0, 5, 5)]] obsdict["{}.obs.flow.csv".format(sim_name)] = obslist obs = flopy.mf6.ModflowUtlobs( gwf, print_input=False, continuous=obsdict ) return sim return None
def build_model(sim_name): if config.buildModel: sim_ws = os.path.join(ws, sim_name) sim = flopy.mf6.MFSimulation(sim_name=sim_name, sim_ws=sim_ws, exe_name=config.mf6_exe) flopy.mf6.ModflowTdis(sim, nper=nper, perioddata=tdis_ds, time_units=time_units) flopy.mf6.ModflowIms( sim, linear_acceleration="bicgstab", outer_maximum=nouter, outer_dvclose=hclose, inner_maximum=ninner, inner_dvclose=hclose, rcloserecord="{} strict".format(rclose), ) gwf = flopy.mf6.ModflowGwf(sim, modelname=sim_name, save_flows=True) flopy.mf6.ModflowGwfdisv( gwf, length_units=length_units, nlay=nlay, top=top, botm=botm, **gridprops, ) flopy.mf6.ModflowGwfnpf( gwf, icelltype=icelltype, k=k11, k33=k33, save_specific_discharge=True, xt3doptions=True, ) flopy.mf6.ModflowGwfic(gwf, strt=strt) theta = np.arange(0.0, 2 * np.pi, 0.2) radius = 1500.0 x = radius * np.cos(theta) y = radius * np.sin(theta) outer = [(x, y) for x, y in zip(x, y)] radius = 1025.0 x = radius * np.cos(theta) y = radius * np.sin(theta) hole = [(x, y) for x, y in zip(x, y)] p = Polygon(outer, holes=[hole]) ix = GridIntersect(gwf.modelgrid, method="vertex", rtree=True) result = ix.intersect(p) ghb_cellids = np.array(result["cellids"], dtype=int) ghb_spd = [] ghb_spd += [[0, i, 0.0, k33 * cell_areas[i] / 10.0] for i in ghb_cellids] ghb_spd = {0: ghb_spd} flopy.mf6.ModflowGwfghb( gwf, stress_period_data=ghb_spd, pname="GHB", ) ncpl = gridprops["ncpl"] rchcells = np.array(list(range(ncpl)), dtype=int) rchcells[ghb_cellids] = -1 rch_spd = [(0, rchcells[i], recharge) for i in range(ncpl) if rchcells[i] > 0] rch_spd = {0: rch_spd} flopy.mf6.ModflowGwfrch(gwf, stress_period_data=rch_spd, pname="RCH") head_filerecord = "{}.hds".format(sim_name) budget_filerecord = "{}.cbc".format(sim_name) flopy.mf6.ModflowGwfoc( gwf, head_filerecord=head_filerecord, budget_filerecord=budget_filerecord, saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], ) return sim return None