Skip to content

Open boundary conditions using SplitExplicitFreeSurface#5351

Open
simone-silvestri wants to merge 94 commits intomainfrom
ss/open-boundary-conditions
Open

Open boundary conditions using SplitExplicitFreeSurface#5351
simone-silvestri wants to merge 94 commits intomainfrom
ss/open-boundary-conditions

Conversation

@simone-silvestri
Copy link
Copy Markdown
Collaborator

@simone-silvestri simone-silvestri commented Mar 2, 2026

This PR implements open boundary conditions for the hydrostatic free surface model compatible with the split explicit free surface. The boundary conditions follow what discussed in #5229, meaning Flather boundary conditions for the barotropic component and "Orlanski" (Radiation) boundary conditions for the three-dimensional evolution.

I need to clean up a bit the PR (for example Flather now stores the external values inside its own struct, but it would be probably better to store it in the condition of the boundary_condition struct.

Since the flow of the algorithm has to change, because the barotropic correction needs to be done after filling up the boundary conditions for the 3d velocities, such that the barotropic components of the boundaries is consistent with the 2d evolution, some refactor is necessary and I would like to open a PR specifically for this (this is actually a positive because it means we can compute the entire w velocity in the update_state in distributed computations).

There is an example that showcases the use of these boundary conditions which we can remove later on.
A part from all the changes that need to be done to clean up the code, this feature should be already fully functional and testable, so if you want to test it @vtamsitt you can give it a try

cc @tomchor

  • Include tests
  • Clean up Flather BC

@vtamsitt
Copy link
Copy Markdown

vtamsitt commented Mar 2, 2026

This PR implements open boundary conditions for the hydrostatic free surface model compatible with the split explicit free surface. The boundary conditions follow what discussed in #5229, meaning Flather boundary conditions for the barotropic component and "Orlanski" (Radiation) boundary conditions for the three-dimensional evolution.

I need to clean up a bit the PR (for example Flather now stores the external values inside its own struct, but it would be probably better to store it in the condition of the boundary_condition struct.

Since the flow of the algorithm has to change, because the barotropic correction needs to be done after filling up the boundary conditions for the 3d velocities, such that the barotropic components of the boundaries is consistent with the 2d evolution, some refactor is necessary and I would like to open a PR specifically for this (this is actually a positive because it means we can compute the entire w velocity in the update_state in distributed computations).

There is an example that showcases the use of these boundary conditions which we can remove later on. A part from all the changes that need to be done to clean up the code, this feature should be already fully functional and testable, so if you want to test it @vtamsitt you can give it a try

cc @tomchor

  • Include tests
  • Clean up Flather BC

@simone-silvestri that was fast! I will see if I can get to this at the end of the week, or @rafmudaf may be able to test first with our current Med config.

Comment thread src/Oceananigans.jl
BoundaryCondition,
FluxBoundaryCondition, ValueBoundaryCondition, GradientBoundaryCondition, OpenBoundaryCondition,
PerturbationAdvection,
PerturbationAdvection, Flather, Radiation,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between these three? Isn't Radiation a subset of PerturbationAdvection?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's the opposite. PerturbationAdvection requires specifying a phase velocity at the boundary while radiation computes it (from what I understood of perturbation advection)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could make the phase velocity computation the condition and then use perturbation advection?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, I mean in either case --- whether Radiation is a subset of PerturbationAdvection, or whether PerturbationAdvection is a subset of Radiation --- in either of those cases, we should not introduce a new type but instead reuse the same type to express both schemes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not introduce a new type but instead reuse the same type to express both schemes.

I'm not sure. Radiation schemes can differ widely in their internals. Having different scheme types for each one may be useful just for the sake of simplicity. That said, the name Radiation is pretty generic and I think most people would call PertubationAdvection, Orlanski, the oblique scheme, and even Flather, radiation schemes.

@simone-silvestri from talking to you at the conference it seems like what you're implementing here for the baroclinic flow is an Orkanski scheme, no?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say just replace the existing periodic one with this. We don't need both.

…ith `SplitExplicitFreeSurface` (#5378)

* Validate any bc on nothing-dimension fields

* Add U and V to field location map

* Fix missing u, v reference

* Add missing b_bg helper function for sponge layer

* Maintain barotropic velocities for free surface

Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com>

* Add sea-surface height to field location map

Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com>

* Remove extra validation dispatch

---------

Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com>
@simone-silvestri
Copy link
Copy Markdown
Collaborator Author

Hello all!

I tried having a crack at running the Bedford Basin model I used for OSM with added OpenBoundaryCondition(Radiation()) for the u and v (along the south and east) boundaries. I'm running these models on GPU, and giving it a go I get:

ERROR: LoadError: InvalidIRError: compiling MethodInstance for Oceananigans.BoundaryConditions.gpu__fill_south_and_north_halo!(::KernelAbstractions.CompilerMetadata{…}, ::OffsetArrays.OffsetArray{…}, ::BoundaryCondition{…}, ::Oceananigans.BoundaryConditions.NoFluxBoundaryCondition, ::Tuple{…}, ::ImmersedBoundaryGrid{…}, ::Tuple{…}) resulted in invalid LLVM IR
Reason: unsupported dynamic function invocation
Stacktrace:
 [1] getbc
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:173
 [2] getbc
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:172
 [3] _fill_south_halo!
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions_open.jl:4
 [4] macro expansion
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions.jl:74
 [5] gpu__fill_south_and_north_halo!
   @ ~/.julia/packages/KernelAbstractions/ecO4B/src/macros.jl:332
 [6] gpu__fill_south_and_north_halo!
   @ ./none:0

Is there a workaround in my model setup where I can get this working on GPU? Do you need more info?

I'm really eager to test/help this PR out any way I can!

Can you show how you have set up the boundary conditions?

@ErikJohnsonOceanography
Copy link
Copy Markdown

Hello all!
I tried having a crack at running the Bedford Basin model I used for OSM with added OpenBoundaryCondition(Radiation()) for the u and v (along the south and east) boundaries. I'm running these models on GPU, and giving it a go I get:

ERROR: LoadError: InvalidIRError: compiling MethodInstance for Oceananigans.BoundaryConditions.gpu__fill_south_and_north_halo!(::KernelAbstractions.CompilerMetadata{…}, ::OffsetArrays.OffsetArray{…}, ::BoundaryCondition{…}, ::Oceananigans.BoundaryConditions.NoFluxBoundaryCondition, ::Tuple{…}, ::ImmersedBoundaryGrid{…}, ::Tuple{…}) resulted in invalid LLVM IR
Reason: unsupported dynamic function invocation
Stacktrace:
 [1] getbc
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:173
 [2] getbc
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:172
 [3] _fill_south_halo!
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions_open.jl:4
 [4] macro expansion
   @ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions.jl:74
 [5] gpu__fill_south_and_north_halo!
   @ ~/.julia/packages/KernelAbstractions/ecO4B/src/macros.jl:332
 [6] gpu__fill_south_and_north_halo!
   @ ./none:0

Is there a workaround in my model setup where I can get this working on GPU? Do you need more info?
I'm really eager to test/help this PR out any way I can!

Can you show how you have set up the boundary conditions?

I have:

u_obc_east = OpenBoundaryCondition(Radiation())
u_obc_south = OpenBoundaryCondition(Radiation())
v_obc_east = OpenBoundaryCondition(Radiation())
v_obc_south = OpenBoundaryCondition(Radiation())

and then later:

u_bcs = FieldBoundaryConditions(
        top = u_wind_stress_bc,
        bottom = u_bot_bc,
        immersed = u_immersed_bc,
        east = u_obc_east,
        south = u_obc_south)

v_bcs = FieldBoundaryConditions(
        top = v_wind_stress_bc,
        bottom = v_bot_bc,
        immersed = v_immersed_bc,    
        east = v_obc_east,
        south = v_obc_south)

boundary_conditions = (
    u = u_bcs,
    v = v_bcs,
    T = T_bcs,
    DIC1 = DIC_bcs_1,
    DIC2 = DIC_bcs_2)
    
.....
    
model = HydrostaticFreeSurfaceModel(
        grid;
        boundary_conditions,
        forcing,
        closure,
        tracers,
        momentum_advection,
        tracer_advection,
        coriolis = HydrostaticSphericalCoriolis(),
        buoyancy = SeawaterBuoyancy(equation_of_state=TEOS10EquationOfState()))

@tomchor
Copy link
Copy Markdown
Member

tomchor commented Apr 7, 2026

Can you show how you have set up the boundary conditions?

I have:

u_obc_east = OpenBoundaryCondition(Radiation())
u_obc_south = OpenBoundaryCondition(Radiation())
v_obc_east = OpenBoundaryCondition(Radiation())
v_obc_south = OpenBoundaryCondition(Radiation())

Don't you have to put a "target" for the OpenBoundaryCondition? Like:

u_obc_east = OpenBoundaryCondition(0, scheme=Radiation())
u_obc_south = OpenBoundaryCondition(0, scheme=Radiation())
v_obc_east = OpenBoundaryCondition(0, scheme=Radiation())
v_obc_south = OpenBoundaryCondition(0, scheme=Radiation())

if you're going for a zero mass flux, for example.

@simone-silvestri
Copy link
Copy Markdown
Collaborator Author

I think if we see that PerturbationAdvection works better for the baroclinic mode we can avoid adding a Radiation BC. The only important pieces to get this going were the "in-halo" barotropic correction and the barotropic Flather BC

@jagoosw
Copy link
Copy Markdown
Collaborator

jagoosw commented Apr 7, 2026

In the soliton case there is no background flow right? If so then PertubationAdvection is just relaxing to zero?

@tomchor
Copy link
Copy Markdown
Member

tomchor commented Apr 7, 2026

I think if we see that PerturbationAdvection works better for the baroclinic mode we can avoid adding a Radiation BC. The only important pieces to get this going were the "in-halo" barotropic correction and the barotropic Flather BC

Fair, but usually it's useful for models to have more than one option of radiation scheme. My impression from talking to ROMS and MITgcm users is that they tend to use different combinations of open BC for different problems, since it's hard to get one BC that works well across the board.

@tomchor
Copy link
Copy Markdown
Member

tomchor commented Apr 7, 2026

In the soliton case there is no background flow right? If so then PertubationAdvection is just relaxing to zero?

If by relaxing you mean the nudging at the boundaries using the timescales then no, it's nudging to the analytical solution. I set it up that way to mimic having a solution from a parent domain. But yes, there's no mean flow in that example.

Comment on lines +88 to +89
outflow_relaxation_timescale :: FT
inflow_relaxation_timescale :: FT
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep it consistent with PerturbationAdvection and call these outflow_timescale and inflow_timescale?

@simone-silvestri
Copy link
Copy Markdown
Collaborator Author

I think this test case might be weirder than I thought. This is with periodic BCs:

barotropic_soliton_split_explicit.mp4

@tomchor
Copy link
Copy Markdown
Member

tomchor commented Apr 7, 2026

Weird! That shouldn't happen though, right?

On another note, after some testing I can see no difference between PerturbationAdvection and Radiation. The differences we see in #5351 (comment) are due to different choices (by accident on my part) of inflow and outflow timescales. I guess that's expected since we're dealing with a barotropic flow?

@simone-silvestri
Copy link
Copy Markdown
Collaborator Author

Hmmm, we might want to reduce the complexity of the case, something like a wave that exits the domain might be a good test (and a wave entering)

@tomchor
Copy link
Copy Markdown
Member

tomchor commented Apr 7, 2026

@simone-silvestri in your simulation with periodic boundary conditions, did you by any chance leave the nudging and sponge layers on?

@simone-silvestri
Copy link
Copy Markdown
Collaborator Author

Ah I hadn't check, indeed, if there are I left them

@tomchor
Copy link
Copy Markdown
Member

tomchor commented Apr 7, 2026

I'm pretty sure that's creating the weird results then.

@ErikJohnsonOceanography
Copy link
Copy Markdown

Can you show how you have set up the boundary conditions?

I have:

u_obc_east = OpenBoundaryCondition(Radiation())
u_obc_south = OpenBoundaryCondition(Radiation())
v_obc_east = OpenBoundaryCondition(Radiation())
v_obc_south = OpenBoundaryCondition(Radiation())

Don't you have to put a "target" for the OpenBoundaryCondition? Like:

u_obc_east = OpenBoundaryCondition(0, scheme=Radiation())
u_obc_south = OpenBoundaryCondition(0, scheme=Radiation())
v_obc_east = OpenBoundaryCondition(0, scheme=Radiation())
v_obc_south = OpenBoundaryCondition(0, scheme=Radiation())

if you're going for a zero mass flux, for example.

I tried following closer to the example provided in internal_tide_open_boundaries.jl, and I am trying to set the boundaries to u and v velocities that are stored in CuArrays that are updated over time.

To do this I tried (just showing u boundaries, v are identically set up):


# Create boundary condition arrays
u_east_array  = on_architecture(arch, zeros(Nφ, Nz))
u_south_array = on_architecture(arch, zeros(Nλ+1, Nz))

@inline get_u_east(i, j, k, grid, clock, p) = @inbounds p.u_east_array[j,k]
@inline get_u_south(i, j, k, grid, clock, p) =  @inbounds p.u_south_array[i,k]

radiation = Radiation(outflow_relaxation_timescale = Inf,
                      inflow_relaxation_timescale = 300)

u_obc_east = OpenBoundaryCondition(get_u_east; scheme = radiation, parameters=(; u_east_array))
u_obc_south = OpenBoundaryCondition(get_u_south; scheme = radiation, parameters=(; u_south_array))

Which ultimately throws:

ERROR: LoadError: InvalidIRError: compiling MethodInstance for Oceananigans.BoundaryConditions.gpu__fill_south_and_north_halo!(::KernelAbstractions.CompilerMetadata{…}, ::OffsetArrays.OffsetArray{…}, ::BoundaryCondition{…}, ::Oceananigans.BoundaryConditions.NoFluxBoundaryCondition, ::Tuple{…}, ::ImmersedBoundaryGrid{…}, ::Tuple{…}) resulted in invalid LLVM IR
Reason: unsupported dynamic function invocation (call to get_u_south)
Stacktrace:
[1] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/continuous_boundary_function.jl:142
[2] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:172
[3] _fill_south_halo!
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/open_boundary_schemes.jl:378
[4] macro expansion
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions.jl:74
[5] gpu__fill_south_and_north_halo!
@ ~/.julia/packages/KernelAbstractions/ecO4B/src/macros.jl:332
[6] gpu__fill_south_and_north_halo!
@ ./none:0

Thanks for the help with this!

@jagoosw
Copy link
Copy Markdown
Collaborator

jagoosw commented Apr 9, 2026

I tried following closer to the example provided in internal_tide_open_boundaries.jl, and I am trying to set the boundaries to u and v velocities that are stored in CuArrays that are updated over time.

To do this I tried (just showing u boundaries, v are identically set up):


# Create boundary condition arrays
u_east_array  = on_architecture(arch, zeros(Nφ, Nz))
u_south_array = on_architecture(arch, zeros(Nλ+1, Nz))

@inline get_u_east(i, j, k, grid, clock, p) = @inbounds p.u_east_array[j,k]
@inline get_u_south(i, j, k, grid, clock, p) =  @inbounds p.u_south_array[i,k]

radiation = Radiation(outflow_relaxation_timescale = Inf,
                      inflow_relaxation_timescale = 300)

u_obc_east = OpenBoundaryCondition(get_u_east; scheme = radiation, parameters=(; u_east_array))
u_obc_south = OpenBoundaryCondition(get_u_south; scheme = radiation, parameters=(; u_south_array))

Which ultimately throws:

ERROR: LoadError: InvalidIRError: compiling MethodInstance for Oceananigans.BoundaryConditions.gpu__fill_south_and_north_halo!(::KernelAbstractions.CompilerMetadata{…}, ::OffsetArrays.OffsetArray{…}, ::BoundaryCondition{…}, ::Oceananigans.BoundaryConditions.NoFluxBoundaryCondition, ::Tuple{…}, ::ImmersedBoundaryGrid{…}, ::Tuple{…}) resulted in invalid LLVM IR
Reason: unsupported dynamic function invocation (call to get_u_south)
Stacktrace:
[1] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/continuous_boundary_function.jl:142
[2] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:172
[3] _fill_south_halo!
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/open_boundary_schemes.jl:378
[4] macro expansion
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions.jl:74
[5] gpu__fill_south_and_north_halo!
@ ~/.julia/packages/KernelAbstractions/ecO4B/src/macros.jl:332
[6] gpu__fill_south_and_north_halo!
@ ./none:0

Thanks for the help with this!

Have you tried running this on CPU? It might give a more descriptive error message. I think the signature for get_u_east and get_u_south are wrong and should be get_u_east(j, k, grid, clock, p) and get_u_south(i, k, grid, clock, p).

@ErikJohnsonOceanography
Copy link
Copy Markdown

I tried following closer to the example provided in internal_tide_open_boundaries.jl, and I am trying to set the boundaries to u and v velocities that are stored in CuArrays that are updated over time.
To do this I tried (just showing u boundaries, v are identically set up):


# Create boundary condition arrays
u_east_array  = on_architecture(arch, zeros(Nφ, Nz))
u_south_array = on_architecture(arch, zeros(Nλ+1, Nz))

@inline get_u_east(i, j, k, grid, clock, p) = @inbounds p.u_east_array[j,k]
@inline get_u_south(i, j, k, grid, clock, p) =  @inbounds p.u_south_array[i,k]

radiation = Radiation(outflow_relaxation_timescale = Inf,
                      inflow_relaxation_timescale = 300)

u_obc_east = OpenBoundaryCondition(get_u_east; scheme = radiation, parameters=(; u_east_array))
u_obc_south = OpenBoundaryCondition(get_u_south; scheme = radiation, parameters=(; u_south_array))

Which ultimately throws:

ERROR: LoadError: InvalidIRError: compiling MethodInstance for Oceananigans.BoundaryConditions.gpu__fill_south_and_north_halo!(::KernelAbstractions.CompilerMetadata{…}, ::OffsetArrays.OffsetArray{…}, ::BoundaryCondition{…}, ::Oceananigans.BoundaryConditions.NoFluxBoundaryCondition, ::Tuple{…}, ::ImmersedBoundaryGrid{…}, ::Tuple{…}) resulted in invalid LLVM IR
Reason: unsupported dynamic function invocation (call to get_u_south)
Stacktrace:
[1] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/continuous_boundary_function.jl:142
[2] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:172
[3] _fill_south_halo!
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/open_boundary_schemes.jl:378
[4] macro expansion
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/fill_halo_regions.jl:74
[5] gpu__fill_south_and_north_halo!
@ ~/.julia/packages/KernelAbstractions/ecO4B/src/macros.jl:332
[6] gpu__fill_south_and_north_halo!
@ ./none:0

Thanks for the help with this!

Have you tried running this on CPU? It might give a more descriptive error message. I think the signature for get_u_east and get_u_south are wrong and should be get_u_east(j, k, grid, clock, p) and get_u_south(i, k, grid, clock, p).

I switched to CPU, and it revealed that the signatures were wrong, as you suspected, however, I also had to drop p, and build the functions like:

@inline get_u_east(j, k, grid, clock) = @inbounds u_east_array[j,k]
@inline get_u_south(i, k, grid, clock) =  @inbounds u_south_array[i,k]
@inline get_v_east(j, k, grid, clock) =  @inbounds v_east_array[j,k]
@inline get_v_south(i, k, grid, clock) =  @inbounds v_south_array[i,k]

u_obc_east = OpenBoundaryCondition(get_u_east; scheme = radiation, parameters=(; u_east_array))
u_obc_south = OpenBoundaryCondition(get_u_south; scheme = radiation, parameters=(; u_south_array))
v_obc_east = OpenBoundaryCondition(get_v_east; scheme = radiation, parameters=(; v_east_array))
v_obc_south = OpenBoundaryCondition(get_v_south; scheme = radiation, parameters=(; v_south_array))

etc. However, now I get:

ERROR: LoadError: ArgumentError: invalid index: -63.675 of type Float64
Stacktrace:
[1] to_index(i::Float64)
@ Base ./indices.jl:300
[2] to_index(A::Matrix{Float64}, i::Float64)
@ Base ./indices.jl:277
[3] _to_indices1(A::Matrix{Float64}, inds::Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}, I1::Float64)
@ Base ./indices.jl:359
[4] to_indices
@ ./indices.jl:354 [inlined]
[5] to_indices
@ ./indices.jl:344 [inlined]
[6] getindex(::Matrix{Float64}, ::Float64, ::Float64)
@ Base ./abstractarray.jl:1290
[7] get_u_south
@ /pool1/data/erikj/BedfordCarbonate/HelperFunctions/buildForcings.jl:37 [inlined]
[8] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/continuous_boundary_function.jl:142 [inlined]
[9] getbc
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/boundary_condition.jl:172 [inlined]
[10] _fill_south_halo!
@ ~/.julia/packages/Oceananigans/GKZsM/src/BoundaryConditions/open_boundary_schemes.jl:378 [inlined]

which makes me realize that in the internal_tide_open_boundaries.jl test case there are two signatures for tidal_forcing, one taking (z,t,p) and the other (i, grid::Oceananigans.Grids.AbstractGrid, clock). Perhaps OpenBoundaryCondition doesn't support discrete functions? Is there an equivalent to the "discrete_form=true" passed to Forcing()? Sorry if these are silly questions!

@jagoosw
Copy link
Copy Markdown
Collaborator

jagoosw commented Apr 10, 2026

which makes me realize that in the internal_tide_open_boundaries.jl test case there are two signatures for tidal_forcing, one taking (z,t,p) and the other (i, grid::Oceananigans.Grids.AbstractGrid, clock). Perhaps OpenBoundaryCondition doesn't support discrete functions? Is there an equivalent to the "discrete_form=true" passed to Forcing()? Sorry if these are silly questions!

Yes you have to pass discrete_form=true, here is the signature:

BoundaryCondition(classification::AbstractBoundaryConditionClassification, condition::Function;
                    parameters = nothing,
                    discrete_form = false,
                    field_dependencies=())

I just realised that you're just passing arrays, so you can actually just put the array directly as the condition:

grid = RectilinearGrid(topology = (Periodic, Bounded, Bounded), size = (10, 10, 10), extent = (1, 1, 1))

south_v = zeros(10, 10)

south_obc = OpenBoundaryCondition(south_v)

Perhaps we need to note in the docstrings that all the boundary conditions take the kwargs of BoundaryCondition @glwagner

@glwagner
Copy link
Copy Markdown
Member

which makes me realize that in the internal_tide_open_boundaries.jl test case there are two signatures for tidal_forcing, one taking (z,t,p) and the other (i, grid::Oceananigans.Grids.AbstractGrid, clock). Perhaps OpenBoundaryCondition doesn't support discrete functions? Is there an equivalent to the "discrete_form=true" passed to Forcing()? Sorry if these are silly questions!

Yes you have to pass discrete_form=true, here is the signature:

BoundaryCondition(classification::AbstractBoundaryConditionClassification, condition::Function;
                    parameters = nothing,
                    discrete_form = false,
                    field_dependencies=())

I just realised that you're just passing arrays, so you can actually just put the array directly as the condition:

grid = RectilinearGrid(topology = (Periodic, Bounded, Bounded), size = (10, 10, 10), extent = (1, 1, 1))

south_v = zeros(10, 10)

south_obc = OpenBoundaryCondition(south_v)

Perhaps we need to note in the docstrings that all the boundary conditions take the kwargs of BoundaryCondition @glwagner

It doesn't make sense to me that we need to pass discrete_form=true for arrays or fields. that should be fixed.

Also, we should discourage or discontinue support for arrays. Field is preferred.

As for the note, I'm not sure I understand the suggestion. The docstring should say something like "see the docstring for BoundaryCondition for kwargs", or copy/paste over. Is the docstring currently incomplete?

@jagoosw
Copy link
Copy Markdown
Collaborator

jagoosw commented Apr 13, 2026

It doesn't make sense to me that we need to pass discrete_form=true for arrays or fields. that should be fixed.
Yeah thats fine it was just a problem with the work around.

Also, we should discourage or discontinue support for arrays. Field is preferred.

As for the note, I'm not sure I understand the suggestion. The docstring should say something like "see the docstring for BoundaryCondition for kwargs", or copy/paste over. Is the docstring currently incomplete?
There are currently no docstrings for the aliases like ValueBoundaryCondition:

help?> ValueBoundaryCondition
search: ValueBoundaryCondition

  No documentation found.

  Oceananigans.BoundaryConditions.ValueBoundaryCondition is a Function.

  # 1 method for generic function "ValueBoundaryCondition" from Oceananigans.BoundaryConditions:
   [1] ValueBoundaryCondition(val; kwargs...)
       @ ~/.julia/packages/Oceananigans/r4zuV/src/BoundaryConditions/boundary_condition.jl:109

so maybe it would be helpful to put something there just pointing to the BoundaryCondition docstring (and the classifcation docstrong)?

@simone-silvestri
Copy link
Copy Markdown
Collaborator Author

Output of validation/open_boundaries/gaussian_pulse_open_boundaries.jl

gaussian_pulse_open_boundaries.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants