Open xkykai opened 1 year ago
cc @simone-silvestri
Hmmm, ∇²
and δ∂
are executing the same code (under the hood the ∇²ᶜᶜᶜ
is calculated as δ∂
for a constant spacing rectilinear grid). The difference between the two calculations yielding different results is how many times you account for an immersed boundary: ∂
operators are boundary-aware (i.e. yield a zero if calculated across an immersed boundary), while δ
operators are not. Despite this, they should yield the same result since the second pass of the derivative should not cross immersed boundaries. I ll take a look
This
using Oceananigans
using Oceananigans.Operators
grid = RectilinearGrid(size = (5, 1, 5),
halo = (4, 4, 4),
x = (0, 1),
y = (0, 1),
z = (-1, 0),
topology = (Bounded, Periodic, Bounded))
slope(x, y) = -0.8
grid = ImmersedBoundaryGrid(grid, GridFittedBottom(slope))
field = CenterField(grid)
rand_field(x, y, z) = rand()
set!(field, rand_field)
∂x = [∂xᶜᶜᶜ(i, 1, k, grid, field) for i in 0:6, k in 0:6]
∂δx = [δxᶜᵃᵃ(i, 1, k, grid, field) / Δxᶜᶜᶜ(i, 1, k, grid) for i in 0:6, k in 0:6]
∂x .≈ ∂δx
would give
7×7 BitMatrix:
1 0 0 0 0 0 1
1 0 1 1 1 1 1
1 0 1 1 1 1 1
1 0 1 1 1 1 1
1 0 1 1 1 1 1
1 0 1 1 1 1 1
1 1 1 1 1 1 1
Though I'm not sure if we'd expect this to work since δxᶜᵃᵃ
are not immersed-boundary aware, right?
yeah, the difference is expected. Now we have to understand if the immersed version is correct
∇²ᶜᶜᶜ
gives the right solution for the pressure solver (correct as in no flow divergence at the boundary) that we are developing for the ImmersedPoissonSolver
here:
https://github.com/xkykai/Oceananigans.jl/blob/df579ed61935378273f2f0e3df0706554be22c30/validation/immersed_boundaries/immersed_pressure_solver.jl#L114
Remember to fill the halos before computing the laplacian.
Anyways, it looks like . Still, these operators should not give different results∂²
gives the "correct" answer when I look at analytical solutions
julia> set!(field, (x, y, z) -> z^2)
5×1×5 Field{Center, Center, Center} on ImmersedBoundaryGrid on CPU
├── grid: 5×1×5 ImmersedBoundaryGrid{Float64, Bounded, Periodic, Bounded} on CPU with 4×4×4 halo
├── boundary conditions: FieldBoundaryConditions
│ └── west: ZeroFlux, east: ZeroFlux, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
└── data: 13×9×13 OffsetArray(::Array{Float64, 3}, -3:9, -3:5, -3:9) with eltype Float64 with indices -3:9×-3:5×-3:9
└── max=0.49, min=0.01, mean=0.21
julia> fill_halo_regions!(field)
julia> ∇² = [∇²ᶜᶜᶜ(i, 1, k, grid, field) for i in 1:5, k in 1:5]
5×5 Matrix{Float64}:
0.0 -6.0 2.0 2.0 2.0
0.0 -6.0 2.0 2.0 2.0
0.0 -6.0 2.0 2.0 2.0
0.0 -6.0 2.0 2.0 2.0
0.0 -6.0 2.0 2.0 2.0
julia> ∂² = [∂²xᶜᶜᶜ(i, 1, k, grid, field) +
∂²yᶜᶜᶜ(i, 1, k, grid, field) +
∂²zᶜᶜᶜ(i, 1, k, grid, field) for i in 1:5, k in 1:5]
5×5 Matrix{Float64}:
0.0 2.0 2.0 2.0 2.0
0.0 2.0 2.0 2.0 2.0
0.0 2.0 2.0 2.0 2.0
0.0 2.0 2.0 2.0 2.0
0.0 2.0 2.0 2.0 2.0
Edit: actually ∇²
seems to be correct because of the immersed boundary
Ok, I see why this is happening. conditional_∂z_c
"throws away" the immersed boundary when it passes through.
Since a second derivative is just a first derivative of a first derivative, the immersed condition is tested only on the "outer" derivative, which doesn't see the immersed boundary. The inner derivative is then just called on the underlying grid and does not satisfy immersed boundary conditions. This does not happen in the ∇²
operator since the "inner" derivative correctly calls the conditional_∂z_c
, thus being aware of the immersed boundaries. Good catch, I ll solve this issue
there it is
Computing the Laplacian on
ImmersedBoundaryGrid
using different methods give different results. Here's a MWE:From above,
∇²
is consistent withδ∂
, but they do not agree with∂∂
. The deviations appear at the regular and immersed boundaries. All 3 methods of calculating Laplacian yield the same result in a non-immersedRectilinearGrid
.It appears that
∇²
andδ∂
are the correct solutions, so the problem is likely to be in the composing of 2 derivative operations on anImmersedBoundaryGrid
. I tried to fix it myself, but I couldn't as I am unfamiliar with the metaprogramming aspects of the code.