Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
997219b
treat all inputs as independent Sobol factors; remove parent-child fi…
divine7022 Mar 24, 2026
c8e8d98
rewrite compute_sobol_indices to use sensobol
divine7022 Mar 24, 2026
2cf1336
use exported trait_sample_bank_size from uncertainty
divine7022 Mar 24, 2026
b2c73f9
add tests for independent Sobol factor design
divine7022 Mar 24, 2026
f030de7
fix overflow handling in input.ens.gen
divine7022 Mar 24, 2026
1993e03
update NEWS.md
divine7022 Mar 24, 2026
322df2c
update CHANGELOG.md
divine7022 Mar 24, 2026
fed4fa9
add workflow Sobol test
divine7022 Mar 24, 2026
83609a8
add sensobol and tibble
divine7022 Mar 24, 2026
ac08afc
update NAMESPACE
divine7022 Mar 24, 2026
41a7c7e
update compute_sobol_indices.Rd
divine7022 Mar 24, 2026
e64b265
update generate_joint_ensemble_design.Rd
divine7022 Mar 24, 2026
947606d
update trait_sample_bank_size.Rd
divine7022 Mar 24, 2026
89ec736
update NEWS.md
divine7022 Mar 24, 2026
81d2613
update CHANGELOG.md
divine7022 Mar 24, 2026
1313dee
updat NEWS.md
divine7022 Mar 24, 2026
849160c
respect parent child relation
divine7022 Mar 24, 2026
a0782b2
add test for parent child support for settings with parent block vs s…
divine7022 Mar 24, 2026
11fafc2
update docker depens
divine7022 Mar 24, 2026
a1230c7
update generate_joint_ensemble_design.Rd
divine7022 Mar 24, 2026
3789859
use 2N param bank size instead of N(k+2), and refactored different pa…
divine7022 Mar 25, 2026
dfeb577
update tests to use 2N param draws
divine7022 Mar 25, 2026
7f48e6c
add libgsl-dev to the apt-get install line. R 4.4 docker image either…
divine7022 Mar 25, 2026
62f8255
on ci env if missing libgsl, now test gracefully skips instead of fai…
divine7022 Mar 25, 2026
6645666
Merge branch 'develop' into sobol_gsa
dlebauer Apr 10, 2026
ceb16d6
Merge remote-tracking branch 'origin/develop' into sobol_gsa
divine7022 Apr 28, 2026
665200a
add ensemble_id, boot, R args
divine7022 Apr 28, 2026
d41fc3b
warn when user method on independent sobol factor is dropped for QRN
divine7022 Apr 28, 2026
eaa357a
regen compute_sobol_indices.Rd
divine7022 Apr 28, 2026
d6e2620
rewrite sobol_analysis as single or multisite
divine7022 Apr 28, 2026
96d7dc0
add tests for ishigami, uniformity, multisite filter, method warn
divine7022 Apr 28, 2026
df82a3f
Merge branch 'sobol_gsa' of github.com:divine7022/pecan into sobol_gsa
divine7022 Apr 28, 2026
23971a1
Merge branch 'develop' into sobol_gsa
dlebauer Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ For more information about this file see also [Keep a Changelog](http://keepacha
## Unreleased

### Added
- Added `sensobol` based global sensitivity design and postprocessing support in `PEcAn.uncertainty`, including saved Sobol design and index outputs.
- Added PEcAn.PEPRMT model, including a demo run with example data
- Add `format_try_for_ma()` and `try_trait_mapping()` to `PEcAn.data.remote` to convert trait data from the external TRY database into the tabular format required by the PEcAn meta-analysis module (#3717).
- Add function `qsub_sda()` for submitting SDA batch jobs by splitting a large number of sites into multiple small groups of sites (#3634).
Expand Down
28 changes: 26 additions & 2 deletions base/workflow/R/run.write.configs.R
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ run.write.configs <- function(settings, ensemble.size, input_design, write = TRU
# number of (pft, trait, quantile) combinations
if (!is.null(input_design) && "ensemble" %in% names(settings)) {
if (nrow(input_design) != ensemble.size) {
stop(
PEcAn.logger::logger.error(
"input_design has ", nrow(input_design), " rows, but ensemble.size is ",
ensemble.size, ".The design matrix must have exactly one row per run."
ensemble.size, ". The design matrix must have exactly one row per run."
)
}
}
Expand Down Expand Up @@ -171,6 +171,26 @@ run.write.configs <- function(settings, ensemble.size, input_design, write = TRU
!is.null(input_design) &&
"param" %in% colnames(input_design)) {
trait_sample_indices <- input_design[["param"]]
if (is.null(trait.samples) || length(trait.samples) == 0) {
PEcAn.logger::logger.error(
"samples.Rdata does not contain trait.samples required for input_design$param"
)
}
trait_sample_indices <- as.integer(trait_sample_indices)
if (any(is.na(trait_sample_indices)) || any(trait_sample_indices < 1L)) {
PEcAn.logger::logger.error("input_design$param must contain positive integer indices")
}
parameter_bank_size <- PEcAn.uncertainty::trait_sample_bank_size(trait.samples)
if (parameter_bank_size == 0L) {
PEcAn.logger::logger.error(
"samples.Rdata does not contain usable trait.samples required for input_design$param"
)
}
if (any(trait_sample_indices > parameter_bank_size)) {
PEcAn.logger::logger.error(
"input_design$param includes indices beyond the available parameter sample bank"
)
}
ensemble.samples <- list()
for (pft in names(trait.samples)) {
pft_traits <- trait.samples[[pft]]
Expand All @@ -182,6 +202,10 @@ run.write.configs <- function(settings, ensemble.size, input_design, write = TRU
)
names(ensemble.samples[[pft]]) <- names(pft_traits)
}
} else if ("ensemble" %in% names(settings) && !is.null(input_design)) {
PEcAn.logger::logger.error(
"input_design must include a `param` column selecting rows from trait.samples"
)
} else {
# use pre-generated samples
ensemble.samples <- existing_data$ensemble.samples
Expand Down
83 changes: 83 additions & 0 deletions base/workflow/tests/testthat/test.run.write.configs.sobol.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
test_that("runModule.run.write.configs uses input_design row count", {
settings <- PEcAn.settings::Settings(
ensemble = list(
size = 3,
samplingspace = list(parameters = list(method = "uniform"))
),
database = list(bety = list(write = FALSE)),
pfts = list(list(posterior.files = "post.distns.Rdata"))
)
input_design <- data.frame(param = seq_len(5))
captured <- new.env(parent = emptyenv())

mockery::stub(
runModule.run.write.configs,
"PEcAn.workflow::run.write.configs",
function(settings, ensemble.size, input_design, write, posterior.files, overwrite) {
captured$ensemble.size <- ensemble.size
captured$input_design <- input_design
list(
ensemble = list(ensemble.id = 123),
pfts = settings$pfts
)
}
)

result <- runModule.run.write.configs(
settings = settings,
input_design = input_design
)

expect_equal(captured$ensemble.size, 5)
expect_identical(captured$input_design, input_design)
expect_equal(result$ensemble$ensemble.id, 123)
})

test_that("run.write.configs validates param against the shortest trait sample bank", {
withr::with_tempdir({
trait.samples <- list(
pftA = list(SLA = seq_len(4)),
pftB = list(SLA = seq_len(3))
)
sa.samples <- list()
runs.samples <- list()
env.samples <- list()
ensemble.samples <- list()
save(
trait.samples,
sa.samples,
runs.samples,
env.samples,
ensemble.samples,
file = file.path(getwd(), "samples.Rdata")
)

settings <- list(
outdir = getwd(),
database = list(),
model = list(type = "FAKE"),
ensemble = list(size = 2),
pfts = list(
list(name = "pftA", posteriorid = NULL),
list(name = "pftB", posteriorid = NULL)
)
)
run_write_configs <- PEcAn.workflow::run.write.configs
mockery::stub(
run_write_configs,
"PEcAn.logger::logger.error",
function(...) stop(paste(...), call. = FALSE)
)

expect_error(
run_write_configs(
settings = settings,
ensemble.size = 2,
input_design = data.frame(param = c(1L, 4L)),
write = FALSE,
overwrite = FALSE
),
"input_design\\$param includes indices beyond the available parameter sample bank"
)
})
})
1 change: 1 addition & 0 deletions docker/depends/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ RUN apt-get update \
librdf0-dev \
libnetcdf-dev \
libudunits2-dev \
libgsl-dev \
libgl1-mesa-dev \
libglu1-mesa-dev \
&& rm -rf /var/lib/apt/lists/*
Expand Down
3 changes: 2 additions & 1 deletion docker/depends/pecan_package_dependencies.csv
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@
"RPostgreSQL","*","models/biocro","Suggests",FALSE
"RSQLite","*","base/db","Suggests",FALSE
"rstac","*","models/peprmt","Suggests",FALSE
"sensitivity","*","modules/uncertainty","Imports",FALSE
"sensobol","*","modules/uncertainty","Imports",FALSE
"sessioninfo","*","base/all","Suggests",FALSE
"sf","*","modules/assim.sequential","Suggests",FALSE
"sf","*","modules/data.atmosphere","Imports",FALSE
Expand Down Expand Up @@ -674,6 +674,7 @@
"tibble","*","modules/data.land","Imports",FALSE
"tibble","*","modules/data.remote","Suggests",FALSE
"tibble","*","modules/meta.analysis","Suggests",FALSE
"tibble","*","modules/uncertainty","Imports",FALSE
"tictoc","*","modules/assim.sequential","Suggests",FALSE
"tidyr","*","base/db","Imports",FALSE
"tidyr","*","models/ed","Imports",FALSE
Expand Down
3 changes: 2 additions & 1 deletion modules/uncertainty/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ Imports:
purrr,
randtoolbox,
rlang,
sensitivity,
sensobol,
tibble,
tidyr
Suggests:
mockery,
Expand Down
1 change: 1 addition & 0 deletions modules/uncertainty/NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export(sd.var)
export(sensitivity.analysis)
export(sensitivity.filename)
export(spline.truncate)
export(trait_sample_bank_size)
export(write.ensemble.configs)
export(write.sa.configs)
importFrom(dplyr,"%>%")
Expand Down
2 changes: 2 additions & 0 deletions modules/uncertainty/NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# PEcAn.uncertainty 1.9.0.9000

* Switched Sobol global sensitivity workflows to `sensobol`, including explicit design metadata and saved Sobol index outputs.
* Treat all inputs (met, initial conditions, events, etc..) as independent Sobol factors; removed parent-child filter that previously confounded events with meteorology.
* run.ensemble.analysis() now respects `settings$modeloutdir` rather than assuming an `out/` folder inside `settings$outdir` (@Akash-paluvai, #3722).
* Added `generate_OAT_SA_design()` for creating input design matrices for
sensitivity analysis. This function ensures non-parameter inputs
Expand Down
Loading
Loading