You will need these packages. Must use the development version of
hydromad
, requires a working compiler (RTools on
Windows).
library(aqp)
library(soilDB)
library(sharpshootR)
# special installation instructions:
# https://github.com/josephguillaume/hydromad#installation
library(hydromad)
Simulate monthly water balances for 50cm of sandy loam vs. 50cm of silt loam soil material in a xeric/thermic climate.
data("ROSETTA.centroids")
idx <- which(ROSETTA.centroids$texture %in% c('sandy loam', 'silt loam'))
vars <- c('texture', 'pwp', 'fc', 'sat', 'awc')
knitr::kable(
ROSETTA.centroids[idx, vars],
row.names = FALSE
)
texture | pwp | fc | sat | awc |
---|---|---|---|---|
sandy loam | 0.0624426 | 0.167354 | 0.3870001 | 0.1049114 |
silt loam | 0.0858854 | 0.293965 | 0.4390000 | 0.2080796 |
# near Sonora, CA
# thermic / xeric climate
# units are mm
PET <- c(0, 0, 5,80, 90, 120, 130, 140, 110, 90, 20, 5)
PPT <- c(0, 150, 200, 120, 20, 0, 0, 0, 10, 20, 30, 60)
# 50cm of soil material -> convert to mm
thick <- 50 * 10
# total water storage for sandy loam texture soil material
AWC.sl <- round(0.1049114 * thick)
# total water storage for silt loam texture soil material
AWC.sil <- round(0.2080796 * thick)
# simulate water balances:
# * run for 5 cycles
# * start in January
# * start with "completely dry" soil conditions
# * keep only the last cycle
wb.sl <- monthlyWB(AWC.sl, PPT, PET, S_init = 0, starting_month = 1, rep = 5, keep_last = TRUE, distribute = TRUE)
wb.sil <- monthlyWB(AWC.sil, PPT, PET, S_init = 0, starting_month = 1, rep = 5, keep_last = TRUE, distribute = TRUE)
All values are mm. U: surplus, S: soil water storage, ET: actual ET, D: deficit.
knitr::kable(wb.sil, digits = 2, row.names = FALSE)
PPT | PET | U | S | ET | D | month | mo | .sim |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0.00 | 95.94 | 0.00 | 0.00 | 1 | Jan | 5 |
150 | 0 | 141.94 | 104.00 | 0.00 | 0.00 | 2 | Feb | 5 |
200 | 5 | 195.00 | 104.00 | 5.00 | 0.00 | 3 | Mar | 5 |
120 | 80 | 40.00 | 104.00 | 80.00 | 0.00 | 4 | Apr | 5 |
20 | 90 | 0.00 | 54.72 | 69.28 | -20.72 | 5 | May | 5 |
0 | 120 | 0.00 | 16.06 | 38.66 | -81.34 | 6 | Jun | 5 |
0 | 130 | 0.00 | 4.22 | 11.83 | -118.17 | 7 | Jul | 5 |
0 | 140 | 0.00 | 1.00 | 3.23 | -136.77 | 8 | Aug | 5 |
10 | 110 | 0.00 | 6.02 | 4.98 | -105.02 | 9 | Sep | 5 |
20 | 90 | 0.00 | 15.01 | 11.01 | -78.99 | 10 | Oct | 5 |
30 | 20 | 0.00 | 39.36 | 5.65 | -14.35 | 11 | Nov | 5 |
60 | 5 | 0.00 | 95.94 | 3.42 | -1.58 | 12 | Dec | 5 |
# compare
par(mar=c(4,4,4,1), bg = 'white', mfcol = c(1, 2))
plotWB(WB = wb.sl, legend.cex = 0.75)
title('50cm of sandy loam texture soil material', line = 3)
plotWB(WB = wb.sil, legend.cex = 0.75)
title('50cm of silt loam texture soil material', line = 3)
# compare
par(mar=c(4,4,4,1), bg = 'white', mfcol = c(1, 2))
plotWB_lines(WB = wb.sl)
title('50cm of sandy loam texture soil material', line = 3)
plotWB_lines(WB = wb.sil)
title('50cm of silt loam texture soil material', line = 3)
As of sharpshootR 2.2, it is possible to “distribute” monthly data into k bins within each month.
Run a single water balance cycle, starting with a completely dry soil. Test the effect of distributing monthly values into 10 bins per month.
wb.sl1 <- monthlyWB(AWC.sil, PPT, PET, S_init = 0, starting_month = 1, rep = 1, distribute = FALSE)
wb.sl2 <- monthlyWB(AWC.sil, PPT, PET, S_init = 0, starting_month = 1, rep = 1, , distribute = TRUE, k = 10, method = 'equal')
par(mar=c(4,4,4,1), bg = 'white', mfcol = c(1, 2))
plotWB(WB = wb.sl1, legend.cex = 0.75)
title('50cm of silt loam texture soil material\nMonthy', line = 1.5)
plotWB(WB = wb.sl2, legend.cex = 0.75)
title('50cm of silt loam texture soil material\nEqual Distribution, 10 bins', line = 1.5)
This time, test the effects of using ‘equal’ vs. ‘random’ distribution of monthly PPT and PET into 10 bins per month.
wb.sl1 <- monthlyWB(AWC.sil, PPT, PET, S_init = 0, starting_month = 1, rep = 1, distribute = TRUE, k = 10, method = 'equal')
wb.sl2 <- monthlyWB(AWC.sil, PPT, PET, S_init = 0, starting_month = 1, rep = 1, distribute = TRUE, k = 10, method = 'random')
par(mar=c(4,4,4,1), bg = 'white', mfcol = c(1, 2))
plotWB(WB = wb.sl1, legend.cex = 0.75)
title('50cm of silt loam texture soil material\nEqual Distribution, 10 bins', line = 1.5)
plotWB(WB = wb.sl2, legend.cex = 0.75)
title('50cm of silt loam texture soil material\nRandom Distribution, 10 bins', line = 1.5)
Series-level summaries of climate provided by fetchOSD()
.
AWC estimated from SSURGO data, via SDA.
s <- 'amador'
x <- fetchOSD(s, extended = TRUE)
# get representative, profile-total AWC from SSURGO
sql <- sprintf("
SELECT chorizon.cokey AS cokey,
SUM(awc_r * (hzdepb_r - hzdept_r)) AS ws
FROM
legend JOIN mapunit ON legend.lkey = mapunit.lkey
JOIN component ON mapunit.mukey = component.mukey
JOIN chorizon ON component.cokey = chorizon.cokey
WHERE compname = '%s'
AND areasymbol != 'US'
GROUP BY chorizon.cokey;", s
)
# get via SDA
res <- SDA_query(sql)
# median AWC in mm
# over all components correlated to named series
AWC <- round(median(res$ws, na.rm = TRUE) * 10)
# monthly climate data from series summary
PPT <- x$climate.monthly$q50[x$climate.monthly$variable == 'Precipitation (mm)']
PET <- x$climate.monthly$q50[x$climate.monthly$variable == 'Potential ET (mm)']
Water year.
# tighter margins
par(mar=c(4,4,2,1), bg = 'white')
# water year
# last iteration
x.wb <- monthlyWB(AWC, PPT, PET, S_init = 0, starting_month = 9, rep = 3, keep_last = TRUE, distribute = TRUE)
plotWB(WB = x.wb)
# convert total ETa into inches
sum(x.wb$ET) * 0.03937
## [1] 9.265973
Calendar year.
# tighter margins
par(mar=c(4,4,2,1), bg = 'white')
# calendar year
# last iteration
x.wb <- monthlyWB(AWC, PPT, PET, S_init = 0, starting_month = 1, rep = 3, keep_last = TRUE, distribute = TRUE)
plotWB(WB = x.wb)
s <- 'auburn'
x <- fetchOSD(s, extended = TRUE)
# get representative, profile-total AWC from SSURGO
sql <- sprintf("SELECT chorizon.cokey AS cokey,
SUM(awc_r * (hzdepb_r - hzdept_r)) AS ws
FROM
legend JOIN mapunit ON legend.lkey = mapunit.lkey
JOIN component ON mapunit.mukey = component.mukey
JOIN chorizon ON component.cokey = chorizon.cokey
WHERE compname = '%s'
AND areasymbol != 'US'
GROUP BY chorizon.cokey;", s)
# get via SDA
res <- SDA_query(sql)
# median AWC in mm
# over all components correlated to named series
AWC <- round(median(res$ws, na.rm = TRUE) * 10)
# monthly climate data from series summary
PPT <- x$climate.monthly$q50[x$climate.monthly$variable == 'Precipitation (mm)']
PET <- x$climate.monthly$q50[x$climate.monthly$variable == 'Potential ET (mm)']
# 3 warm-up cycles
# keep last iteration
# calendar year
x.wb <- monthlyWB(AWC, PPT, PET, S_init = 0, starting_month = 1, rep = 3, keep_last = TRUE, distribute = TRUE)
# tighter margins
par(mar=c(4,4,3,1), bg = 'white', mfcol = c(1, 2))
plotWB(x.wb)
title(sprintf('Monthly Water Balance: %s Series', toupper(s)), line = 2)
plotWB_lines(x.wb)
title(sprintf('Monthly Water Balance: %s Series', toupper(s)), line = 2)
Abstract into a function, and use to compare multiple soils / climatic parameters. A more efficient approach would load all of the data then iterate over chunks.
# x: soil series name
compareMonthlyWB <- function(x, ylim) {
# get climate data
osd <- fetchOSD(x, extended = TRUE)
# get representative, profile-total AWC from SSURGO
sql <- sprintf("
SELECT chorizon.cokey AS cokey,
SUM(awc_r * (hzdepb_r - hzdept_r)) AS ws
FROM
legend JOIN mapunit ON legend.lkey = mapunit.lkey
JOIN component ON mapunit.mukey = component.mukey
JOIN chorizon ON component.cokey = chorizon.cokey
WHERE compname = '%s'
AND areasymbol != 'US'
GROUP BY chorizon.cokey;", x
)
# get via SDA
res <- suppressMessages(SDA_query(sql))
# median AWC in mm
# over all components correlated to named series
AWC <- round(median(res$ws, na.rm = TRUE) * 10)
# monthly climate data from series summary
PPT <- osd$climate.monthly$q50[osd$climate.monthly$variable == 'Precipitation (mm)']
PET <- osd$climate.monthly$q50[osd$climate.monthly$variable == 'Potential ET (mm)']
# do water balance simulation
x.wb <- monthlyWB(AWC, PPT, PET, S_init = 0, starting_month = 1, rep = 3, keep_last = TRUE, distribute = TRUE)
# compose WB figure
plotWB(WB = x.wb, legend.cex = 0.9, ylim = ylim)
# annotate with series name / family level classification
s <- site(osd$SPC)
txt <- sprintf("%s\n%s", s$id, s$family)
title(txt, line = 3, cex.main = 1)
return(x.wb)
}
# custom margins / multi-figure
par(mar = c(4, 4, 5, 1), bg = 'white', mfrow = c(2, 2))
# iterate over these soil series names
soils <- c('amador', 'lucy', 'drummer', 'pierre')
res <- lapply(soils, compareMonthlyWB, ylim = c(-250, 180))
Experimental: summarize water balance results.
res <- do.call('rbind', lapply(res, monthlyWB_summary))
res$series <- soils
knitr::kable(res, digits = 2)
dry | moist | wet | dry_con | moist_con | wet_con | total_deficit | total_surplus | total_AET | annual_AET_PET_ratio | series |
---|---|---|---|---|---|---|---|---|---|---|
61 | 183 | 122 | 61 | 91 | 91 | -618.64 | 225.14 | 235.36 | 0.28 | amador |
0 | 183 | 183 | 0 | 183 | 122 | -121.66 | 434.66 | 833.34 | 0.87 | lucy |
0 | 152 | 213 | 0 | 152 | 152 | -65.11 | 335.11 | 633.89 | 0.91 | drummer |
0 | 304 | 61 | 0 | 244 | 61 | -223.56 | 25.56 | 407.44 | 0.65 | pierre |
# custom margins / multi-figure
par(mar = c(4, 4, 5, 1), bg = 'white', mfrow = c(2, 2))
# iterate over these soil series names
soils <- c('leon', 'tristan', 'miami', 'freznik')
res <- lapply(soils, compareMonthlyWB, ylim = c(-180, 190))
Experimental: summarize water balance results.
res <- do.call('rbind', lapply(res, monthlyWB_summary))
res$series <- soils
knitr::kable(res, digits = 2)
dry | moist | wet | dry_con | moist_con | wet_con | total_deficit | total_surplus | total_AET | annual_AET_PET_ratio | series |
---|---|---|---|---|---|---|---|---|---|---|
0 | 122 | 244 | 0 | 122 | 122 | -40.21 | 350.21 | 973.79 | 0.96 | leon |
0 | 244 | 122 | 0 | 244 | 91 | -391.10 | 197.10 | 205.90 | 0.34 | tristan |
0 | 152 | 213 | 0 | 152 | 152 | -68.19 | 417.19 | 626.81 | 0.90 | miami |
0 | 274 | 91 | 0 | 274 | 91 | -302.97 | 44.97 | 235.03 | 0.44 | freznik |
This document is based on sharpshootR
version 2.3.1 and
soilDB
version 2.8.5.