Skip to contents

What it is

wet publishes the mean flow of British Columbia’s Freshwater Atlas stream segments, in cubic metres per second, for each calendar month and for the year. It is public at s3://fresh-bc/discharge/fwa/v1/. The bucket allows no listing, so a reader starts from the manifest, https://fresh-bc.s3.us-west-2.amazonaws.com/discharge/fwa/v1/manifest.json, which lists every part with its rows, size and md5. The current build has 67 parquet parts, 1.84 GB, built on 15 October 2026 at wet commit acb820f.

  • segment_monthly: one row per segment, month and source with a value, 102,790,688 rows. Month 0 is the annual mean and months 1–12 the calendar months.
  • watershed_monthly: the same per fundamental watershed, the small polygon each segment drains, from the water balance only.

Each row comes from one of two sources:

Routed PCIC (pcic_routed, 1951–2012). The Pacific Climate Impacts Consortium runs the VIC-GL hydrologic model on a 0.0625° grid, driven by observed climate, and routes its runoff with the Raven model (hydromosaic). New Graph’s fork of fwapg places PCIC’s outlets on Freshwater Atlas segments and spreads flow between them by drainage area. The annual value is the mean of the twelve months.

Open water balance (wet_balance, 1981–2010). wet’s own estimate, after Chapman et al. (2018): precipitation less actual evapotranspiration from climate normals, averaged over each watershed’s upstream area and adjusted per hydrologic zone against the Water Survey of Canada’s HYDAT gauges. It covers almost all of BC, and its code and inputs are open.

Which value to use

3,374,133 segments have a value from both sources, and the two differ, so one row per segment is marked as the default with pick. It is chosen once per segment, on annual flow, and the same source is picked for every month:

  • routed PCIC, where it has a value;
  • the balance where routed PCIC’s annual flow is under a fifth of the balance’s on a segment that lies on its own watershed’s line. Off that line (side channels, and connectors and waterbody connections the lookup gives another line’s watershed), routed PCIC is kept however low it is;
  • whichever has a value, where only one does.

Of the 4,907,441 segments in the Freshwater Atlas, pick takes routed PCIC on 3,152,838 (64%), the balance on 1,380,005 (28%; 224,199 of them because routed flow is far low), and 374,598 have neither, almost all of them connection lines and secondary channels with no watershed polygon of their own. The balance takes every segment with a value in the Liard, where routed PCIC has none, and 98% of those in the four Nechako Reservoir groups, where routed flow is far below the balance’s (fwapg#24).

The source `pick` takes on main-flow rivers of stream order 5 and up (wider for higher orders), 6% of BC's segments, and the 315 calibration gauges. Smaller streams are not drawn, nor the 1,557 segments of that order with neither.

The source pick takes on main-flow rivers of stream order 5 and up (wider for higher orders), 6% of BC’s segments, and the 315 calibration gauges. Smaller streams are not drawn, nor the 1,557 segments of that order with neither.

How to read it

Read the parts from the bucket with duckdb. scenario, forcing and source are in each part’s path, not the file, so read with hive_partitioning. Parts are sorted by watershed_group_code, so a read for one group opens a few row groups:

library(wet)
cat <- wet_catalog()   # the manifest: one row per part, with its href
segs <- cat$href[cat$dataset == "discharge/fwa/v1/segment_monthly"]

duck <- DBI::dbConnect(duckdb::duckdb())
DBI::dbExecute(duck, "LOAD httpfs")
# the default annual flow on the Bulkley's segments
DBI::dbGetQuery(duck, sprintf("
  SELECT linear_feature_id, source, q_m3s
  FROM read_parquet([%s], hive_partitioning = true)
  WHERE scenario = 'historical' AND watershed_group_code = 'BULK' AND month = 0 AND pick",
  paste0("'", segs, "'", collapse = ", ")))

Or load it into Postgres beside the Freshwater Atlas:

conn <- DBI::dbConnect(RPostgres::Postgres(), dbname = "fwapg")
wet_db_load(conn, cat)   # discharge.fwa_v1_segment_monthly

Besides flow (q_m3s) a row carries runoff_mm, the same water as a depth over the area upstream (NA for a routed row off its watershed’s own line), coverage, the share of that area the balance’s inputs cover, and period.

How good it is

Both sources are scored against mean annual runoff over 1981–2010 at the 315 HYDAT gauges the balance is calibrated on. Error is modelled minus observed, as a percentage of observed. The balance is scored held out: each Water Survey sub-sub-drainage (such as 08EE) is left out of the fit in turn and predicted from the rest, so a gauge’s neighbours on the same river cannot vouch for it.

Error in mean annual runoff at the calibration gauges. PCIC does not list the gauges it calibrated to, so its errors may be partly in sample, and its flow covers 1951–2012 against observations over 1981–2010.
Routed PCIC, 290 gauges Open water balance (held out), 290 gauges Open water balance (held out), all 315 gauges
Mean absolute error 24.1% 27.6% 27.5%
Bias (mean error) +0.2% +9.0% +8.5%
Middle half of errors −14% to +10% −15% to +24% −16% to +24%
Within ±20% 62% 54% 53%

Routed PCIC is closer than the held-out balance at 170 of the 290 gauges both cover. Where each is weak:

  • Headwaters. The balance averages 31% error at headwater gauges, whose basin holds no other gauge, against 18% at nested ones.
  • Small basins. It averages 40% on basins under 100 km² against 20% on those over 1,000 km².
  • The dry interior. In zone 24, the Southern Thompson Plateau, its 9 gauges average 93%: runoff there is a small remainder of precipitation, so a small error in evapotranspiration is a large one in runoff.
  • The Liard. Routed PCIC has no value at 25 gauges, most of them in the Liard, where the balance is the only estimate.

Limits

  • Coverage. Besides the Liard, routed PCIC has no value in a few northern and border basins, and only some on the outer coast’s islands.
  • The zone adjustment is a close call on headwater basins. There it does not beat raw precipitation less evapotranspiration; it is kept for what it does on larger rivers. Zones with too few gauges for their own adjustment get none.
  • Segments without a value. Of the 374,598, 369,217 have no watershed in the lookup through which the balance reaches a segment.

How the balance is built, and how each of its choices was tested: research/water_balance_method.md.

Validation

Every published value is checked against what it was built from when the product is built; the counts compared and differing are in the build report, discharge_publish_20260717.txt. This article’s routed values at the gauges and the picks on its map are read from that build’s published parts, and its data are not written unless the gauge values equal fwapg’s.