This document provides code and analysis to compare metabolism
results from the Odum open-water method, BASEmetab, and EBASE with known
results from the forward model included in the Fwoxy package. The Odum
open-water method is available from the sine branch of
the WtRegDO package, which includes a new option to output instantaneous
metabolism flux estimates at each time step. The BASEmetab results were
created using this
script. For BASEmetab, the prior distribution for the gas transfer
velocity parameter (K) was based on a mean value from Fwoxy with an
appropriate standard deviation in proportion to the value used in EBASE.
Also note that the BASEmetab model requires a PAR time series, which was
created using the fun_par_sin_model
from Fwoxy. The EBASE
results were created using this
script and is similar to BASEmetab with the exception of a
parameterization for gas exchange following Wanninkhof 2014, i.e., gas
exchange is estimated directly in the model and not calculated
empirically outside of the Bayesian context.
Load the libraries, BASEmetab results, EBASE results, and setup model parameters and constants for the simulated dissolved oxygen time series from Fwoxy.
library(fwoxy)
library(tidyverse)
library(lubridate)
library(WtRegDO)
library(here)
load(file = here('data/fwoxybasemetab.RData'))
load(file = here('data/fwoxyebase.RData'))
# plot colors
colors <- c(gasexd = "red3", gppd = "orange", erd = "purple4", dcdtd = "steelblue3")
# plot breaks, labels
brks <- seq(1, 518400,by = 43200)
labs <- rep(c(0, 12), length.out = length(brks))
# Set model parameters
oxy_ic <- 250 # (mmol/m^3), initial oxygen concentration
a_param <- 0.2 # ((mmol/m^3)/day)/(W/m^2), light efficiency
er_param <- 20 # (mmol/m^3/day), ecosystem respiration
# Constant Forcings
ht_const <- 3 # m, height of the water column
salt_const <- 25 # ppt, salinity
temp_const <- 25 # deg C, water temperature
wspd_const <- 3 # m/s, wind speed at 10 m
Create Fwoxy model using the parameters above. The
example
object creates a plot showing the oxygen time
series and resulting metabolism estimates as flux of dissolved oxygen in
mmol/m3/d. These are volumetric rates.
example <- fwoxy(oxy_ic = oxy_ic, a_param = a_param, er_param = er_param,
ht_in = ht_const, salt_in = salt_const, temp_in = temp_const,
wspd_in = wspd_const)
head(example)
## time, sec oxy, mmol/m3 troc, mmol/m3/d gasex, mmol/m3/d gpp, mmol/m3/d
## 1 0 250.0000 NA NA NA
## 2 900 249.7305 -25.86951 5.869511 0
## 3 1800 249.4617 -25.80931 5.809309 0
## 4 2700 249.1935 -25.74925 5.749247 0
## 5 3600 248.9259 -25.68932 5.689325 0
## 6 4500 248.6589 -25.62954 5.629542 0
## er, mmol/m3/d oxysu, mmol/m3 wspd2, m2/s2 sc kw, m/s
## 1 NA NA NA NA NA
## 2 20 26.27292 9 431.8863 7.757129e-06
## 3 20 26.00345 9 431.8863 7.757129e-06
## 4 20 25.73460 9 431.8863 7.757129e-06
## 5 20 25.46638 9 431.8863 7.757129e-06
## 6 20 25.19878 9 431.8863 7.757129e-06
## oxysat, mmol/m3
## 1 NA
## 2 223.7271
## 3 223.7271
## 4 223.7271
## 5 223.7271
## 6 223.7271
The oxygen time series can be used from the Fwoxy output with the Odum open-water method in WtRegDO. The time series must be formatted to be used with WtRegDO, which includes converting the seconds column to a date/time object (arbitrarily set to the system date), changing the units of oxygen from mmol/m3 to mg/L, and including the constants defined for the Fwoxy input as input to WtRegDO.
tomod <- example %>%
mutate(
DateTimeStamp = force_tz(as.POSIXct(`time, sec`, origin = Sys.Date(), tz = 'UTC'), tzone = 'America/Jamaica'),
DO_obs = `oxy, mmol/m3` * 0.032, # to mg/L, same as g/m3
Temp = temp_const,
WSpd = wspd_const,
Sal = salt_const,
ATemp = NA,
BP = 1013.25,
Tide = NA
) %>%
select(DateTimeStamp, Temp, Sal, DO_obs, WSpd, ATemp, BP, Tide)
head(tomod)
## DateTimeStamp Temp Sal DO_obs WSpd ATemp BP Tide
## 1 2023-03-15 00:00:00 25 25 8.000000 3 NA 1013.25 NA
## 2 2023-03-15 00:15:00 25 25 7.991377 3 NA 1013.25 NA
## 3 2023-03-15 00:30:00 25 25 7.982774 3 NA 1013.25 NA
## 4 2023-03-15 00:45:00 25 25 7.974191 3 NA 1013.25 NA
## 5 2023-03-15 01:00:00 25 25 7.965628 3 NA 1013.25 NA
## 6 2023-03-15 01:15:00 25 25 7.957084 3 NA 1013.25 NA
The Odum open-water method is then used. Note that the location and time zone is required. This will impose some slight differences in the metabolic estimates between Fwoxy and the Odum method because the latter uses a “metabolic day” as the time between sunrises based on the date and location. Also note the chosen method for estimating gas exchange. The results return areal (m2) and volumetric (m3) estimates for metabolism. The first several rows do not include estimates because of internal checks in WtRegDO that verify a “complete” metabolic day is used for the calculations. For the Fwoxy oxygen output, the WtRegDO package treats the first few hours of data as the tail end of an incomplete metabolic day and results are not estimated.
# estimate instantaneous Odum metabolism from Fwoxy output
opmetab <- ecometab(tomod, DO_var = 'DO_obs', tz = 'America/Jamaica', lat = 29.75, long = -85, depth_val = NULL,
depth_vec = ht_const, gasex = 'Wanninkhof', gasave = 'instant', metab_units = 'mmol', instant = T)
head(opmetab)
## DateTimeStamp Temp Sal WSpd BP DO metab_date solar_period
## 1 2023-03-15 00:07:30 25 25 3 1013.25 249.8653 2023-03-14 sunset
## 2 2023-03-15 00:22:30 25 25 3 1013.25 249.5961 2023-03-14 sunset
## 3 2023-03-15 00:37:30 25 25 3 1013.25 249.3276 2023-03-14 sunset
## 4 2023-03-15 00:52:30 25 25 3 1013.25 249.0597 2023-03-14 sunset
## 5 2023-03-15 01:07:30 25 25 3 1013.25 248.7924 2023-03-14 sunset
## 6 2023-03-15 01:22:30 25 25 3 1013.25 248.5257 2023-03-14 sunset
## solar_time day_hrs DOsat dDO H D KL
## 1 2023-03-14 19:47:36 11.94053 1.115411 -25.86951 3 -5.775812 0.6702159
## 2 2023-03-14 19:47:36 11.94053 1.114210 -25.80931 3 -5.715680 0.6702159
## 3 2023-03-14 19:47:36 11.94053 1.113011 -25.74925 3 -5.655688 0.6702159
## 4 2023-03-14 19:47:36 11.94053 1.111815 -25.68932 3 -5.595836 0.6702159
## 5 2023-03-14 19:47:36 11.94053 1.110622 -25.62954 3 -5.536122 0.6702159
## 6 2023-03-14 19:47:36 11.94053 1.109432 -25.56990 3 -5.476548 0.6702159
## Ka Pg Rt NEM Pg_vol Rt_vol
## 1 0.009308554 NA NA NA NA NA
## 2 0.009308554 NA NA NA NA NA
## 3 0.009308554 NA NA NA NA NA
## 4 0.009308554 NA NA NA NA NA
## 5 0.009308554 NA NA NA NA NA
## 6 0.009308554 NA NA NA NA NA
The metabolic output from WtRegDO, BASEmetab, EBASE, and Fwoxy are then combined for a direct comparison. This requires a bit of additional wrangling, the details of which are not important. The output shows the combined time series used to create the comparison plots.
# function to make seconds in opmetab match fwoxy
getsec <- function(x){
sec <- seconds(x)
sec <- sec - (7.5 * 60)
sec <- sec - min(sec)
sec <- as.numeric(sec)
return(sec)
}
# format opmetab to match fwoxy
opmetab <- opmetab %>%
select(DateTimeStamp, dDO, D, Pg_vol, Rt_vol) %>%
mutate(
secs = getsec(DateTimeStamp),
D = -1 * D,
Rt_vol = -1 * Rt_vol,
typ = 'Odum'
) %>%
select(-DateTimeStamp) %>%
gather(var, val, -secs, -typ)
# format BASEmetab to match fwoxy
bsmetab <- fwoxybasemetab %>%
mutate(
secs = getsec(DateTimeStamp),
typ = 'BASEmetab'
) %>%
select(secs, typ, Pg_vol, Rt_vol, D, dDO) %>%
gather(var, val, -secs, -typ) %>%
na.omit()
# format EBASE to match fwoxy
ebmetab <- fwoxyebase %>%
mutate(
secs = getsec(DateTimeStamp),
D = -1 * D / H,
Pg_vol = P / H,
Rt_vol = R / H,
typ = 'EBASE'
) %>%
select(secs, typ, Pg_vol, Rt_vol, D, dDO) %>%
gather(var, val, -secs, -typ) %>%
na.omit()
# combine fwoxy and opmetab
toplo1 <- example %>%
select(
secs = `time, sec`,
dDO = `troc, mmol/m3/d`,
D = `gasex, mmol/m3/d`,
Pg_vol = `gpp, mmol/m3/d`,
Rt_vol = `er, mmol/m3/d`
) %>%
mutate(
typ = 'Fwoxy'
) %>%
gather(var, val, -secs, -typ) %>%
bind_rows(opmetab, bsmetab, ebmetab) %>%
mutate(
var = factor(var, levels = c('D', 'Pg_vol', 'Rt_vol', 'dDO'), labels = c('gasexd', 'gppd', 'erd', 'dcdtd')),
typ = factor(typ, levels = c('Fwoxy', 'Odum', 'BASEmetab', 'EBASE'))
)
head(toplo1)
## secs typ var val
## 1 0 Fwoxy dcdtd NA
## 2 900 Fwoxy dcdtd -25.86951
## 3 1800 Fwoxy dcdtd -25.80931
## 4 2700 Fwoxy dcdtd -25.74925
## 5 3600 Fwoxy dcdtd -25.68932
## 6 4500 Fwoxy dcdtd -25.62954
This shows the time series for the metabolic estimates provided by each method. The plot format is similar to that provided by the Fwoxy package.
ggplot(toplo1, aes(x = secs, y = val, color = var)) +
geom_line() +
facet_wrap(~typ, ncol = 1) +
scale_color_manual(values = colors) +
scale_x_continuous(labels = labs, breaks = brks) +
theme_bw() +
labs(
y = 'Flux, mmol/m3/d',
x = 'Hour of day'
) +
theme(
legend.title = element_blank(),
strip.background = element_blank()
)
This shows a direct comparison of the estimates provided by each method. The y-axis shows the Odum results and the x-axis shows the Fwoxy results. There is a slight difference in phasing of the time series that creates an offset from the 1:1 line. Also note that the difference in respiration is minor but related to the daily estimate for the Odum method versus an overall estimate for the entire time series for the Fwoxy method.
toplo2 <- toplo1 %>%
spread(typ, val)
ggplot(toplo2, aes(x = Fwoxy, y = Odum, color = var)) +
geom_point() +
facet_wrap(~var, ncol = 2, scales = 'free') +
# coord_equal() +
scale_color_manual(values = colors) +
theme_bw() +
geom_abline(intercept = 0, slope = 1) +
labs(
y = 'Odum, Flux, mmol/m3/d',
x = 'Fwoxy, flux, mmol/m3/d'
) +
theme(
legend.title = element_blank(),
strip.background = element_blank()
)
The same comparison as above is made for the BASEmetab results with Fwoxy.
ggplot(toplo2, aes(x = Fwoxy, y = BASEmetab, color = var)) +
geom_point() +
facet_wrap(~var, ncol = 2, scales = 'free') +
scale_color_manual(values = colors) +
theme_bw() +
geom_abline(intercept = 0, slope = 1) +
labs(
y = 'BASEmetab, Flux, mmol/m3/d',
x = 'Fwoxy, Flux, mmol/m3/d'
) +
theme(
legend.title = element_blank(),
strip.background = element_blank()
)
The same comparison as above is made for the EBASE results with Fwoxy.
ggplot(toplo2, aes(x = Fwoxy, y = EBASE, color = var)) +
geom_point() +
facet_wrap(~var, ncol = 2, scales = 'free') +
scale_color_manual(values = colors) +
theme_bw() +
geom_abline(intercept = 0, slope = 1) +
labs(
y = 'EBASE, Flux, mmol/m3/d',
x = 'Fwoxy, Flux, mmol/m3/d'
) +
theme(
legend.title = element_blank(),
strip.background = element_blank()
)
This shows a direct comparison between the methods for each metabolic result as time series.
ggplot(toplo1, aes(x = secs, y = val, color = typ)) +
geom_line() +
facet_wrap(~var, ncol = 1, scales = 'free') +
scale_x_continuous(labels = labs, breaks = brks) +
theme_bw() +
labs(
y = 'Flux, mmol/m3/d',
x = 'Hour of day'
) +
theme(
legend.title = element_blank(),
strip.background = element_blank()
)
All methods produce similar results for the instantaneous metabolic
estimates, although EBASE over-estimates gas exchange and
under-estimates respiration. Fixing the b
parameter in the
EBASE method produces comparable estimates for the other methods. Slight
differences between the Odum and Fwoxy results relate to how the time
series is divided to estimate the rates in the WtRegDO package.
Specifically, the Odum method uses the metabolic day, whereas the Fwoxy
approach uses a fixed day. Additionally, the Odum method calculates
rates based on the midpoint difference of DO between two time steps.
This creates a slight phase offset between the methods. The BASEmetab
results are more similar to the Fwoxy results than the Odum results.
For EBASE, we can compare the individual parameter estimates from
values used to create the Fwoxy input. The a
parameter is
light efficiency and was set at 0.2 (mmol/m3/d)/(W/m2) in the initial
Fwoxy input. The estimate from EBASE is:
a <- fwoxyebase %>%
pull(a) %>%
na.omit() %>%
unique %>%
mean()
a
## [1] 0.2013696
This is very close to the input used for Fwoxy. A second parameter
output from Fwoxy is b
as part of the gas exchange
estimate. A reasonable estimate for this value is 0.251 (cm/hr)/(m2/s2).
The estimate from EBASE is:
b <- fwoxyebase %>%
pull(b) %>%
na.omit() %>%
unique %>%
mean()
b
## [1] 0.4961419