Architecture#
This page explains how CrocoDash is wired together so you can understand, modify, or extend it. For the day-to-day user workflow see the user guide.
The four-step workflow maps onto four modules#
Workflow step |
CrocoDash module(s) |
Primary external dependency |
|---|---|---|
1. Grids (hgrid / topo / vgrid) |
|
|
2. Case setup |
|
VisualCaseGen + CESM CIME |
3a. Configure forcings |
|
(internal) |
3b. Process forcings |
|
regional-mom6, |
Supporting modules you’ll touch when extending CrocoDash:
raw_data_access— unified registry-based interface to data sources (GLORYS, TPXO, GEBCO, GLOFAS, …).logging— consistent logging setup used across the package.
Key design patterns#
Two registries#
Two pieces of CrocoDash are registry-based so users and contributors can extend them without touching core code:
ForcingConfigRegistry(forcing_configurations) — each forcing configuration (Tides, BGC, Rivers, …) is aBaseConfiguratorsubclass that auto-registers via the@registerdecorator. The registry knows which configurators are required, valid, or forbidden for a given compset.ProductRegistry(raw_data_access) — each data source is aForcingProductsubclass whose@accessmethodfunctions are discovered and validated at import time.
See the “Add a new …” guides for the mechanics:
Configure vs. process: why they’re separate#
Step 3a (case.configure_forcings) and 3b (case.process_forcings) are
decoupled on purpose. Configuration is lightweight — it validates arguments,
applies xmlchange/user_nl_* edits, and writes a JSON manifest. Processing
downloads large datasets, regrids, and writes netCDF. In practice these happen
on different machines (or at least different wall-clock budgets).
The extraction system is also fully standalone: after configure_forcings,
a self-contained copy of extract_forcings/ is placed under the case’s
inputdir/. A user can submit python driver.py --all from that directory
without touching CrocoDash again. This makes HPC submission straightforward.
Re-exports from mom6_forge#
CrocoDash deliberately re-exports mom6_forge’s Grid, Topo, VGrid,
GridCreator, TopoEditor, VGridCreator with no modification:
# CrocoDash/grid.py
from mom6_forge.grid import *
The only “wrapper” work happens when CrocoDash needs a mom6_forge object in a CESM context (grid file naming, case registration). Everything else routes straight through.
Validation lives in configure_forcings#
Forcing compatibility rules live with the configurators, not scattered through the workflow. Examples enforced there:
Chlorophyll cannot be provided if BGC is not in the compset
River nutrients cannot be implemented without runoff and BGC in the compset
BGC configurators require
%MARBLin the compset longname
When you add a new configurator, declare its compatibility via
required_for_compsets, allowed_compsets, and forbidden_compsets — don’t
write ad-hoc if/else in case.py.
Data flow#
Case(grid, topo, vgrid, compset, ...)
│
▼
_configure_case (VisualCaseGen / CIME)
│
▼
_create_grid_input_files ──► inputdir/ocn grid files
│
▼
_create_newcase ──► caseroot/ CESM case
│
▼
configure_forcings(...)
│
▼
ForcingConfigRegistry ──► xmlchange + user_nl_* edits
──► inputdir/extract_forcings/config.json
│
▼
process_forcings(...)
│
▼
extract_forcings/driver.py
├─► get_dataset_piecewise (raw_data_access)
├─► regrid_dataset_piecewise (regional-mom6 segments)
├─► merge_piecewise_dataset
├─► bgc / runoff / tides / chl (mom6_forge helpers)
│
▼
──► inputdir/ocnice/... forcing files
Where to add what#
You want to… |
Edit… |
|---|---|
Add a new CESM-compatible forcing (e.g. salt restoring) |
new file in |
Add a new raw data source |
new file in |
Change the regridding of OBCs |
|
Change bathymetry fill behaviour |
|
Add a new |
the relevant configurator’s |
Change the CLI flags of |
|
What CrocoDash does NOT do itself#
CrocoDash is an orchestrator, not a reimplementation. The heavy lifting lives in three submodules:
Task |
Tool |
|---|---|
Regridding + OBC extraction |
|
Grid / bathymetry / vgrid generation, |
|
CESM case creation + GUI |
For the exact function-by-function call list, see Submodule API Usage.
Testing#
CrocoDash uses pytest. Run from the repo root:
# Full suite (mocked / fast)
pytest --ignore=CrocoDash/visualCaseGen -m "not workflow"
# Workflow tests (slower, may hit real data)
pytest -m "workflow"
# With coverage report
pytest --ignore=CrocoDash/visualCaseGen -m "not workflow" \
--cov=CrocoDash --cov-report=xml --cov-branch
Other useful flags:
Flag |
Purpose |
|---|---|
|
verbose per-test names |
|
stop on first failure |
|
don’t swallow |
|
only run tests whose name matches |
When developing extract_forcings:
Use small date ranges and small domains
Prefer
preview=Truein the config to dry-runUse the
--skipCLI flag ondriver.pyto iterate on one component
When developing raw_data_access:
New dataset classes must inherit from
ForcingProductand declare allrequired_metadata/required_args.Validation runs at import time — if metadata is missing, your tests will fail on import, which is the intended behaviour.
Common workflows#
Adding a new feature#
git checkout -b feature/my-featureMake your code changes with proper docstrings and type hints
Add tests
Run
pytestlocallycd docs && make htmlto confirm docs buildOpen a PR
Fixing a bug#
Find or file the issue
git checkout -b fix/issue-descriptionWrite a test that reproduces the bug
Fix until the test passes
Open a PR referencing the issue
See also#
Submodule API usage — one-stop reference for every upstream function CrocoDash calls.