riverarchitect.stranding

Fish stranding risk from wetted areas that disconnect as a hydrograph recedes.

The open-source replacement for the ArcGIS StrandingRisk module. As discharge falls the wetted area shrinks and breaks apart; pools that lose their connection to the main channel trap fish. That is a connected-component problem: threshold the depth raster at the minimum swimming depth of the species and lifestage in question, label the wetted regions, and every region except the one still joined to the main channel is a stranding risk.

Outputs

  • one disconnected_<Q>.tif per discharge;

  • Q_disconnect.tif - the highest discharge at which each cell was disconnected, i.e. the flow at which that spot becomes a trap as the hydrograph recedes;

  • a polygon layer of the individual pools at the worst discharge;

  • a per-discharge table of wetted area, stranded area and pool count.

Relation to the original

The original built a least-cost “escape route” raster per discharge and called a cell disconnected when no route reached the low-flow target polygon - the largest wetted region at the lowest analysed discharge. With the depth threshold applied first, a route exists exactly when the region touches that target, so the least-cost search reduces to the connected-component rule in riverarchitect.raster.disconnected_mask(), seeded from the same low-flow mainstem. target_discharge chooses the discharge that defines it.

The velocity criterion of the original (a fish cannot swim upstream against more than u_max) is not applied; see StrandingRisk.velocity_limited for the flag that records this, and StrandingRisk.u_max for the threshold that would have been used.

riverarchitect.stranding.TRAVEL_THRESHOLDS = {('Chinook salmon', 'adult'): {'h_min': 0.9, 'u_max': 11.0}, ('Chinook salmon', 'fry'): {'h_min': 0.2, 'u_max': 1.9}, ('Chinook salmon', 'juvenile'): {'h_min': 0.3, 'u_max': 1.9}}

Fallback minimum swimming depth and maximum swimming speed per species and lifestage, in U.S. customary units. The packaged Fish.xlsx is the authority - for_fish() reads it first, exactly as the original’s cFish.get_travel_threshold did - and this table is only consulted when the workbook defines no threshold for the pair asked for. Keys are matched case-insensitively, because the workbook writes "Chinook Salmon" while the literature and this table write "Chinook salmon".

riverarchitect.stranding.travel_thresholds(species, lifestage, fish=None)[source]

Swimming thresholds for a species and lifestage.

Reads the Fish.xlsx habitat database first and falls back to TRAVEL_THRESHOLDS, so a pair the workbook does not cover still resolves and a project that has edited its workbook is honoured.

Parameters:
  • species (str) – common name; case and spacing are ignored.

  • lifestage (str) – lifestage; case and spacing are ignored.

  • fish (riverarchitect.sharc.FishDatabase) – an open database to reuse. Optional.

Returns:

{"h_min": ..., "u_max": ...}, with whichever keys are defined.

Return type:

dict

Raises:

KeyError – when neither source defines a minimum swimming depth for the pair.

class riverarchitect.stranding.StrandingRisk(condition, discharges=None, h_min=0.2, unit='us', connectivity=4, target_discharge=None)[source]

Bases: object

Connectivity analysis over a receding hydrograph.

Parameters:
  • condition (Condition or str) – the condition, or its name.

  • discharges (list) – discharges to walk, highest first. Defaults to every hydraulic raster in the condition, sorted descending.

  • h_min (float) – minimum swimming depth. Below it a cell does not count as wetted.

  • unit (str) – "us" or "si"; must match the condition’s rasters.

  • connectivity (int) – 4 (arcpy’s RegionGroup default) or 8.

  • target_discharge (float) – the discharge whose main channel every other discharge is judged against. Defaults to the lowest analysed discharge, which is what the original’s get_target_raster used: the mainstem is the largest wetted region at low flow, and a pool is stranded when no route reaches it. Pass False to fall back to the largest region at each discharge separately.

Variables:

velocity_limited (bool) – always False - the velocity criterion of the original is not applied. Recorded so a caller can state it alongside a result.

velocity_limited = False
species = None

Species and lifestage the thresholds came from, when built by for_fish().

lifestage = None
u_max = None

Maximum swimming speed of that lifestage, recorded but not applied. See velocity_limited.

classmethod for_fish(condition, species='Chinook salmon', lifestage='fry', fish=None, **kwargs)[source]

Build with the travel thresholds of a species and lifestage.

Parameters:
  • condition (Condition or str) – the condition, or its name.

  • species (str) – common name; case and spacing are ignored.

  • lifestage (str) – lifestage; case and spacing are ignored.

  • fish (riverarchitect.sharc.FishDatabase) – an open database to reuse. Optional.

  • **kwargs – passed to the constructor. An explicit h_min wins over the database.

main_channel(reference)[source]

The mainstem a pool has to reach to count as connected, or None.

The largest wetted region at target_discharge. Computed once and reused for every discharge, so a pool that is cut off at low flow stays counted as cut off even when a higher flow happens to make some floodplain patch larger than the channel.

run(output_dir=None, write_rasters=True)[source]

Walk the recession and quantify the disconnected area at each discharge.

Returns:

per_discharge (list of row dicts), total_disconnected_area, worst_discharge, area_unit and the paths written.

Return type:

dict

write_pools(discharge, output_dir, reference=None)[source]

Polygonise the disconnected pools at one discharge into a GeoPackage.