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 9 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
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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{FT}
inflow_timescale :: FT
outflow_timescale :: FT
end

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

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

classification = Open(PerturbationAdvection(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}}

@inline function step_right_boundary!(bc, 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ᵢ₋₁ⁿ⁺¹ + ūⁿ⁺¹ * τ̃) / (1 + τ̃ + U)

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

return nothing
end

@inline function step_left_boundary!(bc, 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ᵢ₋₁ⁿ⁺¹ + ūⁿ⁺¹ * τ̃) / (1 + τ̃ - 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
2 changes: 2 additions & 0 deletions src/Oceananigans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ include("Simulations/Simulations.jl")
# Abstractions for distributed and multi-region models
include("MultiRegion/MultiRegion.jl")

include("boundary_normal_mean_velocity.jl")

#####
##### Needed so we can export names from sub-modules at the top-level
#####
Expand Down
46 changes: 46 additions & 0 deletions src/boundary_normal_mean_velocity.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Adapt
using Oceananigans.AbstractOperations: GridMetricOperation, Ax, Ay, Az
using Oceananigans.BoundaryConditions: BoundaryCondition, Open, PerturbationAdvection

import Adapt: adapt_structure
import Oceananigans.BoundaryConditions: update_boundary_condition!

struct BoundaryNormalMeanVelocity{BV}
boundary_velocity :: BV

BoundaryNormalMeanVelocity(; value::BV = Ref(0.0)) where BV = new{BV}(value)
end

@inline (value::BoundaryNormalMeanVelocity)(args...) = value.boundary_velocity[]

Adapt.adapt_structure(to, mo::BoundaryNormalMeanVelocity) =
BoundaryNormalMeanVelocity(adapt(to, mo.mean_outflow_velocity[]))

const MOPABC = BoundaryCondition{<:Open{<:PerturbationAdvection}, <:BoundaryNormalMeanVelocity}

@inline boundary_normal_area(::Union{Val{:west}, Val{:east}}, grid) = GridMetricOperation((Face, Center, Center), Ax, grid)
@inline boundary_normal_area(::Union{Val{:south}, Val{:north}}, grid) = GridMetricOperation((Center, Face, Center), Ay, grid)
@inline boundary_normal_area(::Union{Val{:bottom}, Val{:top}}, grid) = GridMetricOperation((Center, Center, Face), Az, grid)

@inline boundary_adjacent_index(::Val{:east}, grid) = (size(grid, 1), 1, 1), (2, 3)
@inline boundary_adjacent_index(::Val{:west}, grid) = (2, 1, 1), (2, 3)

@inline boundary_adjacent_index(::Val{:north}, grid) = (1, size(grid, 2), 1), (1, 3)
@inline boundary_adjacent_index(::Val{:south}, grid) = (1, 2, 1), (1, 3)

@inline boundary_adjacent_index(::Val{:top}, grid) = (1, 1, size(grid, 3)), (2, 3)
@inline boundary_adjacent_index(::Val{:bottom}, grid) = (1, 1, 2), (2, 3)

function update_boundary_condition!(bc::MOPABC, val_side, u, model)
grid = model.grid

An = boundary_normal_area(val_side, grid)

(i, j, k), dims = boundary_adjacent_index(val_side, grid)

total_area = sum(An; dims)[i, j, k]

Ū = sum(u * An; dims) / total_area

bc.condition.boundary_velocity[] = Ū[i, j, k]
end
Loading