def test_cell_budget_export(model): m, grid, output_path = model precision = 'single' binary_grid_file = None skip = [] if m.version == 'mf6': precision = 'double' binary_grid_file = os.path.join(m.model_ws, '{}.dis.grb'.format(m.name)) skip = ['WEL'] file = os.path.join(m.model_ws, '{}.cbc'.format(m.name)) #file = 'Examples/data/lpr/lpr_inset.cbc' assert os.path.exists(file) cbobj = bf.CellBudgetFile(file, precision=precision) layers = list(range(cbobj.nlay)) kstpkper = cbobj.get_kstpkper()[0] variables = [ bs.decode().strip() for bs in cbobj.textlist if bs.decode().strip() not in skip ] nrow, ncol = cbobj.nrow, cbobj.ncol cbobj.close() outfiles = export_cell_budget(file, grid, binary_grid_file=binary_grid_file, kstpkper=kstpkper, precision=precision, output_path=output_path) check_files(outfiles, variables, kstpkper) tifs = [f for f in outfiles if f.endswith('.tif')] for f in tifs: with rasterio.open(f) as src: assert src.width == ncol assert src.height == nrow compare_polygons(grid.bbox, box(*src.bounds))
def get_stress_budget_textlist(mf6_stress_budget_output): """Get list of available variable names in a binary budget output file. """ cbobj = bf.CellBudgetFile(mf6_stress_budget_output, precision='double' ) textlist = [t.strip().decode() for t in cbobj.textlist] return textlist
def read_parent_cbc_per(self, kstpkper=(0, 0)): cbbobj = bf.CellBudgetFile(self.cpth) text = {'FLOW RIGHT FACE': 'frf', 'FLOW FRONT FACE': 'fff'} self.cbc = {} for fulltxt, shorttxt in text.items(): self.cbc[shorttxt] = get_surface_bc_flux(cbbobj, fulltxt, kstpkper=kstpkper, idx=0)
def get_output_objects(self): headfile = tuple() cellfile = tuple() # Find output files we want to process. These are the defaults if # no specific file is specified in the configuration for u, f, b in zip(self.mf.external_units, self.mf.external_fnames, self.mf.external_binflag): _, ext = os.path.splitext(f) if ext == ".bud": cellfile = (u, f, b) elif ext == ".bhd": headfile = (u, f, b) else: pass # Headfile head_obj = None with LoggingTimer("Loading head file", logger.info): try: if self.head_file: head_obj = flopy_binary.HeadFile(self.head_file, precision=self.precision) elif headfile: head_obj = flopy_binary.HeadFile(headfile[1], precision=self.precision) else: logger.warning("No Headfile found") except BaseException: logger.exception("Exception occured when trying to load the HeadFile into flopy. Skipping!") # Cell budget file cell_obj = None with LoggingTimer("Loading cell budget file", logger.info): try: if self.cbud_file: cell_obj = flopy_binary.CellBudgetFile(self.cbud_file, precision=self.precision) elif cellfile: cell_obj = flopy_binary.CellBudgetFile(cellfile[1], precision=self.precision) else: logger.warning("No CellBudget file found") except BaseException: logger.exception("Exception occured when trying to load the CellBudgetFile into flopy. Skipping!") return dict(head_obj=head_obj, cell_obj=cell_obj)
def read_mf6_stress_budget_output(mf6_stress_budget_output, text='FLOW-JA-FACE', kstpkper=None): """Reads budget output from any package that follows the imeth=6 structure (e.g. LAK, MAW, SFR, and UZF package(s); for example, output from BUDGET FILEOUT in the options block of the .sfr6 file). Parameters ---------- mf6_stress_budget_output : file path Binary output file text : str Text identifying flow term (e.g. 'FLOW-JA-FACE') Returns ------- df : DataFrame Table with flow results. Columns: node : node number (e.g. stream reach; 1-based) node2 : connecting node (e.g. up or downstream reach; 1-based) q : flow values FLOW-AREA : area of JA-FACE? kstpkper : (timestep, stress period) time : total time in model units """ print('reading {} from\n{}...'.format(text, mf6_stress_budget_output)) ta = time.time() cbobj = bf.CellBudgetFile(mf6_stress_budget_output, precision='double' ) times = cbobj.get_times() dfs = [] if kstpkper is None: kstpkper = cbobj.get_kstpkper() # returns a list of recarrays (length: nnodes); # one for each timestep, stress period records = cbobj.get_data(text=text) else: # otherwise, just get the results # for specified timestep, stress periods if not isinstance(kstpkper, list): kstpkper = [kstpkper] records = [] for ksp in kstpkper: records += cbobj.get_data(text=text, kstpkper=ksp) for i, rec in enumerate(records): df = pd.DataFrame(rec) df['kstpkper'] = [kstpkper[i]] * len(df) df['time'] = [times[i]] * len(df) dfs.append(df.copy()) df = pd.concat(dfs) print("finished in {:.2f}s\n".format(time.time() - ta)) return df.sort_values(by=['time', 'node'])
def convert_uzf_to_rch(mf, issue=None, alpha=None): """ Parameters ---------- mf: Modflow model object with UZF Returns ------- mf: Modflow model object with RCH, in place of UZF """ # update user print('Converting UZF to Recharge.') # IMPORTS import os import flopy import numpy as np import flopy.utils.binaryfile as bf # data from original model run - recharge orig_cbc_file = bf.CellBudgetFile( os.path.join(mf.model_ws, mf.name + '.cbc')) orch_data = orig_cbc_file.get_data(text='uzf recharge') orig_cbc_file.close() # determine cell areas spacex, spacey = np.meshgrid(mf.modelgrid.delr, mf.modelgrid.delc) gridA = spacex * spacey # remove the uzf package mf.remove_package('UZF') mf.remove_package('LMT6') # address issues? if issue is not None: for i in issue: t = i[0] idx = (i[1], i[2], i[3]) orch_data[t][idx] *= 0.9 # recreate stress_period_data dictionary rch_spd = {} print(' >> Creating new stress period data...') if alpha is None: alpha = np.ones((mf.nper, )) for sp in range(mf.nper): rch_spd[sp] = (orch_data[sp][0, ...] / gridA ) * alpha[sp] # translate volumetric/sp to flow rate/d # instantiate the recharge package flopy.modflow.ModflowRch(mf, ipakcb=1, rech=rch_spd) # re-instantiate the LMT package flopy.modflow.ModflowLmt(mf, extension='lmt') return mf
def test_specific_discharge_default(): # load and postprocess mf = flopy.modflow.Modflow.load(namfile_mf2005, check=False) cbc = bf.CellBudgetFile(cbcfile_mf2005) keys = ["FLOW RIGHT FACE", "FLOW FRONT FACE", "FLOW LOWER FACE"] vectors = [cbc.get_data(text=t)[0] for t in keys] qx, qy, qz = flopy.utils.postprocessing.get_specific_discharge(vectors, mf) # overall check overall = np.sum(qx) + np.sum(qy) + np.sum(qz) assert np.allclose(overall, -1.7959892749786377) return
def uzf_arrays(self): """ Make 3d numpy arrays of shape (74*51*549) """ varnames = ['surf_leak', 'uzf_rch', 'uzf_et', 'uzf_run'] variables = ['SURFACE LEAKAGE', 'UZF RECHARGE', 'GW ET', 'HORT+DUNN'] for scenario in self.scenarios: slr_name = op.basename(scenario) slr = slr_name[4:7] uzf_file = op.join(scenario, '{}.uzfcb2.bin'.format(slr_name)) try: uzfobj = bf.CellBudgetFile(uzf_file, precision='single') except: uzfobj = bf.CellBudgetFile(uzf_file, precision='double') for i, variable in enumerate(variables): uzf_data = uzfobj.get_data(text=variable) sys_mat = np.zeros([len(self.ts_day), 74, 51]) for j in range(len(self.ts_day)): sys_mat[j, :, :] = uzf_data[j] # save separately so can load separately and faster path_res = op.join(self.path_picks, '{}_{}.npy'.format(varnames[i], slr)) np.save(path_res, sys_mat) print('UZF arrays pickled to: {}'.format(self.path_picks))
def __init__(self, cbbfile, model_ws, modelname, starting_locs, n, delt, ntimes): self.cbbobj = bf.CellBudgetFile(os.path.join(model_ws, cbbfile)) self.times = self.cbbobj.get_times() self.mf = flopy.modflow.Modflow.load( os.path.join(model_ws, modelname + '.nam')) self.delr = self.mf.dis.delr.array self.delc = self.mf.dis.delc.array self.nlay = self.mf.dis.nlay self.nrow = self.mf.dis.nrow self.ncol = self.mf.dis.ncol self.starting_locs = starting_locs self.n = n self.delt = delt self.ntimes = ntimes
def get_sim_bc(budget_binary,text=None): '''Extracts a single boundary condition from the budget_binary and returns an (nper,nlay,nrow,ncol) array.''' cbc = bf.CellBudgetFile(budget_binary) bc = cbc.get_data(text=text,full3D=True) # Convert to a 4D numpy array nper = len(bc[0]) nlay,nrow,ncol = np.shape(bc[0]) bc_array = np.empty((nper,nlay,nrow,ncol)) for i in range(nper): bc_array[i,:,:,:] = bc[i] return bc_array
def get_flowja_face(cell_budget_file, binary_grid_file, kstpkper=(0, 0), idx=0, precision='double'): """Get FLOW-JA-FACE (cell by cell flows) from MODFLOW 6 budget output and binary grid file. TODO: need test for extracted flowja fluxes """ if isinstance(cell_budget_file, str): cbb = bf.CellBudgetFile(cell_budget_file) if binary_grid_file is None: binary_grid_file = cell_budget_file[::-4] + '.dis.grb' if not os.path.exists(binary_grid_file): binary_grid_file = None else: cbb = cell_budget_file if binary_grid_file is None: print( "Couldn't get FLOW-JA-FACE, need binary grid file for connection information." ) return bgf = MfGrdFile(binary_grid_file) # IA array maps cell number to connection number # (one-based index number of first connection at each cell)? # taking the forward difference then yields nconnections per cell ia = bgf._datadict['IA'] - 1 # Connections in the JA array correspond directly with the # FLOW-JA-FACE record that is written to the budget file. ja = bgf._datadict['JA'] - 1 # cell connections flowja = cbb.get_data(text='FLOW-JA-FACE')[0][0, 0, :] df = get_intercell_connections(ia, ja, flowja) cols = ['n', 'm', 'q'] # get the k, i, j locations for plotting the connections if isinstance(bgf.mg, StructuredGrid): nlay, nrow, ncol = bgf.mg.nlay, bgf.mg.nrow, bgf.mg.ncol k, i, j = get_kij_from_node3d(df['n'].values, nrow, ncol) df['kn'], df['in'], df['jn'] = k, i, j k, i, j = get_kij_from_node3d(df['m'].values, nrow, ncol) df['km'], df['im'], df['jm'] = k, i, j df.reset_index() cols += ['kn', 'in', 'jn', 'km', 'im', 'jm'] return df[cols].copy()
def __init__(self, workspace, modelname, ext='.cbc'): self.CBC = bf.CellBudgetFile(os.path.join(workspace, modelname + ext)) # get active labels self.labels = [ self.__class__.txt2lbl[txt] for txt in self.CBC.textlist if txt in self.__class__.txt2lbl.keys() ] kstpkper = self.CBC.get_kstpkper() nstp = len(kstpkper) # initialize budget for all labels, per label np.array(n, 2) # where np.array[:,0] = inflows and np.array[:,1] = outflows self.budget = {lbl: np.zeros((nstp, 2)) for lbl in self.labels} cbclbl = self.__class__.cbc_label # shorthand for i, sp in enumerate(kstpkper): for label in self.labels: try: rec = self.CBC.get_data(kstpkper=sp, text=cbclbl[label]['text'])[0] if isinstance(rec, np.recarray): self.budget[label][i, 0] = np.sum(rec['q'][rec['q'] > 0]) self.budget[label][i, 1] = np.sum(rec['q'][rec['q'] < 0]) elif label in ['RCH', 'EVT']: self.budget[label][i, 0] = np.sum(rec[1][rec[1] > 0]) self.budget[label][i, 1] = np.sum(rec[1][rec[1] < 0]) else: # 3D array self.budget[label][i, 0] = np.sum(rec[rec > 0]) self.budget[label][i, 1] = np.sum(rec[rec < 0]) except: pass # skips when label not avaiable for stress period
wells = [wel1,wel2,wel3,wel4] wel_spd = {0: wells, 1: wells, 2: wells, 3: wells, 4: wells, 5: wells, 6: wells, 7: wells, 8: wells, 9: wells} wel = flopy.modflow.ModflowWel(mf,stress_period_data=wel_spd,ipakcb=53) # wel.export(os.path.join('grid','wel.shp')) # shutil.copy(os.path.join('grid','grid.prj'),os.path.join('grid','wel.prj')) #write the modflow input files mf.write_input() # Run the MODFLOW model success, buff = mf.run_model(silent=False) cbbobj = bf.CellBudgetFile(os.path.join(model_ws,modelname+'.cbc')) # print(cbbobj.get_) # create contour shapefile headobj = bf.HeadFile(os.path.join(model_ws,modelname+'.hds')) times = headobj.get_times() head = headobj.get_data(totim=times[-1]) levels = np.arange(45,100,5) extent = [xul,xul+Lx,yul-Ly,yul] fig, ax = plt.subplots() plt.imshow(head[0],extent=extent) plt.colorbar() contour = plt.contour(np.flipud(head[0]),levels,extent=extent)
mf.write_input() # Run the model success, mfoutput = mf.run_model(silent=False, pause=False) if not success: raise Exception('MODFLOW did not terminate normally.') # Imports import matplotlib.pyplot as plt import flopy.utils.binaryfile as bf # Create the headfile and budget file objects headobj = bf.HeadFile(modelname+'.hds') times = headobj.get_times() cbb = bf.CellBudgetFile(modelname+'.cbc') # Setup contour parameters levels = np.linspace(0, 10, 11) extent = (delr/2., Lx - delr/2., delc/2., Ly - delc/2.) print('Levels: ', levels) print('Extent: ', extent) # Well point wpt = ((float(ncol/2)-0.5)*delr, (float(nrow/2-1)+0.5)*delc) wpt = (450., 550.) # Make the plots mytimes = [1.0, 101.0, 201.0] for iplot, time in enumerate(mytimes): print('*****Processing time: ', time)
int(dt2[k, 0]) - 1, int(dt2[k, 1]) - 1] = dt2[k, 4] # Load River Cells ID if feature_id == 1: rcid = np.loadtxt('river_cells.dat') # river cell id elif feature_id == 2: rcid = np.loadtxt('GHB_cells.dat') # river cell id elif feature_id == 3: rcid = np.loadtxt('river_n_GHB.dat') # river cell id #print rcid.shape[0] nFeatureCells = rcid.shape[0] ## Read MODFLOW ccf file using flopy cbb = bf.CellBudgetFile('Future_SS.ccf') #cbb.list_records() #list_unique_records_ = cbb.list_unique_records() # Print all RECORDS #print 'nrecords=',cbb.get_nrecords() #print '[.] Extract flow rate data from MODFLOW CCF file =====' #CHD = cbb.get_data(totim=1, text='CONSTANT HEAD', full3D=True)[0] FRF = cbb.get_data(text='FLOW RIGHT FACE', full3D=True)[0] FFF = cbb.get_data(text='FLOW FRONT FACE', full3D=True)[0] FLF = cbb.get_data(text='FLOW LOWER FACE', full3D=True)[0] #FBF = cbb.get_data(totim=1, text='FLOW BACK FACE',full3D=True)[0] RLK = cbb.get_data(text='RIVER LEAKAGE', full3D=True)[0] HDB = cbb.get_data(text='HEAD DEP BOUNDS', full3D=True)[0] RCH = cbb.get_data(text='RECHARGE', full3D=True)[0] MNW = cbb.get_data(text='MNW2', full3D=True)[0] # Convert masked element to zero
def test006_2models_mvr(): # init paths test_ex_name = 'test006_2models_mvr' sim_name = 'test006_2models_mvr' model_names = ['parent', 'child'] pth = os.path.join('..', 'examples', 'data', 'mf6', test_ex_name) run_folder = os.path.join(cpth, test_ex_name) if not os.path.isdir(run_folder): os.makedirs(run_folder) save_folder = os.path.join(run_folder, 'temp') if not os.path.isdir(save_folder): os.makedirs(save_folder) expected_output_folder = os.path.join(pth, 'expected_output') expected_head_file_a = os.path.join(expected_output_folder, 'model1_unch.hds') expected_head_file_aa = os.path.join(expected_output_folder, 'model2_unch.hds') expected_cbc_file_a = os.path.join(expected_output_folder, 'model1_unch.cbc') expected_head_file_b = os.path.join(expected_output_folder, 'model1_adj.hds') expected_head_file_bb = os.path.join(expected_output_folder, 'model2_adj.hds') # load simulation sim = MFSimulation.load(sim_name, 'mf6', exe_name, pth, verify_data=True) # make temp folder to save simulation sim.simulation_data.mfpath.set_sim_path(run_folder) # write simulation to new location sim.set_all_data_external() sim.write_simulation() if run: # run simulation sim.run_simulation() # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_a) head_new = os.path.join(run_folder, 'model1.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) head_file = os.path.join(os.getcwd(), expected_head_file_aa) head_new = os.path.join(run_folder, 'model2.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_file = os.path.join(os.getcwd(), expected_cbc_file_a) budget_obj = bf.CellBudgetFile(budget_file, precision='double') budget_obj.list_records() # test getting models model_dict = sim.model_dict assert len(model_dict) == 2 for model in model_dict.values(): assert model.name in model_names names = sim.model_names assert len(names) == 2 for name in names: assert name in model_names model = sim.get_model(name) assert model.model_type == 'gwf' models = sim.gwf assert len(models) == 2 for model in models: assert model.name in model_names assert model.model_type == 'gwf' # change some settings parent_model = sim.get_model(model_names[0]) maw_pkg = parent_model.get_package('maw') period_data = maw_pkg.perioddata.get_data() period_data[0][0][2] = -1.0 maw_pkg.perioddata.set_data(period_data[0], 0) well_rec_data = maw_pkg.packagedata.get_data() assert (well_rec_data[0][0] == 0) exg_pkg = sim.get_exchange_file('simulation.exg') exg_data = exg_pkg.exchangedata.get_data() for index in range(0, len(exg_data)): exg_data[index][6] = 500.0 exg_pkg.exchangedata.set_data(exg_data) # test getting packages pkg_dict = parent_model.package_dict assert len(pkg_dict) == 6 pkg_names = parent_model.package_names assert len(pkg_names) == 6 # confirm that this is a copy of the original dictionary with references # to the packages del pkg_dict[pkg_names[0]] assert len(pkg_dict) == 5 pkg_dict = parent_model.package_dict assert len(pkg_dict) == 6 old_val = pkg_dict['dis'].nlay.get_data() pkg_dict['dis'].nlay = 22 pkg_dict = parent_model.package_dict assert pkg_dict['dis'].nlay.get_data() == 22 pkg_dict['dis'].nlay = old_val # write simulation again sim.simulation_data.mfpath.set_sim_path(save_folder) sim.write_simulation() if run: # run simulation sim.run_simulation() # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_b) head_new = os.path.join(save_folder, 'model1.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) head_file = os.path.join(os.getcwd(), expected_head_file_bb) head_new = os.path.join(save_folder, 'model2.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) # clean up sim.delete_output_files() # test load_only model_package_check = ['ic', 'maw', 'npf', 'oc'] load_only_lists = [['ic6', 'npf6', 'oc', 'gwf6-gwf6', 'ims'], ['ic', 'maw', 'npf', 'gwf-gwf', 'ims'], ['ic', 'maw6', 'npf']] for load_only in load_only_lists: sim = MFSimulation.load(sim_name, 'mf6', exe_name, pth, load_only=load_only) for model_name in model_names: model = sim.get_model(model_name) for package in model_package_check: assert (package in model.package_type_dict or package in sim.package_type_dict) == \ (package in load_only or '{}6'.format(package) in load_only) assert (len(sim._exchange_files) > 0) == ('gwf6-gwf6' in load_only or 'gwf-gwf' in load_only) assert (len(sim._ims_files) > 0) == ('ims6' in load_only or 'ims' in load_only) # load package by name load_only_list = ['ic6', 'maw', 'npf_p1', 'oc_p2', 'ims'] sim = MFSimulation.load(sim_name, 'mf6', exe_name, pth, load_only=load_only_list) model_parent = sim.get_model('parent') model_child = sim.get_model('child') assert 'oc' not in model_parent.package_type_dict assert 'oc' in model_child.package_type_dict assert 'npf' in model_parent.package_type_dict assert 'npf' not in model_child.package_type_dict if run: # test running a runnable load_only case sim = MFSimulation.load(sim_name, 'mf6', exe_name, pth, load_only=load_only_lists[0]) assert sim.run_simulation()[0] return
def test001a_tharmonic(): # init paths test_ex_name = 'test001a_Tharmonic' model_name = 'flow15' pth = os.path.join('..', 'examples', 'data', 'mf6', test_ex_name) run_folder = os.path.join(cpth, test_ex_name) if not os.path.isdir(run_folder): os.makedirs(run_folder) save_folder = os.path.join(run_folder, 'temp') if not os.path.isdir(save_folder): os.makedirs(save_folder) expected_output_folder = os.path.join(pth, 'expected_output') expected_head_file_a = os.path.join(expected_output_folder, 'flow15_flow_unch.hds') expected_head_file_b = os.path.join(expected_output_folder, 'flow15_flow_adj.hds') expected_cbc_file_a = os.path.join(expected_output_folder, 'flow15_flow_unch.cbc') expected_cbc_file_b = os.path.join(expected_output_folder, 'flow15_flow_adj.cbc') array_util = PyListUtil() # load simulation sim = MFSimulation.load(model_name, 'mf6', exe_name, pth, verbosity_level=0, verify_data=True, write_headers=False) sim.simulation_data.mfpath.set_sim_path(run_folder) # write simulation to new location sim.set_all_data_external() sim.write_simulation(silent=True) model = sim.get_model(model_name) model.export('{}/tharmonic.nc'.format(model.model_ws)) model.export('{}/tharmonic.shp'.format(model.model_ws)) model.dis.botm.export('{}/botm.shp'.format(model.model_ws)) mg = model.modelgrid if run: # run simulation sim.run_simulation() # get expected results budget_file = os.path.join(os.getcwd(), expected_cbc_file_a) budget_obj = bf.CellBudgetFile(budget_file, precision='auto') budget_obj.list_records() budget_frf_valid = np.array( budget_obj.get_data(text=' FLOW JA FACE', full3D=True)) # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_a) head_new = os.path.join(run_folder, 'flow15_flow.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_frf = sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')] assert array_util.array_comp(budget_frf_valid, budget_frf) # change some settings hk_data = sim.simulation_data.mfdata[(model_name, 'npf', 'griddata', 'k')] hk_array = hk_data.get_data() hk_array[0, 0, 1] = 20.0 hk_data.set_data(hk_array) model = sim.get_model(model_name) ic = model.get_package('ic') ic_data = ic.strt ic_array = ic_data.get_data() ic_array[0, 0, 0] = 1.0 ic_array[0, 0, 9] = 1.0 ic_data.set_data(ic_array) get_test = hk_data[0, 0, 0] assert (get_test == 10.0) get_test = hk_data.array assert (array_util.array_comp( get_test, [[10.0, 20.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0]])) get_test = hk_data[:] assert (array_util.array_comp( get_test, [[[10.0, 20.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0]]])) # write simulation again sim.simulation_data.mfpath.set_sim_path(save_folder) sim.write_simulation() if run: # run simulation sim.run_simulation() # get expected results budget_file = os.path.join(os.getcwd(), expected_cbc_file_b) budget_obj = bf.CellBudgetFile(budget_file, precision='auto') budget_frf_valid = np.array( budget_obj.get_data(text=' FLOW JA FACE', full3D=True)) # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_b) head_new = os.path.join(save_folder, 'flow15_flow.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_frf = sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')] assert array_util.array_comp(budget_frf_valid, budget_frf) # clean up sim.delete_output_files() return
def test006_gwf3(): # init paths test_ex_name = 'test006_gwf3' model_name = 'gwf_1' pth = os.path.join('..', 'examples', 'data', 'mf6', test_ex_name) run_folder = os.path.join(cpth, test_ex_name) if not os.path.isdir(run_folder): os.makedirs(run_folder) save_folder = os.path.join(run_folder, 'temp') if not os.path.isdir(save_folder): os.makedirs(save_folder) expected_output_folder = os.path.join(pth, 'expected_output') expected_head_file_a = os.path.join(expected_output_folder, 'flow_unch.hds') expected_head_file_b = os.path.join(expected_output_folder, 'flow_adj.hds') expected_cbc_file_a = os.path.join(expected_output_folder, 'flow_unch.cbc') expected_cbc_file_b = os.path.join(expected_output_folder, 'flow_adj.cbc') array_util = PyListUtil() # load simulation sim = MFSimulation.load(model_name, 'mf6', exe_name, pth, verify_data=True) model = sim.get_model() disu = model.get_package('disu') # test switching disu array to internal array disu.ja = disu.ja.array # test writing hwva and cl12 arrays out to different locations disu.hwva = { 'filename': 'flow.disu.hwva_new.dat', 'factor': 1.0, 'data': disu.hwva.array } disu.cl12 = { 'filename': 'flow.disu.cl12_new.dat', 'factor': 1.0, 'data': disu.cl12.array } # make temp folder to save simulation sim.simulation_data.mfpath.set_sim_path(run_folder) # write simulation to new location sim.set_all_data_external() sim.write_simulation() if run: # run simulation sim.run_simulation() budget_file = os.path.join(os.getcwd(), expected_cbc_file_a) budget_obj = bf.CellBudgetFile(budget_file, precision='double') budget_fjf_valid = np.array( budget_obj.get_data(text=' FLOW JA FACE', full3D=True)) jaentries = budget_fjf_valid.shape[-1] budget_fjf_valid.shape = (-1, jaentries) # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_a) head_new = os.path.join(run_folder, 'flow.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_fjf = np.array(sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')]) assert array_util.array_comp(np.array(budget_fjf_valid), np.array(budget_fjf)) # change some settings model = sim.get_model(model_name) hk = model.get_package('npf').k hk_data = hk.get_data() hk_data[2] = 3.5 hk.set_data(hk_data) ex_happened = False try: hk.make_layered() except: ex_happened = True assert (ex_happened) # write simulation again sim.simulation_data.mfpath.set_sim_path(save_folder) sim.write_simulation() if run: # run simulation sim.run_simulation() # get expected results budget_file = os.path.join(os.getcwd(), expected_cbc_file_b) budget_obj = bf.CellBudgetFile(budget_file, precision='auto') budget_fjf_valid = np.array( budget_obj.get_data(text=' FLOW JA FACE', full3D=True)) jaentries = budget_fjf_valid.shape[-1] budget_fjf_valid.shape = (-1, jaentries) # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_b) head_new = os.path.join(save_folder, 'flow.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_fjf = np.array(sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')]) assert array_util.array_comp(np.array(budget_fjf_valid), np.array(budget_fjf)) # confirm that files did move save_folder = os.path.join(run_folder, 'temp_two') sim.simulation_data.mfpath.set_sim_path(save_folder) # write with "copy_external_files" turned off so external files do not get copied to new location sim.write_simulation( ext_file_action=flopy.mf6.mfbase.ExtFileAction.copy_none) # store strt in an external binary file model = sim.get_model() ic = model.get_package('ic') ic.strt.store_as_external_file('initial_heads.bin', binary=True) strt_data = ic.strt.array # update packages sim.write_simulation() if run: # run simulation sim.run_simulation() # get expected results budget_file = os.path.join(os.getcwd(), expected_cbc_file_b) budget_obj = bf.CellBudgetFile(budget_file, precision='double') budget_fjf_valid = np.array( budget_obj.get_data(text=' FLOW JA FACE', full3D=True)) jaentries = budget_fjf_valid.shape[-1] budget_fjf_valid.shape = (-1, jaentries) # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_b) head_new = os.path.join(save_folder, 'flow.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_fjf = np.array(sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')]) assert array_util.array_comp(np.array(budget_fjf_valid), np.array(budget_fjf)) # confirm that files did not move assert not os.path.isfile(os.path.join(save_folder, 'flow.disu.ja.dat')) assert not os.path.isfile( os.path.join(save_folder, 'flow.disu.iac.dat')) assert not os.path.isfile( os.path.join(save_folder, 'flow.disu.cl12.dat')) assert not os.path.isfile( os.path.join(save_folder, 'flow.disu.area.dat')) assert not os.path.isfile( os.path.join(save_folder, 'flow.disu.hwva.dat')) # confirm external binary file was created assert os.path.isfile(os.path.join(save_folder, 'initial_heads.bin')) # clean up sim.delete_output_files() return
# output result as: # TimeStep, Row, Column, Value import sys import flopy.utils.binaryfile as bf # run paramters n_stress_periods = 132 # ! remember 0 indexing ! idx_time_step = 4 parameter_name = "RIVER LEAKAGE" idx_layer = 0 delim = "\t" # supply a binary .cbb modflow output file cbb_filename = "/Users/Maru/Desktop/MODFLOW_HUGE/V38_Temp_V9.cbb" cbb = bf.CellBudgetFile(cbb_filename) rc = [] # row-column tuples [(row,column),...(row,column)] # supply a tab-delimited filename of zero indexed row and column positions: # row column # 1 2 # 2 4 river_filename = "/Users/Maru/Dropbox/JKMB001_flopy/FA128_RIVER.txt" # This block loads the row-column indexed values identifying river cells fh = open(river_filename, "r") fh.readline() # skip header row [rc.append([int(x) for x in line.strip().split(delim)]) for line in fh] # This block loops through stress periods i to n_stress_periods, gets the data layer for i in range(n_stress_periods):
def cbc_to_netcdf(cbcFile, disFile, locationFile, fileOutput): cbc = binaryfile.CellBudgetFile(cbcFile) variableNames = cbc.unique_record_names() fileHandle = open(disFile, 'r') for line in fileHandle: if "#" not in line.strip().split()[0]: values = line.split() break numberOfLayers = int(values[0]) numberOfRows = int(values[1]) numberOfColumns = int(values[2]) numberOfHRUs = numberOfRows * numberOfColumns numberOfStressPeriods = int(values[3]) timeStepForStressPeriods = [] for index in range(numberOfStressPeriods, 0, -1): fileHandle = open(disFile, 'r') lineNumber = index * -1 values = fileHandle.readlines()[lineNumber].split() numberOfTimeSteps = int(values[1]) timeStepForStressPeriods.append(numberOfTimeSteps) fileHandle = open(locationFile, 'r') values = find_average_resolution(fileHandle, numberOfHRUs, numberOfRows, numberOfColumns) averageOfLatitudeValues = values[0] averageOfLongitudeValues = values[1] latitudeOfFirstHru = values[2] longitudeOfFirstHru = values[3] # Initialize new dataset ncfile = netCDF4.Dataset(fileOutput, mode='w') # Initialize dimensions lat_dim = ncfile.createDimension('lat', numberOfRows) lon_dim = ncfile.createDimension('lon', numberOfColumns) latList = [] latList.append(latitudeOfFirstHru) previousValue = latitudeOfFirstHru lat = ncfile.createVariable('lat', 'f8', ('lat', )) lat.long_name = 'latitude' lat.units = 'degrees_north' for i in range(numberOfRows - 1): newValue = previousValue - averageOfLatitudeValues latList.append(newValue) previousValue = newValue lat[:] = latList lonList = [] lonList.append(longitudeOfFirstHru) previousValue = longitudeOfFirstHru lon = ncfile.createVariable('lon', 'f8', ('lon', )) lon.long_name = 'longitude' lon.units = 'degrees_east' for i in range(numberOfColumns - 1): newValue = previousValue + averageOfLongitudeValues lonList.append(newValue) previousValue = newValue lon[:] = lonList sr = osr.SpatialReference() sr.ImportFromEPSG(4326) crs = ncfile.createVariable( 'crs', 'S1', ) crs.spatial_ref = sr.ExportToWkt() variablePosition = 0 for spIndex in range(numberOfStressPeriods): for tsIndex in range(timeStepForStressPeriods[spIndex]): for varName in variableNames: for layerIndex in range(numberOfLayers): var = ncfile.createVariable( varName.strip() + "_" + str(spIndex + 1) + "_" + str(tsIndex + 1) + "_" + str(layerIndex + 1), 'f8', ('lat', 'lon')) var.layer_name = varName.strip() + "_" + str( spIndex + 1) + "_" + str(tsIndex + 1) + "_" + str(layerIndex + 1) var.layer_desc = "Variable " + varName.strip( ) + ": Stress Period " + str( spIndex + 1) + ", Time Step " + str( tsIndex + 1) + ", Layer " + str(layerIndex + 1) var.layer_units = "none" var.grid_mapping = "crs" values = find_values(cbc, variablePosition, layerIndex) var[:] = values variablePosition += 1 # Global attributes ncfile.title = 'Modflow Cell by Cell by Cell Budget Package' ncfile.bands = 1 ncfile.bands_name = 'nsteps' ncfile.bands_desc = 'Variable information for ' + cbcFile # Close the 'ncfile' object ncfile.close()
def export_cell_budget(cell_budget_file, grid, binary_grid_file=None, kstpkper=None, text=None, idx=0, precision='single', output_path='postproc', suffix=''): """Read a flow component from MODFLOW binary cell budget output; write to raster. Parameters ---------- cell_budget_file : modflow binary cell budget output grid : rOpen.modflow.grid instance text : cell budget record to read (e.g. 'STREAM LEAKAGE') kstpkper : tuple (timestep, stress period) to read idx : index of list returned by cbbobj (usually 0) outfolder : where to write raster """ print('Exporting cell budget info...') print('file: {}'.format(cell_budget_file)) print('binary grid file: {}'.format(binary_grid_file)) cbbobj = bf.CellBudgetFile(cell_budget_file, precision=precision) if kstpkper is None: kstpkper = cbbobj.get_times()[idx] if np.isscalar(kstpkper[0]): kstpkper = [kstpkper] pdfs_dir, rasters_dir, shps_dir = make_output_folders(output_path) if text is not None and not isinstance(text, list): text = [text] names = [r.decode().strip() for r in cbbobj.get_unique_record_names()] if text is not None: names = list(set(text).intersection(names)) if len(names) == 0: print('{} not found in {}'.format(' '.join(text), cell_budget_file)) outfiles = [] for kstp, kper in kstpkper: print('stress period {}, timestep {}'.format(kper, kstp)) for variable in names: if variable == 'FLOW-JA-FACE': df = get_flowja_face(cbbobj, binary_grid_file=binary_grid_file, kstpkper=(kstp, kper), idx=idx, precision=precision) # export the vertical fluxes as rasters # (in the downward direction; so fluxes between 2 layers # would be represented in the upper layer) if df is not None and 'kn' in df.columns and np.any( df['kn'] < df['km']): vflux = df.loc[(df['kn'] < df['km'])] nlay = vflux['km'].max() _, nrow, ncol = grid.shape vflux_array = np.zeros((nlay, nrow, ncol)) vflux_array[vflux['kn'].values, vflux['in'].values, vflux['jn'].values] = vflux.q.values data = vflux_array else: data = get_bc_flux(cbbobj, variable, kstpkper=(kstp, kper), idx=idx) if data is None: print('{} not exported.'.format(variable)) continue outfile = '{}/{}_per{}_stp{}{}.tif'.format(rasters_dir, variable, kper, kstp, suffix) export_array(outfile, data, grid, nodata=0) outfiles.append(outfile) return outfiles
mf.write_input() # Run the model success, mfoutput = mf.run_model(silent=True, pause=False, report=True) if not success: raise Exception("MODFLOW did not terminate normally.") # Imports import matplotlib.pyplot as plt import flopy.utils.binaryfile as bf # Create the headfile and budget file objects headobj = bf.HeadFile(modelname + ".hds") times = headobj.get_times() cbb = bf.CellBudgetFile(modelname + ".cbc") # Setup contour parameters levels = np.linspace(0, 10, 11) extent = (delr / 2.0, Lx - delr / 2.0, delc / 2.0, Ly - delc / 2.0) print("Levels: ", levels) print("Extent: ", extent) # Well point wpt = ((float(ncol / 2) - 0.5) * delr, (float(nrow / 2 - 1) + 0.5) * delc) wpt = (450.0, 550.0) # Make the plots mytimes = [1.0, 101.0, 201.0] for iplot, time in enumerate(mytimes): print("*****Processing time: ", time)
def get_extended_budget( cbcfile, precision="single", idx=None, kstpkper=None, totim=None, boundary_ifaces=None, hdsfile=None, model=None, ): """ Get the flow rate across cell faces including potential stresses applied along boundaries at a given time. Only implemented for "classical" MODFLOW versions where the budget is recorded as FLOW RIGHT FACE, FLOW FRONT FACE and FLOW LOWER FACE arrays. Parameters ---------- cbcfile : str Cell by cell file produced by Modflow. precision : str Binary file precision, default is 'single'. idx : int or list The zero-based record number. kstpkper : tuple of ints A tuple containing the time step and stress period (kstp, kper). The kstp and kper values are zero based. totim : float The simulation time. boundary_ifaces : dictionary {str: int or list} A dictionary defining how to treat stress flows at boundary cells. The keys are budget terms corresponding to stress packages (same term as in the overall volumetric budget printed in the listing file). The values are either a single iface number to be applied to all cells for the stress package, or a list of lists describing individual boundary cells in the same way as in the package input plus the iface number appended. The iface number indicates the face to which the stress flow is assigned, following the MODPATH convention (see MODPATH user guide). Example: boundary_ifaces = { 'RECHARGE': 6, 'RIVER LEAKAGE': 6, 'CONSTANT HEAD': [[lay, row, col, iface], ...], 'WELLS': [[lay, row, col, flux, iface], ...], 'HEAD DEP BOUNDS': [[lay, row, col, head, cond, iface], ...]}. Note: stresses that are not informed in boundary_ifaces are implicitly treated as internally-distributed sinks/sources. hdsfile : str Head file produced by MODFLOW (only required if boundary_ifaces is used). model : flopy.modflow.Modflow object Modflow model instance (only required if boundary_ifaces is used). Returns ------- (Qx_ext, Qy_ext, Qz_ext) : tuple Flow rates across cell faces. Qx_ext is a ndarray of size (nlay, nrow, ncol + 1). Qy_ext is a ndarray of size (nlay, nrow + 1, ncol). The sign is such that the y axis is considered to increase in the north direction. Qz_ext is a ndarray of size (nlay + 1, nrow, ncol). The sign is such that the z axis is considered to increase in the upward direction. """ import flopy.utils.binaryfile as bf # define useful stuff cbf = bf.CellBudgetFile(cbcfile, precision=precision) nlay, nrow, ncol = cbf.nlay, cbf.nrow, cbf.ncol rec_names = cbf.get_unique_record_names(decode=True) err_msg = " not found in the budget file." # get flow across right face Qx_ext = np.zeros((nlay, nrow, ncol + 1), dtype=np.float32) if ncol > 1: budget_term = "FLOW RIGHT FACE" matched_name = [s for s in rec_names if budget_term in s] if not matched_name: raise RuntimeError(budget_term + err_msg) frf = cbf.get_data(idx=idx, kstpkper=kstpkper, totim=totim, text=budget_term) Qx_ext[:, :, 1:] = frf[0] # SWI2 package budget_term_swi = "SWIADDTOFRF" matched_name_swi = [s for s in rec_names if budget_term_swi in s] if matched_name_swi: frf_swi = cbf.get_data(idx=idx, kstpkper=kstpkper, totim=totim, text=budget_term_swi) Qx_ext[:, :, 1:] += frf_swi[0] # get flow across front face Qy_ext = np.zeros((nlay, nrow + 1, ncol), dtype=np.float32) if nrow > 1: budget_term = "FLOW FRONT FACE" matched_name = [s for s in rec_names if budget_term in s] if not matched_name: raise RuntimeError(budget_term + err_msg) fff = cbf.get_data(idx=idx, kstpkper=kstpkper, totim=totim, text=budget_term) Qy_ext[:, 1:, :] = -fff[0] # SWI2 package budget_term_swi = "SWIADDTOFFF" matched_name_swi = [s for s in rec_names if budget_term_swi in s] if matched_name_swi: fff_swi = cbf.get_data(idx=idx, kstpkper=kstpkper, totim=totim, text=budget_term_swi) Qy_ext[:, 1:, :] -= fff_swi[0] # get flow across lower face Qz_ext = np.zeros((nlay + 1, nrow, ncol), dtype=np.float32) if nlay > 1: budget_term = "FLOW LOWER FACE" matched_name = [s for s in rec_names if budget_term in s] if not matched_name: raise RuntimeError(budget_term + err_msg) flf = cbf.get_data(idx=idx, kstpkper=kstpkper, totim=totim, text=budget_term) Qz_ext[1:, :, :] = -flf[0] # SWI2 package budget_term_swi = "SWIADDTOFLF" matched_name_swi = [s for s in rec_names if budget_term_swi in s] if matched_name_swi: flf_swi = cbf.get_data(idx=idx, kstpkper=kstpkper, totim=totim, text=budget_term_swi) Qz_ext[1:, :, :] -= flf_swi[0] # deal with boundary cells if boundary_ifaces is not None: # need calculated heads for some stresses and to check hnoflo and hdry if hdsfile is None: raise ValueError("hdsfile must be provided when using " "boundary_ifaces") hds = bf.HeadFile(hdsfile, precision=precision) head = hds.get_data(idx=idx, kstpkper=kstpkper, totim=totim) # get hnoflo and hdry values if model is None: raise ValueError("model must be provided when using " "boundary_ifaces") noflo_or_dry = np.logical_or(head == model.hnoflo, head == model.hdry) for budget_term, iface_info in boundary_ifaces.items(): # look for budget term in budget file matched_name = [s for s in rec_names if budget_term in s] if not matched_name: raise RuntimeError("Budget term " + budget_term + " not found" ' in "' + cbcfile + '" file.') if len(matched_name) > 1: raise RuntimeError("Budget term " + budget_term + " found" " in several record names. Use a more " " precise name.") Q_stress = cbf.get_data( idx=idx, kstpkper=kstpkper, totim=totim, text=matched_name[0], full3D=True, )[0] # remove potential leading and trailing spaces budget_term = budget_term.strip() # weirdly, MODFLOW puts recharge in all potential recharge cells # and not only the actual cells; thus, correct this by putting 0 # away from water table cells if budget_term == "RECHARGE": # find the water table as the first active cell in each column water_table = np.full((nlay, nrow, ncol), False) water_table[0, :, :] = np.logical_not(noflo_or_dry[0, :, :]) already_found = water_table[0, :, :] for lay in range(1, nlay): if np.sum(already_found) == nrow * ncol: break water_table[lay, :, :] = np.logical_and( np.logical_not(noflo_or_dry[lay, :, :]), np.logical_not(already_found), ) already_found = np.logical_or(already_found, water_table[lay, :, :]) Q_stress[np.logical_not(water_table)] = 0.0 # case where the same iface is assigned to all cells if isinstance(iface_info, int): if iface_info == 1: Qx_ext[:, :, :-1] += Q_stress elif iface_info == 2: Qx_ext[:, :, 1:] -= Q_stress elif iface_info == 3: Qy_ext[:, 1:, :] += Q_stress elif iface_info == 4: Qy_ext[:, :-1, :] -= Q_stress elif iface_info == 5: Qz_ext[1:, :, :] += Q_stress elif iface_info == 6: Qz_ext[:-1, :, :] -= Q_stress # case where iface is assigned individually per cell elif isinstance(iface_info, list): # impose a unique iface (normally = 6) for some stresses # (note: UZF RECHARGE, GW ET and SURFACE LEAKAGE are all # related to the UZF package) if (budget_term == "RECHARGE" or budget_term == "ET" or budget_term == "UZF RECHARGE" or budget_term == "GW ET" or budget_term == "SURFACE LEAKAGE"): raise ValueError("This function imposes the use of a " "unique iface (normally = 6) for the " + budget_term + " budget term.") # loop through boundary cells for cell_info in iface_info: lay, row, col = cell_info[0], cell_info[1], cell_info[2] if noflo_or_dry[lay, row, col]: continue iface = cell_info[-1] # Here, where appropriate, we recalculate Q_stress_cell # using package input. This gives more flexibility than # directly taking the value saved by MODFLOW. Indeed, it # allows for a same type of stress to be applied several # times to the same cell but to different faces # (whereas MODFLOW only saves one lumped value per # stress type per cell). # Note: this flexibility is not supported for: # - FHB package (we would need to interpolate inputs # across time steps as done in the package; complicated) # - RES package (we would need to interpolate inputs # across time steps as done in the package; complicated) # - STR package (we would need first to retrieve river # stage from model outputs; complicated) # - SFR1 package (we would need to retrieve river # stage and conductance from model outputs; complicated) # - SFR2 package (even more complicated than SFR1) # - LAK3 package (we would need to retrieve lake # stage and conductance from model outputs; complicated) # - MNW1 package (we would need to retrieve well head and # conductance from model outputs; complicated) # - MNW2 package (even more complicated than MNW1) if budget_term == "WELLS": Q_stress_cell = cell_info[3] elif budget_term == "HEAD DEP BOUNDS": ghb_head = cell_info[3] ghb_cond = cell_info[4] model_head = head[lay, row, col] Q_stress_cell = ghb_cond * (ghb_head - model_head) elif budget_term == "RIVER LEAKAGE": riv_stage = cell_info[3] riv_cond = cell_info[4] riv_rbot = cell_info[5] model_head = head[lay, row, col] if model_head > riv_rbot: Q_stress_cell = riv_cond * (riv_stage - model_head) else: Q_stress_cell = riv_cond * (riv_stage - riv_rbot) elif budget_term == "DRAINS": drn_stage = cell_info[3] drn_cond = cell_info[4] model_head = head[lay, row, col] if model_head > drn_stage: Q_stress_cell = drn_cond * (drn_stage - model_head) else: continue # Else, take the value saved by MODFLOW. # This includes the budget terms: # - 'CONSTANT HEAD' for: # * head specified through -1 in IBOUND # * head specified in CHD package # * head specified in FHB package # - 'SPECIFIED FLOWS' for flow specified in FHB package # - 'RESERV. LEAKAGE' for RES package # - 'STREAM LEAKAGE' for: # * STR package # * SFR1 package # * SFR2 package # - 'LAKE SEEPAGE' for LAK3 package # - 'MNW' for MNW1 package # - 'MNW2' for MNW2 package # - 'SWIADDTOCH' for SWI2 package else: Q_stress_cell = Q_stress[lay, row, col] if iface == 1: Qx_ext[lay, row, col] += Q_stress_cell elif iface == 2: Qx_ext[lay, row, col + 1] -= Q_stress_cell elif iface == 3: Qy_ext[lay, row + 1, col] += Q_stress_cell elif iface == 4: Qy_ext[lay, row, col] -= Q_stress_cell elif iface == 5: Qz_ext[lay + 1, row, col] += Q_stress_cell elif iface == 6: Qz_ext[lay, row, col] -= Q_stress_cell else: raise TypeError("boundary_ifaces value must be either " "int or list.") return Qx_ext, Qy_ext, Qz_ext
pcg = flopy.modflow.ModflowPcg(mf) # Write the MODFLOW model input files mf.write_input() # Run the MODFLOW model success, buff = mf.run_model() # Post process the results import matplotlib.pyplot as plt import flopy.utils.binaryfile as bf fig = plt.figure(figsize=(10, 10)) ax = fig.add_subplot(1, 1, 1, aspect='equal') hds = bf.HeadFile(os.path.join('data', modelname + '.hds')) times = hds.get_times() head = hds.get_data(totim=times[-1]) levels = np.linspace(0, 10, 11) cbb = bf.CellBudgetFile(os.path.join('data', modelname + '.cbc')) kstpkper_list = cbb.get_kstpkper() frf = cbb.get_data(text='FLOW RIGHT FACE', totim=times[-1])[0] fff = cbb.get_data(text='FLOW FRONT FACE', totim=times[-1])[0] modelmap = flopy.plot.ModelMap(model=mf, layer=0) qm = modelmap.plot_ibound() lc = modelmap.plot_grid() cs = modelmap.contour_array(head, levels=levels) quiver = modelmap.plot_discharge(frf, fff, head=head) plt.show()
import numpy as np import flopy.utils.binaryfile as bf import pandas as pd import glob # set modelname timeType = 'Transient' # 'SteadyState' or 'Transient' modelname = 'Navarro-'+timeType ## load RIV input back_to_base_dir = os.path.join('..', '..', '..', '..', '..', '..', '..') iriv = pd.read_table(os.path.join(back_to_base_dir, 'modflow', 'input', 'iriv.txt'), delimiter=' ') iriv_ReachData = pd.read_table(os.path.join(back_to_base_dir, 'modflow', 'input', 'iriv_ReachData.txt'), delimiter=' ') ## load output files rivout = bf.CellBudgetFile(modelname+'.riv.out', verbose=False) mnwout = bf.CellBudgetFile(modelname+'.mnw2.out', verbose=False) outputTimes = rivout.get_times() # scroll through times start_flag = True for time in outputTimes: ## make a copy of iriv to avoid altering original iriv_copy = iriv.copy() # get riv output data rivout_3D = rivout.get_data(totim=time, text='RIVER LEAKAGE', full3D=True) iriv_copy['leakage'] = rivout_3D[0][iriv['lay'],iriv['row'],iriv['col']] ## join leakage to reach_data iriv_merge = pd.merge(iriv_ReachData[['SegNum', 'row', 'col','seg_proportion']], iriv_copy[['row', 'col', 'leakage']],
def test003_gwfs_disv(): # init paths test_ex_name = 'test003_gwfs_disv' model_name = 'gwf_1' pth = os.path.join('..', 'examples', 'data', 'mf6', test_ex_name) run_folder = os.path.join(cpth, test_ex_name) if not os.path.isdir(run_folder): os.makedirs(run_folder) save_folder = os.path.join(run_folder, 'temp') if not os.path.isdir(save_folder): os.makedirs(save_folder) expected_output_folder = os.path.join(pth, 'expected_output') expected_head_file_a = os.path.join(expected_output_folder, 'model_unch.hds') expected_head_file_b = os.path.join(expected_output_folder, 'model_adj.hds') expected_cbc_file_a = os.path.join(expected_output_folder, 'model_unch.cbc') expected_cbc_file_b = os.path.join(expected_output_folder, 'model_adj.cbc') array_util = PyListUtil() # load simulation sim = MFSimulation.load(model_name, 'mf6', exe_name, pth, verify_data=True) # make temp folder to save simulation sim.simulation_data.mfpath.set_sim_path(run_folder) # write simulation to new location sim.simulation_data.max_columns_of_data = 10 sim.write_simulation() if run: # run simulation sim.run_simulation() # get expected results budget_file = os.path.join(os.getcwd(), expected_cbc_file_a) budget_obj = bf.CellBudgetFile(budget_file, precision='auto') budget_fjf_valid = np.array( budget_obj.get_data(text=' FLOW JA FACE', full3D=True)) head_file = os.path.join(os.getcwd(), expected_head_file_a) head_new = os.path.join(run_folder, 'model.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_frf = sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')] assert array_util.array_comp(budget_fjf_valid, budget_frf) model = sim.get_model(model_name) if shapefile: model.export('{}/{}.shp'.format(pth, test_ex_name)) # change some settings chd_head_left = model.get_package('CHD_LEFT') chd_left_period = chd_head_left.stress_period_data.get_data(0) chd_left_period[4][1] = 15.0 chd_head_left.stress_period_data.set_data(chd_left_period, 0) chd_head_right = model.get_package('CHD_RIGHT') chd_right_period = chd_head_right.stress_period_data chd_right_data = chd_right_period.get_data(0) chd_right_data_slice = chd_right_data[3:10] chd_right_period.set_data(chd_right_data_slice, 0) # write simulation again sim.simulation_data.mfpath.set_sim_path(save_folder) sim.write_simulation() if run: # run simulation sim.run_simulation() # get expected results budget_file = os.path.join(os.getcwd(), expected_cbc_file_b) budget_obj = bf.CellBudgetFile(budget_file, precision='double') budget_fjf_valid = np.array( budget_obj.get_data(text='FLOW JA FACE', full3D=True)) # compare output to expected results head_file = os.path.join(os.getcwd(), expected_head_file_b) head_new = os.path.join(save_folder, 'model.hds') assert pymake.compare_heads(None, None, files1=head_file, files2=head_new) budget_frf = sim.simulation_data.mfdata[(model_name, 'CBC', 'FLOW-JA-FACE')] assert array_util.array_comp(budget_fjf_valid, budget_frf) # clean up sim.delete_output_files() return
obs4_xcoord = 120 obs4_ycoord = 80 obs4_col = int(np.round(obs4_xcoord / delc)) obs4_row = int(np.round((Ly - obs4_ycoord) / delr)) # Plan view fig = plt.figure(figsize=(10, 12)) ax = fig.add_subplot(1, 1, 1) hds = bf.HeadFile(modelName + '.hds') times = hds.get_times() head = hds.get_data(totim=times[-1]) levels = np.linspace(-1, 2.1, 6) cbb = bf.CellBudgetFile(modelName + '.cbc') # read budget file kstpkper_list = cbb.get_kstpkper() # cbb.textlist to get a list of data texts frf = cbb.get_data(text='FLOW RIGHT FACE', totim=times[-1])[0] fff = cbb.get_data(text='FLOW FRONT FACE', totim=times[-1])[0] # flopy plot object pmv = flopy.plot.PlotMapView(model=mf, layer=0) # plot grid lc = pmv.plot_grid() # grid # plot contour cs = pmv.contour_array(head, levels=np.linspace(-1, 3, 16)) # head contour plt.clabel(cs, fontsize=fS, fmt='%1.1f') # contour label
delimiter=' ') ## figure out which runs succeeded (output from CheckFailures script) succ = pd.read_table(os.path.join(dir_runs, 'CheckFailure.csv'), delimiter=",") ## loop through and make output data frame start_flag = True for w in succ.WellNum: # check if model ran successfully converge = succ.Success.loc[(succ['WellNum'] == w)].bool() if converge: ## load output files rivout = bf.CellBudgetFile(os.path.join(dir_runs, prefix_runs + str(w), modelname + '.riv.out'), verbose=False) mnwout = bf.CellBudgetFile(os.path.join(dir_runs, prefix_runs + str(w), modelname + '.mnw2.out'), verbose=False) outputTimes = rivout.get_times() # scroll through times for time in outputTimes: ## make a copy of iriv to avoid altering original iriv_copy = iriv.copy() # get riv output data rivout_3D = rivout.get_data(totim=time, text='RIVER LEAKAGE', full3D=True)
def get_specific_discharge( model, cbcfile, precision="single", idx=None, kstpkper=None, totim=None, boundary_ifaces=None, hdsfile=None, position="centers", ): """ Get the discharge vector at cell centers at a given time. For "classical" MODFLOW versions, we calculate it from the flow rate across cell faces. For MODFLOW 6, we directly take it from MODFLOW output (this requires setting the option "save_specific_discharge" in the NPF package). Parameters ---------- model : flopy.modflow.Modflow object Modflow model instance. cbcfile : str Cell by cell file produced by Modflow. precision : str Binary file precision, default is 'single'. idx : int or list The zero-based record number. kstpkper : tuple of ints A tuple containing the time step and stress period (kstp, kper). The kstp and kper values are zero based. totim : float The simulation time. boundary_ifaces : dictionary {str: int or list} A dictionary defining how to treat stress flows at boundary cells. Only implemented for "classical" MODFLOW versions where the budget is recorded as FLOW RIGHT FACE, FLOW FRONT FACE and FLOW LOWER FACE arrays. The keys are budget terms corresponding to stress packages (same term as in the overall volumetric budget printed in the listing file). The values are either a single iface number to be applied to all cells for the stress package, or a list of lists describing individual boundary cells in the same way as in the package input plus the iface number appended. The iface number indicates the face to which the stress flow is assigned, following the MODPATH convention (see MODPATH user guide). Example: boundary_ifaces = { 'RECHARGE': 6, 'RIVER LEAKAGE': 6, 'WELLS': [[lay, row, col, flux, iface], ...], 'HEAD DEP BOUNDS': [[lay, row, col, head, cond, iface], ...]}. Note: stresses that are not informed in boundary_ifaces are implicitly treated as internally-distributed sinks/sources. hdsfile : str Head file produced by MODFLOW. Head is used to calculate saturated thickness and to determine if a cell is inactive or dry. If not provided, all cells are considered fully saturated. hdsfile is also required if the budget term 'HEAD DEP BOUNDS', 'RIVER LEAKAGE' or 'DRAINS' is present in boundary_ifaces and that the corresponding value is a list. position : str Position at which the specific discharge will be calculated. Possible values are "centers" (default), "faces" and "vertices". Returns ------- (qx, qy, qz) : tuple Discharge vector. qx, qy, qz are ndarrays of size (nlay, nrow, ncol) for a structured grid or size (nlay, ncpl) for an unstructured grid. The sign of qy is such that the y axis is considered to increase in the north direction. The sign of qz is such that the z axis is considered to increase in the upward direction. Note: if hdsfile is provided, inactive and dry cells are set to NaN. """ import flopy.utils.binaryfile as bf # check if budget file has classical budget terms cbf = bf.CellBudgetFile(cbcfile, precision=precision) rec_names = cbf.get_unique_record_names(decode=True) classical_budget_terms = [ "FLOW RIGHT FACE", "FLOW FRONT FACE", "FLOW RIGHT FACE", ] classical_budget = False for budget_term in classical_budget_terms: matched_name = [s for s in rec_names if budget_term in s] if matched_name: classical_budget = True break if hdsfile is not None: hds = bf.HeadFile(hdsfile, precision=precision) head = hds.get_data(idx=idx, kstpkper=kstpkper, totim=totim) if classical_budget: # get extended budget Qx_ext, Qy_ext, Qz_ext = get_extended_budget( cbcfile, precision=precision, idx=idx, kstpkper=kstpkper, totim=totim, boundary_ifaces=boundary_ifaces, hdsfile=hdsfile, model=model, ) # get saturated thickness (head - bottom elev for unconfined layer) if hdsfile is None: sat_thk = model.dis.thickness.array else: sat_thk = get_saturated_thickness(head, model, model.hdry) sat_thk = sat_thk.reshape(model.modelgrid.shape) # inform modelgrid of no-flow and dry cells modelgrid = model.modelgrid if modelgrid._idomain is None: modelgrid._idomain = model.dis.ibound if hdsfile is not None: noflo_or_dry = np.logical_or(head == model.hnoflo, head == model.hdry) modelgrid._idomain[noflo_or_dry] = 0 # get cross section areas along x delc = np.reshape(modelgrid.delc, (1, modelgrid.nrow, 1)) cross_area_x = np.empty(modelgrid.shape, dtype=float) cross_area_x = delc * sat_thk # get cross section areas along y delr = np.reshape(modelgrid.delr, (1, 1, modelgrid.ncol)) cross_area_y = np.empty(modelgrid.shape, dtype=float) cross_area_y = delr * sat_thk # get cross section areas along z cross_area_z = np.ones(modelgrid.shape) * delc * delr # calculate qx, qy, qz if position == "centers": qx = 0.5 * (Qx_ext[:, :, 1:] + Qx_ext[:, :, :-1]) / cross_area_x qy = 0.5 * (Qy_ext[:, 1:, :] + Qy_ext[:, :-1, :]) / cross_area_y qz = 0.5 * (Qz_ext[1:, :, :] + Qz_ext[:-1, :, :]) / cross_area_z elif position == "faces" or position == "vertices": cross_area_x = modelgrid.array_at_faces(cross_area_x, "x") cross_area_y = modelgrid.array_at_faces(cross_area_y, "y") cross_area_z = modelgrid.array_at_faces(cross_area_z, "z") qx = Qx_ext / cross_area_x qy = Qy_ext / cross_area_y qz = Qz_ext / cross_area_z else: raise ValueError('"' + position + '" is not a valid value for ' "position") if position == "vertices": qx = modelgrid.array_at_verts(qx) qy = modelgrid.array_at_verts(qy) qz = modelgrid.array_at_verts(qz) else: # check valid options if boundary_ifaces is not None: import warnings warnings.warn( "the boundary_ifaces option is not implemented " 'for "non-classical" MODFLOW versions where the ' "budget is not recorded as FLOW RIGHT FACE, " "FLOW FRONT FACE and FLOW LOWER FACE; it will be " "ignored", UserWarning, ) if position != "centers": raise NotImplementedError('position can only be "centers" for ' '"non-classical" MODFLOW versions where ' "the budget is not recorded as FLOW " "RIGHT FACE, FLOW FRONT FACE and FLOW " "LOWER FACE") is_spdis = [s for s in rec_names if "DATA-SPDIS" in s] if not is_spdis: err_msg = ("Could not find suitable records in the budget file " "to construct the discharge vector.") raise RuntimeError(err_msg) spdis = cbf.get_data(text="DATA-SPDIS", idx=idx, kstpkper=kstpkper, totim=totim)[0] nnodes = model.modelgrid.nnodes qx = np.full((nnodes), np.nan) qy = np.full((nnodes), np.nan) qz = np.full((nnodes), np.nan) idx = np.array(spdis["node"]) - 1 qx[idx] = spdis["qx"] qy[idx] = spdis["qy"] qz[idx] = spdis["qz"] shape = model.modelgrid.shape qx.shape = shape qy.shape = shape qz.shape = shape # set no-flow and dry cells to NaN if hdsfile is not None and position == "centers": noflo_or_dry = np.logical_or(head == model.hnoflo, head == model.hdry) qx[noflo_or_dry] = np.nan qy[noflo_or_dry] = np.nan qz[noflo_or_dry] = np.nan return qx, qy, qz
'STO_OUT': STO_OUT, 'GHB_OUT': GHB_OUT, 'DRT_OUT': DRT_OUT, 'ET_OUT': ET_OUT, 'Total_In': Total_In_NEW, 'Total_Out': Total_Out_NEW, 'WEL_IN': WEL_IN, 'WEL_OUT': WEL_OUT }) df.to_csv('budget.csv', index=None) if read_ccf: # Read ccf file to get simulated spring flows ifile = mname_prefix + '.ccf' fsize = os.path.getsize(ifile) if fsize > 4000000000: # make sure model is converged (ccf > 4GB) cbb = bf.CellBudgetFile(ifile) # list_unique_records = cbb.list_unique_records() # Print all RECORDS # ncols = 3 # make sure you change this #data_out = np.empty([n_stress_period, ncols]) # Load data drt_cell = np.loadtxt(ifile_loc_spring_cells, delimiter=',', dtype=int) # use "" for python2 n_drt_cells = len(drt_cell) drt_cell = drt_cell - 1 # IMPORTANT - Python index is from 0 Q_Bennetts = [] Q_Manse = [] # fid = open('flow_at_cells.csv', 'w') for ts in range(n_stress_period):