Evaluate light use efficiency.

Daily data

Gather data and create one nice data frame with daily data.

if (!exists("out_eval_ORG"))  load("./calib_results/out_eval_ORG.Rdata")
if (!exists("out_eval_FULL")) load("./calib_results/out_eval_FULL.Rdata")
load("~/eval_pmodel/data/obs_eval_NT_WITHFORCING.Rdata")
mc <- 12.0107  # molecular mass of carbon

## As done for publication:
ddf <- out_eval_FULL$gpp$fluxnet2015$data$ddf %>% 
  left_join(dplyr::select(obs_eval_NT$ddf, date, sitename, fapar, ppfd_fluxnet2015, temp_day_fluxnet2015, vpd_day_fluxnet2015, prec_fluxnet2015, patm_fluxnet2015), by = c("sitename", "date")) %>% 
  mutate(setup_pmodel = "FULL") %>% 
  
  ## Calculate APAR (using interpolated PPFD and fAPAR for very few points)
  mutate(ppfd_fluxnet2015 = myapprox(ppfd_fluxnet2015),
         fapar            = myapprox(fapar)) %>%
  mutate(apar = ppfd_fluxnet2015 * fapar) %>% 

  ## Remove very low APAR 
  dplyr::filter(apar > 0.1) %>% 
  rename(gpp_obs = obs, gpp_mod = mod) %>% 
  
  ## Calculate LUE (division by molecular mass to get LUE in units of mol/mol!)
  mutate(lue_obs = gpp_obs / (mc * apar),
         lue_mod = gpp_mod / (mc * apar) ) %>% 
  
  ## Remove outliers (outside 1.5 times the inter-quartile-range)
  mutate(lue_obs = remove_outliers(lue_obs),
         lue_mod = remove_outliers(lue_mod))

Look at distribution of values and comparison to obs-derived LUE with daily data.

ddf %>% 
  filter(setup_pmodel == "FULL") %>% 
  drop_na(gpp_obs, gpp_mod) %>% 
  mutate(gpp_mod = gpp_mod * 1e3, gpp_obs = gpp_obs * 1e3) %>% 
  gather(modobs, gpp, c(gpp_obs, gpp_mod)) %>% 
  ggplot(aes(x = modobs, y=gpp, fill=modobs)) +
  geom_violin() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("gpp_obs", "gpp_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Source", y=expression(paste("gpp (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")

ddf %>% 
  filter(setup_pmodel == "FULL") %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  gather(modobs, lue, c(lue_obs, lue_mod)) %>% 
  ggplot(aes(x = modobs, y=lue, fill=modobs)) +
  geom_violin() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("lue_obs", "lue_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Vegetation type", y=expression(paste("LUE (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")

ddf %>% 
  filter(setup_pmodel == "FULL") %>% 
  ggplot() +
  geom_histogram(
    aes(x = apar, y = ..density..), 
    color = "black", alpha = 0.3, binwidth = 0.5, 
    position="identity")

gg <- ddf %>% analyse_modobs2("lue_obs", "lue_mod", type = "heat")
## Loading required package: LSD
## Loading required package: ggthemes
gg$gg

Ok. They are on the same order.

Compare coefficient of variations in LUE model.

cv <- function(vec, ...){
  sd(vec, ...) / mean(vec, ...)
}
df_cv <- ddf %>% 
  summarise(gpp_obs = cv(gpp_obs, na.rm=TRUE),
            ppfd_fluxnet2015 = cv(ppfd_fluxnet2015, na.rm=TRUE),
            fapar = cv(fapar, na.rm=TRUE),
            lue_obs = cv(lue_obs, na.rm=TRUE))
print(df_cv)
## # A tibble: 1 x 4
##   gpp_obs ppfd_fluxnet2015 fapar lue_obs
##     <dbl>            <dbl> <dbl>   <dbl>
## 1    1.08            0.601 0.500   0.883

Monthly

Aggregate to monthly values.

Sum GPP and APAR and get LUE from sums ==> works much better? But is dominated by large values.

mdf_nice <- ddf %>%
  mutate(moy = month(date), year = year(date)) %>%
  group_by(sitename, year, moy) %>%
  summarise( apar = sum(apar)) %>%
  dplyr::filter(apar > 30) %>%
  right_join(out_eval_FULL$gpp$fluxnet2015$data$mdf, by=c("sitename", "year")) %>%
  rename(gpp_obs = obs, gpp_mod = mod) %>%
  mutate(lue_obs = gpp_obs / (mc * apar),
         lue_mod = gpp_mod / (mc * apar) ) %>%
  ungroup()  %>%
  left_join(rsofun::metainfo_Tier1_sites_kgclimate_fluxnet2015 %>% dplyr::select(sitename, classid),
            by="sitename")
## Warning: replacing previous import 'dplyr::intersect' by
## 'lubridate::intersect' when loading 'rsofun'
## Warning: replacing previous import 'dplyr::union' by 'lubridate::union'
## when loading 'rsofun'
## Warning: replacing previous import 'dplyr::setdiff' by 'lubridate::setdiff'
## when loading 'rsofun'
## Warning: replacing previous import 'purrr::list_along' by
## 'rlang::list_along' when loading 'rsofun'
## Warning: replacing previous import 'purrr::invoke' by 'rlang::invoke' when
## loading 'rsofun'
## Warning: replacing previous import 'purrr::flatten_raw' by
## 'rlang::flatten_raw' when loading 'rsofun'
## Warning: replacing previous import 'purrr::modify' by 'rlang::modify' when
## loading 'rsofun'
## Warning: replacing previous import 'purrr::as_function' by
## 'rlang::as_function' when loading 'rsofun'
## Warning: replacing previous import 'purrr::flatten_dbl' by
## 'rlang::flatten_dbl' when loading 'rsofun'
## Warning: replacing previous import 'Metrics::ll' by 'rlang::ll' when
## loading 'rsofun'
## Warning: replacing previous import 'purrr::flatten_lgl' by
## 'rlang::flatten_lgl' when loading 'rsofun'
## Warning: replacing previous import 'purrr::flatten_int' by
## 'rlang::flatten_int' when loading 'rsofun'
## Warning: replacing previous import 'purrr::%@%' by 'rlang::%@%' when
## loading 'rsofun'
## Warning: replacing previous import 'purrr::flatten_chr' by
## 'rlang::flatten_chr' when loading 'rsofun'
## Warning: replacing previous import 'purrr::splice' by 'rlang::splice' when
## loading 'rsofun'
## Warning: replacing previous import 'purrr::flatten' by 'rlang::flatten'
## when loading 'rsofun'
## Warning: replacing previous import 'purrr::prepend' by 'rlang::prepend'
## when loading 'rsofun'
## Warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
## Warning: WARNING:
## Warning: Setting option to specify location of SOFUN (Fortran):
## Warning: rsofun.dir.sofun = '~/sofun/'
## Warning: Change this option by:
## Warning: options( list( rsofun.dir.sofun='string_path_where_sofun_is' ) )
## Warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
mdf_nice %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  gather(modobs, lue, c(lue_obs, lue_mod)) %>% 
  ggplot(aes(x = modobs, y=lue, fill=modobs)) +
  geom_violin() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("lue_obs", "lue_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Vegetation type", y=expression(paste("LUE (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")

out_mdf <- mdf_nice %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs", type = "heat")

gg_modobs_mdf_nice <- out_mdf$gg +
  labs(x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")),
       y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")))

gg_modobs_mdf_nice

Mean across daily values ==> works worse? This is now in the paper.

mdf <- ddf %>%
  mutate(moy = month(date), year = year(date)) %>% 
  group_by(sitename, year, moy) %>% 
  summarise(lue_obs = mean(lue_obs, na.rm=TRUE),
            lue_mod = mean(lue_mod, na.rm=TRUE)) %>% 
  mutate(lue_obs = ifelse(is.nan(lue_obs), NA, lue_obs)) %>% 
  mutate(lue_mod = ifelse(is.nan(lue_mod), NA, lue_mod)) %>% 
  ungroup()

mdf %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  gather(modobs, lue, c(lue_obs, lue_mod)) %>% 
  ggplot(aes(x = modobs, y=lue, fill=modobs)) +
  geom_violin() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("lue_obs", "lue_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Vegetation type", y=expression(paste("LUE (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")

out_mdf <- mdf %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs", type = "heat")

gg_modobs_mdf <- out_mdf$gg +
  labs(x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")),
       y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")))
print(gg_modobs_mdf)

Annual

Sum GPP and APAR and get LUE from sums ==> works much better? But is dominated by large values as for monthly

adf_nice <- ddf %>%
  mutate(year = year(date)) %>%
  group_by(sitename, year) %>%
  summarise( apar = sum(apar)) %>%
  # dplyr::filter(apar > 300) %>%
  right_join(out_eval_FULL$gpp$fluxnet2015$data$adf, by=c("sitename", "year")) %>%
  rename(gpp_obs = obs, gpp_mod = mod) %>%
  mutate(lue_obs = gpp_obs / (mc * apar),
         lue_mod = gpp_mod / (mc * apar) ) %>%
  ungroup()  %>%
  left_join(rsofun::metainfo_Tier1_sites_kgclimate_fluxnet2015 %>% dplyr::select(sitename, classid),
            by="sitename")

adf_nice %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  gather(modobs, lue, c(lue_obs, lue_mod)) %>% 
  ggplot(aes(x = modobs, y=lue, fill=modobs)) +
  geom_violin() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("lue_obs", "lue_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Vegetation type", y=expression(paste("LUE (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")

out_adf <- adf_nice %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs")

gg_modobs_adf <- out_adf$gg +
  labs(x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")),
       y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")))

gg_modobs_adf

Mean across daily values ==> works worse? This is now in the paper.

adf <- ddf %>%
  mutate(year = year(date)) %>% 
  group_by(sitename, year) %>% 
  summarise(lue_obs = mean(lue_obs, na.rm=TRUE),
            lue_mod = mean(lue_mod, na.rm=TRUE)) %>% 
  mutate(lue_obs = ifelse(is.nan(lue_obs), NA, lue_obs)) %>% 
  mutate(lue_mod = ifelse(is.nan(lue_mod), NA, lue_mod)) %>% 
  ungroup()

adf %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  gather(modobs, lue, c(lue_obs, lue_mod)) %>% 
  ggplot(aes(x = modobs, y=lue, fill=modobs)) +
  geom_violin() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("lue_obs", "lue_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Vegetation type", y=expression(paste("LUE (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")

out_adf <- adf %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs")

gg_modobs_adf <- out_adf$gg +
  labs(x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")),
       y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")))
print(gg_modobs_adf)

Some sites have really outlier years. These are the ones where modelled LUE is very low and observed very high.

adf <- adf %>% 
  mutate(res = lue_obs - lue_mod)

adf %>% 
  filter(res > quantile(res, 0.99, na.rm = TRUE))
## # A tibble: 9 x 5
##   sitename  year lue_obs lue_mod    res
##   <chr>    <dbl>   <dbl>   <dbl>  <dbl>
## 1 AR-SLu    2009  0.0380 0.0121  0.0259
## 2 AR-SLu    2010  0.0380 0.0129  0.0251
## 3 AR-SLu    2011  0.0345 0.0127  0.0217
## 4 AU-Lox    2008  0.0296 0.0102  0.0194
## 5 BR-Sa3    2004  0.0360 0.0193  0.0167
## 6 CN-Sw2    2010  0.0407 0.0147  0.0260
## 7 DK-Sor    2014  0.0397 0.0223  0.0174
## 8 SD-Dem    2005  0.0518 0.00779 0.0440
## 9 SN-Dhr    2010  0.0454 0.00963 0.0358
adf_nice <- adf_nice %>% 
  mutate(res = lue_obs - lue_mod)

adf_nice %>% 
  filter(res > quantile(res, 0.99, na.rm = TRUE))
## # A tibble: 6 x 11
##   sitename  year  apar gpp_mod     n date       gpp_obs lue_obs lue_mod
##   <chr>    <dbl> <dbl>   <dbl> <int> <date>       <dbl>   <dbl>   <dbl>
## 1 AR-SLu    2011 5674.    863.   365 2011-01-01   2599.  0.0381 0.0127 
## 2 AT-Neu    2007 5493.   1392.   365 2007-01-01   2409.  0.0365 0.0211 
## 3 AT-Neu    2008 5472.   1406.   365 2008-01-01   2621.  0.0399 0.0214 
## 4 AT-Neu    2011 5677.   1411.   365 2011-01-01   2652.  0.0389 0.0207 
## 5 SN-Dhr    2011 3746.    417.   365 2011-01-01   1584.  0.0352 0.00927
## 6 SN-Dhr    2013 3270.    364.   365 2013-01-01   1151   0.0293 0.00927
## # … with 2 more variables: classid <chr>, res <dbl>

Let’s remove them for good and re-calculate correlation of annual values.

adf <- adf %>% 
  filter(res < quantile(res, 0.99, na.rm = TRUE))

out_adf <- adf %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs")

gg_modobs_adf <- out_adf$gg +
  labs(x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")),
       y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")))
gg_modobs_adf

adf_nice <- adf_nice %>% 
  filter(res < quantile(res, 0.99, na.rm = TRUE))


out_adf <- adf_nice %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs")

gg_modobs_adf <- out_adf$gg +
  labs(x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")),
       y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")))
gg_modobs_adf

By site (spatial) and veg type

Now do this with the version that performed better above (adf_nice).

## mean by site
df <- adf_nice %>% 
  group_by(sitename) %>% 
  summarise(lue_obs = mean(lue_obs, na.rm = TRUE),
            lue_mod = mean(lue_mod, na.rm = TRUE)) %>% 
  left_join(rsofun::metainfo_Tier1_sites_kgclimate_fluxnet2015 %>% dplyr::select(sitename, classid), 
            by="sitename") %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3)

## mean by vegetation type
vegdf <- df %>% 
  ungroup() %>% 
  group_by(classid) %>% 
  summarise(lue_obs = mean(lue_obs, na.rm = TRUE),
            lue_mod = mean(lue_mod, na.rm = TRUE))

##################
# FULL setup
##################
out_df <- df %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs", xlab="Modelled LUE", ylab="Observed LUE") # , filnam = "fig/modobs_lue_bysite.pdf"

rsq_lab <- format( out_df$df_metrics %>% dplyr::filter(.metric=="rsq") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 2 )
rmse_lab <- format( out_df$df_metrics %>% dplyr::filter(.metric=="rmse") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )
bias_lab <- format( out_df$df_metrics %>% dplyr::filter(.metric=="bias") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )
slope_lab <- format( out_df$df_metrics %>% dplyr::filter(.metric=="slope") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )
n_lab <- format( out_df$df_metrics %>% dplyr::filter(.metric=="n") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )

out_vegdf <- vegdf %>% 
  rbeni::analyse_modobs2("lue_mod", "lue_obs", xlab="Modelled LUE", ylab="Observed LUE")

rsq_lab2 <- format( out_vegdf$df_metrics %>% dplyr::filter(.metric=="rsq") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 2 )
rmse_lab2 <- format( out_vegdf$df_metrics %>% dplyr::filter(.metric=="rmse") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )
bias_lab2 <- format( out_vegdf$df_metrics %>% dplyr::filter(.metric=="bias") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )
slope_lab2 <- format( out_vegdf$df_metrics %>% dplyr::filter(.metric=="slope") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )
n_lab2 <- format( out_vegdf$df_metrics %>% dplyr::filter(.metric=="n") %>% dplyr::select(.estimate) %>% unlist() %>% unname(), digits = 3 )

## scatterplot
gg_lue_spatial <- ggplot() +
  geom_point(data=df, aes(x=lue_mod, y=lue_obs, color=classid), size=1.5) +
  geom_point(data=vegdf, aes(x=lue_mod, y=lue_obs, color=classid), size=5) +
  geom_smooth(data=df, aes(x=lue_mod, y=lue_obs), method = "lm", color="red", size=0.5) +
  geom_abline(intercept=0, slope=1, linetype="dotted") +
  theme_classic() +
  scale_color_brewer(palette="Paired") +
  labs(
        subtitle = bquote(
          # atop(
            # "Sites:" ~
            italic(R)^2 == .(rsq_lab) ~ (.(rsq_lab2)) ~~~
            # RMSE == .(rmse_lab) ~~~
            # bias == .(bias_lab) ~~~
            slope == .(slope_lab) ~ (.(slope_lab2)) ~~~
            italic(N) == .(n_lab) ~ (.(n_lab2))
          # , 
          # "Vegetation types:" ~
          # italic(R)^2 == .(rsq_lab2) ~~~
          # RMSE == .(rmse_lab2) ~~~
          # bias == .(bias_lab2) ~~~
          # slope == .(slope_lab2) ~~~
          # italic(N) == .(n_lab2) 
        # )
         ),
        x = expression(paste("Modelled LUE (mmol mol" ^{-1}, ")")), 
        y = expression(paste("Observed LUE (mmol mol" ^{-1}, ")")),
        color="")
print(gg_lue_spatial)

# xxxxxx take this
# ggsave("fig/modobs_lue_bysite_classid.pdf", width=5, height=5)


## boxplot 
gg <- df %>% 
  drop_na(lue_obs, lue_mod) %>% 
  mutate(lue_mod = lue_mod * 1e3, lue_obs = lue_obs * 1e3) %>% 
  gather(modobs, lue, c(lue_obs, lue_mod)) %>% 
  ggplot(aes(x=classid, y=lue, fill=modobs)) +
  geom_boxplot() +
  theme_classic() +
  scale_fill_brewer(palette="Paired", 
                    breaks=c("lue_obs", "lue_mod"), 
                    labels=c("Observed", "Modelled")) +
  labs(fill="", x="Vegetation type", y=expression(paste("LUE (mmol mol" ^{-1}, ")"))) + 
  theme(legend.position="top")
print(gg)

# ggsave("fig/boxplot_lue_bysite_classid.pdf", width=5, height=5)

Publication figure

library(cowplot)
## 
## ********************************************************
## Note: As of version 1.0.0, cowplot does not change the
##   default ggplot2 theme anymore. To recover the previous
##   behavior, execute:
##   theme_set(theme_cowplot())
## ********************************************************
## 
## Attaching package: 'cowplot'
## The following object is masked from 'package:ggthemes':
## 
##     theme_map
## The following object is masked from 'package:lubridate':
## 
##     stamp
plot_grid(gg_modobs_mdf, gg_lue_spatial, labels = "auto", label_size = 12, rel_widths = c(1, 1.1))

ggsave("fig/modobs_lue.pdf", width=10, height=5)