[1.537, 4.238, 4.15, 17.05], [1.757, 4.387, 5.2, 24.03], [1.976, 4.497, 6.27, 32.02], [2.196, 4.606, 7.37, 40.86], [2.415, 4.716, 8.49, 50.51], [2.635, 4.826, 9.63, 60.94], [3.771, 63.882, 86.79, 311.2], [4.907, 71.162, 163.46, 747.96], [6.043, 78.442, 248.35, 1356.32], [7.179, 83.771, 340.12, 2146.83], [8.315, 91.541, 438.68, 3060.87], ] # add the reach info to the subbasin subbasin.add_reach(name, maxelev, minelev, slopelen, ftable = ftable) # subbasin land use info (to create perlnds and implnds) landuse_names = ['FOREST', 'ROWCRP', 'GRASS', 'Developed'] areas = [4428.9, 641.63, 776.87, 120.18] # acres # fraction of developed land that is impervious (assume all impervious land) ifraction = 1. # add the landuse subbasin.add_landuse(1988, landuse_names, areas) # create a dictionary of the subbasins
def build_watershed(subbasinfile, flowfile, outletfile, damfile, gagefile, landfile, aggregatefile, VAAfile, years, HUC8, output, plots = True, overwrite = False, format = 'png'): # create a dictionary to store subbasin data subbasins = {} # create a dictionary to keep track of subbasin inlets inlets = {} # read in the flow plane data into an instance of the FlowPlane class sf = Reader(subbasinfile, shapeType = 5) comid_index = sf.fields.index(['ComID', 'N', 9, 0]) - 1 len_index = sf.fields.index(['PlaneLenM', 'N', 8, 2]) - 1 slope_index = sf.fields.index(['PlaneSlope', 'N', 9, 6]) - 1 area_index = sf.fields.index(['AreaSqKm', 'N', 10, 2]) - 1 cx_index = sf.fields.index(['CenX', 'N', 12, 6]) - 1 cy_index = sf.fields.index(['CenY', 'N', 12, 6]) - 1 elev_index = sf.fields.index(['AvgElevM', 'N', 8, 2]) - 1 for record in sf.records(): comid = '{}'.format(record[comid_index]) length = record[len_index] slope = record[slope_index] tot_area = record[area_index] centroid = [record[cx_index], record[cy_index]] elevation = record[elev_index] subbasin = Subbasin(comid) subbasin.add_flowplane(length, slope, 0, centroid, elevation) subbasins[comid] = subbasin # read in the flowline data to an instance of the Reach class sf = Reader(flowfile) outcomid_index = sf.fields.index(['OutComID', 'N', 9, 0]) - 1 gnis_index = sf.fields.index(['GNIS_NAME', 'C', 65, 0]) - 1 reach_index = sf.fields.index(['REACHCODE', 'C', 8, 0]) - 1 incomid_index = sf.fields.index(['InletComID', 'N', 9, 0]) - 1 maxelev_index = sf.fields.index(['MaxElev', 'N', 9, 2]) - 1 minelev_index = sf.fields.index(['MinElev', 'N', 9, 2]) - 1 slopelen_index = sf.fields.index(['SlopeLenKM', 'N', 6, 2]) - 1 slope_index = sf.fields.index(['Slope', 'N', 8, 5]) - 1 inflow_index = sf.fields.index(['InFlowCFS', 'N', 8, 3]) - 1 outflow_index = sf.fields.index(['OutFlowCFS', 'N', 8, 3]) - 1 velocity_index = sf.fields.index(['VelFPS', 'N', 7, 4]) - 1 traveltime_index = sf.fields.index(['TravTimeHR', 'N', 8, 2]) - 1 for record in sf.records(): outcomid = '{}'.format(record[outcomid_index]) gnis = record[gnis_index] reach = record[reach_index] incomid = '{}'.format(record[incomid_index]) maxelev = record[maxelev_index] / 100 minelev = record[minelev_index] / 100 slopelen = record[slopelen_index] slope = record[slope_index] inflow = record[inflow_index] outflow = record[outflow_index] velocity = record[velocity_index] traveltime = record[traveltime_index] if isinstance(gnis, bytes): gnis = '' subbasin = subbasins[outcomid] flow = (inflow + outflow) / 2 subbasin.add_reach(gnis, maxelev, minelev, slopelen, flow = flow, velocity = velocity, traveltime = traveltime) inlets[outcomid] = incomid # open up the outlet file and see if the subbasin has a gage or dam sf = Reader(outletfile) records = sf.records() comid_index = sf.fields.index(['COMID', 'N', 9, 0]) - 1 nid_index = sf.fields.index(['NIDID', 'C', 7, 0]) - 1 nwis_index = sf.fields.index(['SITE_NO', 'C', 15, 0]) - 1 nids = {'{}'.format(r[comid_index]):r[nid_index] for r in records if isinstance(r[nid_index], str)} nwiss = {'{}'.format(r[comid_index]):r[nwis_index] for r in records if r[nwis_index] is not None} # open up the dam file and read in the information for the dams sf = Reader(damfile) records = sf.records() name_index = sf.fields.index(['DAM_NAME', 'C', 65, 0]) - 1 nid_index = sf.fields.index(['NIDID', 'C', 7, 0]) - 1 long_index = sf.fields.index(['LONGITUDE', 'N', 19, 11]) - 1 lat_index = sf.fields.index(['LATITUDE', 'N', 19, 11]) - 1 river_index = sf.fields.index(['RIVER', 'C', 65, 0]) - 1 owner_index = sf.fields.index(['OWN_NAME', 'C', 65, 0]) - 1 type_index = sf.fields.index(['DAM_TYPE', 'C', 10, 0]) - 1 purp_index = sf.fields.index(['PURPOSES', 'C', 254, 0]) - 1 year_index = sf.fields.index(['YR_COMPL', 'C', 10, 0]) - 1 high_index = sf.fields.index(['NID_HEIGHT', 'N', 19, 11]) - 1 mstor_index = sf.fields.index(['MAX_STOR', 'N', 19, 11]) - 1 nstor_index = sf.fields.index(['NORMAL_STO', 'N', 19, 11]) - 1 area_index = sf.fields.index(['SURF_AREA', 'N', 19, 11]) - 1 # iterate through the subbasins and see if they have a dam for comid, subbasin in subbasins.items(): if comid in nids: # if the subbasin has a dam, find the data info in the file nid = nids[comid] r = records[[r[nid_index] for r in records].index(nid)] subbasin.add_dam(nid, r[name_index], r[long_index], r[lat_index], r[river_index], r[owner_index], r[type_index], r[purp_index], r[year_index], r[high_index], r[mstor_index], r[nstor_index], r[area_index] ) # open up the aggregate file to get the landuse group map m, landtypes, groups = get_aggregate_map(aggregatefile) # convert to a list of landuse names names = [landtypes[group] for group in groups] # read the land use data for each year into the subbasins with open(landfile, 'rb') as f: landyears, landuse = pickle.load(f) for comid in subbasins: subbasin = subbasins[comid] subbasin_data = landuse[comid] for year, data in zip(landyears, zip(*subbasin_data)): subbasin.add_landuse(year, names, data) # create an instance of the watershed class watershed = Watershed(HUC8, subbasins) # open up the flowline VAA file to use to establish mass linkages with open(VAAfile, 'rb') as f: flowlines = pickle.load(f) # create a dictionary to connect the comids to hydroseqs hydroseqs = {'{}'.format(flowlines[f].comid): flowlines[f].hydroseq for f in flowlines} # establish the mass linkages using a dictionary "updown" and a list of # head water subbasins updown = {} for comid, subbasin in watershed.subbasins.items(): # get the flowline instance for the outlet comid flowline = flowlines[hydroseqs[comid]] # check if the subbasin is a watershed inlet or a headwater source inlet = hydroseqs[inlets[comid]] if flowlines[inlet].up in flowlines: i = '{}'.format(flowlines[flowlines[inlet].up].comid) subbasin.add_inlet(i) elif flowlines[inlet].up != 0: watershed.add_inlet(comid) else: watershed.add_headwater(comid) # check if the subbasin is a watershed outlet, and if it is not, then # find the downstream reach if flowline.down in flowlines: flowline = flowlines[flowline.down] while '{}'.format(flowline.comid) not in subbasins: flowline = flowlines[flowline.down] updown[comid] = '{}'.format(flowline.comid) else: updown[comid] = 0 watershed.add_outlet('{}'.format(comid)) # open watershed.add_mass_linkage(updown) if output is None: filename = os.getcwd() + '/watershed' plotname = os.getcwd() + '/masslink.%s' % format else: filename = output + '/%s/watershed' % HUC8 plotname = output + '/%s/images/%smasslink.%s' % (HUC8, HUC8, format) if not os.path.isfile(filename) or overwrite: with open(filename, 'wb') as f: pickle.dump(watershed, f) if not os.path.isfile(plotname) and plots or overwrite and plots: plot_mass_flow(watershed, plotname)
name = 'dave stream' # something descriptive maxelev = 110 # elevation at the top of the reach (m) minelev = 100 # elevation at the bottom of the reach (m) slopelen = 10 # the reach length (km) # HSPF uses "FTABLES" to specify the stage-discharge relationship for a reach. # PyHSPF can estimate the FTABLE using the average flow and velocity, or the # FTABLE can be specified directly. here the FTABLE for this subbasin reach # is generated from average flow and velocity. flow = 10 # the inflow (cfs) must use these units velocity = 1 # velocity (fps) again must use these units # add the reach to the subbasin subbasin.add_reach(name, maxelev, minelev, slopelen, flow = flow, velocity = velocity) # here is an alternative set of statements to supply the FTABLE directly. # An FTABLE consists of 4 columns representing the relationships between # depth, surface area, volume, and flow for a reach. HSPF does a linear # interpolation between the depths in the first column to estimate the # other parameters. Up to 18 rows can be used. #ftable = [[0,0,0,0], # [1,1,100,1], # ] #subbasin.add_reach(name, maxelev, minelev, slopelen, ftable = ftable) # another piece of info needed for the subbasins is the land use (used to # subdivide the subbasins into land segments, e.g. soils). so here this subbasin
centroid = [-90, 40] # long, lat name = 'stream' # something descriptive maxelev = 110 # elevation at the top of the reach (m) minelev = 100 # elevation at the bottom of the reach (m) slopelen = 10 # the reach length (km) flow = 12 # the average flow must be in cfs velocity = 1 # velocity must be in fps landuse_names = ['Developed', 'Agriculture', 'Forest'] areas = [20, 40, 40] # add the data for subbasin 100 subbasin.add_flowplane(length, planeslope, centroid, elev) subbasin.add_reach(name, maxelev, minelev, slopelen, flow=flow, velocity=velocity) subbasin.add_landuse(2001, landuse_names, areas) # add the subbasin to the dictionary of subbasins subbasins[number] = subbasin # make another subbasin number = '101' subbasin = Subbasin(number) maxelev = 100 minelev = 90 flow = 12
# the ftable is supplied in the UCI file and replicated here ftable = [[0.0, 0.0, 0.0, 0.0], [0.22, 0.294, 0.04, 0.11], [0.439, 0.588, 0.14, 0.7], [0.659, 0.882, 0.32, 2.04], [0.878, 1.176, 0.56, 4.4], [1.098, 1.398, 0.86, 8.16], [1.318, 1.534, 1.22, 13.6], [1.537, 1.63, 1.6, 20.46], [1.757, 1.688, 2.0, 28.84], [1.976, 1.73, 2.42, 38.42], [2.196, 1.772, 2.84, 49.03], [2.415, 1.814, 3.26, 60.61], [2.635, 1.856, 3.7, 73.13], [3.771, 24.57, 33.38, 373.44], [4.907, 27.368, 62.86, 897.55], [6.043, 30.168, 95.52, 1627.58], [7.179, 32.218, 130.82, 2576.2], [8.315, 35.206, 168.72, 3673.04]] # add the reach info to the subbasin subbasin.add_reach(name, maxelev, minelev, slopelen, ftable=ftable) # subbasin land use info (to create perlnds and implnds) landuse_names = ['Forest', 'Pasture/grass'] areas = [32, 6] # fraction of developed land that is impervious ifraction = 1. # add the landuse subbasin.add_landuse(1988, landuse_names, areas) # add the subbasin to the dictionary