Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Adds a pertubation advection open boundary matching scheme #3977

Draft
wants to merge 32 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d992d81
fix FEOBC
jagoosw Nov 18, 2024
2a374cb
x-boundary condition implemented
jagoosw Dec 4, 2024
babe922
changed relaxation a bit
jagoosw Dec 5, 2024
32cd354
cleaning up + validation case
jagoosw Dec 6, 2024
5a0285f
changed to pointwise
jagoosw Dec 6, 2024
fef6185
oops
jagoosw Dec 6, 2024
fa5a471
fixed open boundary filling + tests
jagoosw Dec 6, 2024
29a3b4a
Merge branch 'main' into jsw/fix-feobc
jagoosw Dec 6, 2024
b55395c
generalised and fixed bug in left boundary
jagoosw Dec 6, 2024
1a9fbec
bump patch
jagoosw Dec 6, 2024
e66f3d1
Formating
jagoosw Dec 6, 2024
dc73eba
Merge branch 'main' into jsw/fix-feobc
jagoosw Dec 10, 2024
51c9938
test problem
jagoosw Dec 10, 2024
94ce249
Merge branch 'main' into jsw/fix-feobc
jagoosw Dec 10, 2024
6ff1bc7
bump patch
jagoosw Dec 10, 2024
b10f833
Merge remote-tracking branch 'origin' into jsw/pertubation-advection-obc
jagoosw Dec 10, 2024
a7cdcfd
Merge branch 'main' into jsw/fix-feobc
jagoosw Dec 11, 2024
62e27b2
clean up
jagoosw Dec 12, 2024
a23adae
boundary normal velocity
jagoosw Dec 12, 2024
5246c9a
oops
jagoosw Dec 12, 2024
a34c927
Rename
jagoosw Dec 12, 2024
0df1abe
finish renaming
jagoosw Dec 12, 2024
ff0c79e
renamed
jagoosw Dec 12, 2024
3257eec
kind of GPU frieldly
jagoosw Dec 12, 2024
07cc471
typo
jagoosw Dec 13, 2024
9ae0b66
bug
jagoosw Dec 13, 2024
ec9dd88
bug
jagoosw Dec 13, 2024
9859c17
Merge branch 'main' into jsw/fix-feobc
jagoosw Dec 14, 2024
0e02a2b
Merge branch 'main' into jsw/fix-feobc
jagoosw Dec 15, 2024
9912b51
Merge remote-tracking branch 'origin/jsw/fix-feobc' into jsw/pertubat…
jagoosw Dec 15, 2024
96495b1
allow forward euler integration
jagoosw Dec 15, 2024
c49ed26
fix adapt
jagoosw Dec 15, 2024
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 Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Oceananigans"
uuid = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
authors = ["Climate Modeling Alliance and contributors"]
version = "0.95.2"
version = "0.95.3"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
Expand Down
1 change: 1 addition & 0 deletions src/BoundaryConditions/BoundaryConditions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ include("update_boundary_conditions.jl")
include("polar_boundary_condition.jl")

include("flat_extrapolation_open_boundary_matching_scheme.jl")
include("perturbation_advection_open_boundary_matching_scheme.jl")
end # module
4 changes: 3 additions & 1 deletion src/BoundaryConditions/fill_halo_regions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ conditions, possibly recursing into `fields` if it is a nested tuple-of-tuples.
# Some fields have `nothing` boundary conditions, such as `FunctionField` and `ZeroField`.
fill_halo_regions!(c::OffsetArray, ::Nothing, args...; kwargs...) = nothing

retrieve_bc(bc) = bc

# Returns the boundary conditions a specific side for `FieldBoundaryConditions` inputs and
# a tuple of boundary conditions for `NTuple{N, <:FieldBoundaryConditions}` inputs
for dir in (:west, :east, :south, :north, :bottom, :top)
extract_side_bc = Symbol(:extract_, dir, :_bc)
@eval begin
@inline $extract_side_bc(bc) = bc.$dir
@inline $extract_side_bc(bc) = retrieve_bc(bc.$dir)
@inline $extract_side_bc(bc::Tuple) = map($extract_side_bc, bc)
end
end
Expand Down
4 changes: 3 additions & 1 deletion src/BoundaryConditions/fill_halo_regions_open.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ end
@inline retrieve_open_bc(bc::OBC) = bc
@inline retrieve_open_bc(bc) = nothing

@inline retrieve_bc(bc::OBC) = nothing

# for regular halo fills, return nothing if the BC is not an OBC
@inline left_open_boundary_condition(boundary_condition, loc) = nothing
@inline left_open_boundary_condition(boundary_conditions, ::Tuple{Face, Center, Center}) = retrieve_open_bc(boundary_conditions.west)
Expand All @@ -59,7 +61,7 @@ end
@inline right_open_boundary_condition(boundary_conditions, ::Tuple{Center, Face, Center}) = retrieve_open_bc(boundary_conditions.north)
@inline right_open_boundary_condition(boundary_conditions, ::Tuple{Center, Center, Face}) = retrieve_open_bc(boundary_conditions.top)

# Opern boundary fill
# Open boundary fill
@inline _fill_west_halo!(j, k, grid, c, bc::OBC, loc, args...) = @inbounds c[1, j, k] = getbc(bc, j, k, grid, args...)
@inline _fill_east_halo!(j, k, grid, c, bc::OBC, loc, args...) = @inbounds c[grid.Nx + 1, j, k] = getbc(bc, j, k, grid, args...)
@inline _fill_south_halo!(i, k, grid, c, bc::OBC, loc, args...) = @inbounds c[i, 1, k] = getbc(bc, i, k, grid, args...)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Oceananigans.Operators: Δx, Δy, Δz
using Oceananigans.Operators: Δxᶜᶜᶜ, Δyᶜᶜᶜ, Δzᶜᶜᶜ

"""
FlatExtrapolation
Expand Down Expand Up @@ -59,12 +59,10 @@ end
return ϕ + Δϕ
end

const c = Center()

@inline function _fill_west_open_halo!(j, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
Δx₁ = Δx(1, j, k, grid, c, c, c)
Δx₂ = Δx(2, j, k, grid, c, c, c)
Δx₃ = Δx(3, j, k, grid, c, c, c)
@inline function _fill_west_halo!(j, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
Δx₁ = Δxᶜᶜᶜ(1, j, k, grid)
Δx₂ = Δxᶜᶜᶜ(2, j, k, grid)
Δx₃ = Δxᶜᶜᶜ(3, j, k, grid)

spacing_factor = Δx₁ / (Δx₂ + Δx₃)

Expand All @@ -75,12 +73,12 @@ const c = Center()
return nothing
end

@inline function _fill_east_open_halo!(j, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
@inline function _fill_east_halo!(j, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
i = grid.Nx + 1

Δx₁ = Δx(i-1, j, k, grid, c, c, c)
Δx₂ = Δx(i-2, j, k, grid, c, c, c)
Δx₃ = Δx(i-3, j, k, grid, c, c, c)
Δx₁ = Δxᶜᶜᶜ(i-1, j, k, grid)
Δx₂ = Δxᶜᶜᶜ(i-2, j, k, grid)
Δx₃ = Δxᶜᶜᶜ(i-3, j, k, grid)

spacing_factor = Δx₁ / (Δx₂ + Δx₃)

Expand All @@ -91,10 +89,10 @@ end
return nothing
end

@inline function _fill_south_open_halo!(i, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
Δy₁ = Δy(i, 1, k, grid, c, c, c)
Δy₂ = Δy(i, 2, k, grid, c, c, c)
Δy₃ = Δy(i, 3, k, grid, c, c, c)
@inline function _fill_south_halo!(i, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
Δy₁ = Δyᶜᶜᶜ(i, 1, k, grid)
Δy₂ = Δyᶜᶜᶜ(i, 2, k, grid)
Δy₃ = Δyᶜᶜᶜ(i, 3, k, grid)

spacing_factor = Δy₁ / (Δy₂ + Δy₃)

Expand All @@ -105,12 +103,12 @@ end
return nothing
end

@inline function _fill_north_open_halo!(i, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
@inline function _fill_north_halo!(i, k, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
j = grid.Ny + 1

Δy₁ = Δy(i, j-1, k, grid, c, c, c)
Δy₂ = Δy(i, j-2, k, grid, c, c, c)
Δy₃ = Δy(i, j-3, k, grid, c, c, c)
Δy₁ = Δyᶜᶜᶜ(i, j-1, k, grid)
Δy₂ = Δyᶜᶜᶜ(i, j-2, k, grid)
Δy₃ = Δyᶜᶜᶜ(i, j-3, k, grid)

spacing_factor = Δy₁ / (Δy₂ + Δy₃)

Expand All @@ -121,10 +119,10 @@ end
return nothing
end

@inline function _fill_bottom_open_halo!(i, j, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
Δz₁ = Δz(i, j, 1, grid, c, c, c)
Δz₂ = Δz(i, j, 2, grid, c, c, c)
Δz₃ = Δz(i, j, 3, grid, c, c, c)
@inline function _fill_bottom_halo!(i, j, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
Δz₁ = Δzᶜᶜᶜ(i, j, 1, grid)
Δz₂ = Δzᶜᶜᶜ(i, j, 2, grid)
Δz₃ = Δzᶜᶜᶜ(i, j, 3, grid)

spacing_factor = Δz₁ / (Δz₂ + Δz₃)

Expand All @@ -135,12 +133,12 @@ end
return nothing
end

@inline function _fill_top_open_halo!(i, j, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
@inline function _fill_top_halo!(i, j, grid, ϕ, bc::FEOBC, loc, clock, model_fields)
k = grid.Nz + 1

Δz₁ = Δz(i, j, k-1, grid, c, c, c)
Δz₂ = Δz(i, j, k-2, grid, c, c, c)
Δz₃ = Δz(i, j, k-3, grid, c, c, c)
Δz₁ = Δzᶜᶜᶜ(i, j, k-1, grid)
Δz₂ = Δzᶜᶜᶜ(i, j, k-2, grid)
Δz₃ = Δzᶜᶜᶜ(i, j, k-3, grid)

spacing_factor = Δz₁ / (Δz₂ + Δz₃)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
using Oceananigans.Operators: Δxᶠᶜᶜ, Δyᶜᶠᶜ, Δzᶜᶜᶠ, Ax_qᶠᶜᶜ, Ay_qᶜᶠᶜ, Az_qᶜᶜᶠ

"""
PerturbationAdvection

For cases where we assume that the internal flow is a small perturbation from
an external prescribed or coarser flow, we can split the velocity into background
and perturbation components:
...
see latex document for now

TODO: check what the coriolis is doing, and check what happens if U is the mean velocity
"""
struct PerturbationAdvection{VT, FT}
backward_step :: VT
inflow_timescale :: FT
outflow_timescale :: FT
end

Adapt.adapt_structure(to, pe::PerturbationAdvection) =
PerturbationAdvection(adapt(to, pe.backward_step),
adapt(to, pe.outflow_timescale),
adapt(to, pe.inflow_timescale))

function PerturbationAdvectionOpenBoundaryCondition(val, FT = Float64;
backward_step = true,
outflow_timescale = Inf,
inflow_timescale = 300.0, kwargs...)

classification = Open(PerturbationAdvection(Val(backward_step), inflow_timescale, outflow_timescale))

@warn "`PerturbationAdvection` open boundaries matching scheme is experimental and un-tested/validated"

return BoundaryCondition(classification, val; kwargs...)
end

const PAOBC = BoundaryCondition{<:Open{<:PerturbationAdvection}}

const BPAOBC = BoundaryCondition{<:Open{<:PerturbationAdvection{Val{true}}}}
const FPAOBC = BoundaryCondition{<:Open{<:PerturbationAdvection{Val{false}}}}

@inline function step_right_boundary!(bc::BPAOBC, l, m, boundary_indices, boundary_adjacent_indices,
grid, u, clock, model_fields, ΔX)
Δt = clock.last_stage_Δt

Δt = ifelse(isinf(Δt), 0, Δt)

ūⁿ⁺¹ = getbc(bc, l, m, grid, clock, model_fields)

uᵢⁿ = @inbounds getindex(u, boundary_indices...)
uᵢ₋₁ⁿ⁺¹ = @inbounds getindex(u, boundary_adjacent_indices...)

U = max(0, min(1, Δt / ΔX * ūⁿ⁺¹))

pa = bc.classification.matching_scheme

τ = ifelse(ūⁿ⁺¹ >= 0, pa.outflow_timescale, pa.inflow_timescale)

τ̃ = Δt / τ

uᵢⁿ⁺¹ = uᵢⁿ + U * (uᵢ₋₁ⁿ⁺¹ - ūⁿ⁺¹)

@inbounds setindex!(u, uᵢⁿ⁺¹, boundary_indices...)

return nothing
end

@inline function step_left_boundary!(bc::BPAOBC, l, m, boundary_indices, boundary_adjacent_indices, boundary_secret_storage_indices,
grid, u, clock, model_fields, ΔX)
Δt = clock.last_stage_Δt

Δt = ifelse(isinf(Δt), 0, Δt)

ūⁿ⁺¹ = getbc(bc, l, m, grid, clock, model_fields)

uᵢⁿ = @inbounds getindex(u, boundary_secret_storage_indices...)
uᵢ₋₁ⁿ⁺¹ = @inbounds getindex(u, boundary_adjacent_indices...)

U = min(0, max(-1, Δt / ΔX * ūⁿ⁺¹))

pa = bc.classification.matching_scheme

τ = ifelse(ūⁿ⁺¹ <= 0, pa.outflow_timescale, pa.inflow_timescale)

τ̃ = Δt / τ

u₁ⁿ⁺¹ = uᵢⁿ - U * (uᵢ₋₁ⁿ⁺¹ - ūⁿ⁺¹)

@inbounds setindex!(u, u₁ⁿ⁺¹, boundary_indices...)
@inbounds setindex!(u, u₁ⁿ⁺¹, boundary_secret_storage_indices...)

return nothing
end


@inline function step_right_boundary!(bc::FPAOBC, l, m, boundary_indices, boundary_adjacent_indices,
grid, u, clock, model_fields, ΔX)
Δt = clock.last_stage_Δt

Δt = ifelse(isinf(Δt), 0, Δt)

ūⁿ⁺¹ = getbc(bc, l, m, grid, clock, model_fields)

uᵢⁿ = @inbounds getindex(u, boundary_indices...)
uᵢ₋₁ⁿ⁺¹ = @inbounds getindex(u, boundary_adjacent_indices...)

U = max(0, min(1, Δt / ΔX * ūⁿ⁺¹))

pa = bc.classification.matching_scheme

τ = ifelse(ūⁿ⁺¹ >= 0, pa.outflow_timescale, pa.inflow_timescale)

τ̃ = Δt / τ

uᵢⁿ⁺¹ = uᵢⁿ + U * (uᵢ₋₁ⁿ⁺¹ - ūⁿ⁺¹) + (ūⁿ⁺¹ - uᵢⁿ) * τ̃

@inbounds setindex!(u, uᵢⁿ⁺¹, boundary_indices...)

return nothing
end

@inline function step_left_boundary!(bc::FPAOBC, l, m, boundary_indices, boundary_adjacent_indices, boundary_secret_storage_indices,
grid, u, clock, model_fields, ΔX)
Δt = clock.last_stage_Δt

Δt = ifelse(isinf(Δt), 0, Δt)

ūⁿ⁺¹ = getbc(bc, l, m, grid, clock, model_fields)

uᵢⁿ = @inbounds getindex(u, boundary_secret_storage_indices...)
uᵢ₋₁ⁿ⁺¹ = @inbounds getindex(u, boundary_adjacent_indices...)

U = min(0, max(-1, Δt / ΔX * ūⁿ⁺¹))

pa = bc.classification.matching_scheme

τ = ifelse(ūⁿ⁺¹ <= 0, pa.outflow_timescale, pa.inflow_timescale)

τ̃ = Δt / τ

u₁ⁿ⁺¹ = uᵢⁿ - U * (uᵢ₋₁ⁿ⁺¹ - ūⁿ⁺¹) + (ūⁿ⁺¹ - uᵢⁿ) * τ̃

@inbounds setindex!(u, u₁ⁿ⁺¹, boundary_indices...)
@inbounds setindex!(u, u₁ⁿ⁺¹, boundary_secret_storage_indices...)

return nothing
end

@inline function _fill_east_halo!(j, k, grid, u, bc::PAOBC, ::Tuple{Face, Any, Any}, clock, model_fields)
i = grid.Nx + 1

boundary_indices = (i, j, k)
boundary_adjacent_indices = (i-1, j, k)

Δx = Δxᶠᶜᶜ(i, j, k, grid)

step_right_boundary!(bc, j, k, boundary_indices, boundary_adjacent_indices, grid, u, clock, model_fields, Δx)

return nothing
end

@inline function _fill_west_halo!(j, k, grid, u, bc::PAOBC, ::Tuple{Face, Any, Any}, clock, model_fields)
boundary_indices = (1, j, k)
boundary_adjacent_indices = (2, j, k)
boundary_secret_storage_indices = (0, j, k)

Δx = Δxᶠᶜᶜ(1, j, k, grid)

step_left_boundary!(bc, j, k, boundary_indices, boundary_adjacent_indices, boundary_secret_storage_indices, grid, u, clock, model_fields, Δx)

return nothing
end
Loading
Loading