Watershed model (SWAT+)¶
Daily water, sediment and nutrient balances of a watershed: the core of the
SWAT+ model (USDA-ARS and Texas A&M AgriLife, version 62.0.1), ported to C++.
For the part of SWAT+ it covers, the port gives SWAT+'s own results, value for
value: weather (measured series and the weather generator), the land phase of
each hydrologic response unit (snow, interception, soil temperature, potential
and actual evapotranspiration, curve number runoff, MUSLE erosion, percolation,
lateral flow, residue and nutrient cycling with the static carbon model, plant
growth, scheduled operations and decision tables), routing units, 1-D aquifers
and SWAT-DEG channels with variable storage or Muskingum routing, and the
tables SWAT+ prints (by day, month, year and average annual). They live in the
ls.hydro.swat module.
A model is a SwatProject: the files of a SWAT+ TxtInOut folder, read with
load_txtinout, or made from the landscape. watershed divides a DEM with
land use and soil maps into subbasins, channels and HRUs as QSWAT+ does,
from_tables writes the project files as the SWAT+ Editor does (the same
files), from_rasters does both. run simulates the project; hru_map and
channel_map put the results back on the map. A project made here also runs
in SWAT+ itself (SwatProject.write).
The erosion of MUSLE uses SWAT+ 62's cover factor C by default: the cover of
the residue times the cover of the growing biomass, in which a tall canopy
hardly protects the soil, so a forest's C (0.5-0.9 under little litter) can
exceed a pasture's. run(..., c_factor="plant") takes the earlier SWAT+
method instead, the plants' minimum C (forest 0.001); only sediment and what
travels with it change.
What the port does not simulate is refused with a clear error when a project uses it (reservoirs, wetlands, pesticides, salts, constituents, Green-Ampt infiltration, the CENTURY carbon model, water allocation...).
import landschaft as ls
project = ls.hydro.swat.load_txtinout("my_model/TxtInOut")
result = ls.hydro.swat.run(project, tables={"hru_ls": "aa", "channel_sd": "day"})
result.table("hru_ls", "aa")["sedyld"] # t/ha per year of each HRU
result.table("channel_sd", "day")["flo_out"] # m3/s leaving each channel
wx = ls.hydro.swat.climate(stations, pcp=pcp, tmax=tmax, tmin=tmin,
monthly={"pcp_hhr": 15.0, "slr_ave": 14.0, "dew_ave": 5.0, "wnd_ave": 3.0})
project = ls.hydro.swat.from_rasters(dem, landuse, soils, landuse_lookup=lu_codes, soil_lookup=soil_codes,
soil_table=usersoil, climate=wx, stream_threshold=2.0)
erosion = ls.hydro.swat.hru_map(project, "sedyld") # t/ha per year, on the DEM's grid
Projects¶
load_txtinout
¶
load_txtinout(path) -> SwatProject
Read a SWAT+ TxtInOut folder, or a zip file of one (the outputs of earlier runs in it are left out).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or path
|
The folder (with |
required |
Returns:
| Type | Description |
|---|---|
SwatProject
|
|
Examples:
The Hubbard Brook W2 example of SWAT+ (SWATPlus-datasets, LGPL-2.1): 10 HRUs, a routing unit, 2 aquifers and a channel, 2000-2002 (its parameters.bsn was written for an earlier SWAT+: the peak rate factor is set to the 484 of SWAT+ 62):
SwatProject
dataclass
¶
The input files of a SWAT+ model (the TxtInOut folder), by name.
Made by load_txtinout(), from_tables() or from_rasters(); run() simulates
it and write() writes the folder for SWAT+ itself. The files are SWAT+
62.0.1's formats; names are matched without regard to case, as on Windows.
Attributes:
| Name | Type | Description |
|---|---|---|
files |
dict
|
|
Examples:
>>> import landschaft as ls
>>> project = ls.hydro.swat.load_txtinout(ls.example_data("swat_hubbard_brook"))
>>> "plants.plt" in project, project.text("time.sim").splitlines()[1].split()
(True, ['day_start', 'yrc_start', 'day_end', 'yrc_end', 'step'])
>>> copy = project.copy()
>>> copy.set_text("time.sim", project.text("time.sim").replace("2002", "2001"))
>>> import tempfile
>>> folder = copy.write(tempfile.mkdtemp()) # a TxtInOut folder SWAT+ itself can run
>>> sorted(p.name for p in folder.iterdir())[:4]
['HQ.tmp', 'STA1.tmp', 'STA14.tmp', 'STA17.tmp']
print_file
¶
The name of the print settings file (file.cio's simulation line, else print.prt).
set_print
¶
Choose what SWAT+ prints (its print.prt): the years it skips before printing and, for each table, the steps printed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
dict or list
|
|
None
|
nyskip
|
int
|
Years simulated before printing (spin-up). |
None
|
Examples:
>>> import landschaft as ls
>>> project = ls.hydro.swat.load_txtinout(ls.example_data("swat_hubbard_brook"))
>>> project.set_print({"hru_ls": ["year", "aa"], "hru_nb": []}, nyskip=1)
>>> [ln.split() for ln in project.text("print.prt").splitlines() if ln.startswith(("hru_ls", "hru_nb"))]
[['hru_nb', 'n', 'n', 'n', 'n'], ['hru_ls', 'n', 'n', 'y', 'y']]
Simulation¶
run
¶
run(
project: SwatProject,
*,
tables=None,
nyskip: int | None = None,
c_factor: str = "swatplus",
) -> SwatResult
Simulate a SWAT+ project, as SWAT+ 62.0.1 does.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project
|
SwatProject
|
The model ( |
required |
tables
|
dict or list
|
What to print, overriding the project's print.prt for this run (see
|
None
|
nyskip
|
int
|
Years simulated before printing, overriding print.prt. |
None
|
c_factor
|
('swatplus', 'plant')
|
The cover and management factor C of MUSLE. |
"swatplus"
|
Returns:
| Type | Description |
|---|---|
SwatResult
|
|
Examples:
>>> import landschaft as ls
>>> project = ls.hydro.swat.load_txtinout(ls.example_data("swat_hubbard_brook"))
>>> result = ls.hydro.swat.run(project, tables={"hru_wb": "aa", "channel_sd": ["day", "aa"]}, nyskip=0)
>>> wb = result.table("hru_wb", "aa") # average annual water balance of each HRU
>>> wb[["precip", "et", "surq_gen", "latq", "perc"]].astype(float).round(1).head(3) # mm per year
precip et surq_gen latq perc
date hru
2002-12-31 1 1243.8 314.2 444.1 1.3 448.8
2 1243.8 314.2 440.0 10.9 443.4
3 1243.8 314.2 436.9 18.0 439.5
>>> q = result.table("channel_sd", "day")["flo_out"] # m3/s leaving the channel
>>> round(float(q.mean()), 3), result.units["channel_sd"]["flo_out"]
(0.005, 'm^3/s')
SwatResult
dataclass
¶
SwatResult(
weather: DataFrame,
tables: dict = dict(),
units: dict = dict(),
warnings: list = list(),
)
Bases: Saveable
What run() simulated.
Attributes:
| Name | Type | Description |
|---|---|---|
weather |
DataFrame
|
The daily weather of each station (index |
tables |
dict
|
What SWAT+ printed (its print.prt, see |
units |
dict
|
|
warnings |
list
|
What SWAT+ would write to |
Examples:
>>> import landschaft as ls
>>> project = ls.hydro.swat.load_txtinout(ls.example_data("swat_hubbard_brook"))
>>> result = ls.hydro.swat.run(project, tables={"basin_wb": ["month", "year"]}, nyskip=1)
>>> result
SwatResult(1096 days, tables: hru_wb[day/month/year/aa], hru_nb[day/month/year/aa], hru_ls[day/month/year/aa], hru_pw[day/month/year/aa], basin_wb[month/year], basin_nb[day/month/year/aa], basin_ls[day/month/year/aa], basin_pw[day/month/year/aa], channel_sd[day/month/year/aa], aquifer[day/month/year/aa])
>>> result.table("basin_wb", "year")[["precip", "et", "surq_gen", "perc"]].astype(float).round(1)
precip et surq_gen perc
date
2001-12-31 1004.1 128.3 356.0 536.7
2002-12-31 1319.2 126.5 532.1 594.6
>>> result.units["basin_wb"]["et"]
'mm'
table
¶
One printed table: result.table("hru_wb", "month").
From the landscape¶
watershed
¶
watershed(
dem,
landuse,
soils,
*,
landuse_lookup,
soil_lookup,
soil_table,
stream_threshold: float | None = None,
outlets=None,
snap: float | None = None,
slope_bands=(),
hru_method: str = "dominant_hru",
thresholds=(0.0, 0.0, 0.0),
min_area: float = 0.0,
area_in_ha: bool = True,
exempt=(),
n_threads: int | None = None,
) -> SwatWatershed
Divide a watershed into subbasins, channels and HRUs, as QSWAT+ does.
The DEM is filled (fill()), drains along D8 directions, and every
cell whose drainage area reaches stream_threshold is a stream. Each stream link
(stream_links(), split at the outlets) is a channel with its
subbasin (watersheds()) and one landscape unit (QSWAT+ without
landscapes); each subbasin has a shallow aquifer, each watershed outlet a deep one.
HRUs are the combinations of land use, soil and slope band in a landscape unit,
selected by hru_method. Channel width and depth come from the drainage area
(QSWAT+'s 1.29 A^0.6 and 0.13 A^0.4, A in km2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dem
|
The elevations (m), in a projected CRS (or longitude / latitude). |
required | |
landuse
|
Land use and soil maps (integer codes), resampled onto the DEM's cells (nearest neighbour) when their grids differ. |
required | |
soils
|
Land use and soil maps (integer codes), resampled onto the DEM's cells (nearest neighbour) when their grids differ. |
required | |
landuse_lookup
|
Land use code -> SWAT+ plant or urban name ( |
required | |
soil_lookup
|
Soil code -> soil name ( |
required | |
soil_table
|
The soils: a |
required | |
stream_threshold
|
float | None
|
The drainage area of a stream, in km2 (default: 1 % of the DEM's area, as QSWAT+ proposes). |
None
|
outlets
|
Watershed outlets (points; |
None
|
|
slope_bands
|
Slope limits in percent between the bands, e.g. |
()
|
|
hru_method
|
('dominant_hru', 'dominant', 'filter', 'area')
|
QSWAT+'s choices: one HRU per landscape unit with the largest combination
( |
"dominant_hru"
|
exempt
|
Land use names never removed by the filters. |
()
|
Returns:
| Type | Description |
|---|---|
SwatWatershed
|
|
Examples:
A 1 km2 stream threshold, one HRU per subbasin (QSWAT+'s default):
>>> w = ls.hydro.swat.watershed(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], stream_threshold=1.0)
>>> w
SwatWatershed(33 subbasins, 33 HRUs, 8075.9 ha)
>>> w.tables["gis_hrus"][["lsu", "landuse", "soil", "slope", "arsub"]].round(1).head(3)
lsu landuse soil slope arsub
0 10 FRSD UPLAND_LOAM 31.9 228.5
1 20 FRSD UPLAND_LOAM 47.9 38.4
2 30 FRSD UPLAND_LOAM 23.0 116.9
Every combination above 10 % of land use, soil and slope (bands 0-15-35-9999 %):
>>> many = ls.hydro.swat.watershed(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], stream_threshold=1.0,
... hru_method="filter", thresholds=(10, 10, 10), slope_bands=(15, 35))
>>> len(many.tables["gis_hrus"])
128
SwatWatershed
dataclass
¶
SwatWatershed(
tables: dict,
subbasins: DataArray,
hrus: DataArray,
channels: DataArray,
notes: list = list(),
)
A watershed divided as QSWAT+ divides it, ready for the SWAT+ Editor's import.
Made by watershed(); from_tables() turns it into a SWAT+ project.
Attributes:
| Name | Type | Description |
|---|---|---|
tables |
dict
|
QSWAT+'s project tables, as DataFrames with its columns: |
subbasins |
DataArray
|
The subbasin (= channel, SWAT+ numbering) of each cell, 0 outside the watershed, NaN where the DEM is missing. |
hrus |
DataArray
|
The HRU of each cell ( |
channels |
DataArray
|
The channel of each stream cell, 0 elsewhere. |
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> w = ls.hydro.swat.watershed(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], stream_threshold=1.0)
>>> w.subbasins.shape, int(w.subbasins.max())
((371, 273), 33)
>>> sorted(w.tables)[:4]
['gis_aquifers', 'gis_channels', 'gis_deep_aquifers', 'gis_hrus']
from_tables
¶
from_tables(
watershed,
climate: SwatClimate,
*,
start=None,
end=None,
codes: dict | None = None,
name: str = "landschaft",
) -> SwatProject
A SWAT+ project from QSWAT+'s tables and the weather, as the SWAT+ Editor makes it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
watershed
|
SwatWatershed or dict
|
The subbasins, channels, landscape units, HRUs, aquifers, routing and soils:
a |
required |
climate
|
SwatClimate
|
The weather ( |
required |
start
|
The simulated period (default: the days all weather files cover, as the editor sets it). |
None
|
|
end
|
The simulated period (default: the days all weather files cover, as the editor sets it). |
None
|
|
codes
|
dict
|
Columns of |
None
|
name
|
str
|
The project name ( |
'landschaft'
|
Returns:
| Type | Description |
|---|---|
SwatProject
|
|
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> w = ls.hydro.swat.watershed(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], stream_threshold=1.0)
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> project = ls.hydro.swat.from_tables(w, wx)
>>> project
SwatProject(62 files)
>>> project.text("time.sim").splitlines()[2].split()
['0', '2001', '0', '2004', '0']
>>> print(project.text("hru-data.hru").splitlines()[2])
1 hru01 topohru01 hyd01 UPLAND_LOAM frsd_lum soilplant1 null snow001 null
from_rasters
¶
from_rasters(
dem,
landuse,
soils,
*,
landuse_lookup,
soil_lookup,
soil_table,
climate: SwatClimate,
start=None,
end=None,
codes: dict | None = None,
name: str = "landschaft",
**options,
) -> SwatProject
A SWAT+ project from a DEM, land use and soil maps, tables and the weather.
watershed() divides the landscape as QSWAT+ does, from_tables() writes
the project as the SWAT+ Editor does; the project runs in run() (or in
SWAT+ itself, write()), and keeps the division
(project.watershed) for hru_map() and channel_map().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dem
|
As |
required | |
landuse
|
As |
required | |
soils
|
As |
required | |
landuse_lookup
|
As |
required | |
soil_lookup
|
As |
required | |
soil_table
|
As |
required | |
climate
|
SwatClimate
|
The weather ( |
required |
start
|
As |
None
|
|
end
|
As |
None
|
|
codes
|
As |
None
|
|
name
|
As |
None
|
|
**options
|
Passed to |
{}
|
Returns:
| Type | Description |
|---|---|
SwatProject
|
|
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> project = ls.hydro.swat.from_rasters(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], climate=wx,
... stream_threshold=1.0)
>>> project
SwatProject(62 files)
>>> project.watershed
SwatWatershed(33 subbasins, 33 HRUs, 8075.9 ha)
>>> result = ls.hydro.swat.run(project, tables={"basin_wb": "aa"})
>>> result.table("basin_wb", "aa")[["precip", "et", "surq_gen", "latq", "perc"]].astype(float).round(1)
precip et surq_gen latq perc
date
2004-12-31 1108.2 507.9 258.7 21.1 294.5
load_qswat_project
¶
The tables of a QSWAT+ project database, for from_tables().
Reads gis_subbasins, gis_channels, gis_lsus, gis_hrus,
gis_aquifers, gis_deep_aquifers, gis_points, gis_routing,
soils_sol and soils_sol_layer from the .sqlite QSWAT+ writes (the
projects without landscapes, lakes, reservoirs or point sources).
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> w = ls.hydro.swat.watershed(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], stream_threshold=1.0)
>>> import sqlite3, tempfile, pathlib
>>> db = pathlib.Path(tempfile.mkdtemp()) / "project.sqlite"
>>> with sqlite3.connect(db) as conn:
... for name, table in w.tables.items():
... _ = table.to_sql(name, conn, index=False)
...
>>> tables = ls.hydro.swat.load_qswat_project(db)
>>> len(tables["gis_hrus"]), sorted(tables)[:3]
(33, ['gis_aquifers', 'gis_channels', 'gis_deep_aquifers'])
example_landscape
¶
The inputs of a small watershed model, from the package's example rasters.
The terrain is the example DEM "orelevation" (11 km x 8 km of the Oregon
Cascades, 433-1390 m) projected to UTM zone 10 at 30 m; the land use comes from
the NDVI "orforest" (forest, FRSD, where it exceeds 0.55, else pasture,
PAST); the soils are two made-up soils by elevation (a group B loam above 900
m, a group C clay loam below); the weather is made up too: one station at the
map's centre, daily rain and temperature for 2001-2004 from a seeded generator
(wet winters, dry summers, about 1100 mm a year). Ready for
watershed() / from_rasters() and climate().
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
Weather¶
climate
¶
climate(
stations,
*,
pcp,
tmax,
tmin,
slr=None,
hmd=None,
wnd=None,
wgn=None,
monthly: dict | None = None,
) -> SwatClimate
The weather of a SWAT+ project from tables.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stations
|
DataFrame
|
One row per station (index: name), with |
required |
pcp
|
Daily DataFrames (index: dates; columns: station names): precipitation (mm), maximum and minimum temperature (deg C), solar radiation (MJ/m2), relative humidity (fraction) and wind speed (m/s). Missing days are NaN (-99 for SWAT+, which generates them); a variable SWAT+ does not get is generated. |
required | |
tmax
|
Daily DataFrames (index: dates; columns: station names): precipitation (mm), maximum and minimum temperature (deg C), solar radiation (MJ/m2), relative humidity (fraction) and wind speed (m/s). Missing days are NaN (-99 for SWAT+, which generates them); a variable SWAT+ does not get is generated. |
required | |
tmin
|
Daily DataFrames (index: dates; columns: station names): precipitation (mm), maximum and minimum temperature (deg C), solar radiation (MJ/m2), relative humidity (fraction) and wind speed (m/s). Missing days are NaN (-99 for SWAT+, which generates them); a variable SWAT+ does not get is generated. |
required | |
slr
|
Daily DataFrames (index: dates; columns: station names): precipitation (mm), maximum and minimum temperature (deg C), solar radiation (MJ/m2), relative humidity (fraction) and wind speed (m/s). Missing days are NaN (-99 for SWAT+, which generates them); a variable SWAT+ does not get is generated. |
required | |
hmd
|
Daily DataFrames (index: dates; columns: station names): precipitation (mm), maximum and minimum temperature (deg C), solar radiation (MJ/m2), relative humidity (fraction) and wind speed (m/s). Missing days are NaN (-99 for SWAT+, which generates them); a variable SWAT+ does not get is generated. |
required | |
wnd
|
Daily DataFrames (index: dates; columns: station names): precipitation (mm), maximum and minimum temperature (deg C), solar radiation (MJ/m2), relative humidity (fraction) and wind speed (m/s). Missing days are NaN (-99 for SWAT+, which generates them); a variable SWAT+ does not get is generated. |
required | |
wgn
|
DataFrame
|
The weather generator statistics, as |
None
|
monthly
|
dict | None
|
Passed to |
None
|
Returns:
| Type | Description |
|---|---|
SwatClimate
|
|
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> wx
SwatClimate(1 stations, pcp, tmax, tmin)
>>> wx.period()
(Timestamp('2001-01-01 00:00:00'), Timestamp('2004-12-31 00:00:00'))
>>> wx.wgn.loc["valley", ["tmp_max_ave", "tmp_min_ave", "pcp_ave", "wet_dry", "pcp_days"]].round(2).head(3)
tmp_max_ave tmp_min_ave pcp_ave wet_dry pcp_days
month
1 5.59 -4.83 151.68 0.78 21.75
2 7.40 -3.06 172.35 0.52 16.25
3 10.59 -0.04 106.60 0.39 15.25
SwatClimate
dataclass
¶
The weather of a SWAT+ project (made by climate()).
Attributes:
| Name | Type | Description |
|---|---|---|
stations |
DataFrame
|
Index: the station names; |
series |
dict
|
|
wgn |
DataFrame
|
The weather generator: index (station, month 1-12), the |
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> sorted(wx.series)
['pcp', 'tmax', 'tmin']
>>> wx.stations
lat lon elev
valley 43.050142 -122.950156 899.0123
wgn_from_series
¶
wgn_from_series(
pcp: DataFrame,
tmax: DataFrame,
tmin: DataFrame,
*,
slr=None,
hmd=None,
wnd=None,
dewpoint=None,
monthly: dict | None = None,
) -> DataFrame
SWAT's weather generator statistics (WXGEN) of each station, from daily series.
By calendar month over all years: the means and sample standard deviations of
the daily maximum and minimum temperature; the mean monthly precipitation
(pcp_ave: the month's total, averaged over the years with data), the
standard deviation and skew coefficient of the daily precipitation (all days),
the probabilities of a wet day after a dry and after a wet day, the mean number
of wet days (precipitation above 0); the mean daily solar radiation, dew point
and wind speed when the series are given.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pcp
|
DataFrame
|
Daily DataFrames (dates x stations): precipitation (mm), maximum and minimum temperature (deg C). |
required |
tmax
|
DataFrame
|
Daily DataFrames (dates x stations): precipitation (mm), maximum and minimum temperature (deg C). |
required |
tmin
|
DataFrame
|
Daily DataFrames (dates x stations): precipitation (mm), maximum and minimum temperature (deg C). |
required |
slr
|
Optional daily solar radiation (MJ/m2), wind speed (m/s) and dew point (deg C). |
None
|
|
wnd
|
Optional daily solar radiation (MJ/m2), wind speed (m/s) and dew point (deg C). |
None
|
|
dewpoint
|
Optional daily solar radiation (MJ/m2), wind speed (m/s) and dew point (deg C). |
None
|
|
hmd
|
Daily relative humidity (fraction): with |
None
|
|
monthly
|
dict | None
|
Values not derived from daily data, by column ( |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Index (station, month); the |
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wgn = ls.hydro.swat.wgn_from_series(ex["pcp"], ex["tmax"], ex["tmin"], monthly=ex["monthly"])
>>> wgn.loc["valley", ["pcp_ave", "pcp_sd", "wet_dry", "wet_wet"]].round(3).head(3)
pcp_ave pcp_sd wet_dry wet_wet
month
1 151.675 7.289 0.784 0.663
2 172.350 9.764 0.522 0.612
3 106.600 6.234 0.391 0.600
Results on the map¶
hru_map
¶
hru_map(
project, variable, *, how: str = "annual", result=None, c_factor: str = "swatplus"
) -> DataArray
An HRU result on the map: each cell takes the value of its HRU.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project
|
SwatProject
|
A project of |
required |
variable
|
str or Series
|
A column of an HRU table ( |
required |
how
|
('annual', 'mean', 'max', 'sum')
|
|
"annual"
|
result
|
SwatResult
|
A run of the project that printed the HRU table ( |
None
|
c_factor
|
('swatplus', 'plant')
|
The USLE C factor of that run (see |
"swatplus"
|
Returns:
| Type | Description |
|---|---|
DataArray
|
On the DEM's grid; NaN outside the watershed and on cells whose land use, soil and slope combination was folded into other HRUs. |
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> project = ls.hydro.swat.from_rasters(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], climate=wx,
... stream_threshold=1.0)
>>> result = ls.hydro.swat.run(project, tables={"hru_ls": "aa", "hru_wb": "aa"}, c_factor="plant")
>>> loss = ls.hydro.swat.hru_map(project, "sedyld", result=result) # t/ha per year, plants' minimum C
>>> loss.shape == ex["dem"].shape, round(float(loss.mean()), 3)
(True, 0.379)
>>> runoff = ls.hydro.swat.hru_map(project, "surq_gen", result=result) # mm per year
>>> round(float(runoff.min()), 1), round(float(runoff.max()), 1)
(1.9, 445.5)
channel_map
¶
A channel result on the stream cells (by default the mean discharge, m3/s).
values: a column of the channel table (CHANNEL_COLUMNS, default
"flo_out") or values by channel number; how and result as
hru_map(). NaN off the streams.
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> project = ls.hydro.swat.from_rasters(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], climate=wx,
... stream_threshold=1.0)
>>> flow = ls.hydro.swat.channel_map(project) # mean m3/s leaving each channel, on the stream cells
>>> round(float(flow.max()), 3)
0.609
reach_discharge
¶
The daily discharge leaving each channel (m3/s, channel_sd's flo_out):
dates x channel number. result: a run that printed channel_sd by day.
Examples:
>>> import landschaft as ls
>>> ex = ls.hydro.swat.example_landscape()
>>> wx = ls.hydro.swat.climate(ex["stations"], pcp=ex["pcp"], tmax=ex["tmax"], tmin=ex["tmin"], monthly=ex["monthly"])
>>> project = ls.hydro.swat.from_rasters(ex["dem"], ex["landuse"], ex["soils"], landuse_lookup=ex["landuse_lookup"],
... soil_lookup=ex["soil_lookup"], soil_table=ex["soil_table"], climate=wx,
... stream_threshold=1.0)
>>> q = ls.hydro.swat.reach_discharge(project) # days x channels, m3/s
>>> q.shape, round(float(q.max().max()), 2)
((1096, 33), 11.1)