riverarchitect.sharc
SHArC: habitat suitability and Seasonal Habitat Area.
The open-source replacement for the ArcGIS SHArC module. It turns 2D hydrodynamic
results into a map of how good the habitat is for a given fish species and lifestage, and
then into a single number a project can be judged on.
The chain
Habitat suitability curves come from
Fish.xlsx: for each species and lifestage, a piecewise-linear curve mapping flow depth, flow velocity, substrate size or cover radius onto a suitability index between 0 and 1.Hydraulic HSI rasters apply those curves to the depth and velocity rasters of a discharge, giving
dsi(depth) andvsi(velocity).Composite HSI (
cHSI) combines them, by geometric mean or product, optionally including a cover HSI, and is masked to the wetted area.Usable area at a discharge is the area where
cHSIexceeds a threshold, optionally weighted by the meancHSIthere.SHArea integrates usable area over the flow duration curve, so a habitat area that only exists at a rare discharge counts for little.
Relation to the original
cHSI.nested_con_raster_calc built one Con() raster per curve segment and took their
cell-wise maximum. That is a piecewise-linear interpolation written the only way arcpy map
algebra allowed; here it is apply_curve(), which is numpy.interp() with the same
end behaviour - hold the first value below the curve, drop to zero above it. The SHArea
integration reproduces the =(E5-E4)/100*F5 column of the original
CONDITION_sharea_template.xlsx.
- class riverarchitect.sharc.FishDatabase(path=None)[source]
Bases:
objectHabitat suitability curves, read from a
Fish.xlsxin the original layout.- Parameters:
path (str) – workbook path. Defaults to the one shipped with the package.
- Variables:
species (list) – species common names, in workbook order.
- resolve_species(species)[source]
Match a species name against the workbook, ignoring case and spacing.
The workbook writes
"Chinook Salmon"; papers, file names and the rest of this package write"Chinook salmon". Matching exactly would make a caller’s choice of capitalisation decide whether an analysis runs, so it does not.
- resolve_lifestage(species, lifestage)[source]
Match a lifestage of a species, ignoring case and spacing.
- static shortname(species, lifestage)[source]
Four-letter code the original used in file names:
chsp,chju, …
- curve(species, lifestage, parameter)[source]
Habitat suitability curve for one species, lifestage and parameter.
- cover_value(species, lifestage, cover_type)[source]
Radius and suitability of a cover type, or None when it is not defined.
- season_dates(species, lifestage)[source]
Start and end of the lifestage’s season, as
(month, day)pairs.Rows 6 and 7 of the lifestage’s suitability column, which is where
cFish.get_season_datesread them. The year in the cell is a placeholder and is ignored; a season that ends before it starts wraps into the next year.- Returns:
((start_month, start_day), (end_month, end_day)), orNonewhen the workbook gives no season for this lifestage.- Return type:
- riverarchitect.sharc.apply_curve(array, curve)[source]
Map raster values onto a habitat suitability index through a piecewise-linear curve.
Replaces
cHSI.HHSI.nested_con_raster_calc. Below the first curve point the first suitability is held; above the last point the suitability is zero, not held - a depth or velocity beyond the curve is unsuitable, not maximally suitable, and clamping there would invent habitat at the highest discharges.- Parameters:
array (numpy.ndarray) – depth, velocity or grain size, with
numpy.nanNoData.curve (tuple) –
(x, y)fromFishDatabase.curve().
- Returns:
suitability index, NoData preserved.
- Return type:
- riverarchitect.sharc.cover_hsi(species, lifestage, layers, profile, unit='us', fish=None, depth=None)[source]
Cover habitat suitability: shelter from substrate, cobbles, boulders, plants and wood.
Depth and velocity say whether a fish can be somewhere. Cover says whether it is safe to be there - a fry in open water at the right depth and velocity is still a meal. The original offered this as the cover option of SHArC and it is what separates a hydraulic habitat model from an ecohydraulic one.
Two kinds of layer, dispatched as
cHSI.CovHSI.call_analysisdid:substratea grain size raster, mapped through its suitability curve like depth or velocity.
cobbles,boulders,plants,woodpresence layers.
cobblesandbouldersare cut out of a grain size raster by the diameter ranges inGRAIN_SIZE_LIMITS;plantsandwoodare given directly. Each element then shelters everything within its radius, taken from the first x value of its curve, and those cells take the curve’s suitability.
The result is the cell-wise maximum across the types present: the best shelter available at a cell is what counts, not the sum of every kind of it.
- Parameters:
species (str) – common name; case and spacing are ignored.
lifestage (str) – lifestage; case and spacing are ignored.
layers (dict) –
{cover type: array}.cobblesandbouldersmay be omitted and derived from asubstrategrain size raster instead.profile (dict) – the raster profile the layers are on, for the cell size.
unit (str) –
"us"or"si"; the grain limits are converted accordingly.fish (FishDatabase) – the curve database. Built by default.
depth (numpy.ndarray) – flow depth. When given, cover is cropped to cells at least as deep as the first point of the depth curve, as the original’s
crop_input_rasterdid - cover a fish cannot reach shelters nothing.
- Returns:
(cover, used)- the suitability array with NoData where no cover applies, and the list of cover types that contributed.(None, [])when none did.- Return type:
- class riverarchitect.sharc.SHArC(condition, unit='us', combine_method='geometric_mean', fish=None, threshold=0.4)[source]
Bases:
objectHabitat suitability analysis for one condition.
- Parameters:
unit (str) –
"us"or"si"; must match the condition’s rasters.combine_method (str) –
"geometric_mean"or"product".fish (FishDatabase) – the curve database. Defaults to the packaged
Fish.xlsx.threshold (float) – cHSI above which a cell counts as usable habitat.
- Variables:
error (bool) – True when at least one discharge could not be processed.
- property discharges
Discharges with both a depth and a velocity raster, ascending.
- composite_hsi(species, lifestage, discharge, reference=None, cover=None, cover_layers=None)[source]
Composite habitat suitability at one discharge.
- Parameters:
species (str) – common name; case and spacing are ignored.
lifestage (str) – lifestage; case and spacing are ignored.
discharge (float) – the discharge to evaluate.
reference (dict) – profile every raster is aligned onto.
cover (numpy.ndarray) – a ready-made cover suitability array.
cover_layers (dict) – cover inputs, from which one is built with
cover_hsi(). Ignored whencoveris given.
- Returns:
(chsi, profile), or(None, None)when the curves are missing.- Return type:
- usable_area(chsi, profile, weighted=False)[source]
Area where cHSI exceeds the threshold, optionally weighted by the mean cHSI.
- cover_layers(extra=None)[source]
Cover layers available in the condition, on its own grid.
Looks for the rasters the cover analysis can use: the grain size raster named by
input_definitions.inpforsubstrate(and, through it, cobbles and boulders), andplants.tif/wood.tifbeside the condition.
- run(species, lifestage, discharges=None, output_dir=None, weighted=False, write_rasters=True, flow_duration=None, cover=False)[source]
Map habitat suitability across discharges and compute SHArea.
- Parameters:
species (str) – common name from the fish database.
lifestage (str) – lifestage from the fish database.
discharges (list) – discharges to evaluate. Defaults to all available.
output_dir (str) – where the cHSI rasters go.
weighted (bool) – weight usable area by the mean cHSI, as the original’s apply weighting option did.
write_rasters (bool) – write one
csi_<code><Q>.tifper discharge.flow_duration (str or dict) – a flow duration workbook, or a
{discharge: % exceedance}mapping. Without it SHArea is not computed.cover (bool or dict) – include a cover habitat suitability index.
Trueuses whatevercover_layers()finds in the condition; a dict supplies or overrides layers. Seecover_hsi().
- Returns:
per_dischargerows,shareawhen a flow duration was given, and the paths written.- Return type:
Integrate usable area over the flow duration curve.
Reproduces the
(E_i - E_{i-1}) / 100 * F_icolumn of the original workbook: a Riemann sum of usable area over cumulative exceedance probability, so habitat that exists only at a rare discharge contributes little.
- riverarchitect.sharc.COMBINE_METHODS = ('geometric_mean', 'product')
Ways of combining the individual suitability indices into a composite one.
- riverarchitect.sharc.COVER_TYPES = ('substrate', 'cobbles', 'boulders', 'plants', 'wood')
Cover types the habitat database defines a curve for, in the order the original combined them.
substrateis a suitability curve on grain size; the rest are presence layers whose influence spreads over a radius.
- riverarchitect.sharc.GRAIN_SIZE_LIMITS = {'boulders': (0.256, 100.0), 'cobbles': (0.064, 0.256)}
Grain diameter range that defines each grain-based cover type, in metres, as
cHSI.CovHSI.define_grain_sizehad them. Converted for a condition in U.S. customary units.