ITADN

Add `scheme` slot to `Value` (`Value{MS}`) and migrate `PerturbationAdvection`'s Center-field path

#5647Openewquon 创建于 2026-05-29
E
ewquoncommented
# Add `scheme` slot to `Value` (`Value{MS}`) and migrate `PerturbationAdvection`'s Center-field path ## Background Today only the `Open` classification carries a scheme slot ([`boundary_condition_classifications.jl:70-72`](https://github.com/CliMA/Oceananigans.jl/blob/main/src/BoundaryConditions/boundary_condition_classifications.jl#L70-L72)): ```julia struct Open{MS} <: AbstractBoundaryConditionClassification scheme :: MS end ``` The other classifications (`Value`, `Gradient`, `Flux`, `Mixed`) are bare singletons: ```julia struct Value <: AbstractBoundaryConditionClassification end ``` This is asymmetric. `Open` is documented as "specify the component of a velocity field normal to a boundary" — fundamentally a face-located concept — yet `Open` is currently the only home for *any* scheme, including schemes whose natural home is a Dirichlet condition on a `Center` scalar. `PerturbationAdvection` is the present-day evidence: it ships under `Open{<:PerturbationAdvection}` with separate halo-fill methods for Face-located fields (u, v, w — semantically correct for Open) and Center-located fields ([`perturbation_advection.jl:272-308`](https://github.com/CliMA/Oceananigans.jl/blob/main/src/BoundaryConditions/perturbation_advection.jl#L272-L308) — tracers, scalars — semantically a stretch). ## Proposed change Add a scheme slot to `Value`, mirroring `Open`: ```julia # src/BoundaryConditions/boundary_condition_classifications.jl struct Value{MS} <: AbstractBoundaryConditionClassification scheme :: MS end Value() = Value(nothing) (v::Value)() = v Adapt.adapt_structure(to, v::Value) = Value(adapt(to, v.scheme)) ``` And extend the `ValueBoundaryCondition` constructor to accept the kwarg: ```julia # src/BoundaryConditions/boundary_condition.jl ValueBoundaryCondition(val; scheme = nothing, kwargs...) = BoundaryCondition(Value(scheme), val; kwargs...) ``` `Value()` is preserved as a default constructor, so every existing `BoundaryCondition{<:Value}` dispatch keeps matching. The change is backwards-compatible for all existing call sites and any downstream code that pattern-matches on `<:Value`. Total surface: ~10 lines in two files. No behavior change for any existing code path. ## Implications for `PerturbationAdvection` With `Value{MS}` available, the principled home for `PerturbationAdvection` splits across two classifications: ```julia const PAOBC_Face = BoundaryCondition{<:Open{<:PerturbationAdvection}} # u, v, w const PAOBC_Center = BoundaryCondition{<:Value{<:PerturbationAdvection}} # tracers, ρθ, ρq ``` The user-facing API would split symmetrically: ```julia # Face fields (boundary value lives on the face — Open is semantically natural) u_bcs = FieldBoundaryConditions(east = OpenBoundaryCondition(U₀; scheme = PerturbationAdvection(...))) # Center fields (Dirichlet target nudging the outermost cell — Value is semantically natural) c_bcs = FieldBoundaryConditions(east = ValueBoundaryCondition(c₀; scheme = PerturbationAdvection(...))) ``` This is the design that would have been chosen if `Value{MS}` had existed when `PerturbationAdvection` was first written. The current "all under `Open`" path for Center fields is a historical artifact of `Open` being the only classification with a scheme slot, not a deliberate semantic choice. ### Suggested migration Not a hard break — a deprecation cycle: 1. Add `Value{MS}` (this issue). 2. Add `PerturbationAdvection` halo-fill methods that dispatch on `<:Value{<:PerturbationAdvection}` for Center fields. The kernel bodies port directly from the existing Center methods on `<:Open{<:PerturbationAdvection}`. 3. Keep the existing `Open{<:PerturbationAdvection}` Center methods with a deprecation warning recommending users switch to `ValueBoundaryCondition(c₀; scheme = PerturbationAdvection(...))`. 4. After a release or two, retire the `Open` Center path. The Face path (u, v, w) stays under `Open` forever — that's where it belongs. Tests in `test_boundary_conditions_integration.jl` covering the Center-field `PerturbationAdvection` path (`test_perturbation_advection_tracer_*`) would gain mirrored `Value{MS}` versions during the migration. ## Downstream motivation Breeze.jl is independently designing an `AcousticRelaxation` scheme for per-substep open-boundary relaxation of ρ and (ρθ) in its compressible-substep solver ([NumericalEarth/Breeze.jl#748](https://github.com/NumericalEarth/Breeze.jl/issues/748), following on from [#747](https://github.com/NumericalEarth/Breeze.jl/pull/747)). The scheme attaches to a `Center` scalar's BC and operates by nudging the outermost cell toward a prescribed wall value — same shape as `PerturbationAdvection`'s Center-field case. Routing it through `Open` would propagate the same semantic stretch; routing through `Value{MS}` is the clean home. So the same upstream change unblocks a downstream consumer *and* lets Oceananigans tidy up an existing inconsistency in its own code. ## Open questions - **`Gradient{MS}` and `Flux{MS}` for symmetry?** Worth considering for completeness — the same kind of pattern could exist for Neumann (e.g., a "relax-the-flux" scheme) or for sophisticated flux parameterizations. Not motivated by any concrete consumer right now. Could be done in this issue or deferred. - **Naming**: keep `MS` as the type parameter name (historical "matching scheme" — same letter that's in `Open{MS}`), or rename to something more descriptive (`S`, `Scheme`)? Consistency with `Open` argues for `MS`. - **`show` methods**: `Base.summary(bc::OBC{Open{MS}}) where MS = string("OpenBoundaryCondition{$MS}: ", ...)` (`show_boundary_conditions.jl:26`). A mirrored method on `BoundaryCondition{<:Value}` would surface the scheme name. Cheap and consistent. ## References - [Oceananigans `Open` classification](https://github.com/CliMA/Oceananigans.jl/blob/main/src/BoundaryConditions/boundary_condition_classifications.jl#L60-L78) - [Oceananigans `PerturbationAdvection`](https://github.com/CliMA/Oceananigans.jl/blob/main/src/BoundaryConditions/perturbation_advection.jl) - [`ValueBoundaryCondition` constructor](https://github.com/CliMA/Oceananigans.jl/blob/main/src/BoundaryConditions/boundary_condition.jl#L109) - [NumericalEarth/Breeze.jl#748](https://github.com/NumericalEarth/Breeze.jl/issues/748) — downstream consumer (Breeze's `AcousticRelaxation` scheme refactor). - [NumericalEarth/Breeze.jl#747](https://github.com/NumericalEarth/Breeze.jl/pull/747) — original Breeze PR where this design conversation started.
1 条评论