def plot_list_budget(listfile, model_name=None, model_start_datetime=None, output_path='postproc', model_length_units=None, model_time_units=None, secondary_axis_units=None, xtick_stride=None, plot_start_date=None, plot_end_date=None): pdfs_dir, _, _ = make_output_folders(output_path) if model_name is None: model_name = Path(listfile).stem df_flux = get_listfile_data(listfile, model_start_datetime=model_start_datetime) df_flux_lake = get_listfile_data(listfile, model_start_datetime=model_start_datetime, budgetkey='LAK BUDGET FOR ENTIRE MODEL') df_flux_sfr = get_listfile_data(listfile, model_start_datetime=model_start_datetime, budgetkey='SFR BUDGET FOR ENTIRE MODEL') # plot summary showing in and out values for all terms plot_budget_summary(df_flux, title_prefix=model_name, model_length_units=model_length_units, model_time_units=model_time_units, secondary_axis_units=secondary_axis_units, xtick_stride=xtick_stride, plot_start_date=plot_start_date, plot_end_date=plot_end_date) # plot summary with only net values for each term #plot_budget_summary(df_flux, title_prefix=model_name, # term_nets=True, # model_length_units=model_length_units, # model_time_units=model_time_units, # secondary_axis_units=secondary_axis_units) out_pdf = os.path.join(pdfs_dir, 'listfile_budget_summary.pdf') plt.savefig(out_pdf) plt.close() print(f'wrote {out_pdf}') pdf_outfile = os.path.join(pdfs_dir, 'listfile_budget_by_term.pdf') with PdfPages(pdf_outfile) as pdf: plotted = set() terms = [c for c in df_flux.columns if c not in {'kstp', 'kper'}] for term in terms: if term not in plotted: plot_budget_term(df_flux, term, title_prefix=model_name, plotted=plotted, model_length_units=model_length_units, model_time_units=model_time_units, secondary_axis_units=secondary_axis_units, xtick_stride=xtick_stride) pdf.savefig() plt.close() if df_flux_lake is not None and len(df_flux_lake) > 0: plotted = set() terms = [c for c in df_flux_lake.columns if c not in {'kstp', 'kper'}] for term in terms: if term not in plotted: title_prefix = '{} Lake Package'.format(model_name) plot_budget_term(df_flux_lake, term, title_prefix=title_prefix, plotted=plotted, model_length_units=model_length_units, model_time_units=model_time_units, secondary_axis_units=secondary_axis_units) pdf.savefig() plt.close() if df_flux_sfr is not None and len(df_flux_sfr) > 0: plotted = set() terms = [c for c in df_flux_sfr.columns if c not in {'kstp', 'kper'}] for term in terms: if term not in plotted: title_prefix = '{} SFR Package'.format(model_name) plot_budget_term(df_flux_sfr, term, title_prefix=title_prefix, plotted=plotted, model_length_units=model_length_units, model_time_units=model_time_units, secondary_axis_units=secondary_axis_units) pdf.savefig() plt.close() print(f'wrote {pdf_outfile}')
def export_drawdown(heads_file, grid, hdry, hnflo, kstpkper0=None, kstpkper1=None, levels=None, interval=None, export_water_table=True, export_layers=False, output_path='postproc', suffix=''): """Export MODFLOW binary head output to rasters and shapefiles. Parameters ---------- modelname : str model base name grid : rOpen.modflow.grid instance hdry : hdry value from UPW package hnflo : hnflo value from BAS package levels : 1D numpy array Values of equal interval contours to write. shps_outfolder : where to write shapefiles rasters_outfolder : where to write rasters Writes ------ * A raster of heads for each layer and a raster of the water table elevation * Shapefiles of head contours for each layer and the water table. """ print('Exporting drawdown...') print('file: {}'.format(heads_file)) if kstpkper0 is not None: print('from stress period {}, timestep {}'.format(*reversed(kstpkper0))) if kstpkper1 is not None: # convert kstpkper1 to a list of tuples or lists if it isn't if np.isscalar(kstpkper1[0]): kstpkper1 = [kstpkper1] pdfs_dir, rasters_dir, shps_dir = make_output_folders(output_path) # Heads output at drawdown period start hdsobj = bf.HeadFile(heads_file) hds0 = hdsobj.get_data(kstpkper=kstpkper0) hds0[(hds0 > 9999) & (hds0 < 0)] = np.nan if export_water_table: wt0 = get_water_table(hds0, nodata=hdry) for kstp, kper in kstpkper1: print(f'to stress period {kper}, timestep {kstp}') print('\n') if (kstp, kper) == (0, 0): print('kstpkper == (0, 0, no drawdown to export') continue # heads output at drawdown period end hds1 = hdsobj.get_data(kstpkper=(kstp, kper)) hds1[(hds1 > 9999) & (hds1 < 0)] = np.nan if export_water_table: wt1 = get_water_table(hds1, nodata=hdry) wt_ddn = wt0 - wt1 outfiles = [] outfile = '{}/wt-ddn_per{}_stp{}{}.tif'.format(rasters_dir, kper, kstp, suffix) ctr_outfile = '{}/wt-ddn_ctr_per{}_stp{}{}.shp'.format(shps_dir, kper, kstp, suffix) export_array(outfile, wt_ddn, grid, nodata=hnflo) export_array_contours(ctr_outfile, wt_ddn, grid, levels=levels, interval=interval, ) outfiles += [outfile, ctr_outfile] if export_layers: ddn = hds0 - hds1 for k, d in enumerate(ddn): outfile = '{}/ddn_lay{}_per{}_stp{}{}.tif'.format(rasters_dir, k, kper, kstp, suffix) ctr_outfile = '{}/ddn_ctr_lay{}_per{}_stp{}{}.shp'.format(shps_dir, k, kper, kstp, suffix) export_array(outfile, d, grid, nodata=hnflo) export_array_contours(ctr_outfile, d, grid, levels=levels ) outfiles += [outfile, ctr_outfile] return outfiles
def export_sfr_results(mf2005_sfr_outputfile=None, mf2005_SfrFile_instance=None, mf6_sfr_stage_file=None, mf6_sfr_budget_file=None, mf6_package_data=None, model=None, model_top=None, grid=None, kstpkper=(0, 0), sfrlinesfile=None, pointsize=0.5, model_length_units=None, model_time_units=None, output_length_units='feet', output_time_units='seconds', gis=True, pdfs=True, output_path='postproc', suffix='', verbose=False): pdfs_dir, rasters_dir, shps_dir = make_output_folders(output_path) m = model if not isinstance(kstpkper, list): kstpkper = [kstpkper] print('Exporting SFR results...') for f in [mf2005_sfr_outputfile, mf6_sfr_stage_file, mf6_sfr_budget_file]: if f is not None: print('file: {}'.format(f)) df = read_sfr_output(mf2005_sfr_outputfile=mf2005_sfr_outputfile, mf2005_SfrFile_instance=mf2005_SfrFile_instance, mf6_sfr_stage_file=mf6_sfr_stage_file, mf6_sfr_budget_file=mf6_sfr_budget_file, mf6_package_data=mf6_package_data, model=model) if model_length_units is None: if model is None: model_length_units = 'meters' else: model_length_units = get_length_units(m) if model_time_units is None: if model is None: model_time_units = 'days' else: model_time_units = get_time_units(m) lmult = convert_length_units(model_length_units, output_length_units) tmult = convert_time_units(model_time_units, output_time_units) unit_text = get_unit_text(output_length_units, output_time_units, 3) if 'GWF' in df.columns: df['Qaquifer'] = -df.GWF # for consistency with MF2005 if 'Qmean' not in df.columns: df['Qmean'] = df[['Qin', 'Qout']].abs().mean(axis=1) # write columns in the output units df['Qmean_{}'.format(unit_text)] = df.Qmean * lmult**3/tmult df['Qaq_{}'.format(unit_text)] = df.Qaquifer * lmult**3/tmult # add model top comparison if available if isinstance(model_top, str): model_top = np.loadtxt(model_top) elif model_top is None and model is not None: model_top = m.dis.top.array if model_top is not None and 'i' in df.columns and 'j' in df.columns: df['model_top'] = model_top[df.i.values, df.j.values] if 'stage' in df.columns: df['above'] = df.stage - df.model_top groups = df.groupby('kstpkper') outfiles = [] if gis: prj_file = None if sfrlinesfile is not None: sfrlines = shp2df(sfrlinesfile) prj_file = sfrlines[:-4] + '.prj' sfrlines.sort_values(by=['iseg', 'ireach'], inplace=True) geoms = sfrlines.geometry else: #assert sr is not None, \ # 'need SpatialReference instance to locate model grid cells' #dfp = groups.get_group((0, 0)).copy() geoms = None #vertices = sr.get_vertices(dfp.i, dfp.j) #geoms = [Polygon(vrt) for vrt in vertices] for kstp, kper in kstpkper: print('stress period {}, timestep {}'.format(kper, kstp)) dfp = groups.get_group((kstp, kper)).copy() if geoms is not None: dfp['geometry'] = geoms #dfp = gp.GeoDataFrame(dfp) #dfp.crs = sr.proj4_str # to use cell polygons instead of lines # verts = m.sr.get_vertices(df.i.values, df.j.values) #df['geometry'] = [Polygon(v) for v in verts] dfp['stp'] = [t[0] for t in dfp['kstpkper']] dfp['per'] = [t[1] for t in dfp['kstpkper']] dfp.drop('kstpkper', axis=1, inplace=True) # geopandas doesn't like tuples outfile = '{}/sfrout_per{}_stp{}{}.shp'.format(shps_dir, kper, kstp, suffix) export_shapefile(outfile, dfp, modelgrid=grid, prj=prj_file) outfiles.append(outfile) #dfp.to_file(outfile) #print('wrote {}'.format(outfile)) if pdfs: # need to add a scale that addresses units for kstp, kper in kstpkper: print('stress period {}, timestep {}'.format(kper, kstp)) df = groups.get_group((kstp, kper)).copy() bf_outfile = '{}/baseflow_per{}_stp{}{}.pdf'.format(pdfs_dir, kper, kstp, suffix) sfr_baseflow_pdf(bf_outfile, df, pointsize=pointsize, verbose=verbose) qaq_outfile = '{}/qaquifer_per{}_stp{}.pdf'.format(pdfs_dir, kper, kstp, suffix) sfr_qaquifer_pdf(qaq_outfile, df, pointsize=pointsize, verbose=verbose) outfiles += [bf_outfile, qaq_outfile] return outfiles
def export_heads(heads_file, grid, hdry, hnflo, kstpkper=(0, 0), levels=None, interval=None, export_water_table=True, export_depth_to_water=False, export_layers=False, land_surface_elevations=None, output_path='postproc', suffix=''): """Export MODFLOW binary head output to rasters and shapefiles. Parameters ---------- modelname : str model base name grid : rOpen.modflow.grid instance hdry : hdry value from UPW package hnflo : hnflo value from BAS package levels : 1D numpy array Values of equal interval contours to write. shps_outfolder : where to write shapefiles rasters_outfolder : where to write rasters Writes ------ * A raster of heads for each layer and a raster of the water table elevation * Shapefiles of head contours for each layer and the water table. """ if np.isscalar(kstpkper[0]): kstpkper = [kstpkper] print('Exporting heads...') print('file: {}'.format(heads_file)) pdfs_dir, rasters_dir, shps_dir = make_output_folders(output_path) outfiles = [] for kstp, kper in kstpkper: print('stress period {}, timestep {}'.format(kper, kstp)) # Heads output hdsobj = bf.HeadFile(heads_file) hds = hdsobj.get_data(kstpkper=(kstp, kper)) if export_water_table or export_depth_to_water: wt = get_water_table(hds, nodata=hdry) wt[(wt > 9999) | (wt < 0)] = np.nan outfile = '{}/wt_per{}_stp{}{}.tif'.format(rasters_dir, kper, kstp, suffix) ctr_outfile = '{}/wt_ctr_per{}_stp{}{}.shp'.format(shps_dir, kper, kstp, suffix) export_array(outfile, wt, grid, nodata=hnflo) export_array_contours(ctr_outfile, wt, grid, levels=levels, interval=interval) outfiles += [outfile, ctr_outfile] if export_depth_to_water: if land_surface_elevations is None: raise ValueError(('export_heads: export_depth_to_water option ' 'requires specification of the land surface')) if not isinstance(land_surface_elevations, np.ndarray): land_surface_elevations = np.loadtxt(land_surface_elevations) # Depth to water dtw = land_surface_elevations - wt # Overpressurization op = dtw.copy() # For DTW, mask areas of overpressurization; # For Overpressurization, mask areas where water table is below land surface op = np.ma.masked_array(op, mask=op > 0) dtw = np.ma.masked_array(dtw, mask=dtw < 0) if np.max(dtw) > 0: #dtw_levels = None #if interval is not None: # dtw_levels = np.linspace(0, np.nanmax(dtw), interval) outfile = '{}/dtw_per{}_stp{}{}.tif'.format(rasters_dir, kper, kstp, suffix) ctr_outfile = '{}/dtw_ctr_per{}_stp{}{}.shp'.format(shps_dir, kper, kstp, suffix) export_array(outfile, dtw, grid, nodata=hnflo) export_array_contours(ctr_outfile, dtw, grid, interval=interval) outfiles += [outfile, ctr_outfile] else: print('Water table is above land surface everywhere, skipping depth to water.') if np.nanmin(op) < 0: #op_levels = None #if interval is not None: # op_levels = np.linspace(0, np.nanmin(op), interval) outfile = '{}/op_per{}_stp{}{}.tif'.format(rasters_dir, kper, kstp, suffix) ctr_outfile = '{}/op_ctr_per{}_stp{}{}.shp'.format(shps_dir, kper, kstp, suffix) export_array(outfile, op, grid, nodata=hnflo) export_array_contours(ctr_outfile, op, grid, interval=interval) outfiles += [outfile, ctr_outfile] else: print('No overpressurization, skipping.') hds[(hds > 9999) | (hds < 0)] = np.nan if export_layers: for k, h in enumerate(hds): outfile = '{}/hds_lay{}_per{}_stp{}{}.tif'.format(rasters_dir, k, kper, kstp, suffix) ctr_outfile = '{}/hds_ctr_lay{}_per{}_stp{}{}.shp'.format(shps_dir, k, kper, kstp, suffix) export_array(outfile, h, grid, nodata=hnflo) export_array_contours(ctr_outfile, h, grid, levels=levels, interval=interval, ) outfiles += [outfile, ctr_outfile] return outfiles
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
def export(model, modelgrid, packages=None, variables=None, output_path='postproc', contours=False, include_inactive_cells=False, gis=True, pdfs=True, **kwargs): pdfs_dir, rasters_dir, shps_dir = make_output_folders(output_path) context = 'model' if packages is None: if 'package' in kwargs: packages = [kwargs.pop('package')] context = 'packages' else: packages = get_package_list(model) else: context = 'packages' if not isinstance(packages, list): packages = [packages] if variables is not None: context = 'variables' variables = get_variable_list(variables) elif 'variable' in kwargs: context = 'variables' variables = get_variable_list(kwargs.pop('variable')) if not isinstance(modelgrid, StructuredGrid): raise NotImplementedError('Unstructured grids not supported') inactive_cells = get_inactive_cells_mask(model) inactive_cells2d = np.all( inactive_cells, axis=0) # ij locations where all layers are inactive filenames = [] for package in packages: if isinstance(package, str): package = getattr(model, package) package_name = package.name[0] print('\n{} package...'.format(package_name)) if variables is None and 'sfr' in package_name.lower(): if 'obs' not in package_name.lower(): export_sfr(package, modelgrid, gis=gis, pdfs=pdfs, shapefile_outfolder=shps_dir, pdf_outfolder=pdfs_dir, filenames=filenames) # TODO: add SFR obs export else: print('skipping; not implemented') if model.version == 'mf6': if package.name[0].lower() == 'dis': variable_context = context == 'variables' and 'thickness' in variables if context in ['model', 'packages'] or variable_context: export_thickness( package.top.array, package.botm.array, modelgrid, filenames, rasters_dir, shps_dir, pdfs_dir, gis=gis, pdfs=pdfs, contours=contours, include_inactive_cells=include_inactive_cells, inactive_cells=inactive_cells, **kwargs) if variables is not None: package_variables = [getattr(package, v, None) for v in variables] package_variables = [v for v in package_variables if v is not None] else: package_variables = package.data_list for v in package_variables: if isinstance(v, DataInterface): if v.array is not None: if isinstance(v.name, list): name = v.name[0].strip('_') if isinstance(v.name, str): name = v.name.strip('_') if variables is not None and \ othername.get(name.lower(), name.lower()) not in variables: return try: export_variable( v, package, modelgrid, inactive_cells, inactive_cells2d, filenames, rasters_dir, shps_dir, pdfs_dir, gis=gis, pdfs=pdfs, contours=contours, include_inactive_cells=include_inactive_cells, **kwargs) except Exception as e: print('skipped, not implemented yet') return filenames