Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add codes to extract SoilGrids soil texture data and derive ensemble … #3406

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
45 changes: 29 additions & 16 deletions models/sipnet/R/write.configs.SIPNET.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ write.config.SIPNET <- function(defaults, trait.values, settings, run.id, inputs

### WRITE *.clim
template.clim <- settings$run$inputs$met$path ## read from settings

if (!is.null(inputs)) {
## override if specified in inputs
if ("met" %in% names(inputs)) {
Expand Down Expand Up @@ -490,22 +489,36 @@ write.config.SIPNET <- function(defaults, trait.values, settings, run.id, inputs
}
} ## end loop over PFTS
####### end parameter update
#working on reading soil file (only working for 1 soil file)
if(length(settings$run$inputs$soilinitcond$path)==1){
soil_IC_list <- PEcAn.data.land::pool_ic_netcdf2list(settings$run$inputs$soilinitcond$path)
#SoilWHC and LitterWHC
if("volume_fraction_of_water_in_soil_at_saturation"%in%names(soil_IC_list$vals)){
#SoilWHC
param[which(param[, 1] == "soilWHC"), 2] <- mean(unlist(soil_IC_list$vals["volume_fraction_of_water_in_soil_at_saturation"]))*100

#LitterWHC
#param[which(param[, 1] == "litterWHC"), 2] <- unlist(soil_IC_list$vals["volume_fraction_of_water_in_soil_at_saturation"])[1]*100
}
if("soil_hydraulic_conductivity_at_saturation"%in%names(soil_IC_list$vals)){
#litwaterDrainrate
param[which(param[, 1] == "litWaterDrainRate"), 2] <- unlist(soil_IC_list$vals["soil_hydraulic_conductivity_at_saturation"])[1]*100/(3600*24)
#working on reading soil file
if (length(settings$run$inputs$soilinitcond$path) > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still no clear how you're handling the case if >1 file is passed in

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the current design is when t=1, only one file path is sampled and passed into the setting based on codes in "write.ensemble.configs". When t>1, file paths of total ensemble size will be passed in but then "template.soilinit" will be assigned with the specific path in the inputs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qianyuxuan I was asking about n=1 versus n>1, not t=1 vs t>1, and I'm still confused -- if you're passed in a whole vector of paths instead of a single one, you should throw an error not continue on, but I'm not seeing that check anywhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the steps for the pass of met files: https://github.com/PecanProject/pecan/blob/develop/models/sipnet/R/write.configs.SIPNET.R#L21-L29. I did find that a whole vector of met paths (10 ERA5 ensemble met paths defined in the settings) was passed in when t>1. But I don't think it is an error as the specific path will be overwritten by the one listed in the restart met input later.

template.soilinit <- settings$run$inputs$soilinitcond$path ## read from settings

if (!is.null(inputs)) {
## override if specified in inputs
if ("soilinitcond" %in% names(inputs)) {
template.soilinit <- inputs$soilinitcond$path
}
}
}
soil_IC_list <- PEcAn.data.land::pool_ic_netcdf2list(template.soilinit)
# Calculate the thickness of soil layers based on the assumption that the depth values are at bottoms and the first layer top is at 0
if ("depth" %in% names(soil_IC_list$dims)) {
thickness<-c(soil_IC_list$dims$depth[1],diff(soil_IC_list$dims$depth))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this line still work if the product only has one layer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, should/could there be an "else" here? A bunch of code below continues to check for "depth" being defined, but doesn't ever use depth again -- instead you're just using this to ensure thickness is defined.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

#SoilWHC
if ("volume_fraction_of_water_in_soil_at_saturation" %in% names(soil_IC_list$vals)) {
# Calculate the soilWHC for the whole soil profile in cm
soilWHC_total <- sum(unlist(soil_IC_list$vals["volume_fraction_of_water_in_soil_at_saturation"])*thickness)
param[which(param[, 1] == "soilWHC"), 2] <- soilWHC_total
#LitterWHC in cm (top soil layer)
param[which(param[, 1] == "litterWHC"), 2] <- unlist(soil_IC_list$vals["volume_fraction_of_water_in_soil_at_saturation"])[1]*thickness[1]
}
if ("soil_hydraulic_conductivity_at_saturation" %in% names(soil_IC_list$vals)) {
#litwaterDrainrate in cm/day
param[which(param[, 1] == "litWaterDrainRate"), 2] <- unlist(soil_IC_list$vals["soil_hydraulic_conductivity_at_saturation"])[1]*100/(3600*24)
}
}else{
PEcAn.logger::logger.warn("No depth info was found in the soil file. Please check whether the parameters are for the whole profile")
}
}
if (!is.null(IC)) {
ic.names <- names(IC)
## plantWoodInit gC/m2
Expand Down
2 changes: 1 addition & 1 deletion modules/assim.sequential/R/metSplit.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ metSplit <- function(conf.settings, inputs, settings, model, no_split = FALSE, o
furrr::future_pmap(list(conf.settings %>% `class<-`(c("list")), inputs, model), function(settings, inputs, model) {
# Loading the model package - this is required bc of the furrr
library(paste0("PEcAn.",model), character.only = TRUE)

inputs.split <- list()
if (!no_split) {
for (i in seq_len(nens)) {
Expand Down
84 changes: 68 additions & 16 deletions modules/assim.sequential/R/sda.enkf_MultiSite.R
Original file line number Diff line number Diff line change
Expand Up @@ -355,17 +355,33 @@ sda.enkf.multisite <- function(settings,
#reformatting params
new.params <- sda_matchparam(settings, ensemble.samples, site.ids, nens)
}
#sample met ensemble members
#TODO: incorporate Phyllis's restart work
# sample all inputs specified in the settings$ensemble not just met
inputs <- PEcAn.settings::papply(conf.settings,function(setting) {
PEcAn.uncertainty::input.ens.gen(
settings = setting,
input = "met",
method = setting$ensemble$samplingspace$met$method,
parent_ids = NULL
)
})

#sample all inputs specified in the settings$ensemble
#now looking into the xml
samp <- conf.settings$ensemble$samplingspace
#finding who has a parent
parents <- lapply(samp,'[[', 'parent')
#order parents based on the need of who has to be first
order <- names(samp)[lapply(parents, function(tr) which(names(samp) %in% tr)) %>% unlist()]
#new ordered sampling space
samp.ordered <- samp[c(order, names(samp)[!(names(samp) %in% order)])]
#performing the sampling
inputs <- vector("list", length(conf.settings))
# For the tags specified in the xml I do the sampling
for (s in seq_along(conf.settings)){
if (is.null(inputs[[s]])) {
inputs[[s]] <- list()
}
for (i in seq_along(samp.ordered)){
#call the function responsible for generating the ensemble
inputs[[s]][[names(samp.ordered)[i]]] <- input.ens.gen(settings=conf.settings[[s]],
input=names(samp.ordered)[i],
method=samp.ordered[[i]]$method,
parent_ids=NULL)
}
}


###------------------------------------------------------------------------------------------------###
### loop over time ###
###------------------------------------------------------------------------------------------------###
Expand All @@ -379,7 +395,42 @@ sda.enkf.multisite <- function(settings,
if (t>1){
#for next time step split the met if model requires
#-Splitting the input for the models that they don't care about the start and end time of simulations and they run as long as their met file.
inputs.split <- metSplit(conf.settings, inputs, settings, model, no_split = FALSE, obs.times, t, nens, restart_flag = FALSE, my.split_inputs)
#set start and end date for splitting met
start.time = obs.times[t - 1] #always start timestep before

if(restart_flag){
stop.time = settings$run$site$met.end
}else{
stop.time = obs.times[t]
}


#-Splitting the input for the models that they don't care about the start and end time of simulations and they run as long as their met file.
inputs.split <-
furrr::future_pmap(list(conf.settings %>% `class<-`(c("list")), inputs, model), function(settings, inputs, model) {
# Loading the model package - this is required bc of the furrr
library(paste0("PEcAn.",model), character.only = TRUE)

inputs.split <- inputs
if (!no_split) {
for (i in seq_len(nens)) {
#---------------- model specific split inputs
inputs.split$met$samples[i] <- do.call(
my.split_inputs,
args = list(
settings = settings,
start.time = (lubridate::ymd_hms(start.time, truncated = 3) + lubridate::second(lubridate::hms("00:00:01"))),
stop.time = lubridate::ymd_hms(stop.time, truncated = 3),
inputs = inputs$met$samples[[i]])
)
}
} else{
inputs.split <- inputs
}
inputs.split
})



#---------------- setting up the restart argument for each site separately and keeping them in a list
restart.list <-
Expand Down Expand Up @@ -412,9 +463,8 @@ sda.enkf.multisite <- function(settings,
X <- X
}else{
if (control$debug) browser()
out.configs <- conf.settings %>%
`class<-`(c("list")) %>%
furrr::future_map2(restart.list, function(settings, restart.arg) {

out.configs <-furrr::future_pmap(list(conf.settings %>% `class<-`(c("list")),restart.list, inputs), function(settings, restart.arg, inputs) {
# Loading the model package - this is required bc of the furrr
library(paste0("PEcAn.",settings$model$type), character.only = TRUE)
# wrtting configs for each settings - this does not make a difference with the old code
Expand All @@ -425,6 +475,7 @@ sda.enkf.multisite <- function(settings,
model = settings$model$type,
write.to.db = settings$database$bety$write,
restart = restart.arg,
samples=inputs,
rename = TRUE
)
}) %>%
Expand Down Expand Up @@ -768,4 +819,5 @@ sda.enkf.multisite <- function(settings,
# }
## MCD: I commented the above "if" out because if you are restarting from a previous forecast, this might delete the files in that earlier folder
} ### end loop over time
} # sda.enkf
} # sda.enkf

Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ template <- PEcAn.settings::Settings(list(
ensemble = structure(list(size = 25, variable = "NPP",
samplingspace = structure(list(
parameters = structure(list(method = "lhc")),
soilinitcond = structure(list(method = "sampling")),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check to make sure there aren't other inputs that are being left out

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is the operational SDA using a LHC sampling of the posterior parameters? That's not random.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. The current SDA workflow used "get.parameter.samples(settings, ens.sample.method = settings$ensemble$samplingspace$parameters$method)" to sample parameters and the method is "lhc".

met = structure(list(method = "sampling"))
))
)),
Expand Down
1 change: 1 addition & 0 deletions modules/data.land/NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export(soil2netcdf)
export(soil_params)
export(soil_process)
export(soilgrids_soilC_extract)
export(soilgrids_texture_extraction)
export(subset_layer)
export(to.Tag)
export(to.TreeCode)
Expand Down
2 changes: 2 additions & 0 deletions modules/data.land/R/extract_soil_nc.R
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ extract_soil_nc <- function(in.file,outdir,lat,lon){
#' * `soil_thermal_conductivity_at_saturation`
#' * `soil_thermal_capacity`
#' * `soil_albedo`

#'
#' @param varname character vector. See details
#'
Expand Down Expand Up @@ -383,6 +384,7 @@ soil.units <- function(varname = NA){
"soil_thermal_conductivity_at_saturation","W m-1 K-1",
"soil_thermal_capacity","J kg-1 K-1",
"soil_albedo","1"

),
ncol=2,byrow = TRUE))
colnames(variables) <- c('var','unit')
Expand Down
Loading
Loading