From b55f35427a293628b113aaa80bc87e29334321b3 Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Mon, 7 Sep 2026 13:05:23 +0530 Subject: [PATCH] test(sipnet): cover JSON segmentation and restart chaining Signed-off-by: Gaurav Chaudhary --- CHANGELOG.md | 1 + models/sipnet/NEWS.md | 1 + .../testthat/test-write_segmented_configs.R | 71 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6669cf3174..a5f6080a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ For more information about this file see also [Keep a Changelog](http://keepacha ## Unreleased ### Added +- Added regression coverage for SIPNET event-JSON segmentation and segmented restart chaining (#4021). - Added ensemble calibration diagnostics to `inst/ilamb/` in PEcAn.benchmark (rank histogram, spread-skill ratio, coverage, reliability) for assessing whether an ensemble's spread is well calibrated against observations, complementing the ensemble-mean benchmarking. - Added regional calibration diagnostics to `inst/ilamb/` in PEcAn.benchmark: break the ensemble calibration assessment down by land cover class and by EPA/CEC ecoregion, reusing the ensemble calibration diagnostics, with figures. - Added an ESA CCI biomass benchmark extension to `inst/ilamb/` in PEcAn.benchmark: a converter for the ESACCI Biomass v7.0 product (2015-2024, with per-pixel uncertainty) to ILAMB-compatible netCDF, plus an observation-error test showing the ensemble overconfidence persists against a modern benchmark and after accounting for observation uncertainty. diff --git a/models/sipnet/NEWS.md b/models/sipnet/NEWS.md index 202cf10bd5..2e89ddde39 100644 --- a/models/sipnet/NEWS.md +++ b/models/sipnet/NEWS.md @@ -1,5 +1,6 @@ # PEcAn.SIPNET 1.10.0.9000 +* Added regression coverage for SIPNET event-JSON segmentation and segmented restart chaining (#4021). * Improvements to the job.sh written by `write_segmented_configs`: - Now places README.txt, segments.csv, and the full log files from each segment, into the outdir (as was already done for one-segment runs). diff --git a/models/sipnet/tests/testthat/test-write_segmented_configs.R b/models/sipnet/tests/testthat/test-write_segmented_configs.R index 07c3f01298..228621e3b5 100644 --- a/models/sipnet/tests/testthat/test-write_segmented_configs.R +++ b/models/sipnet/tests/testthat/test-write_segmented_configs.R @@ -92,6 +92,29 @@ test_that("write_segmented_configs", { ) } + # Each segment writes its own restart and later segments read the previous one. + segment_rundirs <- file.path( + run_path, "segments", sprintf("segment_%03d", 1:3), "run" + ) + for (seg in 1:3) { + config <- readLines(file.path(segment_rundirs[seg], "1", "sipnet.in")) + restart_in <- grep("^[[:space:]]*RESTART_IN[[:space:]]*=", config, value = TRUE) + restart_out <- grep("^[[:space:]]*RESTART_OUT[[:space:]]*=", config, value = TRUE) + + expect_identical( + restart_out, + paste("RESTART_OUT =", file.path(segment_rundirs[seg], "restart.out")) + ) + if (seg == 1) { + expect_length(restart_in, 0) + } else { + expect_identical( + restart_in, + paste("RESTART_IN =", file.path(segment_rundirs[seg - 1], "restart.out")) + ) + } + } + # job.sh includes calls to segment scripts jobsh <- readLines(file.path(run_path, "job.sh")) expect_match(jobsh, "bash .*segment_001/run/1/job.sh", all = FALSE) @@ -99,6 +122,54 @@ test_that("write_segmented_configs", { expect_match(jobsh, "bash .*segment_003/run/1/job.sh", all = FALSE) }) +test_that("segment_dataframe falls back to event_json for the configured site", { + pth <- withr::local_tempdir() + events_path <- file.path(pth, "events.json") + jsonlite::write_json( + list( + list( + site_id = "a", + events = list( + list(event_type = "planting", date = "2025-01-02", crop_code = "D12"), + list(event_type = "planting", date = "2025-01-05", crop_code = "G6") + ) + ), + list( + site_id = "b", + events = list( + list(event_type = "planting", date = "2025-01-03", crop_code = "P1") + ) + ) + ), + path = events_path, + auto_unbox = TRUE + ) + run_settings <- PEcAn.settings::as.Settings(list( + run = list( + site = list(id = "a", site.pft = list(veg = "pft1")), + inputs = list(event_json = list(path = events_path)), + start.date = "2025-01-01", + end.date = "2025-01-10" + ) + )) + + result <- PEcAn.SIPNET:::segment_dataframe(run_settings) + + expect_equal(nrow(result), 3) + expect_identical(result$site_id, rep("a", 3)) + expect_identical(result$segment_id, c("001", "002", "003")) + expect_identical( + result$start_date, + as.Date(c("2025-01-01", "2025-01-02", "2025-01-05")) + ) + expect_identical( + result$end_date, + as.Date(c("2025-01-01", "2025-01-04", "2025-01-10")) + ) + expect_identical(result$crop_code, c(NA_character_, "D12", "G6")) + expect_identical(result$pft[1], "pft1") +}) + test_that("segment_dataframe returns empty when run start is after all crop cycles", { pth <- withr::local_tempdir() crp_chg_path <- file.path(pth, "cycles-a.csv")