From ba974e351ff65fea69a4e78475bebbdce4b7fce4 Mon Sep 17 00:00:00 2001 From: Yisreal Date: Fri, 6 Sep 2024 19:26:22 +0800 Subject: [PATCH 1/4] Only Generate job.sh --- models/fates/R/write.configs.FATES.R | 773 ++++++--------------------- 1 file changed, 164 insertions(+), 609 deletions(-) diff --git a/models/fates/R/write.configs.FATES.R b/models/fates/R/write.configs.FATES.R index 5b8fabb6a6..67d82a4496 100644 --- a/models/fates/R/write.configs.FATES.R +++ b/models/fates/R/write.configs.FATES.R @@ -9,23 +9,40 @@ ##' @return none ##' @export ##' @author Mike Dietze, Shawn Serbin +##-------------------------------------------------------------------------------------------------# # nolint + +# example trait.values list +trait.values <- list() +trait.values$temperate.coniferous <- list() +trait.values$env <- list() + +tc_traits <- as.data.frame(matrix(c(9999, 8888), nrow=1, ncol=2)) +colnames(tc_traits) <- c("leaf_turnover_rate", "veg_respiration_Q10") +# Fates names for these params are "fates_leaf_long", "q10_mr" + +trait.values$temperate.coniferous <- tc_traits +settings <- './test.fates.xml' +run.id <- 'test_oneyear' + +# example trait.values list + write.config.FATES <- function(defaults, trait.values, settings, run.id){ ## site information site <- settings$run$site - site.id <- as.numeric(site$id) + site.id <- site$id # change1: 772 -> SOD1 # find out where things are - local.rundir <- file.path(settings$rundir, run.id) ## this is on local machine for staging - rundir <- file.path(settings$host$rundir, run.id) ## this is on remote machine for execution - casedir <- file.path(rundir,"case") - outdir <- file.path(settings$host$outdir, run.id) - refcase <- settings$model$binary - bld <- file.path(refcase,"bld") - binary <- file.path(bld,"cesm.exe") - indir <- file.path(rundir,"input") ## input directory - default <- settings$run$inputs$default$path ## reference inputs file structure - site_name <- paste0(site.id %/% 1000000000, "-", site.id %% 1000000000) + #local.rundir <- file.path(settings$rundir, run.id) ## this is on local machine for staging + #rundir <- file.path(settings$host$rundir, run.id) ## this is on remote machine for execution + #casedir <- rundir # file.path(rundir,run.id) ## /ctsm-api/resources/cases/case_SOD1, change2: 'case' -> site.id + #outdir <- file.path(settings$host$outdir, run.id) + #refcase <- settings['model']['binary'] # question1: refcase==casedir? + #bld <- file.path(refcase,"bld") + #binary <- file.path(bld,"cesm.exe") + #indir <- file.path(rundir,"data/shared") ## input directory + #default <- settings$run$inputs$default$path ## reference inputs file structure + #site_name <- paste0(site.id, "_c", run.id) ## change3 ## DATES ## CLM is a bit odd and takes a start date and length, so we need to precompute @@ -42,49 +59,50 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ ## SITE INFO --> DOMAIN FILE (lat/lon) # - should also store this in the refcase directory for PEcAn so we can grab from there, and not the PEcAn package - gridres <- 0.125 ## ultimately this should be a variable - lat <- as.numeric(site$lat) - lon <- (as.numeric(site$lon) + 360) %% 360 ## make sure coords in 0-360 range, not negative - domain.default <- system.file("domain.lnd.1x1pt-brazil_navy.090715.nc",package="PEcAn.FATES") - domain.file <- file.path(local.rundir,paste0("domain.lnd.",site_name,".nc")) - file.copy(domain.default,domain.file) - domain.nc <- ncdf4::nc_open(domain.file,write=TRUE) - ncdf4::ncvar_put(nc=domain.nc, varid='xc', vals=lon) - ncdf4::ncvar_put(nc=domain.nc, varid='yc', vals=lat) - ncdf4::ncvar_put(nc=domain.nc, varid='xv', vals=lon+c(-1,1,1,-1)*gridres) - ncdf4::ncvar_put(nc=domain.nc, varid='yv', vals=lat+c(-1,-1,1,1)*gridres) - ncdf4::ncvar_put(nc=domain.nc, varid='area', vals=(2*gridres*pi/180)^2) - ncdf4::nc_close(domain.nc) + #gridres <- 0.125 ## ultimately this should be a variable + #lat <- as.numeric(site$lat) + #lon <- (as.numeric(site$lon) + 360) %% 360 ## make sure coords in 0-360 range, not negative + #domain.default <- system.file("domain.lnd.360x720_gswp3.0v1.c170606.nc",package="PEcAn.FATES") + #domain.file <- file.path(local.rundir,paste0("domain.lnd.fv0.9x1.25_gx1v7_",site_name,".nc")) + #file.copy(domain.default,domain.file) + #domain.nc <- ncdf4::nc_open(domain.file,write=TRUE) + #ncdf4::ncvar_put(nc=domain.nc, varid='xc', vals=lon) + #ncdf4::ncvar_put(nc=domain.nc, varid='yc', vals=lat) + #ncdf4::ncvar_put(nc=domain.nc, varid='xv', vals=lon+c(-1,1,1,-1)*gridres) + #ncdf4::ncvar_put(nc=domain.nc, varid='yv', vals=lat+c(-1,-1,1,1)*gridres) + #ncdf4::ncvar_put(nc=domain.nc, varid='area', vals=(2*gridres*pi/180)^2) + #ncdf4::nc_close(domain.nc) ## SURF - should also store this in the refcase directory for PEcAn so we can grab from there, and not the PEcAn package - surf.default <- system.file("surfdata_1x1_brazil_16pfts_Irrig_CMIP6_simyr2000_c171214.nc",package = "PEcAn.FATES") - surf.file <- file.path(local.rundir,paste0("surfdata_",site_name,"_simyr2000.nc")) - file.copy(surf.default,surf.file) - Sys.chmod(surf.file) - surf.nc <- ncdf4::nc_open(surf.file,write=TRUE) - ncdf4::ncvar_put(nc=surf.nc, varid='LONGXY', vals=lon) - ncdf4::ncvar_put(nc=surf.nc, varid='LATIXY', vals=lat) - ncdf4::nc_close(surf.nc) + #surf.default <- system.file("surfdata_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr2000_c190214.nc",package = "PEcAn.FATES") + #surf.file <- file.path(local.rundir,paste0("surfdata_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr2000_",site_name, ".nc")) + #file.copy(surf.default,surf.file) + #Sys.chmod(surf.file) + #surf.nc <- ncdf4::nc_open(surf.file,write=TRUE) + #ncdf4::ncvar_put(nc=surf.nc, varid='LONGXY', vals=lon) + #ncdf4::ncvar_put(nc=surf.nc, varid='LATIXY', vals=lat) + #ncdf4::nc_close(surf.nc) + ## DATM & DATM Stream?? ## MET HEADERS - if(!is.null(settings$run$inputs$met)){ + #if(!is.null(settings$run$inputs$met)){ ## DATM HEADER: datm_atm_in - datm <- readLines(con=system.file("datm_atm_in.template",package = "PEcAn.FATES"),n=-1) - datm <- gsub('@DOMAIN@', file.path(indir,"share/domains/domain.clm",basename(domain.file)), datm) - datm <- gsub('@START_YEAR@',lubridate::year(start_date), datm) - datm <- gsub('@END_YEAR@',lubridate::year(end_date), datm) - writeLines(datm, con=file.path(local.rundir, "datm_atm_in")) + #datm <- readLines(con=system.file("datm_atm_in.template",package = "PEcAn.FATES"),n=-1) + #datm <- gsub('@DOMAIN@', file.path(indir,"share/domains/domain.clm",basename(domain.file)), datm) + #datm <- gsub('@START_YEAR@',lubridate::year(start_date), datm) + #datm <- gsub('@END_YEAR@',lubridate::year(end_date), datm) + #writeLines(datm, con=file.path(local.rundir, "datm_atm_in")) - ## DATM STREAM MET - met <- readLines(con=system.file("datm.streams.txt.PEcAn_met.template",package = "PEcAn.FATES"),n=-1) - met <- gsub('@INDIR@',indir, met) + ### DATM STREAM MET + #met <- readLines(con=system.file("datm.streams.txt.PEcAn_met.template",package = "PEcAn.FATES"),n=-1) + #met <- gsub('@INDIR@',indir, met) #domain.file.name <- paste0("domain.lnd.",site_name,".nc") #met <- gsub('@DOMAIN@',domain.file.name, met) # attempting to provide correct domain file name - met <- gsub('@MET_PATH@',settings$run$inputs$met$path, met) - met.files <- dir(settings$run$inputs$met$path,"*.nc") - met <- gsub('@MET_FILES@',paste(met.files,collapse = "\n "), met) - writeLines(met, con=file.path(local.rundir, "datm.streams.txt.PEcAn_met")) + #met <- gsub('@MET_PATH@',settings$run$inputs$met$path, met) + #met.files <- dir(settings$run$inputs$met$path,"*.nc") + #met <- gsub('@MET_FILES@',paste(met.files,collapse = "\n"), met) + #writeLines(met, con=file.path(local.rundir, "datm.streams.txt.PEcAn_met")) } # ... need to set this up so that if MET is blank it can run with default CLM met @@ -105,70 +123,64 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ jobsh <- readLines(con=system.file("template.job", package = "PEcAn.FATES"), n=-1) } - # create host specific setttings - hostsetup <- "" - if (!is.null(settings$model$prerun)) { - hostsetup <- paste(hostsetup, sep="\n", paste(settings$model$prerun, collapse="\n")) - } - if (!is.null(settings$host$prerun)) { - hostsetup <- paste(hostsetup, sep="\n", paste(settings$host$prerun, collapse="\n")) - } + # create host specific settings + # hostsetup <- "" + # if (!is.null(settings$model$prerun)) { + # hostsetup <- paste(hostsetup, sep="\n", paste(settings$model$prerun, collapse="\n")) + # } + # if (!is.null(settings$host$prerun)) { + # hostsetup <- paste(hostsetup, sep="\n", paste(settings$host$prerun, collapse="\n")) + # } - hostteardown <- "" - if (!is.null(settings$model$postrun)) { - hostteardown <- paste(hostteardown, sep="\n", paste(settings$model$postrun, collapse="\n")) - } - if (!is.null(settings$host$postrun)) { - hostteardown <- paste(hostteardown, sep="\n", paste(settings$host$postrun, collapse="\n")) - } + # hostteardown <- "" + # if (!is.null(settings$model$postrun)) { + # hostteardown <- paste(hostteardown, sep="\n", paste(settings$model$postrun, collapse="\n")) + # } + # if (!is.null(settings$host$postrun)) { + # hostteardown <- paste(hostteardown, sep="\n", paste(settings$host$postrun, collapse="\n")) + # } # create job.sh - jobsh <- gsub('@HOST_SETUP@', hostsetup, jobsh) - jobsh <- gsub('@HOST_TEARDOWN@', hostteardown, jobsh) + #jobsh <- gsub('@HOST_SETUP@', hostsetup, jobsh) + #jobsh <- gsub('@HOST_TEARDOWN@', hostteardown, jobsh) ## Machine configs - # ./create_newcase -case @CASEDIR@ -res 1x1_brazil -compset ICLM45ED -mach @MACHINE@ -compiler @COMPILER@ -project @PROJECT@ + # ./create_newcase –case A –res @RES@ –compset @COMPSET@ –driver @DRIVER@ –machine @MACHINE@ –run-unsupported if (!is.null(settings$model$machine)) { machine <- paste(settings$model$machine, collapse="\n") } else { - machine <- "eddi" + machine <- "container-nlp" } jobsh <- gsub('@MACHINE@', machine, jobsh) - if (!is.null(settings$model$compiler)) { - compiler <- paste(settings$model$compiler, collapse="\n") + if (!is.null(settings$model$driver)) { + driver <- paste(settings$model$driver, collapse="\n") } else { - compiler <- "gnu" + driver <- "nuopc" } - jobsh <- gsub('@COMPILER@', compiler, jobsh) - if (!is.null(settings$model$resolution)) { - resolution <- paste(settings$model$resolution, collapse="\n") - } else { - resolution <- "1x1_brazil" - } - jobsh <- gsub('@RES@', resolution, jobsh) + jobsh <- gsub('@DRIVER@', driver, jobsh) if (!is.null(settings$model$compset)) { compset <- paste(settings$model$compset, collapse="\n") } else { - compset <- "I2000Clm50FatesGs" + compset <- "2000_DATM%GSWP3v1_CLM51%FATES_SICE_SOCN_MOSART_SGLC_SWAV" } jobsh <- gsub('@COMPSET@', compset, jobsh) - if (!is.null(settings$model$project)) { - project <- paste(settings$model$project, collapse="\n") + if (!is.null(settings$model$res)) { + res <- paste(settings$model$res, collapse="\n") } else { - project <- "pecan" + res <- "CLM_USRDAT" } - jobsh <- gsub('@PROJECT@', project, jobsh) + jobsh <- gsub('@RES@', res, jobsh) ## PATHS - jobsh <- gsub('@RUNDIR@', rundir, jobsh) - jobsh <- gsub('@CASEDIR@', casedir, jobsh) - jobsh <- gsub('@OUTDIR@', outdir, jobsh) - jobsh <- gsub('@REFCASE@', refcase, jobsh) - jobsh <- gsub('@BLD@', bld, jobsh) - jobsh <- gsub('@BINARY@', binary, jobsh) - jobsh <- gsub('@INDIR@', indir, jobsh) - jobsh <- gsub('@DEFAULT@', default, jobsh) - jobsh <- gsub('@SITE_NAME@', site_name, jobsh) + #jobsh <- gsub('@RUNDIR@', rundir, jobsh) + #jobsh <- gsub('@CASEDIR@', casedir, jobsh) + #jobsh <- gsub('@OUTDIR@', outdir, jobsh) + #jobsh <- gsub('@REFCASE@', refcase, jobsh) + #jobsh <- gsub('@BLD@', bld, jobsh) + #jobsh <- gsub('@BINARY@', binary, jobsh) + #jobsh <- gsub('@INDIR@', indir, jobsh) + #jobsh <- gsub('@DEFAULT@', default, jobsh) + #jobsh <- gsub('@SITE_NAME@', site_name, jobsh) ## DATES -> ENV_RUN jobsh <- gsub('@START_DATE@', start_date, jobsh) @@ -181,7 +193,8 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ writeLines(jobsh, con=file.path(settings$rundir, run.id, "job.sh")) Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) -# + +write.config.FATES(default, trait.values, test.fates.xml, run.id) # ## Write PARAMETER file ## COPY AND OPEN DEFAULT PARAMETER FILES @@ -191,103 +204,76 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ # CLM #clm.param.default <- system.file("clm5_params.c171117.nc",package="PEcAn.FATES") #clm.param.file <- file.path(local.rundir,paste0("clm_params.",run.id,".nc")) - clm.param.default <- file.path(refcase,"clm5_params.c171117.nc") # probably need to allow custom param file names here (pecan.xml?) - clm.param.file <- file.path(local.rundir,paste0("clm_params.",run.id,".nc")) - file.copy(clm.param.default,clm.param.file) - clm.param.nc <- ncdf4::nc_open(clm.param.file,write=TRUE) + ## Position of parameters file? + #clm.param.default <- file.path(refcase,"clm5_params.c171117.nc") # probably need to allow custom param file names here (pecan.xml?) + #clm.param.file <- file.path(local.rundir,paste0("clm_params.",run.id,".nc")) + #file.copy(clm.param.default,clm.param.file) + #clm.param.nc <- ncdf4::nc_open(clm.param.file,write=TRUE) # FATES #fates.param.default <- system.file("fates_params_2troppftclones.c171018_sps.nc",package="PEcAn.FATES") # above is a temporary param file corrected for the tropics by lowering freezing tolerace parameters - fates.param.default <- file.path(refcase,"fates_params_2troppftclones.c171018_sps.nc") # probably need to allow custom param file names here (pecan.xml?) - fates.param.file <- file.path(local.rundir,paste0("fates_params.",run.id,".nc")) - file.copy(fates.param.default,fates.param.file) - fates.param.nc <- ncdf4::nc_open(fates.param.file,write=TRUE) + #fates.param.default <- file.path(refcase,"fates_params_2troppftclones.c171018_sps.nc") # probably need to allow custom param file names here (pecan.xml?) + #fates.param.file <- file.path(local.rundir,paste0("fates_params.",run.id,".nc")) + #file.copy(fates.param.default,fates.param.file) + #fates.param.nc <- ncdf4::nc_open(fates.param.file,write=TRUE) ## Loop over PFTS - npft <- length(trait.values) - PEcAn.logger::logger.debug(npft) - PEcAn.logger::logger.debug(dim(trait.values)) - PEcAn.logger::logger.debug(names(trait.values)) + #npft <- length(trait.values) + #PEcAn.logger::logger.debug(npft) + #PEcAn.logger::logger.debug(dim(trait.values)) + #PEcAn.logger::logger.debug(names(trait.values)) #pftnames <- stringr::str_trim(tolower(ncvar_get(param.nc,"pftname"))) - pftnames <- stringr::str_trim(tolower(ncdf4::ncvar_get(clm.param.nc,"pftname"))) - PEcAn.logger::logger.debug(paste0("CLM PFT names: "),pftnames) - for (i in seq_len(npft)) { - pft <- trait.values[[i]] - print(c("PFT",i)) - PEcAn.logger::logger.info(pft) - pft.name <- names(trait.values)[i] - if(is.null(pft.name) | is.na(pft.name)){ - PEcAn.logger::logger.error("pft.name missing") - } else { - PEcAn.logger::logger.info(paste("PFT =",pft.name)) - PEcAn.logger::logger.debug(paste0("fates-clm PFT number: ",which(pftnames==pft.name))) - } - if(pft.name == 'env') next ## HACK, need to remove env from default + #pftnames <- stringr::str_trim(tolower(ncdf4::ncvar_get(clm.param.nc,"pftname"))) + #PEcAn.logger::logger.debug(paste0("CLM PFT names: "),pftnames) + #for (i in seq_len(npft)) { + #pft <- trait.values[[i]] + #print(c("PFT",i)) + #PEcAn.logger::logger.info(pft) + #pft.name <- names(trait.values)[i] + #if(is.null(pft.name) | is.na(pft.name)){ + #PEcAn.logger::logger.error("pft.name missing") + #} else { + #PEcAn.logger::logger.info(paste("PFT =",pft.name)) + #PEcAn.logger::logger.debug(paste0("fates-clm PFT number: ",which(pftnames==pft.name))) + #} + #if(pft.name == 'env') next ## HACK, need to remove env from default ## Match PFT name to COLUMN - ipft <- match(tolower(pft.name),pftnames) - PEcAn.logger::logger.debug(paste0("ipft: ",ipft)) + #ipft <- match(tolower(pft.name),pftnames) + #PEcAn.logger::logger.debug(paste0("ipft: ",ipft)) - if(is.na(ipft)){ - PEcAn.logger::logger.severe(paste("Unmatched PFT",pft.name, - "in FATES. PEcAn does not yet support non-default PFTs for this model")) - } + #if(is.na(ipft)){ + #PEcAn.logger::logger.severe(paste("Unmatched PFT",pft.name, + #"in FATES. PEcAn does not yet support non-default PFTs for this model")) + #} # hard code hack until we can use more than 2 pfts in FATES - ipft <- 2 - PEcAn.logger::logger.debug(paste0("*** PFT number hard-coded to ", ipft," in fates. This will be updated when FATES allows more PFTs")) + #ipft <- 2 + #PEcAn.logger::logger.debug(paste0("*** PFT number hard-coded to ", ipft," in fates. This will be updated when FATES allows more PFTs")) ## Special variables used in conversions # leafC <- pft['leafC']/100 ## percent to proportion - leafC <- NA - if(is.na(leafC)) leafC <- 0.48 + #leafC <- NA + #if(is.na(leafC)) leafC <- 0.48 # determine photo pathway - photo_flag <- ncdf4::ncvar_get(fates.param.nc,varid="fates_c3psn", start = ipft, count = 1) - PEcAn.logger::logger.debug(paste0("Photosynthesis pathway flag value: ", photo_flag)) + #photo_flag <- ncdf4::ncvar_get(fates.param.nc,varid="fates_c3psn", start = ipft, count = 1) + #PEcAn.logger::logger.debug(paste0("Photosynthesis pathway flag value: ", photo_flag)) ## Loop over VARIABLES - for (v in seq_along(pft)) { - var <- names(pft)[v] + #for (v in seq_along(pft)) { + #var <- names(pft)[v] ## THESE NEED SOME FOLLOW UP ### ----- Leaf physiological parameters # Vcmax - if(var == "Vcmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_vcmax25top', start = ipft, count = 1, - vals=pft[v]) ## (umol CO2 m-2 s-1) - } # Ball-Berry slope - if(var == "stomatal_slope.BB"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_BB_slope', start = ipft, count = 1, - vals=pft[v]) - } - + # Ball-Berry intercept - c3. We need to figure out how to set either C3 or C4 values? Based on the PFT? # TODO: allow setting this for C3 and/or C4 PFTs # right now, each are just one dimension, will need to revist this if this changes. - if(var == "cuticular_cond"){ - if (photo_flag==0) { - PEcAn.logger::logger.debug("** Setting C4 cuticular conductance value") - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_bbopt_c4', start = 1, count = 1, - vals=pft[v]) - } else if (photo_flag==1) { - PEcAn.logger::logger.debug("** Setting C3 cuticular conductance value") - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_bbopt_c3', start = 1, count = 1, - vals=pft[v]) - } else { - PEcAn.logger::logger.warn(" ** FATES photosynthesis pathway flag not set. cuticular conductance not set **") - } - } - - ## missing from params.nc - # if(var == "cuticular_cond"){ - # gH2O_per_mol <- 18.01528 - # ncvar_put(nc=param.nc, varid='gsmin', start = ipft, count = 1, - # vals=pft[v]*gH2O_per_mol*1e-12) ### umol H2O m-2 s-1 -> [m s-1] - # } # T response params - modified Arrhenius params for Vcmax, Jmax, and TPU # -- NOT YET IMPLEMENTED IN BETYdb. FATES params: @@ -295,39 +281,17 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ # fates_vcmaxse, fates_jmaxse, fates_tpuse # Ha activation energy for vcmax - FATES units: J/mol - if(var == "Ha_Modified_Arrhenius_Vcmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_vcmaxha', start = ipft, count = 1, - vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units) - } - + # Hd deactivation energy for vcmax - FATES units: J/mol - if(var == "Hd_Modified_Arrhenius_Vcmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_vcmaxhd', start = ipft, count = 1, - vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units) - } - + # Ha activation energy for Jmax - FATES units: J/mol - if(var == "Ha_Modified_Arrhenius_Jmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_jmaxha', start = ipft, count = 1, - vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units) - } # Hd deactivation energy for Jmax - FATES units: J/mol - if(var == "Hd_Modified_Arrhenius_Jmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_jmaxhd', start = ipft, count = 1, - vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units) - } - + # deltaS Vcmax - BETY units:J/mol/K; FATES units: J/mol/K - if(var == "deltaS_Vcmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_vcmaxse', start = ipft, count = 1, - vals=pft[v]) ## convert from kj/mol to J/mol (FATES units) - } + # deltaS Jmax - BETY units:J/mol/K; FATES units: J/mol/K - if(var == "deltaS_Jmax"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_jmaxse', start = ipft, count = 1, - vals=pft[v]) ## convert from kj/mol to J/mol (FATES units) - } + ### ----- Leaf physiological parameters @@ -337,56 +301,15 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ # ncvar_put(nc=param.nc, varid='background_mort_rate', start = ipft, count = 1, # vals=pft[v]) # } - if(var == "r_fract"){ ## Fraction of carbon balance remaining after maintenance costs have been met that is dedicated to seed production. [0-1] - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_seed_alloc', start = ipft, count = 1, - vals=pft[v]) - } - ## This one is currently allpft level but should be pft level - no longer in FATES params, what was this changed to? - if(var == "agf_bs"){ ## The fraction of sapwood and structural biomass that is above ground [0-1] - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_allom_agb_frac', start = ipft, count = 1, - vals=pft[v]) - } - ## PFT-level variables - if(var == "seed_rain_kgC"){ ## External seed rain from outside site (non-mass conserving) ; - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_seed_rain', start = ipft, count = 1, - vals=pft[v]) - } + ## missing from params.nc # if(var == "cuticular_cond"){ # gH2O_per_mol <- 18.01528 # ncvar_put(nc=param.nc, varid='gsmin', start = ipft, count = 1, # vals=pft[v]*gH2O_per_mol*1e-12) ### umol H2O m-2 s-1 -> [m s-1] # } - if(var == "DBH_at_HTMAX"){ ## note in FATES parameter list about switching to HTMAX - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_allom_dbh_maxheight', start = ipft, count = 1, - vals=pft[v]) ## [cm] - } - if(var == "growth_resp_factor"){ ## r_growth = grperc * (gpp+r_maint) fates_grperc:long_name = "Growth respiration factor" ; - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_grperc', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "SLA"){ ## default 0.012 - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_slatop', start = ipft, count = 1, - vals=PEcAn.utils::ud_convert(pft[v],"m2 kg-1","m2 g-1")/leafC) - } - if(var == "leaf_turnover_rate"){ ## fates_leaf_long:long_name = "Leaf longevity (ie turnover timescale)" ; - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_leaf_long', start = ipft, count = 1, - vals=1/pft[v]) ## leaf_long = 1/leaf_turnover_rate, 1/years -> years - } - if(var == "root_turnover_rate"){ ## fates_root_long:long_name = "root longevity (alternatively, turnover time)" ; - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_root_long', start = ipft, count = 1, - vals=1/pft[v]) ## root_long = 1/root_turnover_rate, 1/years -> years - } - if(var == "c2n_leaf"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_leafcn', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "fineroot2leaf"){ #"Allocation parameter: new fine root C per new leaf C" units = "gC/gC" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_froot_leaf', start = ipft, count = 1, - vals=pft[v]) - } - + # if(var == "sapwood_ratio"){ # leaf to sapwood area ratio. IS THIS NOW fates_sapwood_ratio(fates_pft)?? # ncvar_put(nc=fates.param.nc, varid='latosa', start = ipft, count = 1, # vals=PEcAn.utils::ud_convert(pft[v],"m2 m-2","m2 cm-2")) @@ -402,224 +325,16 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ # fates_allom_latosa_slp:units = "unitless" ; # fates_allom_latosa_int = 0.001, 0.001 ; # fates_allom_latosa_slp = 0, 0 ; - if(var == "sapwood_ratio"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_allom_latosa_int', start = ipft, count = 1, - vals=PEcAn.utils::ud_convert(pft[v],"m2 m-2","m2 cm-2")) - } - if(var == "leaf_width"){ # Characteristic leaf dimension use for aerodynamic resistance - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_dleaf', start = ipft, count = 1, - vals=PEcAn.utils::ud_convert(pft[v],"mm","m")) - #PEcAn.logger::logger.debug(paste0("fates_dleaf: ",PEcAn.utils::ud_convert(pft[v],"mm","m"))) # temp debugging - } - ## Currently not in param.nc file despite being on NGEE-T parameter list - # if(var == "nonlocal_dispersal"){ # Place-holder parameter for important seed dispersal parameters - # ncvar_put(nc=param.nc, varid='seed_dispersal_x', start = ipft, count = 1, - # vals=pft[v]) - # } - if(var == "hgt_min"){ # the minimum height (ie starting height) of a newly recruited plant" ; - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_hgt_min', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "leaf_reflect_nir"){ # Leaf reflectance: near-IR [0-1] - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_rholnir', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "leaf_reflect_vis"){ # Leaf reflectance: visible [0-1] - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_rholvis', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "wood_reflect_nir"){ # Stem reflectance: near-IR [0-1] - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_rhosnir', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "wood_reflect_vis"){ # Stem reflectance: visible [0-1] - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_rhosvis', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "leaf_trans_nir"){ # Leaf transmittance: near-IR - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_taulnir', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "leaf_trans_vis"){ # Leaf transmittance: visible pft - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_taulvis', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "wood_trans_nir"){ # Stem transmittance: near-IR - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_tausnir', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "wood_trans_vis"){ # Stem transmittance: visible - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_tausvis', start = ipft, count = 1, - vals=pft[v]) - } - if(var == "orient_factor"){ # Leaf/stem orientation index [-0/4 SOM 1 - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='rf_l1s1_bgc', start = 1, count = 1, - vals=pft[v]) - } - if(var == "rf_l2s1_bgc"){ ## respiration fraction litter 2 to SOM 1 - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='rf_l2s1_bgc', start = 1, count = 1, - vals=pft[v]) - } - if(var == "rf_l3s2_bgc"){ ## respiration fraction from litter 3 to SOM 2 - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='rf_l3s2_bgc', start = 1, count = 1, - vals=pft[v]) - } - if(var == "rf_s2s1_bgc"){ ## respiration fraction SOM 2 to SOM 1 - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='rf_s2s1_bgc', start = 1, count = 1, - vals=pft[v]) - } - if(var == "rf_s2s3_bgc"){ ## Respiration fraction for SOM 2 -> SOM 3 - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='rf_s2s3_bgc', start = 1, count = 1, - vals=pft[v]) - } - if(var == "rf_s3s1_bgc"){ ## respiration fraction SOM 3 to SOM 1 - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='rf_s3s1_bgc', start = 1, count = 1, - vals=pft[v]) - } - if(var == "Q10_frozen_soil"){ ## Separate q10 for frozen soil respiration rates - REMOVED FROM FATES PARAMS? - ncdf4::ncvar_put(nc=fates.param.nc, varid='froz_q10', start = 1, count = 1, - vals=pft[v]) - } + #if(var == "veg_respiration_Q10"){ ## Q10 for maintenance respiration. CLM param. q10_mr(allpfts) + #ncdf4::ncvar_put(nc=clm.param.nc, varid='q10_mr', start = 1, count = 1, + #vals=pft[v]) + #} ## NONE indexed ## -- FIRE - if(var == "max_fire_duration"){ ## maximum duration of fire none hours - # fates_max_durat:long_name = "spitfire parameter, fire maximum duration, Equation 14 Thonicke et al 2010" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_max_durat',vals=pft[v]) - } - if(var == "nfires"){ ## The number of fires initiated per m2 per year, from lightning and humans - # fates_nignitions:long_name = "number of daily ignitions (nfires = nignitions*FDI*area_scaling)" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_nignitions',vals=pft[v]) - } - if(var == "fuel_energy"){ ## energy content of fuel [kj kg-1] - # fates_fuel_energy:long_name = "pitfire parameter, heat content of fuel" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_fuel_energy',vals=pft[v]) - } - if(var == "fuel_particle_density"){ ## particle density of fuel [kg m-3] - # fates_part_dens:long_name = "spitfire parameter, oven dry particle density, Table A1 Thonicke et al 2010" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_part_dens',vals=pft[v]) - } - if(var == "durat_slope"){ ## SPITFIRE: change in fire duration with fire danger index. from Canadian Forest Service - # fates_durat_slope:long_name = "spitfire parameter, fire max duration slope, Equation 14 Thonicke et al 2010" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_durat_slope',vals=pft[v]) - } - if(var == "miner_damp"){ ## SPITFIRE mineral dampening coefficient - # fates_miner_damp:long_name = "spitfire parameter, mineral-dampening coefficient EQ A1 Thonicke et al 2010 " - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_miner_damp',vals=pft[v]) - } - if(var == "fuel_minerals"){ ## mineral content of fuel - # fates_miner_total:long_name = "spitfire parameter, total mineral content, Table A1 Thonicke et al 2010" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_miner_total',vals=pft[v]) - } - if(var == "alpha_scorch_height"){ ## SPITFIRE scorch height parameter - # fates_alpha_SH:long_name = "spitfire parameter, alpha scorch height, Equation 16 Thonicke et al 2010" - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_alpha_SH',vals=pft[v]) - } - if(var == "fdi_a"){ ## SPITFIRE Constant in calculation of dewpoint for Fire Danger Index (FDI) - # fates_fdi_a:long_name = "spitfire parameter (unknown) " - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_fdi_a',vals=pft[v]) - } - if(var == "fdi_alpha"){ ## SPITFIRE Constant in calculation of dewpoint for Fire Danger Index (FDI) - # fates_fdi_alpha:long_name = "spitfire parameter, EQ 7 Venevsky et al. GCB 2002,(modified EQ 8 Thonicke et al. 2010) " - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_fdi_alpha',vals=pft[v]) - } - if(var == "fdi_b"){ ## SPITFIRE Constant in calculation of dewpoint for Fire Danger Index (FDI) - # fates_fdi_b:long_name = "spitfire parameter (unknown) " - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_fdi_b',vals=pft[v]) - } + ## -- CANOPY #if(var == "canopy_max_spread"){ ## Maximum allowable "dynamic ratio of dbh to canopy area" for cohorts in closed canopies. - [cm/m2] # ncdf4::ncvar_put(nc=fates.param.nc, varid='maxspread',vals=pft[v]) @@ -804,32 +375,16 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ # SAV Surface Area to Volume Ratio of fuel class litterclass cm-1 ## NCWD dimensioned Size:4 - if(var == "CWD_frac1"){ ##Fraction of coarse woody debris (CWD) that is moved into each of the four woody fuel classes - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_CWD_frac', start = 1, count = 1, - vals=pft[v]) - } - if(var == "CWD_frac2"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_CWD_frac', start = 2, count = 1, - vals=pft[v]) - } - if(var == "CWD_frac3"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_CWD_frac', start = 3, count = 1, - vals=pft[v]) - } - if(var == "CWD_frac4"){ - ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_CWD_frac', start = 4, count = 1, - vals=pft[v]) - } - } ## end loop over VARIABLES - } ## end loop over PFTs + #} ## end loop over VARIABLES + #} ## end loop over PFTs #ncdf4::nc_close(param.nc) - ncdf4::nc_close(clm.param.nc) - ncdf4::nc_close(fates.param.nc) + #ncdf4::nc_close(clm.param.nc) + #ncdf4::nc_close(fates.param.nc) # ## Write SETTINGS file # -} +#} #---------------------------------------------------------------------------------------------------------------------# ### EOF From 69af60e4fb8cf795e9eba064d2d5646ec36dcbc9 Mon Sep 17 00:00:00 2001 From: Yisreal Date: Tue, 10 Sep 2024 05:11:43 +0800 Subject: [PATCH 2/4] remove extra lines --- models/fates/R/write.configs.FATES.R | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/models/fates/R/write.configs.FATES.R b/models/fates/R/write.configs.FATES.R index 67d82a4496..e04bbfb073 100644 --- a/models/fates/R/write.configs.FATES.R +++ b/models/fates/R/write.configs.FATES.R @@ -10,20 +10,6 @@ ##' @export ##' @author Mike Dietze, Shawn Serbin ##-------------------------------------------------------------------------------------------------# # nolint - -# example trait.values list -trait.values <- list() -trait.values$temperate.coniferous <- list() -trait.values$env <- list() - -tc_traits <- as.data.frame(matrix(c(9999, 8888), nrow=1, ncol=2)) -colnames(tc_traits) <- c("leaf_turnover_rate", "veg_respiration_Q10") -# Fates names for these params are "fates_leaf_long", "q10_mr" - -trait.values$temperate.coniferous <- tc_traits -settings <- './test.fates.xml' -run.id <- 'test_oneyear' - # example trait.values list write.config.FATES <- function(defaults, trait.values, settings, run.id){ @@ -49,7 +35,7 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ ## this needs to be generalized to fractional years, but accounting for 365 day year start_date <- as.Date(settings$run$start.date) end_date <- as.Date(settings$run$end.date) - stop_n <- as.numeric(end_date - start_date, units="days") - PEcAn.utils::n_leap_day(start_date,end_date) + 1 + stop_n <- as.numeric(end_date - start_date, units="days") #- PEcAn.utils::n_leap_day(start_date,end_date) + 1 ##-----------------------------------------------------------------------## ## ## @@ -104,7 +90,7 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ #met <- gsub('@MET_FILES@',paste(met.files,collapse = "\n"), met) #writeLines(met, con=file.path(local.rundir, "datm.streams.txt.PEcAn_met")) - } + #} # ... need to set this up so that if MET is blank it can run with default CLM met # ... fill in this template, the met template, and then have jobs.sh put them in the right place. # ... Test, then adjust DB to have met required @@ -120,7 +106,8 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ if (!is.null(settings$model$jobtemplate) && file.exists(settings$model$jobtemplate)) { jobsh <- readLines(con=settings$model$jobtemplate, n=-1) } else { - jobsh <- readLines(con=system.file("template.job", package = "PEcAn.FATES"), n=-1) + jobsh <- readLines("/Users/mac/Documents/pecan/models/fates/R/template.job") + #jobsh <- readLines(con=system.file("template.job", package = "PEcAn.FATES"), n=-1) } # create host specific settings @@ -190,11 +177,9 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ ## MET --> DATM # jobsh <- gsub('@SITE_MET@', settings$run$inputs$met$path, jobsh) ## FOR FIRST STEP, CAN USE DEFAULT - - writeLines(jobsh, con=file.path(settings$rundir, run.id, "job.sh")) + writeLines(jobsh, file.path(settings$rundir, run.id, "job.sh")) Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) -write.config.FATES(default, trait.values, test.fates.xml, run.id) # ## Write PARAMETER file ## COPY AND OPEN DEFAULT PARAMETER FILES @@ -385,6 +370,6 @@ write.config.FATES(default, trait.values, test.fates.xml, run.id) # ## Write SETTINGS file # -#} +} #---------------------------------------------------------------------------------------------------------------------# ### EOF From b169a7a6d6883514e14a312d316f18e02990bde0 Mon Sep 17 00:00:00 2001 From: Yisreal Date: Tue, 24 Sep 2024 21:50:03 +0800 Subject: [PATCH 3/4] update model_info.json for fates --- models/fates/model_info.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 models/fates/model_info.json diff --git a/models/fates/model_info.json b/models/fates/model_info.json new file mode 100644 index 0000000000..50c853d8f1 --- /dev/null +++ b/models/fates/model_info.json @@ -0,0 +1,16 @@ +{ + "name": "FATES", + "type": "FATES", + "version": "@VERSION@", + "binary": "@BINARY@", + "description": "FATES is a numerical terrestrial ecosystem model, which is an external module running in the given “Host Land Model”, such as CLM-CTSM, E3SM and ELM.", + "creator": "Rob Kooper ", + "contributors": [], + "links": { + "source": "https://github.com/NGEET/fates", + "issues": "https://github.com/NGEET/fates/issues", + "documentation": "https://fates-users-guide.readthedocs.io/en/latest/" + }, + "inputs": {}, + "bibtex": [] +} From dd2feced40b2b11b17617e626e7a3559d4e0c5f9 Mon Sep 17 00:00:00 2001 From: Yisreal Date: Tue, 24 Sep 2024 21:51:10 +0800 Subject: [PATCH 4/4] Initially update Dockerfile of fates from sipnet --- models/fates/Dockerfile | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 models/fates/Dockerfile diff --git a/models/fates/Dockerfile b/models/fates/Dockerfile new file mode 100644 index 0000000000..36ce339541 --- /dev/null +++ b/models/fates/Dockerfile @@ -0,0 +1,42 @@ +# this needs to be at the top, what version are we building +ARG IMAGE_VERSION="latest" + +# ---------------------------------------------------------------------- +# BUILD SIPNET BINARY +# ---------------------------------------------------------------------- +FROM pecan/models:${IMAGE_VERSION} as model-binary + +# Some variables that can be used to set control the docker build +ARG MODEL_VERSION=git + +# download, unzip and build sipnet +WORKDIR /src +RUN git clone https://github.com/PecanProject/fates.git \ + && cd sipnet \ + && if [ "${MODEL_VERSION}" != "git" ]; then git checkout ${MODEL_VERSION}; fi \ + && make + +######################################################################## + +# ---------------------------------------------------------------------- +# BUILD PECAN FOR FATES +# ---------------------------------------------------------------------- +FROM pecan/models:${IMAGE_VERSION} + + +# ---------------------------------------------------------------------- +# SETUP FOR SPECIFIC SIPNET VERSION +# ---------------------------------------------------------------------- + +# Some variables that can be used to set control the docker build +ARG MODEL_VERSION=git + +# Setup model_info file +COPY model_info.json /work/model.json +RUN sed -i -e "s/@VERSION@/${MODEL_VERSION}/g" \ + -e "s#@BINARY@#/usr/local/bin/fates.${MODEL_VERSION}#g" /work/model.json + +# COPY sipnet binary +COPY --from=model-binary /src/CESM/fates /usr/local/bin/fates.${MODEL_VERSION} + +# /src/CESM/fates?