Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1c115f4
Added river-route dependency
Apr 28, 2026
64abcff
Remove RAPID dependencies
Apr 29, 2026
5823206
Deleted RAPIDpy directory
Apr 29, 2026
4e8c03b
Removed build_petsc and build_rapid from make family
Apr 30, 2026
f8c9bb1
Removed petsc dummy file
Apr 30, 2026
eb7b1da
Added river-route to build_venv.ecf
Apr 30, 2026
acd3338
Updated ens_member.ecf and created run_river_route_forecast.py
May 1, 2026
e8c02c8
Updated prep_task.ecf and related init scripts
May 1, 2026
a529d6c
Removed RAPID from headers and remaining .ecf files
May 1, 2026
7fce1fe
Removed dead start.py
May 1, 2026
b3a095b
Dropped RAPID references from prep module
May 11, 2026
0b48c35
Removed basininflow referenecs
May 11, 2026
5e9fe09
Updated day_one_forecast and other RAPID-aware modules
May 11, 2026
4950d26
Renamed workflow/scripts/rapid directory and references
May 11, 2026
5ee7074
Final RAPID renames
May 11, 2026
a2030cc
Removed dead diss_fc family
May 12, 2026
174a8b3
Removed unused HRES constants
May 13, 2026
a6f2840
Fixed python dependency
May 13, 2026
d65923d
Cleaned up old variable references
May 13, 2026
90c05c1
Updated REAME and set specific python dependency
May 13, 2026
f3b2528
Add workflow simplification plan
Jun 8, 2026
7d2a1a5
Phase 1 cleanup: fix logger bug, typo, dead imports/vars
Jun 8, 2026
11caefd
Phase 2: add pytest harness, unit tests, and CI
Jun 9, 2026
ec2a164
Phase 3: centralize duplicated zarr writing, json loading, return per…
Jun 10, 2026
1ccab32
Add Phase 4 handoff notes to PLAN.md
Jun 11, 2026
c66258a
Phase 4a: name HRES member, thickness, stream-order, and window const…
Jun 11, 2026
e34a865
Make comfies importable on Python 3.12+ and add suite definition smok…
Jun 11, 2026
078effb
Replace builder magic numbers with named constants and an is_00z_cycl…
Jun 11, 2026
ac780dd
Run CI on a conda environment so ecflow suite tests execute; declare …
Jun 11, 2026
5ed2385
Fix CI: drop Python 3.11 (river-route needs >=3.12) and pin ecflow<5.17
Jun 12, 2026
15064a2
Consolidate builder config reads into one documented block; refresh PLAN
Jun 12, 2026
adee6da
Remove dead rd (research) mode and fix stale README entries
Jun 15, 2026
1f8616c
Merge pull request #27 from JakeGimenes/rapid-to-river-route
msouff Jun 24, 2026
9fe454b
Merge branch 'geoglows:main' into workflow-simplification
JakeGimenes Jun 24, 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
38 changes: 38 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: tests

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.13"]

defaults:
run:
# Login shell so the micromamba environment stays activated across steps.
shell: bash -el {0}

steps:
- uses: actions/checkout@v4

# ecflow is not on PyPI; it is installed from conda-forge via the
# environment file. river-route and the rest come along with it.
- name: Create environment
uses: mamba-org/setup-micromamba@v2
with:
environment-file: environment.yml
create-args: >-
python=${{ matrix.python-version }}
cache-environment: true

- name: Install package with dev dependencies
run: pip install -e ".[dev]"

- name: Run tests
run: pytest -q --cov=geoglows_ecflow.resources --cov-report=term-missing
116 changes: 116 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Workflow Simplification Plan

A living plan for simplifying the `geoglows_ecflow` workflow. Branched off the
`rapid-to-river-route` work (PR #27), so all references below assume the
river-route codebase, not the RAPID `main`.

## Goals

1. **Reduce complexity** — eliminate duplication, simplify functions, separate
inputs from logic.
2. **Make implicit explicit** — name constants and configuration, split mixed
functions, document non-obvious behavior.
3. **Improve maintainability** — make different configurations easy to run and
add a unit-test safety net.

## Scope

- **In scope:** `geoglows_ecflow/resources/*.py`,
`geoglows_ecflow/workflow/builders/builder.py`,
`geoglows_ecflow/workflow/parts/*`, and the `.ecf` task scripts.
- **Mostly frozen:** `geoglows_ecflow/workflow/comfies/*` — vendored ECMWF
framework code (Apache 2.0, ~4,700 lines). Left untouched except for the
minimal Python-3.12+ compatibility fixes noted below (the suite could not be
imported at all without them).

## Decisions

- **Tests:** unit tests on the pure functions, plus in-memory
suite-definition smoke tests (these were originally deferred but pulled
forward to guard the builder refactor).
- **HRES member:** high-resolution is always ensemble member **52**, kept as a
single named constant `HRES_ENSEMBLE_MEMBER` rather than a configurable value.

---

## Phase 1 — Pure cleanup (no behavior change) — DONE

- [x] `builder.py`: fix `Task("dimmy")` typo.
- [x] `helper_functions.py`: fix `create_logger` so file logging attaches.
- [x] `builder.py`: remove duplicate imports and the duplicated `nodes` import.
- [x] `builder.py`: remove read-but-unused config vars.
- [x] `builder.py`: fix stale docstring ("GLOFAS suite" → GEOGloWS).
- [x] `generate_esri_table.py`: fix `int or str` type hint.
- [x] Standardize the `argparse(nargs=1)` + `args.x[0]` antipattern.

## Phase 2 — Test harness + CI — DONE

- [x] Add `pytest` (+ `pytest-cov`) as a dev dependency.
- [x] Create `tests/` with fixtures.
- [x] Unit tests for the pure functions (ensemble parsing, VPU listing, date
parsing, state-init lookback, forecast preprocess, return-period /
exceedance, init-flow time index, zarr round-trip).
- [x] GitHub Actions workflow (`.github/workflows/tests.yml`). Now builds a
conda env from `environment.yml` (ecflow has no PyPI wheel) on a
Python **3.12–3.13** matrix and runs the whole suite.

## Phase 3 — Centralize duplication — DONE

- [x] Shared zarr-writing helper (`resources/zarr_io.py`).
- [x] `helper_functions.load_forecast_run` loader.
- [x] `RETURN_PERIODS` defined once and used for the ladders.
- [x] Standardized `logging` setup (`configure_logging`).

## Phase 4 — Make implicit explicit — MOSTLY DONE

- [x] `HRES_ENSEMBLE_MEMBER = 52` — used in `netcdf_to_zarr.py` and the
`range(1, HRES_ENSEMBLE_MEMBER + 1)` ensemble loop in `builder.py`.
- [ ] `nco_calc.ecf` `grep -v ..._52.nc` (×3) — **decision pending**: wire an
ecflow `%HRES_MEMBER%` variable vs. leave `52` + a comment. Highest risk:
wrong wiring silently changes which member is excluded from the mean.
- [x] `EMOS_BASE != "12"` gate (×3) → `is_00z_cycle()` helper.
- [x] Magic numbers named: thickness ladder (`THICKNESS_THRESHOLDS`),
stream-order (`MIN_STREAM_ORDER`), 10-day window (`FORECAST_WINDOW_DAYS`),
`MEM` values (`ENS_TASK_MEM_MB` / `ARCHIVE_QINIT_MEM_MB`).
- [x] Timer offsets (`hours=7`/`hours=9`/`"14:15"`) — **resolved by deletion**:
they lived only in the broken `rd`/research-mode branch, which has been
removed (see follow-ups). Nothing to extract; revisit if `rd` returns.
- [x] Consolidate `self.config.get(...)` reads in `builder.py` into one
documented block.

## Follow-ups (later tasks)

- ecFlow-**server** tests (building the def against a live server / `--dry`);
the in-memory structural tests are done, this is the heavier version.
- README refresh (carried over from PR #27 review).
- **comfies is incompatible with ecflow 5.17+.** Its node wrappers set
`Variable.parent` (`ooflow.py:1925`), which ecflow 5.17 made a read-only
built-in, so building any suite raises `AttributeError`. Worked around by
pinning `ecflow<5.17` in `environment.yml`; the real fix is to rename
comfies' parent-tracking attribute so it no longer collides.
- **Research (`rd`) mode removed.** `mode='rd'` was the only path with
`follow_osuite=False` and crashed unconditionally at `barrier_hh.ymd`
(`barrier_hh` is a `NominalTime`, which has no `ymd`) — broken since the
original 2024-07-25 authoring, so never usable. Removed the `rd` choice, the
`follow_osuite`/`in_production`/`in_test` flags, the non-`follow_osuite`
branch (the `+7h`/`+9h`/`14:15` run timers), and the dead crash line. `prod`
and `test` are the remaining modes. If research mode is wanted again, it
should be reintroduced correctly (with the intended barrier-repeat wiring).

---

## Current status

**Branch `workflow-simplification`** (fork `JakeGimenes`), open as a PR against
`rapid-to-river-route`. Phases 1–3 complete; Phase 4 complete except the
`nco_calc.ecf` decision. The timer constants are resolved by deletion (the
`rd`/research mode that owned them has been removed). **33 pytest tests pass** —
the resources tests run anywhere; the suite-definition tests require `ecflow`
(conda-forge).

The vendored `comfies` framework got the minimum Python-3.12+ compatibility
fixes needed to import it at all (`imp` → `importlib`, `pkg_resources` →
`packaging`); everything else in `comfies/*` is unchanged.

**Remaining actionable work:** the `nco_calc.ecf` `HRES_MEMBER` decision and the
README refresh.
46 changes: 22 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ECFLOW RAPID workflow for GEOGloWS
# ECFLOW workflow for GEOGloWS streamflow forecasting

![GEOGloWS VPUCode Coverage](images/geoglows_vpucode_coverage.png)
*Coverage of GEOGloWS VPUCode basins. Source: [Riley Hales](mailto:rchales@byu.edu).*
Expand All @@ -18,8 +18,7 @@ pip install -e .

## Non-Python Dependencies

- rapid>=20210423
- ecflow>=5.11.3
- ecflow>=5.11.3,<5.17
- nco>=5.1.8
- ksh>=2020.0.0

Expand All @@ -33,7 +32,7 @@ pip install -e .
mars_bond_id='251'
staticdata = '/path/to/assets'
workroot = f'/path/to/workroot'
mode = 'test' # suite mode ('rd':research, 'test':test, 'prod':production)
mode = 'test' # suite mode ('test':test, 'prod':production)
expver = 'geoglows'
exparch = '/path/to/archive'
iniexparch = '/path/to/init_archive'
Expand Down Expand Up @@ -81,18 +80,10 @@ pip install -e .
)

# --------------------------------------------
# Configuration of EFAS software packages
# Configuration of GEOGloWS software packages
# which are installed together with the suite.
# --------------------------------------------
packages = dict(
model = dict(
srcdir = 'git+https://github.com/c-h-david/rapid.git@20210423',
),

petsc = dict(
srcdir = srcroot + 'petsc_reqs',
),

scripts = dict(
srcdir = srcroot + 'scripts',
),
Expand Down Expand Up @@ -123,19 +114,26 @@ ecflow_start.sh -d /path/to/ecflow_home

## Local run example

```Python
import subprocess
from geoglows_ecflow import geoglows_forecast_job, client
Generate the suite definition (via CLI or Python):

# Start server
subprocess.run(['bash', '/path/to/local_server_start.sh'])
```bash
gdeploy --config /path/to/config.cfg
```

# Create definition
geoglows_forecast_job.create("/path/to/config.cfg")
```python
from geoglows_ecflow.workflow.create import main
main("/path/to/config.cfg")
```

Start a local ecflow server, then load and begin the suite:

```bash
bash /path/to/local_ecflow_start.sh
```

# Add definition to server
client.add_definition("/path/to/definition.def", "<HOST>:<PORT>")
```python
from geoglows_ecflow import client

# Begin definition
client.begin("definition_name")
client.add_definition("/path/to/deploy_dir/suite.def", "localhost:2500")
client.begin("suite_name", "localhost:2500")
```
8 changes: 6 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ channels:
- conda-forge
- defaults
dependencies:
- ecflow
- python>=3.12,<3.14
- pip
# comfies' node wrappers set Variable.parent, which ecflow 5.17 made
# read-only; pin below that until comfies is updated.
- ecflow<5.17
- nco
- pyyaml
- numpy
Expand All @@ -17,4 +21,4 @@ dependencies:
- boto3
- requests
- pip:
- basininflow @ git+https://pypi.org/project/basininflow/
- river-route>=2.1.1
Empty file.
Loading
Loading