Skip to content

Commit 43ca1c7

Browse files
authored
Merge pull request #58 from ccmmf/caladapt-downloader
Caladapt download + conversion files
2 parents 49862ea + f096d60 commit 43ca1c7

3 files changed

Lines changed: 255 additions & 1 deletion

File tree

tools/caladapt_download_grid.R

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env Rscript
2+
3+
# Get hourly weather data from Caladapt's WRF climate scenarios
4+
# for all grid cells covering a set of parcels
5+
#
6+
# Caution: Expect long runtimes -- my statewide download took on the order of
7+
# 10 min per model-year = ~4 hours per model when fetching 203 grid cells
8+
# from 2024 to 2051.
9+
10+
# TODO Consider downloading models in parallel via furrr::future_walk,
11+
# copying the approach in ERA5_met_extract.R.
12+
13+
options <- list(
14+
optparse::make_option("--parcel_geom_file",
15+
default = "data_raw/management/crops/v4.1.2/parcels-consolidated.gpkg",
16+
help = "file containing polygons defining the area of interest"
17+
),
18+
optparse::make_option("--output_dir",
19+
default = "data_raw/wrf_45km_nc",
20+
help = paste(
21+
"Directory to write output.",
22+
"It will contain one subdir per grid cell downloaded,",
23+
"each with one netcdf per year per model.",
24+
"Will also contain a `parcel_to_grid` CSV mapping each parcel id to",
25+
"a CalAdapt grid cell."
26+
)
27+
),
28+
optparse::make_option("--start_year",
29+
default = 2024,
30+
help = "First year of projections to retrieve"
31+
),
32+
optparse::make_option("--end_year",
33+
default = 2024,
34+
help = "Last year of projections to retrieve"
35+
),
36+
optparse::make_option("--models",
37+
default = paste0(
38+
"CESM2,CNRM-ESM2-1,EC-Earth3,EC-Earth3-Veg,",
39+
"FGOALS-g3,MIROC6,MPI-ESM1-2-HR,TaiESM1"
40+
),
41+
help = paste(
42+
"Comma-separated list of GCMs to retrieve.",
43+
"See `caladaptaer::cae_models(\"WRF\")` for valid names."
44+
)
45+
),
46+
optparse::make_option("--scenario",
47+
default = "ssp370",
48+
help = paste(
49+
"Climate scenario. See `caladaptaer::cae_scenarios(\"WRF\")`",
50+
"for valid values."
51+
)
52+
),
53+
optparse::make_option("--resolution",
54+
default = "d01",
55+
help = "Spatial resolution: 'd01' for 45km, 'd02' for 9km, 'd03' for 3km."
56+
)
57+
) |>
58+
# Show default values in help message
59+
purrr::modify(\(x) {
60+
x@help <- paste(x@help, "[default: %default]")
61+
x
62+
})
63+
64+
args <- optparse::OptionParser(option_list = options) |>
65+
optparse::parse_args()
66+
67+
68+
69+
# Needs caladaptaer, available via
70+
# remotes::install_github("lebauerapproach/caladaptaer")
71+
# install.packages("CFtime")
72+
73+
# library(caladaptaer)
74+
# library(tidyverse)
75+
76+
models <- strsplit(args$models, ",")[[1]] |>
77+
trimws()
78+
79+
centroids <- terra::vect(args$parcel_geom_file) |>
80+
_[,"parcel_id"] |>
81+
terra::centroids() |>
82+
terra::project("epsg:4326") |>
83+
as.data.frame(geom="XY") |>
84+
dplyr::rename(lon = x, lat = y)
85+
86+
# Easiest current way to get a reference grid: fetch one timepoint with no
87+
# location specified
88+
# (future caladaptaer releases may add a more streamlined catalog lookup)
89+
caladapt_ref <- caladaptaer::cae_fetch(
90+
variable = "t2",
91+
model = "CESM2",
92+
scenario = args$scenario,
93+
start_time = "2050-07-01T00:00:00",
94+
end_time = "2050-07-01T00:00:00",
95+
resolution = args$resolution,
96+
timescale = "1hr"
97+
)
98+
99+
gridid <- caladaptaer::cae_grid_cells(centroids, caladapt_ref)
100+
if (!dir.exists(args$output_dir)) {
101+
dir.create(args$output_dir, recursive = TRUE)
102+
}
103+
gridid |>
104+
dplyr::mutate(
105+
dplyr::across(
106+
dplyr::contains(c("lon", "lat")),
107+
\(x) round(x, 5)
108+
)
109+
) |>
110+
write.csv(
111+
file = file.path(
112+
args$output_dir,
113+
paste0("parcel_to_grid_", args$resolution, ".csv")
114+
),
115+
row.names = FALSE
116+
)
117+
118+
119+
cells_to_fetch <- gridid |>
120+
dplyr::distinct(cell_id, cell_lon, cell_lat) |>
121+
dplyr::rename(lon = cell_lon, lat = cell_lat, site_id = cell_id)
122+
123+
get_one_model <- function(modelname) {
124+
caladaptaer::cae_build_met_drivers(
125+
sites = cells_to_fetch,
126+
model = modelname,
127+
scenario = args$scenario,
128+
start_year = args$start_year,
129+
end_year = args$end_year,
130+
outdir = args$output_dir,
131+
resolution = args$resolution
132+
)
133+
}
134+
135+
models |>
136+
purrr::walk(get_one_model)

workflow/01_ERA5_nc_to_clim.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
# This is basically a thin wrapper around `met2model.SIPNET()`.
77
# Only the filenames are specific to ERA5 by assuming each file is named
8-
# "ERA5.<ens_id>.<year>nc" with ens_id between 1 and 10.
8+
# "ERA5.<ens_id>.<year>.nc" with ens_id between 1 and 10.
99

1010
## --------- runtime values: change for your system and simulation ---------
1111

workflow/01_WRF_nc_to_clim.R

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env Rscript
2+
3+
# Converts Caladapt WRF meteorology data from PEcAn's standard netCDF format
4+
# (each combination of site+ensemble member gets one file per year)
5+
# to Sipnet `clim` driver files (each site_ens gets one ASCII file for the whole
6+
# simulation interval).
7+
8+
# This is a thin wrapper around `met2model.SIPNET()` enforcing a filename
9+
# convention that makes sense for gridded WRF data: Instead of the ensemble
10+
# numbers seen in some other met code (eg ERA5), we use GCM name as ensemble id.
11+
# Input files: `<nc_dir>/<gridid>/<GCM>.<scenario>.<yyyy>.nc`
12+
# Output files: `<sipnet_dir>/<gridid>/<GCM>.<scenario>.<start_date>.<end_date>.clim`
13+
14+
# TODO:
15+
# Does not currently encode WRF domain (aka resolution) anywhere other than the
16+
# default folder names (which are only advisory).
17+
# Should this be written into filenames for clarity?
18+
19+
options <- list(
20+
optparse::make_option("--nc_dir",
21+
default = "data_raw/wrf_45km_nc",
22+
help = paste(
23+
"Path to your existing WRF data in PEcAn CF format, organized as",
24+
"single-model, single-year netcdfs in subdirectories per grid cell.",
25+
"Files should be named",
26+
"'<nc_dir>/<gridid>/<model>.<scenario>.<year>.nc'"
27+
)
28+
),
29+
optparse::make_option("--sipnet_dir",
30+
default = "data/WRF_45km_SIPNET",
31+
help = paste(
32+
"Output path:",
33+
"single-site, multi-year Sipnet clim files, one per ensemble member.",
34+
"Files will be named",
35+
"<sipnet_dir>/<gridid>/<model>.<scenario>.<start>.<end>.clim"
36+
)
37+
),
38+
optparse::make_option("--cells_wanted_file",
39+
default = "data_raw/wrf_45km_nc/parcel_to_grid_d01.csv",
40+
help = paste(
41+
"CSV file with one row per location to be extracted.",
42+
"Only column `cell_id` is used."
43+
)
44+
),
45+
optparse::make_option("--start_date",
46+
default = "2024-01-01",
47+
help = "Date to begin clim file"
48+
),
49+
optparse::make_option("--end_date",
50+
default = "2051-12-31",
51+
help = "Date to end clim file"
52+
),
53+
optparse::make_option("--models",
54+
default = paste0(
55+
"CESM2,CNRM-ESM2-1,EC-Earth3,EC-Earth3-Veg,",
56+
"FGOALS-g3,MIROC6,MPI-ESM1-2-HR,TaiESM1"
57+
),
58+
help = paste(
59+
"Comma-separated list of GCMs to convert.",
60+
"See `caladaptaer::cae_models(\"WRF\")` for valid names."
61+
)
62+
),
63+
optparse::make_option("--scenario",
64+
default = "ssp370",
65+
help = paste(
66+
"Climate scenario. See `caladaptaer::cae_scenarios(\"WRF\")`",
67+
"for valid values."
68+
)
69+
),
70+
optparse::make_option("--n_cores",
71+
default = 1L,
72+
help = "number of CPUs to use in parallel"
73+
),
74+
optparse::make_option("--parallel_strategy",
75+
default = "multisession",
76+
help = "Strategy for parallel conversion, passed to future::plan()"
77+
)
78+
) |>
79+
# Show default values in help message
80+
purrr::modify(\(x) {
81+
x@help <- paste(x@help, "[default: %default]")
82+
x
83+
})
84+
85+
args <- optparse::OptionParser(option_list = options) |>
86+
optparse::parse_args()
87+
88+
89+
90+
91+
future::plan(args$parallel_strategy, workers = args$n_cores)
92+
93+
site_info <- read.csv(args$cells_wanted_file) |>
94+
dplyr::distinct(cell_id)
95+
site_info$start_date <- args$start_date
96+
site_info$end_date <- args$end_date
97+
98+
models <- strsplit(args$models, ",")[[1]] |>
99+
trimws()
100+
101+
file_info <- site_info |>
102+
dplyr::cross_join(data.frame(gcm = models))
103+
104+
if (!dir.exists(args$sipnet_dir)) {
105+
dir.create(args$sipnet_dir, recursive = TRUE)
106+
}
107+
furrr::future_pwalk(
108+
file_info,
109+
function(gcm, start_date, end_date, cell_id, ...) {
110+
PEcAn.SIPNET::met2model.SIPNET(
111+
in.path = file.path(args$nc_dir, cell_id),
112+
start_date = start_date,
113+
end_date = end_date,
114+
in.prefix = paste0(gcm, ".", args$scenario),
115+
outfolder = file.path(args$sipnet_dir, cell_id)
116+
)
117+
}
118+
)

0 commit comments

Comments
 (0)