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))
示例#5
0
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)
示例#6
0
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')