-
Notifications
You must be signed in to change notification settings - Fork 190
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
(0.91.14) Extend Lagrangian advection to immersed grids and add tests #3765
Conversation
# Left-right bounds of the previous, non-immersed cell | ||
xᴿ, yᴿ, zᴿ = node(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) | ||
xᴸ, yᴸ, zᴸ = node(i⁻, j⁻, k⁻, ibg, f, f, f) | ||
|
||
Cʳ = restitution | ||
x⁺ = enforce_boundary_conditions(Bounded(), x, xᴸ, xᴿ, Cʳ) | ||
y⁺ = enforce_boundary_conditions(Bounded(), y, yᴸ, yᴿ, Cʳ) | ||
z⁺ = enforce_boundary_conditions(Bounded(), z, zᴸ, zᴿ, Cʳ) | ||
|
||
end | ||
Cʳ = restitution | ||
x⁺ = enforce_boundary_conditions(Bounded(), x, xᴸ, xᴿ, Cʳ) | ||
y⁺ = enforce_boundary_conditions(Bounded(), y, yᴸ, yᴿ, Cʳ) | ||
z⁺ = enforce_boundary_conditions(Bounded(), z, zᴸ, zᴿ, Cʳ) | ||
else | ||
x⁺, y⁺, z⁺ = x, y, z |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part of the algorithm was failing so I had to change it. However, I'm not familiar with the lagrangian advection algorithm so I'm sure if this is the right way to do things. Can someone double-check this part? From what I can tell, @Jamie-Hilditch and @jagoosw were the main authors of this algorithm, so maybe we should hear from them also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be cleaner todo
if immersed_cell
...
return ...
else
return x, y, z
end
But otherwise I agree this looks like it is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can also use an ifelse
syntax to avoid branching:
xb⁺ = enforce_boundary_conditions(Bounded(), x, xᴸ, xᴿ, Cʳ)
yb⁺ = enforce_boundary_conditions(Bounded(), y, yᴸ, yᴿ, Cʳ)
zb⁺ = enforce_boundary_conditions(Bounded(), z, zᴸ, zᴿ, Cʳ)
immersed = immersed_cell(i, j, k, ibg)
x⁺ = ifelse(immersed, xb⁺, x)
y⁺ = ifelse(immersed, yb⁺, y)
z⁺ = ifelse(immersed, zb⁺, z)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part of the algorithm was failing so I had to change it. However, I'm not familiar with the lagrangian advection algorithm so I'm sure if this is the right way to do things. Can someone double-check this part? From what I can tell, @Jamie-Hilditch and @jagoosw were the main authors of this algorithm, so maybe we should hear from them also.
You've not really touched the couple of things I contributed so it looks good from my end.
src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
Let me know if there's anything else needed. If there are no other code suggestions this should be ready for merging. |
I'm happy but this is one for @simone-silvestri, @jagoosw or someone else with the power to write. |
@simone-silvestri @jagoosw @glwagner could please I get a review from someone? |
# Left bounds of the previous cell | ||
xᴿ = xnode(i⁻ + 1, j, k, ibg, f, f, f) | ||
yᴿ = ynode(i, j⁻ + 1, k, ibg, f, f, f) | ||
zᴿ = znode(i, j, k⁻ + 1, ibg, f, f, f) | ||
|
||
Cʳ = restitution | ||
x⁺ = enforce_boundary_conditions(Bounded(), x, xᴸ, xᴿ, Cʳ) | ||
y⁺ = enforce_boundary_conditions(Bounded(), y, yᴸ, yᴿ, Cʳ) | ||
z⁺ = enforce_boundary_conditions(Bounded(), z, zᴸ, zᴿ, Cʳ) | ||
# Right bounds of the previous cell | ||
xᴸ = xnode(i⁻, j, k, ibg, f, f, f) | ||
yᴸ = ynode(i, j⁻, k, ibg, f, f, f) | ||
zᴸ = znode(i, j, k⁻, ibg, f, f, f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite different from how it was written before.
For example it might be that:
xnode(i⁻, j, k, ibg, f, f, f) != node(i⁻, j⁻, k⁻, ibg, f, f, f)[1]
(not necessarily for a rectilinear grid but possibly for a curvilinear one)
Was there a bug in the previous implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there was a bug with the previous implementation and it needed re-writing. Specifically, it was failing for Flat
dimensions iirc. I'm not familiar with how this is implemented in curvilinear coords, and I don't remember lagrangian tracking being done in them before. Can we keep the code as it currently is in the PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, I understand why node(i⁻+1, j⁻+1, k⁻+1, ibg, f, f, f)
would fail, but node(i⁻, j⁻, k⁻, ibg, f, f, f)
should exist also for Flat
topologies. Can we do this:
xᴸ, yᴸ, zᴸ = node(i⁻, j⁻, k⁻, ibg, f, f, f)
and keep the right boundaries as written in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous code fails not because of the +1
index in the flat dimension, but because it doesn't return anything for the flat dimension:
julia> grid_base = RectilinearGrid(topology = (Periodic, Flat, Periodic), size=(5, 5), extent=(1, 1))
5×1×5 RectilinearGrid{Float64, Periodic, Flat, Periodic} on CPU with 3×0×3 halo
├── Periodic x ∈ [0.0, 1.0) regularly spaced with Δx=0.2
├── Flat y
└── Periodic z ∈ [-1.0, 0.0) regularly spaced with Δz=0.2
julia> node(2, 2, 2, grid_base, Center(), Center(), Center())
(0.3, -0.7)
So in these cases the statement xᴸ, yᴸ, zᴸ = node(i⁻, j⁻, k⁻, ibg, f, f, f)
fails with
Got exception outside of a @test
BoundsError: attempt to access Tuple{Float64, Float64} at index [3]
Stacktrace:
[1] indexed_iterate
@ ./tuple.jl:92 [inlined]
[2] bounce_immersed_particle
@ ~/repos/Oceananigans.jl2/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl:75 [inlined]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, if I understand your comment correctly, we can just replace
xᴿ = xnode(i⁻ + 1, j, k, ibg, f, f, f)
yᴿ = ynode(i, j⁻ + 1, k, ibg, f, f, f)
zᴿ = znode(i, j, k⁻ + 1, ibg, f, f, f)
with
xᴿ = xnode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
yᴿ = ynode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
zᴿ = znode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
I think that should be equivalent. Note that node()
is just a shorthand for (xnode, ynode, znode)
Oceananigans.jl/src/Grids/nodes_and_spacings.jl
Lines 35 to 37 in 0f52a6a
@inline _node(i, j, k, grid, ℓx, ℓy, ℓz) = (ξnode(i, j, k, grid, ℓx, ℓy, ℓz), | |
ηnode(i, j, k, grid, ℓx, ℓy, ℓz), | |
rnode(i, j, k, grid, ℓx, ℓy, ℓz)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to use ξnode
than node[1]
which is a hack and not as easy to understand either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, I think there are at least 2 separate issues being discussed here.
- The indices to be used when calling the location for the right indices. The code before this PR was
node(i⁻+1, j⁻+1, k⁻+1, ibg, f, f, f)
, which I believe should translate toξnode(i⁻+1, j⁻+1, k⁻+1, ibg, f, f, f)
and the same forη
andr
, with the same indices (that's how the PR actually is). @simone-silvestri seems to think that the correct call should be (as per a code suggestion below)
xᴿ = xnode(i⁻ + 1, j⁻, k⁻, ibg, f, f, f)
yᴿ = ynode(i⁻, j⁻ + 1, k⁻, ibg, f, f, f)
zᴿ = znode(i⁻, j⁻, k⁻ + 1, ibg, f, f, f)
or perhaps with ξ
, η
and r
, but importantly here is that the indices are different. @simone-silvestri, could you elaborate?
- @glwagner is suggesting using
ξnode
(η
andr
) instead ofxnode
(andy
andz
). This is how it was in the code before this PR, but I think we actually wantxnode
andynode
since the advection is performed with velocities inlength/time
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what's correct. Seems like there is a missing test... but maybe @simone-silvestri can say. We did use this code on the sphere I thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I am a bit confused which node should be the correct ``right'' node. I guess if there are tests now and the i⁻+1, j⁻+1, k⁻+1, ibg, f, f, f
signature works, then the implementation is correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be fair, tests works regardless of which of the two signatures we're considering here, so whatever the difference is, the tests don't pick up on it. I think I'll keep the algorithm as close to as it was before this PR as possible. This includes using the i⁻+1, j⁻+1, k⁻+1, ibg, f, f, f
signature. As for the xnode
versus ξnode
debate, I actually realized the existing code used xnode
for the non-immersed part of the algorithm and ξnode
for the immersed grid. Likely the latter was done in error, so I'll keep everything as xnode
for now. We can revisit this is the future if we find evidence that this isn't the proper way to do things.
xᴿ = xnode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) | ||
yᴿ = ynode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) | ||
zᴿ = znode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
xᴿ = xnode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) | |
yᴿ = ynode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) | |
zᴿ = znode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f) | |
xᴿ = xnode(i⁻ + 1, j⁻, k⁻, ibg, f, f, f) | |
yᴿ = ynode(i⁻, j⁻ + 1, k⁻, ibg, f, f, f) | |
zᴿ = znode(i⁻, j⁻, k⁻ + 1, ibg, f, f, f) |
sorry if I am going back and forth, but I am now convinced this is the correct right bounds formulation, the left bounds look good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure about this? The original algorithm had this:
xᴿ, yᴿ, zᴿ = node(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
The node()
call is equivalent to three independent calls to xnode
, ynode
and znode
with the same arguments:
Oceananigans.jl/src/Grids/nodes_and_spacings.jl
Lines 35 to 37 in 0f52a6a
@inline _node(i, j, k, grid, ℓx, ℓy, ℓz) = (ξnode(i, j, k, grid, ℓx, ℓy, ℓz), | |
ηnode(i, j, k, grid, ℓx, ℓy, ℓz), | |
rnode(i, j, k, grid, ℓx, ℓy, ℓz)) |
So to me, the original algorithm should translate to:
xᴿ = xnode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
yᴿ = ynode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
zᴿ = znode(i⁻ + 1, j⁻ + 1, k⁻ + 1, ibg, f, f, f)
which is what this PR currently has implemented. Am I missing something?
Or maybe you're saying that the original algorithm was wrong to begin with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Sorry it took me so long to get to this
Closes #3761