Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ examples = [

# Developer examples from docs/src/developers/ directory
developer_examples = [
Example("EarthSystemModel interface", "slab_ocean", false),
# Example("EarthSystemModel interface", "slab_ocean", false),
]

# Filter out long-running examples unless NUMERICAL_EARTH_BUILD_ALL_EXAMPLES is set
Expand Down
5 changes: 3 additions & 2 deletions examples/global_climate_simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ viscous_closure = Oceananigans.TurbulenceClosures.HorizontalScalarBiharmoni
closures = (catke_closure, eddy_closure, viscous_closure)
nothing #hide

# The ocean simulation, complete with initial conditions for temperature and salinity from ECCO.
# The ocean simulation, complete with initial conditions for temperature and salinity from ECCO on Jan 1st, 1992.

ocean = ocean_simulation(grid;
momentum_advection,
Expand All @@ -63,7 +63,8 @@ ocean = ocean_simulation(grid;

ecco_set = MetadataSet(:temperature, :salinity,
:sea_ice_thickness, :sea_ice_concentration;
dataset = ECCO4Monthly())
dataset = ECCO4Monthly(),
date = DateTime(1992, 1, 1))
Oceananigans.set!(ocean.model, ecco_set) # T, S

# The sea-ice simulation, complete with initial conditions for sea-ice thickness and sea-ice concentration from ECCO.
Expand Down
4 changes: 2 additions & 2 deletions examples/near_global_ocean_simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ ocean = ocean_simulation(grid)
ocean.model

# We initialize the ocean model with ECCO4 temperature and salinity for January 1, 1992.

set!(ocean.model, MetadataSet(:temperature, :salinity; dataset=ECCO4Monthly()))
date = DateTime(1992, 1, 1)
set!(ocean.model, MetadataSet(:temperature, :salinity; dataset=ECCO4Monthly(), date))

# ### Prescribed atmosphere and radiation
#
Expand Down
27 changes: 15 additions & 12 deletions examples/one_degree_simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,28 +83,31 @@ sea_ice = sea_ice_simulation(grid, ocean; advection=tracer_advection)
# We initialize the ocean and sea ice models with data from the ECCO state estimate.

date = DateTime(1993, 1, 1)
ecco_set = MetadataSet(:temperature, :salinity,
:sea_ice_thickness, :sea_ice_concentration;
dataset = ECCO4Monthly(), date)
ecco_variables = (:temperature, :salinity, :sea_ice_thickness, :sea_ice_concentration)
ecco_set = MetadataSet(ecco_variables; dataset = ECCO4Monthly(), date)

# A single MetadataSet drives both components; variables not in
# `variable_glossary` for a given model fall through silently.
set!(ocean.model, ecco_set) # picks up :temperature, :salinity → T, S
set!(sea_ice.model, ecco_set) # picks up :sea_ice_thickness, :sea_ice_concentration → h, ℵ

# ### Atmospheric forcing
# ### JRA55-based atmospheric state, radiation, and land model
#
# We force the simulation with data derived from the JRA55-do atmospheric reanalysis,
# which include the atmospheric state and radiative fluxes, as well as
# land-based freshwater fluxes from rivers and icebergs.
#
# In the radiation component we prescribed a latitude-dependent ocean albedo due to
# Large & Yeager 2009.

# We force the simulation with a JRA55-do atmospheric reanalysis.
land = JRA55PrescribedLand(arch)
atmosphere = JRA55PrescribedAtmosphere(arch)
# Use a latitude-dependent ocean albedo (Large & Yeager 2009); keep the
# default ocean emissivity (0.97) and sea-ice surface (albedo 0.7,
# emissivity 1.0).
radiation = JRA55PrescribedRadiation(arch;
ocean_surface = SurfaceRadiationProperties(albedo = LatitudeDependentAlbedo()))
land = JRA55PrescribedLand(arch)

# ### Coupled simulation
ocean_surface = SurfaceRadiationProperties(albedo = LatitudeDependentAlbedo())
radiation = JRA55PrescribedRadiation(arch; ocean_surface)

# ### Coupled simulation
#
# Now we are ready to build the coupled ocean--sea ice model and bring everything
# together into a `simulation`.

Expand Down
64 changes: 45 additions & 19 deletions src/DataWrangling/metadata.jl
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,12 @@ end
#####

struct MetadataSet{V, D, R, N, F}
names :: N # NTuple{K, Symbol} — verbose dataset variable names
dataset :: V # shared
dates :: D # shared; scalar or AbstractVector
region :: R # shared
dir :: String # shared
filenames :: F # NamedTuple keyed by `names`, one entry per variable
names :: N # NTuple{K, Symbol} — verbose dataset variable names
dataset :: V # shared
dates :: D # shared; scalar or AbstractVector
region :: R # shared
dir :: String # shared
filenames :: F # NamedTuple keyed by `names`, one entry per variable
end

"""
Expand Down Expand Up @@ -401,6 +401,8 @@ function MetadataSet(variable_names::Symbol...;
return MetadataSet(variable_names, dataset, effective_dates, region, dir, filenames)
end

MetadataSet(names::NTuple{<:Any, <:Symbol}; kw...) = MetadataSet(names...; kw...)

# Property access: variables first via filenames lookup, struct fields second.
function Base.getproperty(mset::MetadataSet, name::Symbol)
if name in fieldnames(MetadataSet)
Expand Down Expand Up @@ -506,14 +508,40 @@ Only the intersection of `names` and `mset.names` is forwarded.
The default `names` is every glossary key — fine for permissive models. Models
that throw on unknown kwargs (`HydrostaticFreeSurfaceModel`, `SeaIceModel`)
override the 2-argument form to pass a narrower `names`, letting a single
multi-component MetadataSet drive both an ocean and a sea-ice model:

```julia
mset = MetadataSet(:temperature, :salinity,
:sea_ice_thickness, :sea_ice_concentration;
dataset = ECCO4Monthly(), date = start_date)
set!(ocean.model, mset) # consumes :temperature, :salinity → T, S
set!(sea_ice.model, mset) # consumes :sea_ice_thickness, :sea_ice_concentration → h, ℵ
multi-component MetadataSet drive both an ocean and a sea-ice model.
Each model's override of `set!(model, ::MetadataSet)` filters the same `mset`
down to the variables that model knows how to consume:

```jldoctest
using NumericalEarth
using Oceananigans
using Statistics
using Dates

grid = LatitudeLongitudeGrid(size = (60, 30, 5),
longitude = (-180, 180),
latitude = (-60, 60),
z = (-5000, 0),
halo = (7, 7, 7))

ocean = ocean_simulation(grid)

mset = MetadataSet(:temperature, :salinity;
dataset = ECCO4Monthly(),
date = DateTime(1993, 1, 1))

# Ocean override routes :temperature → T, :salinity → S; sea-ice vars are
# filtered out. A `set!(sea_ice.model, mset)` call against the same `mset`
# would route :sea_ice_thickness → h, :sea_ice_concentration → ℵ.
set!(ocean.model, mset)

T = ocean.model.tracers.T
(min = round(minimum(T), digits = 2),
max = round(maximum(T), digits = 2),
mean = round(mean(T), digits = 2))

# output
(min = -1.06, max = 21.41, mean = 3.3)
```
"""
function Fields.set!(model, mset::MetadataSet, names=keys(variable_glossary))
Expand All @@ -528,11 +556,9 @@ end
# `set!` looks up kwargs.
using Oceananigans.Models.HydrostaticFreeSurfaceModels: HydrostaticFreeSurfaceModel
function Fields.set!(model::HydrostaticFreeSurfaceModel, mset::MetadataSet)
short = (propertynames(model.velocities)...,
propertynames(model.tracers)...,
propertynames(model.free_surface)...)
names = Tuple(n for (n, s) in variable_glossary if s in short)
return set!(model, mset, names)
hfsm_short_names = (propertynames(model.velocities)..., propertynames(model.tracers)..., :η)
valid_long_names = Tuple(long_name for (long_name, short_name) in variable_glossary if short_name in hfsm_short_names)
return set!(model, mset, valid_long_names)
end

# Sea ice: ClimaSeaIce's `set!(::SeaIceModel; h, ℵ)` only accepts these two.
Expand Down
Loading