def combined_fis(database: str, label: str, veg_type: str, max_drainage_area: float): """ Combined beaver dam capacity FIS :param network: Shapefile path containing necessary FIS inputs :param label: Plain English label identifying vegetation type ("Existing" or "Historical") :param veg_type: Vegetation type suffix added to end of output ShapeFile fields :param max_drainage_area: Max drainage above which features are not processed. :return: None """ log = Logger('Combined FIS') log.info('Processing {} vegetation'.format(label)) veg_fis_field = 'oVC_{}'.format(veg_type) capacity_field = 'oCC_{}'.format(veg_type) dam_count_field = 'mCC_{}_CT'.format(veg_type) fields = [ veg_fis_field, 'iGeo_Slope', 'iGeo_DA', 'iHyd_SP2', 'iHyd_SPLow', 'iGeo_Len' ] reaches = load_attributes( database, fields, ' AND '.join(['({} IS NOT NULL)'.format(f) for f in fields])) calculate_combined_fis(reaches, veg_fis_field, capacity_field, dam_count_field, max_drainage_area) write_db_attributes(database, reaches, [capacity_field, dam_count_field], log) log.info('Process completed successfully.')
def vegetation_fis(database: str, label: str, veg_type: str): """Calculate vegetation suitability for each reach in a BRAT SQLite database Arguments: database {str} -- Path to BRAT SQLite database label {str} -- Either 'historic' or 'existing'. Only used for lof messages. veg_type {str} -- Prefix either 'EX' for existing or 'HPE' for historic """ log = Logger('Vegetation FIS') log.info('Processing {} vegetation'.format(label)) streamside_field = 'iVeg_30{}'.format(veg_type) riparian_field = 'iVeg100{}'.format(veg_type) out_field = 'oVC_{}'.format(veg_type) feature_values = load_attributes( database, [streamside_field, riparian_field], '({} IS NOT NULL) AND ({} IS NOT NULL)'.format(streamside_field, riparian_field)) calculate_vegegtation_fis(feature_values, streamside_field, riparian_field, out_field) write_db_attributes(database, feature_values, [out_field]) log.info('Process completed successfully.')
def calculate_conservation(database: str): """ Perform conservation calculations Args: database (str): path to BRAT geopackage Returns: dict: dictionary of conservation values keyed by Reach ID """ log = Logger('Conservation') # Verify all the input fields are present and load their values reaches = load_attributes( database, [ 'oVC_HPE', 'oVC_EX', 'oCC_HPE', 'oCC_EX', 'iGeo_Slope', 'mCC_HisDep', 'iPC_VLowLU', 'iPC_HighLU', 'iPC_LU', 'oPC_Dist', 'iHyd_SPLow', 'iHyd_SP2', 'iPC_Canal' ], '(oCC_EX IS NOT NULL) AND (mCC_HisDep IS NOT NULL)') log.info('Calculating conservation for {:,} reaches.'.format(len(reaches))) risks = load_lookup(database, 'SELECT Name, RiskID AS ID FROM DamRisks') limitations = load_lookup( database, 'SELECT Name, LimitationID AS ID FROM DamLimitations') opportunties = load_lookup( database, 'SELECT Name, OpportunityID AS ID FROM DamOpportunities') for values in reaches.values(): # Areas beavers can build dams, but could have undesireable impacts values['RiskID'] = calc_risks(risks, values['oCC_EX'], values['oPC_Dist'], values['iPC_LU'], values['iPC_Canal']) # Areas beavers can't build dams and why values['LimitationID'] = calc_limited( limitations, values['oVC_HPE'], values['oVC_EX'], values['oCC_EX'], values['iGeo_Slope'], values['iPC_LU'], values['iHyd_SPLow'], values['iHyd_SPLow']) # Conservation and restoration opportunties values['OpportunityID'] = calc_opportunities( opportunties, risks, values['RiskID'], values['oCC_HPE'], values['oCC_EX'], values['mCC_HisDep'], values['iPC_VLowLU'], values['iPC_HighLU']) log.info('Conservation calculation complete') return reaches
def hydrology_validation(idaho_db, brat_db): # Load the input fields required as well as the pyBRAT3 output fields feature_values = load_attributes(paths['Network'], 'ReachID', [ veg_fis_field, 'iGeo_Slope', 'iGeo_DA', 'iHyd_SP2', 'iHyd_SPLow', 'iGeo_Len' ]) expected_output = load_attributes(paths['Network'], 'ReachID', [com_capacity_field, com_density_field]) # Do the combined FIS calculation calculate_combined_fis(feature_values, veg_fis_field, com_capacity_field, com_density_field, max_drainage_area) # Merge the results into a master list for reach, feature in feature_values.items(): capacity_values.append((expected_output[reach][com_capacity_field], feature[com_capacity_field])) density_values.append((expected_output[reach][com_density_field], feature[com_density_field])) # Plot the master list validation_chart(capacity_values, '{} Combined FIS Capacity'.format(label)) validation_chart(density_values, '{} Combined FIS Density'.format(label))
def write_reach_attributes(feature_class, database, original_fields, field_aliases): """ Write reach values to a ShapeFile with some preprocessing to convert database fields to ShapeFile fields Arguments: feature_class {str} -- Path to output ShapeFile output_values {dict} -- dictionary. Key is ReachID and values is dictionary of values keyed by database field name original_fields {dict} -- OGR datatype keyed to list of database field names field_aliases {dict} -- Field names used in out_values dictionary (i.e. databaes field names) keyed to ShapeFile field names that will be written to ShapeFile null_value {var} -- ShapeFiles can't store NULL values, so this value is substituted for any NULLs in database """ for data_type, fields in original_fields.items(): shp_fields = list(fields) values = load_attributes(database, fields) # ShapeFiles can't store Nulls. null_value = None if data_type == ogr.OFTInteger: null_value = -1 elif data_type == ogr.OFTReal: null_value = -1.0 # duplicate any values that are stored in a different ShapeFile field than in the database for original, alias in field_aliases.items(): if original not in fields: continue # Ensure the fields list now contains the ShapeFile field name instead of the database field name shp_fields[shp_fields.index(original)] = alias for valdict in values.values(): valdict[alias] = valdict[original] write_attributes(feature_class, values, 'ReachID', shp_fields, data_type, null_value)
def hydrology(gpkg_path: str, prefix: str, huc: str): """Calculate low flow, peak flow discharges for each reach in a BRAT database Arguments: database {str} -- Path to BRAT SQLite database prefix {str} -- Q2 or QLow identifying which discharge to calculate huc {str} -- watershed identifier Raises: Exception: When the watershed is missing the regional discharge equation """ hydrology_field = 'iHyd_Q{}'.format(prefix) streampower_field = 'iHyd_SP{}'.format(prefix) log = Logger('Hydrology') log.info('Calculating Q{} hydrology for HUC {}'.format(prefix, huc)) log.info('Discharge field: {}'.format(hydrology_field)) log.info('Stream power field: {}'.format(streampower_field)) # Load the hydrology equation for the HUC with SQLiteCon(gpkg_path) as database: database.curs.execute( 'SELECT Q{} As Q FROM Watersheds WHERE WatershedID = ?'.format( prefix), [huc]) equation = database.curs.fetchone()['Q'] equation = equation.replace('^', '**') if not equation: raise Exception('Missing {} hydrology formula for HUC {}'.format( prefix, huc)) log.info('Regional curve: {}'.format(equation)) # Load the hydrology CONVERTED parameters for the HUC (the values will be in the same units as used in the regional equations) database.curs.execute( 'SELECT Parameter, ConvertedValue FROM vwHydroParams WHERE WatershedID = ?', [huc]) params = { row['Parameter']: row['ConvertedValue'] for row in database.curs.fetchall() } [ log.info('Param: {} = {:.2f}'.format(key, value)) for key, value in params.items() ] # Load the conversion factor for converting reach attribute drainage areas to the values used in the regional equations database.curs.execute( 'SELECT Conversion FROM HydroParams WHERE Name = ?', [DRNAREA_PARAM]) drainage_conversion_factor = database.curs.fetchone()['Conversion'] log.info('Reach drainage area attribute conversion factor = {}'.format( drainage_conversion_factor)) # Load the discharges for each reach reaches = load_attributes(gpkg_path, ['iGeo_DA'], '(iGeo_DA IS NOT NULL)') log.info('{:,} reaches loaded with valid drainage area values'.format( len(reaches))) # Calculate the discharges for each reach results = calculate_hydrology(reaches, equation, params, drainage_conversion_factor, hydrology_field) log.info('{:,} reach hydrology values calculated.'.format(len(results))) # Write the discharges to the database write_db_attributes(gpkg_path, results, [hydrology_field]) # Convert discharges to stream power with SQLiteCon(gpkg_path) as database: database.curs.execute( 'UPDATE ReachAttributes SET {0} = ROUND((1000 * 9.80665) * iGeo_Slope * ({1} * 0.028316846592), 2)' ' WHERE ({1} IS NOT NULL) AND (iGeo_Slope IS NOT NULL)'.format( streampower_field, hydrology_field)) database.conn.commit() log.info('Hydrology calculation complete')