From 4b72263facb5b1ed40691f0903178c56698a4587 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Fri, 6 Sep 2024 13:24:45 +0200 Subject: [PATCH 01/17] extend lagrangian advection to all AbstractGrids --- .../lagrangian_particle_advection.jl | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl index c8f8b90361..eafcf53d35 100644 --- a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl +++ b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl @@ -48,27 +48,26 @@ bouncing the particle off the immersed boundary with a coefficient or `restituti X = flattened_node((x, y, z), ibg) # Determine current particle cell - fi, fj, fk = fractional_indices(X, ibg.underlying_grid, (c, c, c)) + fi, fj, fk = fractional_indices(X, ibg.underlying_grid, c, c, c) i, j, k = truncate_fractional_indices(fi, fj, fk) if immersed_cell(i, j, k, ibg) # Determine whether particle was _previously_ in a non-immersed cell i⁻, j⁻, k⁻ = previous_particle_indices - if !immersed_cell(i⁻, j⁻, k⁻, ibg) - # 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) + # 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 end - return x⁺, y⁺, z⁺ + return (x⁺, y⁺, z⁺) end """ @@ -134,7 +133,7 @@ given `velocities`, time-step `Δt, and coefficient of `restitution`. z⁺ = enforce_boundary_conditions(tz, z⁺, zᴸ, zᴿ, Cʳ) if grid isa ImmersedBoundaryGrid previous_particle_indices = current_particle_indices # particle has been advected - x⁺, y⁺, z⁺ = bounce_immersed_particle((x⁺, y⁺, z⁺), grid, Cʳ, previous_particle_indices) + (x⁺, y⁺, z⁺) = bounce_immersed_particle((x⁺, y⁺, z⁺), grid, Cʳ, previous_particle_indices) end return (x⁺, y⁺, z⁺) @@ -145,11 +144,13 @@ end # * Sphere metric for `LatitudeLongitudeGrid` and geographic coordinates @inline x_metric(i, j, grid::RectilinearGrid) = 1 @inline x_metric(i, j, grid::LatitudeLongitudeGrid{FT}) where FT = @inbounds 1 / (grid.radius * hack_cosd(grid.φᵃᶜᵃ[j])) * FT(360 / 2π) +@inline x_metric(i, j, grid::ImmersedBoundaryGrid) = x_metric(i, j, grid.underlying_grid) @inline y_metric(i, j, grid::RectilinearGrid) = 1 @inline y_metric(i, j, grid::LatitudeLongitudeGrid{FT}) where FT = 1 / grid.radius * FT(360 / 2π) +@inline y_metric(i, j, grid::ImmersedBoundaryGrid) = y_metric(i, j, grid.underlying_grid) -@kernel function _advect_particles!(particles, restitution, grid::AbstractUnderlyingGrid, Δt, velocities) +@kernel function _advect_particles!(particles, restitution, grid::AbstractGrid, Δt, velocities) p = @index(Global) @inbounds begin From 23346039b90d6a435526ce70bfc44257cca3beb0 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Fri, 6 Sep 2024 15:16:02 +0200 Subject: [PATCH 02/17] cleaner syntax --- .../lagrangian_particle_advection.jl | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl index eafcf53d35..496f8ea59b 100644 --- a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl +++ b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl @@ -51,21 +51,22 @@ bouncing the particle off the immersed boundary with a coefficient or `restituti fi, fj, fk = fractional_indices(X, ibg.underlying_grid, c, c, c) i, j, k = truncate_fractional_indices(fi, fj, fk) - if immersed_cell(i, j, k, ibg) - # Determine whether particle was _previously_ in a non-immersed cell - i⁻, j⁻, k⁻ = previous_particle_indices - - # 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ʳ) - else - x⁺, y⁺, z⁺ = x, y, z - end + # Determine whether particle was _previously_ in a non-immersed cell + i⁻, j⁻, k⁻ = previous_particle_indices + + # 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 + 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) return (x⁺, y⁺, z⁺) end From 25d02a63cf3340aac607f32780c30d278f3c2d08 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Fri, 6 Sep 2024 15:57:09 +0200 Subject: [PATCH 03/17] bugfix for immersed grids with flat dimensions --- .../lagrangian_particle_advection.jl | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl index 496f8ea59b..e82dc5447c 100644 --- a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl +++ b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl @@ -54,14 +54,20 @@ bouncing the particle off the immersed boundary with a coefficient or `restituti # Determine whether particle was _previously_ in a non-immersed cell i⁻, j⁻, k⁻ = previous_particle_indices - # 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) + # 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) + + # 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) Cʳ = restitution - 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ʳ) + xb⁺ = enforce_boundary_conditions(topology(ibg)[1] == Flat ? Flat() : Bounded(), x, xᴸ, xᴿ, Cʳ) + yb⁺ = enforce_boundary_conditions(topology(ibg)[2] == Flat ? Flat() : Bounded(), y, yᴸ, yᴿ, Cʳ) + zb⁺ = enforce_boundary_conditions(topology(ibg)[3] == Flat ? Flat() : Bounded(), z, zᴸ, zᴿ, Cʳ) immersed = immersed_cell(i, j, k, ibg) x⁺ = ifelse(immersed, xb⁺, x) From c37be1246f04567738d252c766deba16f6073282 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Fri, 6 Sep 2024 15:58:05 +0200 Subject: [PATCH 04/17] add tests with immersed boundary grid --- test/test_lagrangian_particle_tracking.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index 7eaa8410f7..4f0b6640f0 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -269,6 +269,19 @@ lagrangian_particle_test_grid(arch, ::Periodic, z) = lagrangian_particle_test_grid(arch, ::Flat, z) = RectilinearGrid(arch; topology=(Periodic, Flat, Bounded), size=(5, 5), x=(-1, 1), z) +lagrangian_particle_test_grid_expanded(arch, ::Periodic, z) = + RectilinearGrid(arch; topology=(Periodic, Periodic, Bounded), size=(10, 5, 5), x=(-2, 2), y=(-1, 1), z) +lagrangian_particle_test_grid_expanded(arch, ::Flat, z) = + RectilinearGrid(arch; topology=(Periodic, Flat, Bounded), size=(10, 5), x=(-2, 2), z) + +function lagrangian_particle_test_immersed_grid(arch, y_topo, z) + underlying_grid = lagrangian_particle_test_grid_expanded(arch, y_topo, z) + x_immersed_boundary(x, z) = ifelse(x < -1, 1, ifelse(x > 1, +1, 0)) + x_immersed_boundary(x, y, z) = x_immersed_boundary(x, z) + GFB = GridFittedBoundary(x_immersed_boundary) + return ImmersedBoundaryGrid(underlying_grid, GFB) +end + @testset "Lagrangian particle tracking" begin timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) y_topologies = (Periodic(), Flat()) @@ -278,5 +291,9 @@ lagrangian_particle_test_grid(arch, ::Flat, z) = @info " Testing Lagrangian particle tracking [$(typeof(arch)), $timestepper] with y $(typeof(y_topo)) on vertically $z_grid_type grid ..." grid = lagrangian_particle_test_grid(arch, y_topo, z) run_simple_particle_tracking_tests(grid, timestepper) + + @info " Testing Lagrangian particle tracking [$(typeof(arch)), $timestepper] with y $(typeof(y_topo)) on vertically $z_grid_type immersed grid ..." + grid = lagrangian_particle_test_immersed_grid(arch, y_topo, z) + run_simple_particle_tracking_tests(grid, timestepper) end end From 5e28d4b863c8c628c5b00c07c380d3c5a3d15866 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Fri, 6 Sep 2024 16:13:40 +0200 Subject: [PATCH 05/17] oops, wrong topology --- test/test_lagrangian_particle_tracking.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index 4f0b6640f0..bb2b3cedd4 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -270,15 +270,15 @@ lagrangian_particle_test_grid(arch, ::Flat, z) = RectilinearGrid(arch; topology=(Periodic, Flat, Bounded), size=(5, 5), x=(-1, 1), z) lagrangian_particle_test_grid_expanded(arch, ::Periodic, z) = - RectilinearGrid(arch; topology=(Periodic, Periodic, Bounded), size=(10, 5, 5), x=(-2, 2), y=(-1, 1), z) + RectilinearGrid(arch; topology=(Periodic, Periodic, Bounded), size=(5, 5, 5), x=(-1, 1), y=(-1, 1), z = 2 .*z) lagrangian_particle_test_grid_expanded(arch, ::Flat, z) = - RectilinearGrid(arch; topology=(Periodic, Flat, Bounded), size=(10, 5), x=(-2, 2), z) + RectilinearGrid(arch; topology=(Periodic, Flat, Bounded), size=(5, 5), x=(-1, 1), z = 2 .*z) function lagrangian_particle_test_immersed_grid(arch, y_topo, z) underlying_grid = lagrangian_particle_test_grid_expanded(arch, y_topo, z) - x_immersed_boundary(x, z) = ifelse(x < -1, 1, ifelse(x > 1, +1, 0)) - x_immersed_boundary(x, y, z) = x_immersed_boundary(x, z) - GFB = GridFittedBoundary(x_immersed_boundary) + z_immersed_boundary(x, z) = ifelse(z < -1, 1, ifelse(z > 1, +1, 0)) + z_immersed_boundary(x, y, z) = z_immersed_boundary(x, z) = ifelse(z < -1, 1, ifelse(z > 1, +1, 0)) + GFB = GridFittedBoundary(z_immersed_boundary) return ImmersedBoundaryGrid(underlying_grid, GFB) end From 9634e515f9e76c43ab888207ce5d146c028da8ce Mon Sep 17 00:00:00 2001 From: tomaschor Date: Fri, 6 Sep 2024 16:49:40 +0200 Subject: [PATCH 06/17] convert immersed function to boolean output --- test/test_lagrangian_particle_tracking.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index bb2b3cedd4..673a79c5b8 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -276,8 +276,8 @@ lagrangian_particle_test_grid_expanded(arch, ::Flat, z) = function lagrangian_particle_test_immersed_grid(arch, y_topo, z) underlying_grid = lagrangian_particle_test_grid_expanded(arch, y_topo, z) - z_immersed_boundary(x, z) = ifelse(z < -1, 1, ifelse(z > 1, +1, 0)) - z_immersed_boundary(x, y, z) = z_immersed_boundary(x, z) = ifelse(z < -1, 1, ifelse(z > 1, +1, 0)) + z_immersed_boundary(x, z) = ifelse(z < -1, true, ifelse(z > 1, true, false)) + z_immersed_boundary(x, y, z) = z_immersed_boundary(x, z) GFB = GridFittedBoundary(z_immersed_boundary) return ImmersedBoundaryGrid(underlying_grid, GFB) end From abff4914a32037f6f3a18a19c2efd30f8bb7c2f9 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Mon, 9 Sep 2024 13:53:14 +0200 Subject: [PATCH 07/17] simplify --- test/test_lagrangian_particle_tracking.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index 673a79c5b8..ae9113d8f4 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -292,8 +292,10 @@ end grid = lagrangian_particle_test_grid(arch, y_topo, z) run_simple_particle_tracking_tests(grid, timestepper) - @info " Testing Lagrangian particle tracking [$(typeof(arch)), $timestepper] with y $(typeof(y_topo)) on vertically $z_grid_type immersed grid ..." - grid = lagrangian_particle_test_immersed_grid(arch, y_topo, z) - run_simple_particle_tracking_tests(grid, timestepper) + if z isa NTuple{2} # Test immersed regular grids + @info " Testing Lagrangian particle tracking [$(typeof(arch)), $timestepper] with y $(typeof(y_topo)) on vertically $z_grid_type immersed grid ..." + grid = lagrangian_particle_test_immersed_grid(arch, y_topo, z) + run_simple_particle_tracking_tests(grid, timestepper) + end end end From 97b197fe8bbfc93c561668a5d52918ccd7113145 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Mon, 9 Sep 2024 14:11:52 +0200 Subject: [PATCH 08/17] clean up logic --- .../lagrangian_particle_advection.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl index e82dc5447c..174b950eb9 100644 --- a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl +++ b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl @@ -38,6 +38,8 @@ Do nothing on Flat dimensions. const f = Face() const c = Center() +immersed_boundary_topology(grid_topology) = ifelse(grid_topology == Flat, Flat(), Bounded()) + """ bounce_immersed_particle((x, y, z), grid, restitution, previous_particle_indices) @@ -65,9 +67,10 @@ bouncing the particle off the immersed boundary with a coefficient or `restituti zᴸ = znode(i, j, k⁻, ibg, f, f, f) Cʳ = restitution - xb⁺ = enforce_boundary_conditions(topology(ibg)[1] == Flat ? Flat() : Bounded(), x, xᴸ, xᴿ, Cʳ) - yb⁺ = enforce_boundary_conditions(topology(ibg)[2] == Flat ? Flat() : Bounded(), y, yᴸ, yᴿ, Cʳ) - zb⁺ = enforce_boundary_conditions(topology(ibg)[3] == Flat ? Flat() : Bounded(), z, zᴸ, zᴿ, Cʳ) + tx, ty, tz = map(immersed_boundary_topology, topology(ibg)) + xb⁺ = enforce_boundary_conditions(tx, x, xᴸ, xᴿ, Cʳ) + yb⁺ = enforce_boundary_conditions(ty, y, yᴸ, yᴿ, Cʳ) + zb⁺ = enforce_boundary_conditions(tz, z, zᴸ, zᴿ, Cʳ) immersed = immersed_cell(i, j, k, ibg) x⁺ = ifelse(immersed, xb⁺, x) From 8bcdef1d698a7d9f13fdb4791fa34ada0111c4a6 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Mon, 9 Sep 2024 14:12:33 +0200 Subject: [PATCH 09/17] bump patch version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index ed748560e7..962dd11a0d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Oceananigans" uuid = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09" authors = ["Climate Modeling Alliance and contributors"] -version = "0.91.13" +version = "0.91.14" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" From 81ff38fe3ee247a8b5dd43c8830153f032bc2291 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Mon, 9 Sep 2024 18:44:32 +0200 Subject: [PATCH 10/17] added docstring --- .../lagrangian_particle_advection.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl index 174b950eb9..9b2b1e36b3 100644 --- a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl +++ b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl @@ -38,6 +38,11 @@ Do nothing on Flat dimensions. const f = Face() const c = Center() +""" + immersed_boundary_topology(grid_topology) + +Unless `Flat`, immersed boundaries are treated as `Bounded` regardless of underlying grid topology. +""" immersed_boundary_topology(grid_topology) = ifelse(grid_topology == Flat, Flat(), Bounded()) """ From 31bec4e2606dcd4498e028c8952cbb28b3887f40 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Mon, 16 Sep 2024 20:22:30 -0300 Subject: [PATCH 11/17] correct indices --- .../lagrangian_particle_advection.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl index 9b2b1e36b3..9ab519c23b 100644 --- a/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl +++ b/src/Models/LagrangianParticleTracking/lagrangian_particle_advection.jl @@ -62,14 +62,14 @@ bouncing the particle off the immersed boundary with a coefficient or `restituti i⁻, j⁻, k⁻ = previous_particle_indices # 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) + 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) # 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) + 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) Cʳ = restitution tx, ty, tz = map(immersed_boundary_topology, topology(ibg)) From 1fd6833a352d3e85c8a280704d1ba77e7aeb6052 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Tue, 17 Sep 2024 22:17:38 -0300 Subject: [PATCH 12/17] add LatLonGrid to tests --- test/test_lagrangian_particle_tracking.jl | 106 ++++++++++++++-------- 1 file changed, 66 insertions(+), 40 deletions(-) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index ae9113d8f4..4da1f4cde4 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -15,8 +15,14 @@ struct TestParticle{T} end function particle_tracking_simulation(; grid, particles, timestepper=:RungeKutta3, velocities=nothing) - model = NonhydrostaticModel(; grid, timestepper, velocities, particles) - set!(model, u=1, v=1) + if grid isa RectilinearGrid + model = NonhydrostaticModel(; grid, timestepper, velocities, particles) + set!(model, u=1, v=1) + else + set!(velocities.u, 1) + set!(velocities.v, 1) + model = HydrostaticFreeSurfaceModel(; grid, velocities=PrescribedVelocityFields(; velocities...), particles) + end sim = Simulation(model, Δt=1e-2, stop_iteration=1) jld2_filepath = "test_particles.jld2" @@ -34,7 +40,7 @@ function particle_tracking_simulation(; grid, particles, timestepper=:RungeKutta return sim, jld2_filepath, nc_filepath end -function run_simple_particle_tracking_tests(grid, timestepper) +function run_simple_particle_tracking_tests(grid, timestepper=:QuasiAdamsBashforth) arch = architecture(grid) @@ -51,17 +57,19 @@ function run_simple_particle_tracking_tests(grid, timestepper) particles = LagrangianParticles(x=xs, y=ys, z=zs) @test particles isa LagrangianParticles - sim, jld2_filepath, nc_filepath = particle_tracking_simulation(; grid, particles, timestepper) - model = sim.model - run!(sim) + if grid isa RectilinearGrid + sim, jld2_filepath, nc_filepath = particle_tracking_simulation(; grid, particles, timestepper) + model = sim.model + run!(sim) - # Just test we run without errors - @test length(model.particles) == P - @test propertynames(model.particles.properties) == (:x, :y, :z) + # Just test we run without errors + @test length(model.particles) == P + @test propertynames(model.particles.properties) == (:x, :y, :z) - rm(jld2_filepath) - rm(nc_filepath) - rm("particles_checkpoint_iteration0.jld2") + rm(jld2_filepath) + rm(nc_filepath) + rm("particles_checkpoint_iteration0.jld2") + end ##### ##### Test Boundary restitution @@ -89,7 +97,7 @@ function run_simple_particle_tracking_tests(grid, timestepper) @test all(zᶠ .≈ (top_boundary - 0.15)) ##### - ##### Test custom particle "SpeedTrackingParticle" + ##### Test custom particle "TestParticle" ##### xs = on_architecture(arch, zeros(P)) @@ -103,8 +111,7 @@ function run_simple_particle_tracking_tests(grid, timestepper) # Test custom constructor particles = StructArray{TestParticle}((xs, ys, zs, us, vs, ws, ss)) - velocities = VelocityFields(grid) - u, v, w = velocities + u, v, w = velocities = VelocityFields(grid) speed = Field(√(u * u + v * v + w * w)) tracked_fields = merge(velocities, (; s=speed)) @@ -116,29 +123,31 @@ function run_simple_particle_tracking_tests(grid, timestepper) lagrangian_particles = LagrangianParticles(particles; tracked_fields) @test lagrangian_particles isa LagrangianParticles - model = NonhydrostaticModel(; grid, timestepper, - velocities, particles=lagrangian_particles, - background_fields=(v=background_v,)) + if grid isa RectilinearGrid + model = NonhydrostaticModel(; grid, timestepper, + velocities, particles=lagrangian_particles, + background_fields=(v=background_v,)) - set!(model, u=1) + set!(model, u=1) - sim = Simulation(model, Δt=1e-2, stop_iteration=1) + sim = Simulation(model, Δt=1e-2, stop_iteration=1) - jld2_filepath = "test_particles.jld2" - sim.output_writers[:particles_jld2] = - JLD2OutputWriter(model, (; particles=model.particles), - filename=jld2_filepath, schedule=IterationInterval(1)) + jld2_filepath = "test_particles.jld2" + sim.output_writers[:particles_jld2] = + JLD2OutputWriter(model, (; particles=model.particles), + filename=jld2_filepath, schedule=IterationInterval(1)) - nc_filepath = "test_particles.nc" - sim.output_writers[:particles_nc] = - NetCDFOutputWriter(model, model.particles, filename=nc_filepath, schedule=IterationInterval(1)) + nc_filepath = "test_particles.nc" + sim.output_writers[:particles_nc] = + NetCDFOutputWriter(model, model.particles, filename=nc_filepath, schedule=IterationInterval(1)) - sim.output_writers[:checkpointer] = Checkpointer(model, schedule=IterationInterval(1), - dir=".", prefix="particles_checkpoint") + sim.output_writers[:checkpointer] = Checkpointer(model, schedule=IterationInterval(1), + dir=".", prefix="particles_checkpoint") - rm(jld2_filepath) - rm(nc_filepath) - rm("particles_checkpoint_iteration1.jld2") + rm(jld2_filepath) + rm(nc_filepath) + rm("particles_checkpoint_iteration1.jld2") + end sim, jld2_filepath, nc_filepath = particle_tracking_simulation(; grid, particles=lagrangian_particles, timestepper, velocities) model = sim.model @@ -164,8 +173,10 @@ function run_simple_particle_tracking_tests(grid, timestepper) @test size(w) == tuple(P) @test size(s) == tuple(P) - @test all(x .≈ 0.01) - @test all(y .≈ 0.01) + if grid isa RectilinearGrid + @test all(x .≈ 0.01) + @test all(y .≈ 0.01) + end @test all(z .≈ 0.5) @test all(u .≈ 1) @test all(v .≈ 1) @@ -185,8 +196,10 @@ function run_simple_particle_tracking_tests(grid, timestepper) @test size(w) == (P, 2) @test size(s) == (P, 2) - @test all(x[:, end] .≈ 0.01) - @test all(y[:, end] .≈ 0.01) + if grid isa RectilinearGrid + @test all(x[:, end] .≈ 0.01) + @test all(y[:, end] .≈ 0.01) + end @test all(z[:, end] .≈ 0.5) @test all(u[:, end] .≈ 1) @test all(v[:, end] .≈ 1) @@ -210,8 +223,10 @@ function run_simple_particle_tracking_tests(grid, timestepper) @test size(file["timeseries/particles/1"].w) == tuple(P) @test size(file["timeseries/particles/1"].s) == tuple(P) - @test all(file["timeseries/particles/1"].x .≈ 0.01) - @test all(file["timeseries/particles/1"].y .≈ 0.01) + if grid isa RectilinearGrid + @test all(file["timeseries/particles/1"].x .≈ 0.01) + @test all(file["timeseries/particles/1"].y .≈ 0.01) + end @test all(file["timeseries/particles/1"].z .≈ 0.5) @test all(file["timeseries/particles/1"].u .≈ 1) @test all(file["timeseries/particles/1"].v .≈ 1) @@ -250,8 +265,10 @@ function run_simple_particle_tracking_tests(grid, timestepper) @test size(w) == tuple(P) @test size(s) == tuple(P) - @test all(x .≈ 0.01) - @test all(y .≈ 0.01) + if grid isa RectilinearGrid + @test all(x .≈ 0.01) + @test all(y .≈ 0.01) + end @test all(z .≈ 0.5) @test all(u .≈ 1) @test all(v .≈ 1) @@ -282,6 +299,9 @@ function lagrangian_particle_test_immersed_grid(arch, y_topo, z) return ImmersedBoundaryGrid(underlying_grid, GFB) end +lagrangian_particle_test_curvilinear_grid(arch, z) = + LatitudeLongitudeGrid(arch; size=(5, 5, 5), longitude=(-1, 1), latitude=(-1, 1), z, precompute_metrics=true) + @testset "Lagrangian particle tracking" begin timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) y_topologies = (Periodic(), Flat()) @@ -298,4 +318,10 @@ end run_simple_particle_tracking_tests(grid, timestepper) end end + + for arch in archs, (z_grid_type, z) in pairs(vertical_grids) + @info " Testing Lagrangian particle tracking [$(typeof(arch))] with a LatitudeLongitudeGrid with vertically $z_grid_type z coordinate ..." + grid = lagrangian_particle_test_curvilinear_grid(arch, z) + run_simple_particle_tracking_tests(grid) + end end From 9635d039f40f856bb9c4acb8349fa4ea374e5dff Mon Sep 17 00:00:00 2001 From: tomaschor Date: Wed, 18 Sep 2024 11:02:46 -0300 Subject: [PATCH 13/17] write speed differently to try and avoid using too much parameter space --- test/test_lagrangian_particle_tracking.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index 4da1f4cde4..4a8bf632a2 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -112,7 +112,7 @@ function run_simple_particle_tracking_tests(grid, timestepper=:QuasiAdamsBashfor particles = StructArray{TestParticle}((xs, ys, zs, us, vs, ws, ss)) u, v, w = velocities = VelocityFields(grid) - speed = Field(√(u * u + v * v + w * w)) + speed = Field(√(u^2 + v^2 + w^2)) tracked_fields = merge(velocities, (; s=speed)) # applying v component of advection with background field to ensure it is included From a06faf1be272c29d095c10a224f9ec296740bcdf Mon Sep 17 00:00:00 2001 From: tomaschor Date: Wed, 18 Sep 2024 11:40:34 -0300 Subject: [PATCH 14/17] use only horizontal speed --- test/test_lagrangian_particle_tracking.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_lagrangian_particle_tracking.jl b/test/test_lagrangian_particle_tracking.jl index 4a8bf632a2..fb60c23beb 100644 --- a/test/test_lagrangian_particle_tracking.jl +++ b/test/test_lagrangian_particle_tracking.jl @@ -112,7 +112,7 @@ function run_simple_particle_tracking_tests(grid, timestepper=:QuasiAdamsBashfor particles = StructArray{TestParticle}((xs, ys, zs, us, vs, ws, ss)) u, v, w = velocities = VelocityFields(grid) - speed = Field(√(u^2 + v^2 + w^2)) + speed = Field(√(u * u + v * v)) tracked_fields = merge(velocities, (; s=speed)) # applying v component of advection with background field to ensure it is included From f590acb335d92a6625e56a0aaf2fc43eb3093fb7 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Wed, 18 Sep 2024 12:48:55 -0300 Subject: [PATCH 15/17] fix docs and convert code to doctest --- docs/src/model_setup/lagrangian_particles.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/model_setup/lagrangian_particles.md b/docs/src/model_setup/lagrangian_particles.md index 2db8c9fd94..d0403aa439 100644 --- a/docs/src/model_setup/lagrangian_particles.md +++ b/docs/src/model_setup/lagrangian_particles.md @@ -108,15 +108,15 @@ Particle properties can be written to disk using JLD2 or NetCDF. When writing to JLD2 you can pass `model.particles` as part of the named tuple of outputs. -```julia -JLD2OutputWriter(model, (particles=model.particles,), prefix="particles", schedule=TimeInterval(15)) +```jldoctest particles +JLD2OutputWriter(model, (particles=model.particles,), filename="particles", schedule=TimeInterval(15)) ``` When writing to NetCDF you should write particles to a separate file as the NetCDF dimensions differ for particle trajectories. You can just pass `model.particles` straight to `NetCDFOutputWriter`: -```julia -NetCDFOutputWriter(model, model.particles, filepath="particles.nc", schedule=TimeInterval(15)) +```jldoctest particles +NetCDFOutputWriter(model, model.particles, filename="particles.nc", schedule=TimeInterval(15)) ``` !!! warn "Outputting custom particle properties to NetCDF" From 65e76c0de36170f860a7748bc44750b77eaa678a Mon Sep 17 00:00:00 2001 From: tomaschor Date: Thu, 19 Sep 2024 07:39:52 -0300 Subject: [PATCH 16/17] add output to doctest --- docs/src/model_setup/lagrangian_particles.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/src/model_setup/lagrangian_particles.md b/docs/src/model_setup/lagrangian_particles.md index d0403aa439..d3c79e9797 100644 --- a/docs/src/model_setup/lagrangian_particles.md +++ b/docs/src/model_setup/lagrangian_particles.md @@ -110,6 +110,15 @@ When writing to JLD2 you can pass `model.particles` as part of the named tuple o ```jldoctest particles JLD2OutputWriter(model, (particles=model.particles,), filename="particles", schedule=TimeInterval(15)) + +# output +JLD2OutputWriter scheduled on TimeInterval(15 seconds): +├── filepath: ./particles.jld2 +├── 1 outputs: particles +├── array type: Array{Float64} +├── including: [:grid, :coriolis, :buoyancy, :closure] +├── file_splitting: NoFileSplitting +└── file size: 17.6 KiB ``` When writing to NetCDF you should write particles to a separate file as the NetCDF dimensions differ for @@ -117,6 +126,15 @@ particle trajectories. You can just pass `model.particles` straight to `NetCDFOu ```jldoctest particles NetCDFOutputWriter(model, model.particles, filename="particles.nc", schedule=TimeInterval(15)) + +# output +NetCDFOutputWriter scheduled on TimeInterval(15 seconds): +├── filepath: ./particles.nc +├── dimensions: particle_id(10), time(0) +├── 1 outputs: particles +└── array type: Array{Float64} +├── file_splitting: NoFileSplitting +└── file size: 9.9 KiB ``` !!! warn "Outputting custom particle properties to NetCDF" From 0cfe076a0d408a24b8f8f7afd075d9924ae48344 Mon Sep 17 00:00:00 2001 From: tomaschor Date: Thu, 19 Sep 2024 08:30:40 -0300 Subject: [PATCH 17/17] add filtering --- docs/src/model_setup/lagrangian_particles.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/model_setup/lagrangian_particles.md b/docs/src/model_setup/lagrangian_particles.md index d3c79e9797..1ea76db5cb 100644 --- a/docs/src/model_setup/lagrangian_particles.md +++ b/docs/src/model_setup/lagrangian_particles.md @@ -108,6 +108,10 @@ Particle properties can be written to disk using JLD2 or NetCDF. When writing to JLD2 you can pass `model.particles` as part of the named tuple of outputs. +```@meta +DocTestFilters = r"└── file size: [0-9]*.[0-9]* KiB" +``` + ```jldoctest particles JLD2OutputWriter(model, (particles=model.particles,), filename="particles", schedule=TimeInterval(15)) @@ -140,3 +144,7 @@ NetCDFOutputWriter scheduled on TimeInterval(15 seconds): !!! warn "Outputting custom particle properties to NetCDF" NetCDF does not support arbitrary data types. If you need to write custom particle properties to disk that are not supported by NetCDF then you should use JLD2 (which should support almost any Julia data type). + +```@meta +DocTestFilters = nothing +```