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

(0.91.14) Extend Lagrangian advection to immersed grids and add tests #3765

Merged
merged 24 commits into from
Sep 21, 2024

Conversation

tomchor
Copy link
Collaborator

@tomchor tomchor commented Sep 6, 2024

Closes #3761

Comment on lines 58 to 67
# 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
Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator

@simone-silvestri simone-silvestri Sep 6, 2024

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)

Copy link
Contributor

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.

@tomchor tomchor changed the title Extend Lagrangian advection to immersed grids and add tests (0.91.14) Extend Lagrangian advection to immersed grids and add tests Sep 9, 2024
Copy link
Contributor

@Jamie-Hilditch Jamie-Hilditch left a 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!

@tomchor
Copy link
Collaborator Author

tomchor commented Sep 10, 2024

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.

@Jamie-Hilditch
Copy link
Contributor

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.

@tomchor
Copy link
Collaborator Author

tomchor commented Sep 15, 2024

@simone-silvestri @jagoosw @glwagner could please I get a review from someone?

Comment on lines 64 to 72
# 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)
Copy link
Collaborator

@simone-silvestri simone-silvestri Sep 16, 2024

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?

Copy link
Collaborator Author

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?

Copy link
Collaborator

@simone-silvestri simone-silvestri Sep 16, 2024

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?

Copy link
Collaborator Author

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]

Copy link
Collaborator Author

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)

@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))

Copy link
Member

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.

Copy link
Collaborator Author

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.

  1. 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 η and r, 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?

  1. @glwagner is suggesting using ξnode (η and r) instead of xnode (and y and z). This is how it was in the code before this PR, but I think we actually want xnode and ynode since the advection is performed with velocities in length/time, no?

Copy link
Member

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.

Copy link
Collaborator

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

Copy link
Collaborator Author

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.

Comment on lines +65 to +67
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)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
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

Copy link
Collaborator Author

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:

@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?

Copy link
Collaborator

@jagoosw jagoosw left a 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

@tomchor tomchor merged commit 6649223 into main Sep 21, 2024
46 checks passed
@tomchor tomchor deleted the tc/ibg-tracking branch September 21, 2024 14:05
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.

LagrangianParticles not working with ImmersedGrids
5 participants