def main(): """ Builds a grid for the MODFLOW component of the USGS hydrologic model, GSFLOW. """ options, flags = gscript.parser() basin = options['basin'] pp = options['pour_point'] raster_input = options['raster_input'] dx = options['dx'] dy = options['dy'] grid = options['output'] mask = options['mask_output'] bc_cell = options['bc_cell'] # basin='basins_tmp_onebasin'; pp='pp_tmp'; raster_input='DEM'; raster_output='DEM_coarse'; dx=dy='500'; grid='grid_tmp'; mask='mask_tmp' """ # Fatal if raster input and output are not both set _lena0 = (len(raster_input) == 0) _lenb0 = (len(raster_output) == 0) if _lena0 + _lenb0 == 1: gscript.fatal("You must set both raster input and output, or neither.") """ # Fatal if bc_cell set but mask and grid are false if bc_cell != '': if (mask == '') or (pp == ''): gscript.fatal( 'Mask and pour point must be set to define b.c. cell') # Create grid -- overlaps DEM, three cells of padding gscript.use_temp_region() reg = gscript.region() reg_grid_edges_sn = np.linspace(reg['s'], reg['n'], reg['rows']) reg_grid_edges_we = np.linspace(reg['w'], reg['e'], reg['cols']) g.region(vector=basin, ewres=dx, nsres=dy) regnew = gscript.region() # Use a grid ratio -- don't match exactly the desired MODFLOW resolution grid_ratio_ns = np.round(regnew['nsres'] / reg['nsres']) grid_ratio_ew = np.round(regnew['ewres'] / reg['ewres']) # Get S, W, and then move the unit number of grid cells over to get N and E # and include 3 cells of padding around the whole watershed _s_dist = np.abs(reg_grid_edges_sn - (regnew['s'] - 3. * regnew['nsres'])) _s_idx = np.where(_s_dist == np.min(_s_dist))[0][0] _s = float(reg_grid_edges_sn[_s_idx]) _n_grid = np.arange(_s, reg['n'] + 3 * grid_ratio_ns * reg['nsres'], grid_ratio_ns * reg['nsres']) _n_dist = np.abs(_n_grid - (regnew['n'] + 3. * regnew['nsres'])) _n_idx = np.where(_n_dist == np.min(_n_dist))[0][0] _n = float(_n_grid[_n_idx]) _w_dist = np.abs(reg_grid_edges_we - (regnew['w'] - 3. * regnew['ewres'])) _w_idx = np.where(_w_dist == np.min(_w_dist))[0][0] _w = float(reg_grid_edges_we[_w_idx]) _e_grid = np.arange(_w, reg['e'] + 3 * grid_ratio_ew * reg['ewres'], grid_ratio_ew * reg['ewres']) _e_dist = np.abs(_e_grid - (regnew['e'] + 3. * regnew['ewres'])) _e_idx = np.where(_e_dist == np.min(_e_dist))[0][0] _e = float(_e_grid[_e_idx]) # Finally make the region g.region(w=str(_w), e=str(_e), s=str(_s), n=str(_n), nsres=str(grid_ratio_ns * reg['nsres']), ewres=str(grid_ratio_ew * reg['ewres'])) # And then make the grid v.mkgrid(map=grid, overwrite=gscript.overwrite()) # Cell numbers (row, column, continuous ID) v.db_addcolumn(map=grid, columns='id int', quiet=True) colNames = np.array(gscript.vector_db_select(grid, layer=1)['columns']) colValues = np.array( gscript.vector_db_select(grid, layer=1)['values'].values()) cats = colValues[:, colNames == 'cat'].astype(int).squeeze() rows = colValues[:, colNames == 'row'].astype(int).squeeze() cols = colValues[:, colNames == 'col'].astype(int).squeeze() nrows = np.max(rows) ncols = np.max(cols) cats = np.ravel([cats]) _id = np.ravel([ncols * (rows - 1) + cols]) _id_cat = [] for i in range(len(_id)): _id_cat.append((_id[i], cats[i])) gridTopo = VectorTopo(grid) gridTopo.open('rw') cur = gridTopo.table.conn.cursor() cur.executemany("update " + grid + " set id=? where cat=?", _id_cat) gridTopo.table.conn.commit() gridTopo.close() # Cell area v.db_addcolumn(map=grid, columns='area_m2', quiet=True) v.to_db(map=grid, option='area', units='meters', columns='area_m2', quiet=True) # Basin mask if len(mask) > 0: # Fine resolution region: g.region(n=reg['n'], s=reg['s'], w=reg['w'], e=reg['e'], nsres=reg['nsres'], ewres=reg['ewres']) # Rasterize basin v.to_rast(input=basin, output=mask, use='val', value=1, overwrite=gscript.overwrite(), quiet=True) # Coarse resolution region: g.region(w=str(_w), e=str(_e), s=str(_s), n=str(_n), nsres=str(grid_ratio_ns * reg['nsres']), ewres=str(grid_ratio_ew * reg['ewres'])) r.resamp_stats(input=mask, output=mask, method='sum', overwrite=True, quiet=True) r.mapcalc('tmp' + ' = ' + mask + ' > 0', overwrite=True, quiet=True) g.rename(raster=('tmp', mask), overwrite=True, quiet=True) r.null(map=mask, null=0, quiet=True) # Add mask location (1 vs 0) in the MODFLOW grid v.db_addcolumn(map=grid, columns='basinmask double precision', quiet=True) v.what_rast(map=grid, type='centroid', raster=mask, column='basinmask') """ # Resampled raster if len(raster_output) > 0: r.resamp_stats(input=raster_input, output=raster_output, method='average', overwrite=gscript.overwrite(), quiet=True) """ # Pour point if len(pp) > 0: v.db_addcolumn(map=pp, columns=('row integer', 'col integer'), quiet=True) v.build(map=pp, quiet=True) v.what_vect(map=pp, query_map=grid, column='row', query_column='row', quiet=True) v.what_vect(map=pp, query_map=grid, column='col', query_column='col', quiet=True) # Next point downstream of the pour point # Requires pp (always) and mask (sometimes) # Dependency set above w/ gscript.fatal if len(bc_cell) > 0: ########## NEED TO USE TRUE TEMPORARY FILE ########## # May not work with dx != dy! v.to_rast(input=pp, output='tmp', use='val', value=1, overwrite=True) r.buffer(input='tmp', output='tmp', distances=float(dx) * 1.5, overwrite=True) r.mapcalc('tmp2 = if(tmp==2,1,null()) * ' + raster_input, overwrite=True) g.rename(raster=('tmp2', 'tmp'), overwrite=True, quiet=True) #r.mapcalc('tmp = if(isnull('+raster_input+',0,(tmp == 2)))', overwrite=True) #g.region(rast='tmp') #r.null(map=raster_input, r.drain(input=raster_input, start_points=pp, output='tmp2', overwrite=True) r.mapcalc('tmp3 = tmp2 * tmp', overwrite=True, quiet=True) g.rename(raster=('tmp3', 'tmp'), overwrite=True, quiet=True) #r.null(map='tmp', setnull=0) # Not necessary: center point removed above r.to_vect(input='tmp', output=bc_cell, type='point', column='z', overwrite=gscript.overwrite(), quiet=True) v.db_addcolumn(map=bc_cell, columns=('row integer', 'col integer', 'x double precision', 'y double precision'), quiet=True) v.build(map=bc_cell, quiet=True) v.what_vect(map=bc_cell, query_map=grid, column='row', \ query_column='row', quiet=True) v.what_vect(map=bc_cell, query_map=grid, column='col', \ query_column='col', quiet=True) v.to_db(map=bc_cell, option='coor', columns=('x,y')) # Find out if this is diagonal: finite difference works only N-S, W-E colNames = np.array(gscript.vector_db_select(pp, layer=1)['columns']) colValues = np.array( gscript.vector_db_select(pp, layer=1)['values'].values()) pp_row = int(colValues[:, colNames == 'row'].astype(int).squeeze()) pp_col = int(colValues[:, colNames == 'col'].astype(int).squeeze()) colNames = np.array( gscript.vector_db_select(bc_cell, layer=1)['columns']) colValues = np.array( gscript.vector_db_select(bc_cell, layer=1)['values'].values()) bc_row = int(colValues[:, colNames == 'row'].astype(int).squeeze()) bc_col = int(colValues[:, colNames == 'col'].astype(int).squeeze()) # Also get x and y while we are at it: may be needed later bc_x = float(colValues[:, colNames == 'x'].astype(float).squeeze()) bc_y = float(colValues[:, colNames == 'y'].astype(float).squeeze()) if (bc_row != pp_row) and (bc_col != pp_col): # If not diagonal, two possible locations that are adjacent # to the pour point _col1, _row1 = str(bc_col), str(pp_row) _col2, _row2 = str(pp_col), str(bc_row) # Check if either of these is covered by the basin mask _ismask_1 = gscript.vector_db_select(grid, layer=1, where='(row == ' + _row1 + ') AND (col ==' + _col1 + ')', columns='basinmask') _ismask_1 = int(_ismask_1['values'].values()[0][0]) _ismask_2 = gscript.vector_db_select(grid, layer=1, where='(row == ' + _row2 + ') AND (col ==' + _col2 + ')', columns='basinmask') _ismask_2 = int(_ismask_2['values'].values()[0][0]) # If both covered by mask, error if _ismask_1 and _ismask_2: gscript.fatal( 'All possible b.c. cells covered by basin mask.\n\ Contact the developer: awickert (at) umn(.)edu') # Otherwise, those that keep those that are not covered by basin # mask and set ... # ... wait, do we want the point that touches as few interior # cells as possible? # maybe just try setting both and seeing what happens for now! else: # Get dx and dy dx = gscript.region()['ewres'] dy = gscript.region()['nsres'] # Build tool to handle multiple b.c. cells? bcvect = vector.Vector(bc_cell) bcvect.open('rw') _cat_i = 2 if not _ismask_1: # _x should always be bc_x, but writing generalized code _x = bc_x + dx * (int(_col1) - bc_col) # col 1 at w edge _y = bc_y - dy * (int(_row1) - bc_row) # row 1 at n edge point0 = Point(_x, _y) bcvect.write( point0, cat=_cat_i, attrs=(None, _row1, _col1, _x, _y), ) bcvect.table.conn.commit() _cat_i += 1 if not _ismask_2: # _y should always be bc_y, but writing generalized code _x = bc_x + dx * (int(_col2) - bc_col) # col 1 at w edge _y = bc_y - dy * (int(_row2) - bc_row) # row 1 at n edge point0 = Point(_x, _y) bcvect.write( point0, cat=_cat_i, attrs=(None, _row2, _col2, _x, _y), ) bcvect.table.conn.commit() # Build database table and vector geometry bcvect.build() bcvect.close() g.region(n=reg['n'], s=reg['s'], w=reg['w'], e=reg['e'], nsres=reg['nsres'], ewres=reg['ewres'])
def main(): """ Links each river segment to the next downstream segment in a tributary network by referencing its category (cat) number in a new column. "0" means that the river exits the map. """ options, flags = gscript.parser() streams = options['input_streams'] basins = options['input_basins'] downstream_cat = options['cat'] x_outlet = float(options['x_outlet']) y_outlet = float(options['y_outlet']) output_basins = options['output_basin'] output_streams = options['output_streams'] output_pour_point = options['output_pour_point'] #print options #print flags # Check that either x,y or cat are set if (downstream_cat != '') or ((x_outlet != '') and (y_outlet != '')): pass else: gscript.fatal( 'You must set either "cat" or "x_outlet" and "y_outlet".') # NEED TO ADD IF-STATEMENT HERE TO AVOID AUTOMATIC OVERWRITING!!!!!!!!!!! if downstream_cat == '': # Need to find outlet pour point -- start by creating a point at this # location to use with v.distance try: v.db_droptable(table='tmp', flags='f') except: pass tmp = vector.Vector('tmp') _cols = [(u'cat', 'INTEGER PRIMARY KEY'), (u'x', 'DOUBLE PRECISION'), (u'y', 'DOUBLE PRECISION'), (u'strcat', 'DOUBLE PRECISION')] tmp.open('w', tab_name='tmp', tab_cols=_cols) point0 = Point(x_outlet, y_outlet) tmp.write( point0, cat=1, attrs=(str(x_outlet), str(y_outlet), 0), ) tmp.table.conn.commit() tmp.build() tmp.close() # Now v.distance gscript.run_command('v.distance', from_='tmp', to=streams, upload='cat', column='strcat') #v.distance(_from_='tmp', to=streams, upload='cat', column='strcat') downstream_cat = gscript.vector_db_select(map='tmp', columns='strcat') downstream_cat = int(downstream_cat['values'].values()[0][0]) # Attributes of streams colNames = np.array(vector_db_select(streams)['columns']) colValues = np.array(vector_db_select(streams)['values'].values()) tostream = colValues[:, colNames == 'tostream'].astype(int).squeeze() cats = colValues[:, colNames == 'cat'].astype(int).squeeze() # = "fromstream" # Find network basincats = [downstream_cat] # start here most_upstream_cats = [downstream_cat ] # all of those for which new cats must be sought while True: if len(most_upstream_cats) == 0: break tmp = list(most_upstream_cats) # copy to a temp file: old values most_upstream_cats = [] # Ready to accept new values for ucat in tmp: most_upstream_cats += list(cats[tostream == int(ucat)]) basincats += most_upstream_cats basincats = list(set(list(basincats))) basincats_str = ','.join(map(str, basincats)) # Many basins out -- need to use overwrite flag in future! #SQL_OR = 'rnum = ' + ' OR rnum = '.join(map(str, basincats)) SQL_OR = 'cat = ' + ' OR cat = '.join(map(str, basincats)) if len(basins) > 0: v.extract(input=basins, output=output_basins, where=SQL_OR, overwrite=gscript.overwrite(), quiet=True) if len(streams) > 0: v.extract(input=streams, output=output_streams, cats=basincats_str, overwrite=gscript.overwrite(), quiet=True) # If we want to output the pour point location if len(output_pour_point) > 0: _pp = gscript.vector_db_select(map=streams, columns='x2,y2', where='cat=' + str(downstream_cat)) _xy = np.squeeze(_pp['values'].values()) _x = float(_xy[0]) _y = float(_xy[1]) # NEED TO ADD IF-STATEMENT HERE TO AVOID AUTOMATIC OVERWRITING!!!!!!!!!!! try: v.db_droptable(table=output_pour_point, flags='f') except: pass pptmp = vector.Vector(output_pour_point) _cols = [(u'cat', 'INTEGER PRIMARY KEY'), (u'x', 'DOUBLE PRECISION'), (u'y', 'DOUBLE PRECISION')] pptmp.open('w', tab_name=output_pour_point, tab_cols=_cols) point0 = Point(_x, _y) pptmp.write( point0, cat=1, attrs=(str(_x), str(_y)), ) pptmp.table.conn.commit() pptmp.build() pptmp.close()
def main(): """ Links each river segment to the next downstream segment in a tributary network by referencing its category (cat) number in a new column. "0" means that the river exits the map. """ options, flags = gscript.parser() streams = options["input_streams"] basins = options["input_basins"] downstream_cat = options["cat"] x_outlet = float(options["x_outlet"]) y_outlet = float(options["y_outlet"]) output_basins = options["output_basin"] output_streams = options["output_streams"] output_pour_point = options["output_pour_point"] draindir = options["draindir"] snapflag = flags["s"] # print options # print flags # Check that either x,y or cat are set if (downstream_cat != "") or ((x_outlet != "") and (y_outlet != "")): pass else: gscript.fatal( 'You must set either "cat" or "x_outlet" and "y_outlet".') # NEED TO ADD IF-STATEMENT HERE TO AVOID AUTOMATIC OVERWRITING!!!!!!!!!!! if snapflag or (downstream_cat != ""): if downstream_cat == "": # Need to find outlet pour point -- start by creating a point at this # location to use with v.distance try: v.db_droptable(table="tmp", flags="f") except: pass tmp = vector.Vector("tmp") _cols = [ ("cat", "INTEGER PRIMARY KEY"), ("x", "DOUBLE PRECISION"), ("y", "DOUBLE PRECISION"), ("strcat", "DOUBLE PRECISION"), ] tmp.open("w", tab_name="tmp", tab_cols=_cols) point0 = Point(x_outlet, y_outlet) tmp.write( point0, cat=1, attrs=(str(x_outlet), str(y_outlet), 0), ) tmp.table.conn.commit() tmp.build() tmp.close() # Now v.distance gscript.run_command("v.distance", from_="tmp", to=streams, upload="cat", column="strcat") # v.distance(_from_='tmp', to=streams, upload='cat', column='strcat') downstream_cat = gscript.vector_db_select(map="tmp", columns="strcat") downstream_cat = int(downstream_cat["values"].values()[0][0]) # Attributes of streams colNames = np.array(vector_db_select(streams)["columns"]) colValues = np.array(vector_db_select(streams)["values"].values()) tostream = colValues[:, colNames == "tostream"].astype(int).squeeze() cats = colValues[:, colNames == "cat"].astype( int).squeeze() # = "fromstream" # Find network basincats = [downstream_cat] # start here most_upstream_cats = [ downstream_cat ] # all of those for which new cats must be sought while True: if len(most_upstream_cats) == 0: break tmp = list(most_upstream_cats) # copy to a temp file: old values most_upstream_cats = [] # Ready to accept new values for ucat in tmp: most_upstream_cats += list(cats[tostream == int(ucat)]) basincats += most_upstream_cats basincats = list(set(list(basincats))) basincats_str = ",".join(map(str, basincats)) # Many basins out -- need to use overwrite flag in future! # SQL_OR = 'rnum = ' + ' OR rnum = '.join(map(str, basincats)) # SQL_OR = 'cat = ' + ' OR cat = '.join(map(str, basincats)) SQL_LIST = "cat IN (" + ", ".join(map(str, basincats)) + ")" if len(basins) > 0: v.extract( input=basins, output=output_basins, where=SQL_LIST, overwrite=gscript.overwrite(), quiet=True, ) if len(streams) > 0: v.extract( input=streams, output=output_streams, cats=basincats_str, overwrite=gscript.overwrite(), quiet=True, ) else: # Have coordinates and will limit the area that way. r.water_outlet( input=draindir, output="tmp", coordinates=(x_outlet, y_outlet), overwrite=True, ) r.to_vect(input="tmp", output="tmp", type="area", overwrite=True) v.clip(input=basins, clip="tmp", output=output_basins, overwrite=True) basincats = gscript.vector_db_select( "basins_inbasin").values()[0].keys() basincats_str = ",".join(map(str, basincats)) if len(streams) > 0: v.extract( input=streams, output=output_streams, cats=basincats_str, overwrite=gscript.overwrite(), quiet=True, ) # If we want to output the pour point location if len(output_pour_point) > 0: # NEED TO ADD IF-STATEMENT HERE TO AVOID AUTOMATIC OVERWRITING!!!!!!!!!!! try: v.db_droptable(table=output_pour_point, flags="f") except: pass if snapflag or (downstream_cat != ""): _pp = gscript.vector_db_select(map=streams, columns="x2,y2", where="cat=" + str(downstream_cat)) _xy = np.squeeze(_pp["values"].values()) _x = float(_xy[0]) _y = float(_xy[1]) else: _x = x_outlet _y = y_outlet pptmp = vector.Vector(output_pour_point) _cols = [ ("cat", "INTEGER PRIMARY KEY"), ("x", "DOUBLE PRECISION"), ("y", "DOUBLE PRECISION"), ] pptmp.open("w", tab_name=output_pour_point, tab_cols=_cols) point0 = Point(_x, _y) pptmp.write( point0, cat=1, attrs=(str(_x), str(_y)), ) pptmp.table.conn.commit() pptmp.build() pptmp.close()
def main(): """ Builds a grid for the MODFLOW component of the USGS hydrologic model, GSFLOW. """ options, flags = gscript.parser() basin = options["basin"] pp = options["pour_point"] raster_input = options["raster_input"] dx = options["dx"] dy = options["dy"] grid = options["output"] mask = options["mask_output"] bc_cell = options["bc_cell"] # basin='basins_tmp_onebasin'; pp='pp_tmp'; raster_input='DEM'; raster_output='DEM_coarse'; dx=dy='500'; grid='grid_tmp'; mask='mask_tmp' """ # Fatal if raster input and output are not both set _lena0 = (len(raster_input) == 0) _lenb0 = (len(raster_output) == 0) if _lena0 + _lenb0 == 1: gscript.fatal("You must set both raster input and output, or neither.") """ # Fatal if bc_cell set but mask and grid are false if bc_cell != "": if (mask == "") or (pp == ""): gscript.fatal( "Mask and pour point must be set to define b.c. cell") # Create grid -- overlaps DEM, three cells of padding g.region(raster=raster_input, ewres=dx, nsres=dy) gscript.use_temp_region() reg = gscript.region() reg_grid_edges_sn = np.linspace(reg["s"], reg["n"], reg["rows"]) reg_grid_edges_we = np.linspace(reg["w"], reg["e"], reg["cols"]) g.region(vector=basin, ewres=dx, nsres=dy) regnew = gscript.region() # Use a grid ratio -- don't match exactly the desired MODFLOW resolution grid_ratio_ns = np.round(regnew["nsres"] / reg["nsres"]) grid_ratio_ew = np.round(regnew["ewres"] / reg["ewres"]) # Get S, W, and then move the unit number of grid cells over to get N and E # and include 3 cells of padding around the whole watershed _s_dist = np.abs(reg_grid_edges_sn - (regnew["s"] - 3.0 * regnew["nsres"])) _s_idx = np.where(_s_dist == np.min(_s_dist))[0][0] _s = float(reg_grid_edges_sn[_s_idx]) _n_grid = np.arange(_s, reg["n"] + 3 * grid_ratio_ns * reg["nsres"], grid_ratio_ns * reg["nsres"]) _n_dist = np.abs(_n_grid - (regnew["n"] + 3.0 * regnew["nsres"])) _n_idx = np.where(_n_dist == np.min(_n_dist))[0][0] _n = float(_n_grid[_n_idx]) _w_dist = np.abs(reg_grid_edges_we - (regnew["w"] - 3.0 * regnew["ewres"])) _w_idx = np.where(_w_dist == np.min(_w_dist))[0][0] _w = float(reg_grid_edges_we[_w_idx]) _e_grid = np.arange(_w, reg["e"] + 3 * grid_ratio_ew * reg["ewres"], grid_ratio_ew * reg["ewres"]) _e_dist = np.abs(_e_grid - (regnew["e"] + 3.0 * regnew["ewres"])) _e_idx = np.where(_e_dist == np.min(_e_dist))[0][0] _e = float(_e_grid[_e_idx]) # Finally make the region g.region( w=str(_w), e=str(_e), s=str(_s), n=str(_n), nsres=str(grid_ratio_ns * reg["nsres"]), ewres=str(grid_ratio_ew * reg["ewres"]), ) # And then make the grid v.mkgrid(map=grid, overwrite=gscript.overwrite()) # Cell numbers (row, column, continuous ID) v.db_addcolumn(map=grid, columns="id int", quiet=True) colNames = np.array(gscript.vector_db_select(grid, layer=1)["columns"]) colValues = np.array( gscript.vector_db_select(grid, layer=1)["values"].values()) cats = colValues[:, colNames == "cat"].astype(int).squeeze() rows = colValues[:, colNames == "row"].astype(int).squeeze() cols = colValues[:, colNames == "col"].astype(int).squeeze() nrows = np.max(rows) ncols = np.max(cols) cats = np.ravel([cats]) _id = np.ravel([ncols * (rows - 1) + cols]) _id_cat = [] for i in range(len(_id)): _id_cat.append((_id[i], cats[i])) gridTopo = VectorTopo(grid) gridTopo.open("rw") cur = gridTopo.table.conn.cursor() cur.executemany("update " + grid + " set id=? where cat=?", _id_cat) gridTopo.table.conn.commit() gridTopo.close() # Cell area v.db_addcolumn(map=grid, columns="area_m2 double precision", quiet=True) v.to_db(map=grid, option="area", units="meters", columns="area_m2", quiet=True) # Basin mask if len(mask) > 0: # Fine resolution region: g.region( n=reg["n"], s=reg["s"], w=reg["w"], e=reg["e"], nsres=reg["nsres"], ewres=reg["ewres"], ) # Rasterize basin v.to_rast( input=basin, output=mask, use="val", value=1, overwrite=gscript.overwrite(), quiet=True, ) # Coarse resolution region: g.region( w=str(_w), e=str(_e), s=str(_s), n=str(_n), nsres=str(grid_ratio_ns * reg["nsres"]), ewres=str(grid_ratio_ew * reg["ewres"]), ) r.resamp_stats(input=mask, output=mask, method="sum", overwrite=True, quiet=True) r.mapcalc("tmp" + " = " + mask + " > 0", overwrite=True, quiet=True) g.rename(raster=("tmp", mask), overwrite=True, quiet=True) r.null(map=mask, null=0, quiet=True) # Add mask location (1 vs 0) in the MODFLOW grid v.db_addcolumn(map=grid, columns="basinmask double precision", quiet=True) v.what_rast(map=grid, type="centroid", raster=mask, column="basinmask") """ # Resampled raster if len(raster_output) > 0: r.resamp_stats(input=raster_input, output=raster_output, method='average', overwrite=gscript.overwrite(), quiet=True) """ # Pour point if len(pp) > 0: v.db_addcolumn(map=pp, columns=("row integer", "col integer"), quiet=True) v.build(map=pp, quiet=True) v.what_vect(map=pp, query_map=grid, column="row", query_column="row", quiet=True) v.what_vect(map=pp, query_map=grid, column="col", query_column="col", quiet=True) # Next point downstream of the pour point # Requires pp (always) and mask (sometimes) # Dependency set above w/ gscript.fatal # g.region(raster='DEM') # dx = gscript.region()['ewres'] # dy = gscript.region()['nsres'] if len(bc_cell) > 0: ########## NEED TO USE TRUE TEMPORARY FILE ########## # May not work with dx != dy! v.to_rast(input=pp, output="tmp", use="val", value=1, overwrite=True) r.buffer(input="tmp", output="tmp", distances=float(dx) * 1.5, overwrite=True) r.mapcalc("tmp2 = if(tmp==2,1,null()) * " + raster_input, overwrite=True) # r.mapcalc('tmp = if(isnull('+raster_input+',0,(tmp == 2)))', overwrite=True) # g.region(rast='tmp') # r.null(map=raster_input, # g.region(raster=raster_input) # r.resample(input=raster_input, output='tmp3', overwrite=True) r.resamp_stats(input=raster_input, output="tmp3", method="minimum", overwrite=True) r.drain(input="tmp3", start_points=pp, output="tmp", overwrite=True) # g.region(w=str(_w), e=str(_e), s=str(_s), n=str(_n), nsres=str(grid_ratio_ns*reg['nsres']), ewres=str(grid_ratio_ew*reg['ewres'])) # r.resamp_stats(input='tmp2', output='tmp3', overwrite=True) # g.rename(raster=('tmp3','tmp2'), overwrite=True, quiet=True) r.mapcalc("tmp3 = tmp2 * tmp", overwrite=True, quiet=True) g.rename(raster=("tmp3", "tmp"), overwrite=True, quiet=True) # r.null(map='tmp', setnull=0) # Not necessary: center point removed above r.to_vect( input="tmp", output=bc_cell, type="point", column="z", overwrite=gscript.overwrite(), quiet=True, ) v.db_addcolumn( map=bc_cell, columns=( "row integer", "col integer", "x double precision", "y double precision", ), quiet=True, ) v.build(map=bc_cell, quiet=True) v.what_vect(map=bc_cell, query_map=grid, column="row", query_column="row", quiet=True) v.what_vect(map=bc_cell, query_map=grid, column="col", query_column="col", quiet=True) v.to_db(map=bc_cell, option="coor", columns=("x,y")) # Of the candidates, the pour point is the closest one # v.db_addcolumn(map=bc_cell, columns=('dist_to_pp double precision'), quiet=True) # v.distance(from_=bc_cell, to=pp, upload='dist', column='dist_to_pp') # Find out if this is diagonal: finite difference works only N-S, W-E colNames = np.array(gscript.vector_db_select(pp, layer=1)["columns"]) colValues = np.array( gscript.vector_db_select(pp, layer=1)["values"].values()) pp_row = colValues[:, colNames == "row"].astype(int).squeeze() pp_col = colValues[:, colNames == "col"].astype(int).squeeze() colNames = np.array( gscript.vector_db_select(bc_cell, layer=1)["columns"]) colValues = np.array( gscript.vector_db_select(bc_cell, layer=1)["values"].values()) bc_row = colValues[:, colNames == "row"].astype(int).squeeze() bc_col = colValues[:, colNames == "col"].astype(int).squeeze() # Also get x and y while we are at it: may be needed later bc_x = colValues[:, colNames == "x"].astype(float).squeeze() bc_y = colValues[:, colNames == "y"].astype(float).squeeze() if (bc_row != pp_row).all() and (bc_col != pp_col).all(): if bc_row.ndim > 0: if len(bc_row) > 1: for i in range(len(bc_row)): """ UNTESTED!!!! And probably unimportant -- having 2 cells with river going through them is most likely going to happen with two adjacent cells -- so a side and a corner """ _col1, _row1 = str(bc_col[i]), str(pp_row[i]) _col2, _row2 = str(pp_col[i]), str(bc_row[i]) # Check if either of these is covered by the basin mask _ismask_1 = gscript.vector_db_select( grid, layer=1, where="(row == " + _row1 + ") AND (col ==" + _col1 + ")", columns="basinmask", ) _ismask_1 = int(_ismask_1["values"].values()[0][0]) _ismask_2 = gscript.vector_db_select( grid, layer=1, where="(row == " + _row2 + ") AND (col ==" + _col2 + ")", columns="basinmask", ) _ismask_2 = int(_ismask_2["values"].values()[0][0]) # check if either of these is the other point """ NOT DOING THIS YET -- HAVEN'T THOUGHT THROUGH IF ACTUALLY NECESSARY. (And this is an edge case anyway) """ # If both covered by mask, error if _ismask_1 and _ismask_2: gscript.fatal( "All possible b.c. cells covered by basin mask.\n\ Contact the developer: awickert (at) umn(.)edu" ) # If not diagonal, two possible locations that are adjacent # to the pour point _col1, _row1 = str(bc_col), str(pp_row) _col2, _row2 = str(pp_col), str(bc_row) # Check if either of these is covered by the basin mask _ismask_1 = gscript.vector_db_select( grid, layer=1, where="(row == " + _row1 + ") AND (col ==" + _col1 + ")", columns="basinmask", ) _ismask_1 = int(_ismask_1["values"].values()[0][0]) _ismask_2 = gscript.vector_db_select( grid, layer=1, where="(row == " + _row2 + ") AND (col ==" + _col2 + ")", columns="basinmask", ) _ismask_2 = int(_ismask_2["values"].values()[0][0]) # If both covered by mask, error if _ismask_1 and _ismask_2: gscript.fatal( "All possible b.c. cells covered by basin mask.\n\ Contact the developer: awickert (at) umn(.)edu") # Otherwise, those that keep those that are not covered by basin # mask and set ... # ... wait, do we want the point that touches as few interior # cells as possible? # maybe just try setting both and seeing what happens for now! else: # Get dx and dy # dx = gscript.region()['ewres'] # dy = gscript.region()['nsres'] # Build tool to handle multiple b.c. cells? bcvect = vector.Vector(bc_cell) bcvect.open("rw") _cat_i = 2 if _ismask_1 != 0: # _x should always be bc_x, but writing generalized code _x = bc_x + float(dx) * (int(_col1) - bc_col ) # col 1 at w edge _y = bc_y - float(dy) * (int(_row1) - bc_row ) # row 1 at n edge point0 = Point(_x, _y) bcvect.write( point0, cat=_cat_i, attrs=(None, _row1, _col1, _x, _y), ) bcvect.table.conn.commit() _cat_i += 1 if _ismask_2 != 0: # _y should always be bc_y, but writing generalized code _x = bc_x + float(dx) * (int(_col2) - bc_col ) # col 1 at w edge _y = bc_y - float(dy) * (int(_row2) - bc_row ) # row 1 at n edge point0 = Point(_x, _y) bcvect.write( point0, cat=_cat_i, attrs=(None, _row2, _col2, _x, _y), ) bcvect.table.conn.commit() # Build database table and vector geometry bcvect.build() bcvect.close() g.region( n=reg["n"], s=reg["s"], w=reg["w"], e=reg["e"], nsres=reg["nsres"], ewres=reg["ewres"], )