NestedSimulation abstraction + ERA5 regional hindcast example#233
NestedSimulation abstraction + ERA5 regional hindcast example#233ewquon wants to merge 56 commits into
Conversation
9d673f4 to
5463396
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This reverts commit 5463396.
|
Okay, the model state should be ready for dynamic initialization. A couple of important notes:
|
|
@ewquon should we add terrain? Terrain following should work for the fully compressible formulation (just not substepping) |
Hallelujah! I'm happy to add that in. Anything that gets us closer to reality sooner rather than later is a win in my book. |
| # | ||
| # Despite the name (chosen for consistency with `ocean_simulation` / | ||
| # `atmosphere_simulation`), `child_simulation` returns an `AbstractModel` — the | ||
| # Breeze `atmosphere_simulation` helper returns a model, not a `Simulation`, |
There was a problem hiding this comment.
is this true? Would it be possible to have consistent naming? It might get confusing if the behavior is bit lost in here in a comment
There was a problem hiding this comment.
actually would be nice to not need extensive commenting
There was a problem hiding this comment.
Thanks for probing this @simone-silvestri. Turns out this is totally unused code — I'm tossing it
| # The child carries the actual prognostic state and the Open BCs / interior | ||
| # `Relaxation` forcings that reference the parent's `FieldTimeSeries`. Wrapping | ||
| # the child in `NestedModel` lifts the parent-sync into the integrator itself | ||
| # (where it belongs — it's not output behavior), so a plain | ||
| # `Simulation(NestedModel(parent, child))` just works. | ||
| # | ||
| # All Oceananigans model-protocol calls (`clock`, `grid`, `fields`, | ||
| # `prognostic_fields`, `update_state!`, ...) forward to the child via | ||
| # `Base.getproperty` plus a small set of explicit dispatches. Only | ||
| # `time_step!` carries new behavior — step the child, then advance the parent | ||
| # by the elapsed Δt. |
There was a problem hiding this comment.
all this probably belongs in a docs page?
| @inline function Base.getproperty(nm::NestedModel, name::Symbol) | ||
| if name === :parent || name === :child | ||
| return getfield(nm, name) | ||
| end | ||
| return getproperty(getfield(nm, :child), name) | ||
| end |
There was a problem hiding this comment.
so the property of a nested model are redirected to the child? Maybe the nested model should have its own clock? Also this means that nested.grid is the grid of the child model?
There was a problem hiding this comment.
The nested model clock behavior will be updated when I address #330
nested.grid is the grid of the child model
Yes
| # Surface freshwater fluxes are meaningless for a volumetric atmosphere acting as | ||
| # a nesting parent; default to `nothing` there. The surface_*_flux accessors and | ||
| # `extract_field_time_series` already handle the Nothing branch. | ||
| function default_freshwater_flux(grid, times; volumetric=false) |
There was a problem hiding this comment.
ERA5 does not come with 2D freshwater fluxes even if other fields are 3D?
There was a problem hiding this comment.
ERA5 does accumulate the surface quantities that contribute to the freshwater flux. This comment and code design is narrowly focused (only lateral, no surface BCs yet) and is confusing. I will fix
…nostics) Factor the moist-thermodynamic-state → Breeze CompressibleDynamics prognostic (ρ, θˡⁱ, qᵗ) conversion into one Field-based helper: - declare the `breeze_prognostic_state` generic in Atmospheres (exported and re-exported from NumericalEarth), mirroring `atmosphere_simulation` - add the method in NumericalEarthBreezeExt, dispatched on Breeze.ThermodynamicConstants In examples/era5_breeze.jl, route both the parent FieldTimeSeries population and the child initial condition through it (dropping the duplicated ρ/θˡⁱ/qᵗ formulas), and switch the Davies relaxation to the `parent_forcings` helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- In `populate_parent_snapshot!`, pull the pressure-level variables from one `MetadataSet` (#235) instead of repeating the `Metadatum` kwargs per variable. - Bundle the nine parent-side `FieldTimeSeries` into a single `parent_series` NamedTuple (the `metadata_field.jl` idiom) rather than nine identical allocations; update the downstream BC / Davies / fill references. - TODO the wholesale collapse into a `dates`-spanning `FieldTimeSeries(pl, grid)` once terrain support (#241) lands. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cleanup comments, drop leading underscore from helper functions Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com> Co-authored-by: Eliot Quon <eliot@aeolus.earth>
`child_simulation` (and its `build_child_model` / `parent_variables` helpers, including the Breeze-ext methods) had zero callers: the example and the test suite wire `parent_boundary_conditions` + `parent_forcings` + `NestedSimulation` directly, and per the design notes its single `variables` tuple can't serve both the BC (prognostic) and forcing (specific) key conventions. Drop the two files plus their includes/exports. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add two testsets to test_nested_simulation.jl: - unit test for `breeze_prognostic_state` — the dry/p=pˢᵗ limit exactly, and the moist + condensate case against the documented (ρ, θˡⁱ, qᵗ) formulas; - integration test wiring a Breeze `AtmosphereModel` as a `NestedSimulation` child via `atmosphere_simulation(…).model` + `parent_boundary_conditions`, asserting the #220 contract (Simulation → .model is an AbstractModel) and a stable few-step run. Both verified on CPU; the integration set runs per `test_architectures` (GPU on GPU CI). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per review (Simone), flip the kwarg polarity so the default surface atmosphere reads `two_dimensional = true` and the 3D nesting-parent form is `two_dimensional = false`. Behavior is unchanged — the default path (2D surface, for ocean / sea-ice coupling) is identical. Simplify the helper comments and update the field-set testset accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per review (Simone): the freshwater (precipitation) flux is a surface (2D) field that datasets such as ERA5 provide regardless of whether the dynamics fields are 3D. So `default_freshwater_flux` no longer branches on `two_dimensional` — it always builds the 2D `PrescribedPrecipitationFlux`. `two_dimensional` now controls only the velocity/tracer/pressure dimensionality; omit the flux explicitly with `freshwater_flux = nothing` (e.g. a NestedSimulation parent that needs no surface coupling). Extend the field-set test: a 3D atmosphere keeps its surface freshwater flux, and opt-out is via the keyword. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…to eq/era5_breeze_land
…on rename Oceananigans 0.110 renamed Open→NormalFlow and OpenBoundaryCondition→ NormalFlowBoundaryCondition with no alias, breaking the lateral-BC helper under the main-merge compat bump. Update the helper, the Interpolated wrapper docs, and the nested-simulation tests; narrow Oceananigans compat to 0.110.1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The atmosphere→exchange state interpolation read dynamics.reference_state.density, which is `nothing` for CompressibleDynamics (prognostic density, no anelastic reference state), breaking AtmosphereLandModel coupling of a compressible Breeze atmosphere. Use Breeze's dynamics-agnostic dynamics_density / surface_pressure accessors instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regression for the interpolate_state! compressible fix: an AtmosphereLandModel wrapping a Breeze CompressibleDynamics atmosphere constructs and wraps as a NestedSimulation child (exercises the coupled update_state! → interpolate_state! path). Construction-level — stepping the coupled child awaits a Breeze energy-flux/qᵛ fix for the compressible path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
@glwagner @kaiyuan-cheng
Adds
examples/era5_breeze.jl— a building block for a regional modeling example that will eventually couple Breeze (compressible solver, in development) to forthcoming SlabLand and SlabOcean components.We download ERA5 reanalysis over an SGP-centered LAM bounding box (HI-SCALE 2016-09-10 case day) and interpolate onto a
LatitudeLongitudeGridsized for ~3 km horizontal cells at the domain center latitude.Tᵥis computed as a derived field usingBreeze.ThermodynamicConstantsfor theRᵥ/Rd − 1coefficient.Punch list
Notes
Nz=1rather than a 2-D(Bounded, Bounded, Flat)grid, sidesteppingCliMA/Oceananigans.jl#5473(Flat↔non-Flatinterpolate!errors with a crypticBoundsError; #5474 will convert that to a clearArgumentErrorbut does not lift the restriction). Mirrors the pattern inexamples/ERA5_hourly_data.jl.LatitudeLongitudeGrid. A future variant on a projected Cartesian grid would benefit from theset!projection support proposed in Add map projection support toset!forRectilinearGridtargets #232.Test plan
~/.cdsapircconfigured.