Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/commons/rscommons/national_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def _get_urls(params: Dict[str, str]):

items = TNM.get_items(params)

if items['error'] and items['error'] is not None:
if items.get('error') is not None:
log.error(f'TNM API error: {items["error"]}')
raise Exception(f'TNM API error: {items["error"]}')

Expand Down
23 changes: 20 additions & 3 deletions lib/commons/rscommons/shapefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,15 +516,32 @@ def copy_feature_class_shapefile(inpath, epsg, outpath, intersect_shape=None, cl
# Note that this makes the subsequent intersection process a lot more
# performant because the SetSaptialFilter() uses the ShapeFile's spatial
# index which is much faster than manually checking if all pairs of features intersect.
#
# SetSpatialFilter() expects geometry in the input layer's CRS,
# but intersect_shape/clip_shape are in the output EPSG. We need to transform
# them to the input CRS for the spatial filter to work correctly.
reverse_transform = None
if intersect_shape or clip_shape:
outSpatialRefTemp = osr.SpatialReference()
outSpatialRefTemp.ImportFromEPSG(int(epsg))
outSpatialRefTemp.SetAxisMappingStrategy(inSpatialRef.GetAxisMappingStrategy())
reverse_transform = osr.CoordinateTransformation(outSpatialRefTemp, inSpatialRef)

intersect_geom = None
if intersect_shape:
intersect_geom = ogr.CreateGeometryFromWkb(intersect_shape.wkb)
inLayer.SetSpatialFilter(intersect_geom)
# Transform to input CRS for spatial filter
intersect_geom_filter = ogr.CreateGeometryFromWkb(intersect_shape.wkb)
intersect_geom_filter.Transform(reverse_transform)
inLayer.SetSpatialFilter(intersect_geom_filter)

clip_geom = None
if clip_shape:
# Keep clip_geom in output EPSG for intersection operation later
clip_geom = ogr.CreateGeometryFromWkb(clip_shape.wkb)
inLayer.SetSpatialFilter(clip_geom)
# Transform a copy to input CRS for spatial filter only
clip_geom_filter = ogr.CreateGeometryFromWkb(clip_shape.wkb)
clip_geom_filter.Transform(reverse_transform)
inLayer.SetSpatialFilter(clip_geom_filter)

outpath_dir = os.path.dirname(outpath)
safe_makedirs(outpath_dir)
Expand Down
10 changes: 5 additions & 5 deletions packages/blm_context/blm_context/layer_descriptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
"VEGHEIGHT": ["LandFire Existing Vegetation Height (EVH) raster: Average height of the dominant vegetation. Version 2.2.0: Reflects adjustments to vegetation and fuels since LF 2016 Remap in disturbed areas for disturbances recorded in 2017-2020. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.2.0"],
"HDIST": ["LandFire Historical Disturbance (HDst) raster: The latest 10 years of Annual Disturbance products are used to identify disturbance year, type, and severity. Starting with LF Remap, HDist replaces VDist from previous LF versions incorporating pre-disturbance vegetation logic (based on disturbance year and vegetation type). The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"HDIST": ["LandFire Historical Disturbance (HDist) raster: The latest 10 years of Annual Disturbance products are used to identify disturbance year, type, and severity. Starting with LF Remap, HDist replaces VDist from previous LF versions incorporating pre-disturbance vegetation logic (based on disturbance year and vegetation type). The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.2.0"],
"FDIST": ["LandFire Fuel Disturbance (FDst) raster: The latest 10 years of Annual Disturbance products representing disturbance year and original disturbance code. FDist was a refinement of VDist in LF 1.x products and is a refinement of Historical Disturbance in LF Remap to more accurately represent disturbance scenarios within the fuels environment. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"FDIST": ["LandFire Fuel Disturbance (FDist) raster: The latest 10 years of Annual Disturbance products representing disturbance year and original disturbance code. FDist was a refinement of VDist in LF 1.x products and is a refinement of Historical Disturbance in LF Remap to more accurately represent disturbance scenarios within the fuels environment. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.2.0"],
"FCCS": ["LandFire Fuel Characteristic Classification System (FCCS) raster: Describes the phsical characteristics of a relatively uniform unit on a lanscape that represents a distinct fire environment; provides land managers, regulators, and scientists with a nationally consistent and durable procedure to characterize and classify fuelbed characteristics to predict fuel consumption and smoke production. For LF Remap, FCCS will be released as part of the final release for CONUS. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
Expand All @@ -35,11 +35,11 @@
"VEGDEPARTURE": ["LandFire Vegetation Depature (VDEP) raster: Range from 0-100 depicting the amount that current vegetation has departed from simulated historical vegetation reference. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.2.0"],
"SCLASS": ["LandFire Succession Classes (SCla) raster: Current vegetation conditions with respect to vegetation species composition, cover, and height ranges of successional states occurring within each biophysical setting. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"SCLASS": ["LandFire Succession Classes (SClass) raster: Current vegetation conditions with respect to vegetation species composition, cover, and height ranges of successional states occurring within each biophysical setting. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.2.0"],
"OWNERSHIP": ["Land ownership obtained from the Bureau of Management (BLM) Land Surface Agency. A single ShapeFile was downloaded and then pre-processed to remove invalid geometries and other irregularities.",
"https://landscape.blm.gov/geoportal/catalog/search/resource/details.page?uuid=%7B2A8B8906-7711-4AF7-9510-C6C7FD991177%7D",
"OWNERSHIP": ["Land ownership obtained from the Bureau of Land Management (BLM) Surface Management Agency. A single geodatabase was downloaded and then converted to shapefile, pre-processed to remove invalid geometries and other irregularities.",
"https://gbp-blm-egis.hub.arcgis.com/datasets/6bf2e737c59d4111be92420ee5ab0b46/about",
""],
"FAIR_MARKET": ["Fair Market Value raster generated from research by Christoph Nolte. This raster was downloaded and converted to US dollars per hectare.",
"https://placeslab.org/fmv-usa/",
Expand Down
6 changes: 3 additions & 3 deletions packages/channel/channel/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,9 @@ def main():
bankfull_params = parse_metadata(args.bankfull_function_params)

reach_codes = {}
reach_codes['flowline'] = args.flowline_reach_codes.split(',') if args.flowline_reach_codes else None
reach_codes['flowarea'] = args.flowarea_reach_codes.split(',') if args.flowarea_reach_codes else None
reach_codes['waterbody'] = args.waterbody_reach_codes.split(',') if args.waterbody_reach_codes else None
reach_codes['flowline'] = [x.strip() for x in args.flowline_reach_codes.split(',')] if args.flowline_reach_codes else None
reach_codes['flowarea'] = [x.strip() for x in args.flowarea_reach_codes.split(',')] if args.flowarea_reach_codes else None
reach_codes['waterbody'] = [x.strip() for x in args.waterbody_reach_codes.split(',')] if args.waterbody_reach_codes else None

if args.precip is not None:
precip = args.precip
Expand Down
3 changes: 3 additions & 0 deletions packages/rscontext/rscontext/hydro_derivatives.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ def create_spatial_view(nhd_gpkg_path: str, network_layer: str, join_table: str,
with sqlite3.connect(nhd_gpkg_path) as conn:
curs = conn.cursor()
curs.execute(f"DROP VIEW IF EXISTS {out_view}")
# Clean up GeoPackage metadata from any previous view with this name
curs.execute(f"DELETE FROM gpkg_contents WHERE table_name = '{out_view}'")
curs.execute(f"DELETE FROM gpkg_geometry_columns WHERE table_name = '{out_view}'")
# create the view with specified of the fields from the flowline table and add the fields from the join table. the fields from the join table should have an ailas of the value in the dict.
curs.execute(f"CREATE VIEW {out_view} AS SELECT {', '.join([f'{network_layer}.{field} AS {alias}' for field, alias in network_fields.items()])}, {', '.join(
[f'{join_table}.{field} AS {alias}' for field, alias in join_fields.items()])} FROM {network_layer} LEFT JOIN {join_table} ON {network_layer}.{join_id} = {join_table}.{join_id}")
Expand Down
10 changes: 5 additions & 5 deletions packages/rscontext/rscontext/layer_descriptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@
"2.4.0"
],
"HDIST": [
"LandFire Historical Disturbance (HDst) raster: The latest 10 years of Annual Disturbance products are used to identify disturbance year, type, and severity. Starting with LF Remap, HDist replaces VDist from previous LF versions incorporating pre-disturbance vegetation logic (based on disturbance year and vegetation type). The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"LandFire Historical Disturbance (HDist) raster: The latest 10 years of Annual Disturbance products are used to identify disturbance year, type, and severity. Starting with LF Remap, HDist replaces VDist from previous LF versions incorporating pre-disturbance vegetation logic (based on disturbance year and vegetation type). The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.4.0"
],
"FDIST": [
"LandFire Fuel Disturbance (FDst) raster: The latest 10 years of Annual Disturbance products representing disturbance year and original disturbance code. FDist was a refinement of VDist in LF 1.x products and is a refinement of Historical Disturbance in LF Remap to more accurately represent disturbance scenarios within the fuels environment. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"LandFire Fuel Disturbance (FDist) raster: The latest 10 years of Annual Disturbance products representing disturbance year and original disturbance code. FDist was a refinement of VDist in LF 1.x products and is a refinement of Historical Disturbance in LF Remap to more accurately represent disturbance scenarios within the fuels environment. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.4.0"
],
Expand All @@ -60,13 +60,13 @@
"2.4.0"
],
"SCLASS": [
"LandFire Succession Classes (SCla) raster: Current vegetation conditions with respect to vegetation species composition, cover, and height ranges of successional states occurring within each biophysical setting. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"LandFire Succession Classes (SClass) raster: Current vegetation conditions with respect to vegetation species composition, cover, and height ranges of successional states occurring within each biophysical setting. The source is a single raster for the entire nation that is downloaded and then clipped to the riverscapes context project extent.",
"https://landfire.gov/data_overviews.php",
"2.4.0"
],
"OWNERSHIP": [
"Land ownership obtained from the Bureau of Management (BLM) Land Surface Agency. A single ShapeFile was downloaded and then pre-processed to remove invalid geometries and other irregularities.",
"https://landscape.blm.gov/geoportal/catalog/search/resource/details.page?uuid=%7B2A8B8906-7711-4AF7-9510-C6C7FD991177%7D",
"Land ownership obtained from the Bureau of Land Management (BLM) Surface Management Agency. A single geodatabase was downloaded and then converted to shapefile, pre-processed to remove invalid geometries and other irregularities.",
"https://gbp-blm-egis.hub.arcgis.com/datasets/6bf2e737c59d4111be92420ee5ab0b46/about",
""
],
"FAIR_MARKET": [
Expand Down
46 changes: 34 additions & 12 deletions packages/rscontext/rscontext/rs_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@
# These are the Prism BIL types we expect
PrismTypes = ['PPT', 'TMEAN', 'TMIN', 'TMAX', 'TDMEAN', 'VPDMIN', 'VPDMAX']

# LANDFIRE input raster filenames
# Download from: https://landfire.gov/getdata.php -> Full Extent Downloads -> CONUS
# Note: Different products have different latest versions available:
# - BPS (Biophysical Settings) represents historic/potential vegetation and is only updated
# periodically. LF 2020 (version 220) is currently the latest.
# - Other products (EVT, EVC, EVH, etc.) represent current conditions and are updated annually.
# LF 2023 (version 240) is currently used.
# When LANDFIRE releases new versions, update the filenames here.
LANDFIRE_INPUTS = {
'EVT': 'LC23_EVT_240.tif', # Existing Vegetation Type - LF 2023
'BPS': 'LC20_BPS_220.tif', # Biophysical Settings - LF 2020 (latest available)
'EVC': 'LC23_EVC_240.tif', # Existing Vegetation Cover - LF 2023
'EVH': 'LC23_EVH_240.tif', # Existing Vegetation Height - LF 2023
'HDist': 'LC23_HDist_240.tif', # Historic Disturbance - LF 2023
'FDist': 'LC23_FDist_240.tif', # Fuel Disturbance - LF 2023
'FCCS': 'LC23_FCCS_240.tif', # Fuel Characteristic Classification System - LF 2023
'VCC': 'LC23_VCC_240.tif', # Vegetation Condition Class - LF 2023
'VDep': 'LC23_VDep_240.tif', # Vegetation Departure - LF 2023
'SClass': 'LC23_SClass_240.tif', # Succession Classes - LF 2023
}

LYR_DESCRIPTIONS_JSON = os.path.join(os.path.os.path.dirname(__file__), 'layer_descriptions.json')
LayerTypes = {
# key: (name, id, tag, relpath)
Expand Down Expand Up @@ -461,17 +482,18 @@ def rs_context(huc: str, landfire_dir: str, ownership: str, fair_market: str, ec
################################################################################################################################################
# Clip and re-project the existing and historic vegetation
log.info('Processing existing and historic vegetation rasters.')
# Uses LANDFIRE_INPUTS config defined at top of file - update filenames there when new versions are released
in_veg_rasters = [
os.path.join(landfire_dir, 'LC23_EVT_240.tif'),
os.path.join(landfire_dir, 'LC20_BPS_220.tif'),
os.path.join(landfire_dir, 'LC23_EVC_240.tif'),
os.path.join(landfire_dir, 'LC23_EVH_240.tif'),
os.path.join(landfire_dir, 'LC23_HDst_240.tif'),
os.path.join(landfire_dir, 'LC23_FDst_240.tif'),
os.path.join(landfire_dir, 'LC23_FCCS_240.tif'),
os.path.join(landfire_dir, 'LC23_VCC_240.tif'),
os.path.join(landfire_dir, 'LC23_VDep_240.tif'),
os.path.join(landfire_dir, 'LC23_SCla_240.tif')
os.path.join(landfire_dir, LANDFIRE_INPUTS['EVT']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['BPS']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['EVC']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['EVH']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['HDist']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['FDist']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['FCCS']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['VCC']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['VDep']),
os.path.join(landfire_dir, LANDFIRE_INPUTS['SClass']),
]
out_veg_rasters = [existing_clip, historic_clip, veg_cover_clip, veg_height_clip,
hdist_clip, fdist_clip, fccs_clip, veg_condition_clip, veg_departure_clip, sclass_clip]
Expand Down Expand Up @@ -596,8 +618,8 @@ def rs_context(huc: str, landfire_dir: str, ownership: str, fair_market: str, ec
return {
'DEM': dem_raster,
'Slope': slope_raster,
'ExistingVeg': os.path.join(landfire_dir, 'LC20_EVT_220.tif'),
'HistoricVeg': os.path.join(landfire_dir, 'LC20_BPS_220.tif'),
'ExistingVeg': os.path.join(landfire_dir, LANDFIRE_INPUTS['EVT']),
'HistoricVeg': os.path.join(landfire_dir, LANDFIRE_INPUTS['BPS']),
'NHD': nhd
}

Expand Down