|
| 1 | +# Copilot instructions |
| 2 | + |
| 3 | +Wflow — Julia hydrological modeling framework (Julia ≥ 1.10). Installation via `pixi.toml`. |
| 4 | + |
| 5 | +## Repository layout |
| 6 | +- `Wflow/src/` — core package source |
| 7 | +- `Wflow/test/` — tests (`TestItemRunner.jl`, `@testitem` macros) |
| 8 | +- `build/` — binary compilation scripts |
| 9 | +- `server/` — ZMQ-based BMI server |
| 10 | +- `docs/` — Quarto documentation (targets hydrologists); Julia code blocks execute using `docs/docs_utils.jl` |
| 11 | +- `data/`, `utils/` — test data and utility scripts |
| 12 | + |
| 13 | +## Key dependencies |
| 14 | +NCDatasets, BasicModelInterface, Graphs, Polyester, StaticArrays, CFTime, Accessors, Parameters, EnumX, OrderedCollections |
| 15 | + |
| 16 | +## Internal systems (do not reimplement) |
| 17 | +- **Unit system** (`units.jl`): `Unit` struct for dimensional analysis, `to_SI`/`from_SI`, timestep-dependent `dt` units |
| 18 | +- **Standard name metadata** (`standard_name/`): `OrderedDict` mapping standard names → `ParameterMetadata` (lens, unit, default, type, flags). Used for NetCDF I/O, TOML binding, docs |
| 19 | +- **Config system** (`config_structure.jl`, `config_init.jl`, `config_utils.jl`): `Config` wraps TOML as typed `AbstractConfigSection` structs. `InputEntry` handles netCDF ref / uniform value / external name |
| 20 | +- **NetCDF I/O** (`io.jl`): `NCReader`/`Writer`; `ncread` combines config lookup + reading + defaults + unit conversion |
| 21 | +- **Network/graph** (`network.jl`, `routing/utils.jl`, `subdomains.jl`): `flowgraph` converts LDD → DiGraph; `NetworkLand`/`NetworkRiver` store 1D↔2D index maps, edge connectivity, subdomain decomposition |
| 22 | +- **Threading** (`utils.jl`): `threaded_foreach` — `Threads.@spawn` (≤8 threads) or `Polyester.@batch` |
| 23 | +- **Numeric helpers** (`utils.jl`): `scurve`, `pow`, `tosecond`, `bounded_divide`, `lattometres`, `svectorscopy`, etc. |
| 24 | + |
| 25 | +## Architecture |
| 26 | +- Central type: `Model{R, L, M, T}` — routing, land model, mass balance, model type tag |
| 27 | +- **Land models** (`AbstractLandModel`): vertical per-cell fluxes. `LandHydrologySBM` (hydrology), `SoilLossModel` (sediment) |
| 28 | +- **Routing** (`Routing{O,R,S}`): `overland_flow`, `river_flow`, `subsurface_flow` — each concrete or null (`No*` type) |
| 29 | +- **Model type tags** (dispatch singletons): `SbmModel`, `SbmGwfModel`, `SedimentModel` |
| 30 | +- **Immutable struct updates**: use `@reset` from Accessors.jl |
| 31 | + |
| 32 | +## Simulation loop (`run_timestep!`) |
| 33 | +1. `advance!(clock)` |
| 34 | +2. `load_dynamic_input!` |
| 35 | +3. `storage_prev!` |
| 36 | +4. `update_model!` |
| 37 | +5. `compute_mass_balance!` |
| 38 | +6. `write_output` |
| 39 | + |
| 40 | +## Model types (`config.model.type`) |
| 41 | +- `sbm`: SBM soil + kinematic wave subsurface + surface routing (snow, glaciers, reservoirs, demand) |
| 42 | +- `sbm_gwf`: like `sbm` but 2D groundwater flow replaces lateral subsurface |
| 43 | +- `sediment`: soil erosion/sediment transport, `NoMassBalance` |
| 44 | + |
| 45 | +## Routing (`config.model.land_routing`, `config.model.river_routing`) |
| 46 | +- `kinematic_wave` (default): parallel via subdomains |
| 47 | +- `local_inertial`: shallow water equations, staggered grid; combined 2D when both land+river use it |
| 48 | + |
| 49 | +## Domain & indexing |
| 50 | +- `Domain` has `land`, `river`, `reservoir`, `drain` sub-domains (each: Network + Parameters) |
| 51 | +- Internal 1D arrays over active cells only; `indices` (1D→2D), `reverse_indices` (2D→1D, 0=inactive) |
| 52 | + |
| 53 | +## BMI (`bmi.jl`) |
| 54 | +- `BMI.initialize`, `update`, `update_until`, `finalize` |
| 55 | +- `get_value_ptr` uses standard name lens system; CSDMS-style names |
| 56 | +- 6 grid IDs: 0=reservoir, 1=drain, 2=river, 3–5=land |
| 57 | +- `API` TOML section lists exposed variables |
| 58 | +- Layered soil: name pattern `"soil_layer_N_..."` → SVector index |
| 59 | + |
| 60 | +## States |
| 61 | +- Cold/warm start: `config.model.cold_start__flag`; warm reads from `config.state.path_input` |
| 62 | +- `extract_required_states(config)`, `check_states(config)`, `set_states!(path, model)` |
| 63 | +- 3D (x,y,time) and 4D (x,y,layer,time) NetCDF variables; layered → SVector |
| 64 | + |
| 65 | +## Forcing |
| 66 | +- `AtmosphericForcing`: precipitation, potential_evaporation, temperature |
| 67 | +- Right-labeling: timestamp marks end of accumulation period |
| 68 | +- `load_dynamic_input!` = `update_forcing!` + `update_cyclic!` |
| 69 | +- Reservoir: precip/evap averaged over coverage cells, zeroed in land model |
| 70 | + |
| 71 | +## Testing |
| 72 | +- To run a subset of test items filtered by name use e.g. for unit tests |
| 73 | + |
| 74 | +``` |
| 75 | +pixi run julia --project=Wflow --eval='using Pkg; Pkg.test(test_args=[\"unit\"])' |
| 76 | +``` |
| 77 | + |
| 78 | +- `TestItemRunner.jl` with `@testitem` (not `@testset`); unit tests prefixed `"unit: "` |
| 79 | +- Test data: `utils/download_test_data.jl` → Moselle/Piave datasets |
| 80 | +- Integration: init model → run 1–2 steps → assert values with `≈` |
| 81 | +- State restart test: continuous run == cold-start + warm-start split |
| 82 | +- `Aqua.jl` for code quality checks |
| 83 | + |
| 84 | +## Code style (mandatory) |
| 85 | +- Multiple dispatch; prefer immutable structs; `@kwdef` for defaults |
| 86 | +- Precise argument types in signatures |
| 87 | +- Docstrings on all computational code specifying units of all variables |
| 88 | +- No single-symbol iteration variables — use descriptive `*_idx` names |
| 89 | +- Minimize function arguments; pass structs, unpack only at lowest level; no `NamedTuple` wrappers |
| 90 | +- Code must be clear from hydrological, mathematical, and CS perspectives |
| 91 | + |
| 92 | +## Performance (mandatory) |
| 93 | +- Zero allocations during simulation loops |
| 94 | +- No type instabilities (`@code_warntype`) |
| 95 | +- Target static compatibility |
| 96 | +- PrecompileTools.jl for startup |
| 97 | + |
| 98 | +## Documentation |
| 99 | +- Quarto-based; Julia code blocks execute during render using `docs/docs_utils.jl` |
| 100 | +- Keep non-executed example code in sync with actual source files |
0 commit comments