- 
                Notifications
    You must be signed in to change notification settings 
- Fork 271
Add write.events.SIPNET function #3623
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
          
     Merged
      
      
            infotroph
  merged 34 commits into
  PecanProject:develop
from
dlebauer:write_events_sipnet
  
      
      
   
  Oct 26, 2025 
      
    
  
     Merged
                    Changes from 5 commits
      Commits
    
    
            Show all changes
          
          
            34 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      6e09b06
              
                Add write.events.SIPNET function with tests and documentation; update…
              
              
                dlebauer cbeae59
              
                update changelog and news
              
              
                dlebauer 0d0306d
              
                create test events.json files instead of creating them on the fly
              
              
                dlebauer 6e277b4
              
                make json pretty
              
              
                dlebauer 6e122a1
              
                Merge branch 'develop' into write_events_sipnet
              
              
                infotroph fc36141
              
                Update test.met2model.R
              
              
                dlebauer bbe1dfc
              
                Apply suggestion from @dlebauer
              
              
                dlebauer 40aad4a
              
                Apply suggestion from @dlebauer
              
              
                dlebauer a42e506
              
                Apply suggestion from @dlebauer
              
              
                dlebauer b7bef4c
              
                Apply suggestion from @dlebauer
              
              
                dlebauer 90c62e0
              
                Apply suggestion from @dlebauer
              
              
                dlebauer 407a8c0
              
                Apply suggestion from @dlebauer
              
              
                dlebauer 8fd9f81
              
                Apply suggestion from @dlebauer
              
              
                dlebauer 1508bfd
              
                Update write.events.SIPNET.R
              
              
                dlebauer 5523a13
              
                Update write.events.SIPNET.R
              
              
                dlebauer 780b877
              
                Update write.events.SIPNET.R
              
              
                dlebauer 82a86b5
              
                write all params of harvest event
              
              
                infotroph 595a7b6
              
                declare jsonlite import
              
              
                infotroph 9d534f6
              
                add harv params in tests
              
              
                infotroph 00f8bf6
              
                Merge pull request #8 from infotroph/write_events_sipnet_ckb
              
              
                dlebauer 7054620
              
                import %||%
              
              
                infotroph f91c229
              
                Merge branch 'develop' into write_events_sipnet
              
              
                infotroph f800475
              
                fix build error
              
              
                dlebauer bf3b456
              
                typo
              
              
                dlebauer b57bd58
              
                New function to validate events.json files; moved example events.json…
              
              
                dlebauer cfd616a
              
                add jsonlite suggests to data.land
              
              
                dlebauer 7211cc3
              
                use system.file for test fixtures
              
              
                dlebauer 338db76
              
                return NA if no validator
              
              
                dlebauer 79c17d8
              
                Update models/sipnet/DESCRIPTION
              
              
                dlebauer b84ef76
              
                Update docker/depends/pecan_package_dependencies.csv
              
              
                dlebauer f7761a8
              
                - require testthat >= 3.1.0 to support new mocking features in tests …
              
              
                dlebauer 8e3bd1a
              
                Update CHANGELOG and NEWS
              
              
                dlebauer 579942b
              
                Update testthat version requirement and documentation for validate_ev…
              
              
                dlebauer b70da2a
              
                Merge branch 'develop' into write_events_sipnet
              
              
                dlebauer File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
          Some comments aren't visible on the classic Files Changed page.
        
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| ## TODO: | ||
| ## - integrate call into write.configs.SIPNET | ||
| ## - parameterize planting allocation fractions | ||
| ## - make sure files are written in correct output directory | ||
| ## - map crops associated w/ planting and harvest --> PFTs; this will need to be handled separate from events.in | ||
| #' Write SIPNET events.in files from a PEcAn events.json | ||
| #' | ||
| #' Reads a single PEcAn events.json containing one or more site objects and | ||
| #' writes one SIPNET `events.in` file per site. Events are translated according to [SIPNET's `events.in` | ||
| #' specification](https://pecanproject.github.io/sipnet/parameters/#agronomic-events). | ||
| #' The writer expects inputs to already match the PEcAn MVP schema v0.1.0 naming and units where applicable. | ||
| #' | ||
| #' @details | ||
| #' - Supported `event_type` values: `tillage`, `planting`, `fertilization`, | ||
| #' `irrigation`, `harvest`. | ||
| #' - Units translated from PEcAn standard_vars to SIPNET events.in specification: | ||
| #' `kg/m^2` to `g/m^2`; irrigation `amount_mm` to `cm`. | ||
| #' - Planting allocation uses fixed internal parameters. Future work should use the same values | ||
| #' that are written to `sipnet.parms` (e.g. after integrating this into `write.configs.SIPNET`) | ||
| #' | ||
| #' @param events_json character. Path to an `events.json` file containing an | ||
| #' array of site objects with `site_id`, optional `pft`, and `events`. | ||
| #' @param outdir character. Output directory where per-site `events-<site>.in` | ||
| #' files are written. | ||
| #' | ||
| #' @return Invisibly, a vector of files written. | ||
| #' | ||
| #' @examples | ||
| #' # Example with two events for a single site | ||
| #' tmp <- withr::local_tempfile(fileext = ".json") | ||
| #' site <- list( | ||
| #' site_id = "EX1", | ||
| #' events = list( | ||
| #' list(event_type = "tillage", date = "2022-02-04", tillage_eff_0to1 = 0.2), | ||
| #' list(event_type = "planting", date = "2022-02-19", leaf_c_kg_m2 = 0.01) | ||
| #' ) | ||
| #' ) | ||
| #' jsonlite::write_json(list(site), tmp, auto_unbox = TRUE) | ||
| #' outdir <- withr::local_tempdir() | ||
| #' files <- write.events.SIPNET(tmp, outdir) | ||
| #' files | ||
| #' | ||
|         
                  infotroph marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| #' @export | ||
| write.events.SIPNET <- function(events_json, outdir) { | ||
|         
                  dlebauer marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| x <- jsonlite::fromJSON(events_json, simplifyVector = FALSE) | ||
| site_objs <- if (!is.null(x$site_id)) list(x) else x | ||
|         
                  dlebauer marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| files_written <- vector() | ||
|  | ||
| leafAllocation <- 0.50 | ||
| woodAllocation <- 0.15 | ||
| fineRootAllocation <- 0.10 | ||
| coarseRootAllocation <- 0.25 | ||
|  | ||
| # Unit conversion helpers | ||
| kg2g <- as.numeric(PEcAn.utils::ud_convert(1, "kg", "g")) # 1000 | ||
| mm2cm <- as.numeric(PEcAn.utils::ud_convert(1, "mm", "cm")) # 0.1 | ||
|  | ||
| # For each site, build event time series and write file | ||
| for (site in site_objs) { | ||
| sid <- site$site_id | ||
| evs <- site$events | ||
| # Order by date and build lines | ||
| dates <- as.Date(vapply(evs, function(e) e$date, character(1))) | ||
|         
                  dlebauer marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| ord <- order(dates) | ||
|         
                  dlebauer marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| lines <- vector() | ||
|         
                  infotroph marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved         
                  dlebauer marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| for (idx in ord) { | ||
| e <- evs[[idx]] | ||
|         
                  infotroph marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved         
                  dlebauer marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| d <- as.Date(e$date) | ||
| year <- as.integer(format(d, "%Y")) | ||
| day <- as.integer(strftime(d, "%j")) | ||
|         
                  dlebauer marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved         
                  dlebauer marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| type <- e$event_type | ||
| if (type == "tillage") { | ||
| f <- if (is.null(e$tillage_eff_0to1)) 0 else e$tillage_eff_0to1 | ||
|         
                  dlebauer marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| lines <- c(lines, sprintf("%d %d till %s", year, day, f)) | ||
| } else if (type == "planting") { | ||
| # infer total planted biomass from leaf pool and allocation fraction | ||
| leaf_g <- as.numeric(if (is.null(e$leaf_c_kg_m2)) 0 else e$leaf_c_kg_m2) * kg2g | ||
| total_g <- if (leafAllocation > 0) leaf_g / leafAllocation else leaf_g | ||
| wood_g <- woodAllocation * total_g | ||
| fr_g <- fineRootAllocation * total_g | ||
| cr_g <- coarseRootAllocation * total_g | ||
| lines <- c(lines, sprintf("%d %d plant %s %s %s %s", year, day, leaf_g, wood_g, fr_g, cr_g)) | ||
| } else if (type == "fertilization") { | ||
| orgN_g <- as.numeric(if (is.null(e$org_n_kg_m2)) 0 else e$org_n_kg_m2) * kg2g | ||
| orgC_g <- as.numeric(if (is.null(e$org_c_kg_m2)) 0 else e$org_c_kg_m2) * kg2g | ||
| nh4_g <- as.numeric(if (is.null(e$nh4_n_kg_m2)) 0 else e$nh4_n_kg_m2) * kg2g | ||
| no3_g <- as.numeric(if (is.null(e$no3_n_kg_m2)) 0 else e$no3_n_kg_m2) * kg2g | ||
| minN_g <- nh4_g + no3_g | ||
| lines <- c(lines, sprintf("%d %d fert %s %s %s", year, day, orgN_g, orgC_g, minN_g)) | ||
| } else if (type == "irrigation") { | ||
| amt_cm <- as.numeric(if (is.null(e$amount_mm)) 0 else e$amount_mm) * mm2cm | ||
| method_code <- if (is.null(e$method) || e$method == "soil") 1 else 0 | ||
| lines <- c(lines, sprintf("%d %d irrig %s %s", year, day, amt_cm, method_code)) | ||
| } else if (type == "harvest") { | ||
| frac <- if (is.null(e$frac_above_removed_0to1)) 0 else e$frac_above_removed_0to1 | ||
| lines <- c(lines, sprintf("%d %d harv %s", year, day, frac)) | ||
| } | ||
| } | ||
| dir.create(outdir, showWarnings = FALSE, recursive = TRUE) | ||
| fp <- file.path(outdir, sprintf("events-%s.in", sid)) | ||
| writeLines(lines, fp) | ||
| files_written <- c(files_written, fp) | ||
| } | ||
| invisible(files_written) | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
      
      Oops, something went wrong.
      
    
  
        
          
          
            40 changes: 40 additions & 0 deletions
          
          40 
        
  models/sipnet/tests/testthat/event_fixtures/events_site1.json
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| [ | ||
| { | ||
| "site_id": ["EX1"], | ||
| "events": [ | ||
| { | ||
| "event_type": ["tillage"], | ||
| "date": ["2022-02-04"], | ||
| "tillage_eff_0to1": [0.2] | ||
| }, | ||
| { | ||
| "event_type": ["tillage"], | ||
| "date": ["2022-02-09"], | ||
| "tillage_eff_0to1": [0.1] | ||
| }, | ||
| { | ||
| "event_type": ["irrigation"], | ||
| "date": ["2022-02-09"], | ||
| "amount_mm": [50], | ||
| "method": ["soil"] | ||
| }, | ||
| { | ||
| "event_type": ["fertilization"], | ||
| "date": ["2022-02-09"], | ||
| "org_n_kg_m2": [0], | ||
| "org_c_kg_m2": [0], | ||
| "nh4_n_kg_m2": [0.01] | ||
| }, | ||
| { | ||
| "event_type": ["planting"], | ||
| "date": ["2022-02-19"], | ||
| "leaf_c_kg_m2": [0.01] | ||
| }, | ||
| { | ||
| "event_type": ["harvest"], | ||
| "date": ["2022-09-07"], | ||
| "frac_above_removed_0to1": [0.1] | ||
| } | ||
| ] | ||
| } | ||
| ] | 
        
          
          
            35 changes: 35 additions & 0 deletions
          
          35 
        
  models/sipnet/tests/testthat/event_fixtures/events_site1_site2.json
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| [ | ||
| { | ||
| "site_id": "S1", | ||
| "pft": "PFT", | ||
| "events": [ | ||
| { | ||
| "event_type": "tillage", | ||
| "date": "2022-01-15", | ||
| "tillage_eff_0to1": 0.1 | ||
| }, | ||
| { | ||
| "event_type": "harvest", | ||
| "date": "2022-09-01", | ||
| "frac_above_removed_0to1": 0.2 | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "site_id": "S2", | ||
| "pft": "PFT", | ||
| "events": [ | ||
| { | ||
| "event_type": "planting", | ||
| "date": "2022-03-01", | ||
| "leaf_c_kg_m2": 0.01 | ||
| }, | ||
| { | ||
| "event_type": "irrigation", | ||
| "date": "2022-03-10", | ||
| "amount_mm": 10, | ||
| "method": "soil" | ||
| } | ||
| ] | ||
| } | ||
| ] | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| context("write.events.SIPNET") | ||
|  | ||
| # Helper to remove excess whitespace | ||
| norm <- function(x) gsub("\\s+", " ", trimws(x)) | ||
|  | ||
| testthat::test_that("write.events.SIPNET produces expected lines", { | ||
| ev_json1 <- testthat::test_path("event_fixtures/events_site1.json") | ||
| outdir <- withr::local_tempdir() | ||
| files <- write.events.SIPNET(ev_json1, outdir) | ||
| expect_length(files, 1) | ||
| got <- readLines(files[1]) | ||
| expected <- c( | ||
| "2022 35 till 0.2", | ||
| "2022 40 till 0.1", | ||
| "2022 40 irrig 5 1", | ||
| "2022 40 fert 0 0 10", | ||
| "2022 50 plant 10 3 2 5", | ||
| "2022 250 harv 0.1" | ||
| ) | ||
| expect_equal(norm(got), norm(expected)) | ||
|         
                  dlebauer marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| }) | ||
|  | ||
| testthat::test_that("write.events.SIPNET handles multi-site events.json (one file per site)", { | ||
| ev_json2 <- testthat::test_path("event_fixtures/events_site1_site2.json") | ||
| outdir <- withr::local_tempdir() | ||
| files <- write.events.SIPNET(ev_json2, outdir) | ||
| testthat::expect_length(files, 2) | ||
| testthat::expect_true(all(file.exists(files))) | ||
| # quick sanity checks for each site's first/last event ordering | ||
| got1 <- readLines(files[grepl("events-S1\\.in$", files)]) | ||
| got2 <- readLines(files[grepl("events-S2\\.in$", files)]) | ||
| testthat::expect_true(startsWith(norm(got1[1]), "2022 15 till")) | ||
| testthat::expect_true(startsWith(norm(tail(got1, 1)), "2022 244 harv")) | ||
| testthat::expect_true(startsWith(norm(got2[1]), "2022 60 plant")) | ||
| testthat::expect_true(startsWith(norm(tail(got2, 1)), "2022 69 irrig")) | ||
| }) | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.