Skip to content

Commit 97bccfa

Browse files
committed
Merge branch 'develop' into fix/migrate-oat-sa-generator
2 parents 51449e9 + 9c6ab9b commit 97bccfa

40 files changed

Lines changed: 1060 additions & 323 deletions
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: Docker build (fork PRs)
2+
3+
# A fast check for Docker build errors introduced by the current PR.
4+
# Implemented separately from the full-stack build in docker.yml because
5+
# pull requests opened from forks get a read-only GITHUB_TOKEN and cannot push
6+
# to ghcr.io/pecanproject, so the normal Docker GHA workflow (docker.yml) skips
7+
# them (see the gate on its `rversion` job). This workflow gives those PRs a
8+
# real "does the image stack still build" signal without pushing anything.
9+
#
10+
# The images build on top of each other (depends -> base -> models -> sipnet).
11+
# The normal workflow runs each as a separate job and pulls the parent back from
12+
# ghcr, which needs a registry we can't push to from a fork. Here we build the
13+
# whole chain in a single job with plain `docker build`, so each image stays in
14+
# the runner's local image store and the next `FROM pecan/<parent>:latest`
15+
# resolves locally. No registry, no push, no secrets.
16+
#
17+
# Scope is the core linear chain only (depends -> base -> models -> sipnet). It
18+
# fits the default runner disk (~19 GB free; the resident stack is ~5-6 GB). The
19+
# other model binaries, baseplus (docs/executor/api) and extras images are not
20+
# built here to keep the job within disk and time budget.
21+
22+
on:
23+
pull_request:
24+
workflow_dispatch:
25+
26+
permissions:
27+
contents: read
28+
29+
jobs:
30+
build-stack:
31+
# Only fork PRs. Same-repo PRs are already covered by docker.yml, which can
32+
# push pr-* tags to ghcr because they run with a writable token.
33+
if: github.event.pull_request.head.repo.full_name != github.repository
34+
runs-on: ubuntu-latest
35+
env:
36+
R_VERSION: "4.4"
37+
steps:
38+
- uses: actions/checkout@v6
39+
40+
- name: Disk space before build
41+
run: df -h /
42+
43+
# NOTE: do not add docker/setup-buildx-action here. Plain `docker build`
44+
# uses the default docker-engine builder, which resolves each
45+
# `FROM pecan/<parent>:latest` from the local image store built by the
46+
# previous step. The docker-container buildx driver would not see those
47+
# local images and every FROM after depends would fail.
48+
- name: Build depends -> base -> models -> sipnet (no push)
49+
run: |
50+
set -euxo pipefail
51+
52+
# depends: FROM rocker/tidyverse:${R_VERSION}
53+
docker build -f docker/depends/Dockerfile \
54+
--build-arg R_VERSION="${R_VERSION}" \
55+
-t pecan/depends:latest \
56+
docker/depends
57+
58+
# base: FROM pecan/depends:latest (resolved from the local store)
59+
docker build -f docker/base/Dockerfile \
60+
-t pecan/base:latest \
61+
.
62+
63+
# models: FROM pecan/base:latest
64+
docker build -f docker/models/Dockerfile \
65+
-t pecan/models:latest \
66+
docker/models
67+
68+
# sipnet: FROM pecan/models:latest
69+
docker build -f models/sipnet/Dockerfile \
70+
--build-arg MODEL_VERSION=git \
71+
-t pecan/model-sipnet-git:latest \
72+
models/sipnet
73+
74+
- name: Disk space after build
75+
if: always()
76+
run: df -h /

.github/workflows/docker.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ jobs:
4242
# As an ugly workaround, we assign it to a job output instead.
4343
# ----------------------------------------------------------------------
4444
rversion:
45+
# Every build job below needs this job, so gating it here skips the whole
46+
# push-based Docker stack for pull requests opened from forks. Forks get a
47+
# read-only GITHUB_TOKEN and cannot push to ghcr.io/pecanproject, so those
48+
# jobs always failed at the push step. Fork PRs are instead built (without
49+
# pushing) by docker-build-pr.yml. Non-fork events (push, merge_group,
50+
# schedule, workflow_dispatch) and same-repo PRs still run the full stack.
51+
if: >-
52+
github.event_name != 'pull_request' ||
53+
github.event.pull_request.head.repo.full_name == github.repository
4554
runs-on: ubuntu-latest
4655
steps:
4756
- id: mon

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ For more information about this file see also [Keep a Changelog](http://keepacha
99
## Unreleased
1010

1111
### Added
12+
- Added `make_scorecard.sh` and documentation to `inst/ilamb/` in PEcAn.benchmark for generating and serving the ILAMB HTML scorecard.
1213
- New function `PEcAn.utils::netcdf2df()` flattens all dims and vars of a netCDF into a dataframe,
1314
with units attached as an attribute.
1415
- New package `PEcAn.RothC` runs the RothC soil carbon model.
@@ -31,6 +32,7 @@ For more information about this file see also [Keep a Changelog](http://keepacha
3132
- Added `PEcAn.data.land::event_parquet_to_json` for generating PEcAn `event.json` files from well-formatted event parquet files, with support for ensembles of events.
3233

3334
### Fixed
35+
- Docker GHA workflow no longer fails on pull requests opened from forks (#3618).
3436
- Removed unused `grid2netcdf()` from `PEcAn.data.remote` and fixed R CMD check reference notes for `download.LandTrendr.AGB()` (#2758).
3537
- Fixed broken pecanproject.github.io, pecan.gitbooks.io, and other outdated documentation links across book_source, tutorials, models, modules, web, and shiny files (#3710).
3638
- Added note to DEV-INTRO.md documenting Traefik workaround for Apple Silicon (ARM64) Macs: use `traefik:v2.11` with `platform: linux/arm64` to fix 404 errors (#3910)

base/workflow/R/run.write.configs.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#' Write model-specific run scripts and configuration files
22
#'
3-
#' @md
43
#' Generates run scripts and configuration files for all analyses (ensemble
54
#' and/or sensitivity analysis) specified in the provided settings. Delegates
65
#' the model-specific config writing to the appropriate `write.config.*`
@@ -43,6 +42,8 @@
4342
#' appended. This forces use of only files within this workflow, to avoid
4443
#' confusion.
4544
#'
45+
#' @md
46+
#'
4647
#' @param settings a PEcAn settings list
4748
#' @param ensemble.size number of ensemble runs
4849
#' @param input_design Input design data.frame coordinating input files across

base/workflow/man/run.write.configs.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

book_source/03_topical_pages/05_models/ldndc.Rmd

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
## LDNDC {#models-ldndc}
22

3-
| Model Information | |
4-
| -- | -- |
5-
| Home Page | https://ldndc.imk-ifu.kit.edu/about/model.php |
6-
| Source Code | |
7-
| License | |
8-
| Authors | Prof. Dr. Klaus Butterbach-Bahl, Dr. Edwin Haas, ... |
9-
| PEcAn Integration | Henri Kajasilta |
3+
| Model Information | |
4+
| -- | -- |
5+
| Home Page | https://ldndc.imk-ifu.kit.edu/about/model.php |
6+
| Source Code | https://codebase.helmholtz.cloud/landscapedndc/ldndc_v1.36 |
7+
| License | |
8+
| Authors | Prof. Dr. Klaus Butterbach-Bahl, Dr. Edwin Haas, ... |
9+
| PEcAn Integration | Henri Kajasilta |
1010

1111
### Introduction
1212

@@ -101,4 +101,4 @@ Many configurations for the model are (less surprisingly) written in `write.conf
101101

102102
In order to obtain the LDNDC model, the credentials are required. The user can request them from the developers of the model. With the credentials, the pre-compiled LDNDC program can be downloaded here: https://ldndc.imk-ifu.kit.edu/download/download-model.php
103103

104-
Once the necessary files have been obtained, the user should execute the installation script found in the ldndc-'_version-number_' directory. On linux, executing would happen with the command `sh install.sh`. A successful installation will create a `.ldndc` directory in the user's home directory. (Note, that this `.ldndc` directory path will be used in `write.configs.LDNDC`.) Running the simulations is done by calling the ldndc executable (found in the `/bin` directory) and giving the path to the project file containing the specs of the simulation. Detailed instructions and how to play with these setups can be found in the user guide.
104+
Once the necessary files have been obtained, the user should execute the installation script found in the ldndc-'_version-number_' directory. On linux, executing would happen with the command `sh install.sh`. A successful installation will create a `.ldndc` directory in the user's home directory. (Note, that this `.ldndc` directory path will be used in `write.configs.LDNDC`.) Running the simulations is done by calling the ldndc executable (found in the `/bin` directory) and giving the path to the project file containing the specs of the simulation. Detailed instructions and how to play with these setups can be found in the user guide.

docker/depends/pecan_package_dependencies.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@
495495
"rcrossref","*","base/db","Suggests",FALSE
496496
"readr","*","models/ldndc","Imports",FALSE
497497
"readr","*","modules/assim.sequential","Suggests",FALSE
498+
"readr","*","modules/data.land","Suggests",FALSE
498499
"REddyProc","*","modules/data.atmosphere","Imports",FALSE
499500
"redland","*","modules/data.land","Suggests",FALSE
500501
"reshape","*","modules/data.remote","Suggests",FALSE
@@ -700,6 +701,7 @@
700701
"units","*","modules/data.atmosphere","Imports",FALSE
701702
"units",">= 0.8.7","base/utils","Imports",FALSE
702703
"urltools","*","base/remote","Imports",FALSE
704+
"usethis","*","modules/data.land","Suggests",FALSE
703705
"utils","*","base/all","Imports",FALSE
704706
"utils","*","base/logger","Imports",FALSE
705707
"utils","*","models/ed","Imports",FALSE

models/sipnet/R/write.configs.SIPNET.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,11 @@ write.config.SIPNET <- function(defaults, trait.values, settings, run.id, inputs
545545
id <- which(param[, 1] == "litterBreakdownRate")
546546
param[id, 2] <- pft.traits[which(pft.trait.names == "turn_over_time")]
547547
}
548+
549+
# fracLitterRespired, fraction of litter breakdown respired vs moved to soil
550+
if ("fracLitterRespired" %in% pft.trait.names) {
551+
param[which(param[, 1] == "fracLitterRespired"), 2] <- pft.traits[which(pft.trait.names == "fracLitterRespired")]
552+
}
548553
# frozenSoilEff
549554
if ("frozenSoilEff" %in% pft.trait.names) {
550555
param[which(param[, 1] == "frozenSoilEff"), 2] <- pft.traits[which(pft.trait.names == "frozenSoilEff")]
@@ -594,6 +599,9 @@ write.config.SIPNET <- function(defaults, trait.values, settings, run.id, inputs
594599
if ("GDD" %in% pft.trait.names) {
595600
param[which(param[, 1] == "gddLeafOn"), 2] <- pft.traits[which(pft.trait.names == "GDD")]
596601
}
602+
if ("leafOnReallocFrac" %in% pft.trait.names) {
603+
param[which(param[, 1] == "leafOnReallocFrac"), 2] <- pft.traits[which(pft.trait.names == "leafOnReallocFrac")]
604+
}
597605

598606
# Fraction of leaf fall per year (should be 1 for decid)
599607
if ("fracLeafFall" %in% pft.trait.names) {

models/sipnet/inst/template.param_v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ soilRespMoistEffect 1.000000
3030
leafOnDay 144
3131
gddLeafOn 500
3232
soilTempLeafOn 12.0
33+
leafOnReallocFrac 0.2
3334
leafOffDay 285
3435
leafGrowth 126
3536
fracLeafFall 1

modules/benchmark/inst/ilamb/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,21 @@ score relative to the other variables, and the `weight` on each dataset block
296296
sets how much that dataset counts within its variable. Both are relative
297297
weights, not percentages. See the inline comments in the config for the full
298298
per-field reference.
299+
300+
## Generating the scorecard
301+
302+
ILAMB produces an interactive HTML scorecard alongside the numeric scores. To
303+
generate it for a window, run `make_scorecard.sh` against that window's model
304+
root (built by the pipeline above):
305+
306+
```bash
307+
export ILAMB_ROOT=/path/to/ILAMB_ROOT
308+
./make_scorecard.sh 2012_2014
309+
./make_scorecard.sh 2015_2023
310+
```
311+
312+
Each run writes a self-contained static site (`index.html` plus assets) to a
313+
build directory, which can be served directly by copying it under a web
314+
server's document root. The scorecard uses the clean model roots, so it lists
315+
PEcAn alongside the individual CMIP6 and TRENDY models and the ensemble means,
316+
rather than the 100 individual PEcAn members used for the spread analysis.

0 commit comments

Comments
 (0)