Skip to content

Add shifting for InFlow-buffer particles #768

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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
93 changes: 91 additions & 2 deletions src/callbacks/particle_shifting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ function particle_shifting!(u, v, system, v_ode, u_ode, semi, u_cache, dt)
return u
end

function particle_shifting!(u, v, system::FluidSystem, v_ode, u_ode, semi,
u_cache, dt)
function particle_shifting!(u, v, system::FluidSystem, v_ode, u_ode, semi, u_cache, dt)
# Wrap the cache vector to an NDIMS x NPARTICLES matrix.
# We need this buffer because we cannot safely update `u` while iterating over it.
delta_r = wrap_u(u_cache, system, semi)
Expand Down Expand Up @@ -123,3 +122,93 @@ function Base.show(io::IO, ::MIME"text/plain",
summary_box(io, "ParticleShiftingCallback")
end
end

# For `OpenBoundarySPHSystem` with an `InFlow`-zone, we need a high quality transition
# from the boundary zone to the fluid domain, as small perturbations can lead to instabilities.
function particle_shifting!(u, v,
system::OpenBoundarySPHSystem{<:Any, <:BoundaryZone{<:InFlow}},
v_ode, u_ode, semi, u_cache, dt)
(; fluid_system, boundary_zone) = system
(; zone_origin, spanning_set) = boundary_zone

# Wrap the cache vector to an NDIMS x NPARTICLES matrix.
# We need this buffer because we cannot safely update `u` while iterating over it.
delta_r = wrap_u(u_cache, system, semi)
set_zero!(delta_r)

v_max = maximum(particle -> norm(current_velocity(v, system, particle)),
eachparticle(system))

# TODO this needs to be adapted to multi-resolution.
# Section 3.2 explains what else needs to be changed.
Wdx = smoothing_kernel(system, particle_spacing(system, 1), 1)
h = smoothing_length(system, 1)

# We use the neighborhood search (NHS) of the fluid system.
# This is appropriate because we only want to shift the buffer particles near the transition plane.
# Therefore, we use half of the compact support as the maximum distance within which the buffer particles are shifted.
max_dist = 0.5 * compact_support(system_smoothing_kernel(system),
smoothing_length(system, 1))

foreach_system(semi) do neighbor_system
u_neighbor = wrap_u(u_ode, neighbor_system, semi)
v_neighbor = wrap_v(v_ode, neighbor_system, semi)

neighborhood_search = get_neighborhood_search(fluid_system, neighbor_system, semi)

@threaded semi for particle in each_moving_particle(system)
particle_coords = current_coords(u, system, particle)

particle_position = particle_coords - zone_origin

# Distance to transition plane
dist = dot(particle_position, spanning_set[1])

if dist <= max_dist
for neighbor in PointNeighbors.eachneighbor(particle_coords,
neighborhood_search)
Copy link
Member

Choose a reason for hiding this comment

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

  1. This is not public API.
  2. This is not available for every NHS implementation.

I see two options:

  1. Use foreach_point_neighbor and skip all particle-neighbor pairs with particle outside the max distance (benchmark performance and compare with this function here).
  2. If this is not fast enough, we can make foreach_neighbor public API.

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 first option is not an option, because their exists no NHS for OpenBoundarySPHSystems.
Buffer particles don't need to interact with other particles or with itself.
I like the second option

Copy link
Member

@efaulhaber efaulhaber Apr 14, 2025

Choose a reason for hiding this comment

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

Buffer particles don't need to interact with other particles or with itself.

You are just implementing an interaction between buffer particles and other particles.

You can't just use another NHS and assume it works for a different set of particles. This is what PointNeighbors.requires_update is for.

neighbor_coords = current_coords(u_neighbor, neighbor_system, neighbor)

pos_diff = particle_coords - neighbor_coords
distance2 = dot(pos_diff, pos_diff)

# Check if the neighbor is within the search radius
if distance2 <= neighborhood_search.search_radius^2
distance = sqrt(distance2)

m_b = hydrodynamic_mass(neighbor_system, neighbor)
rho_a = particle_density(v, system, particle)
rho_b = particle_density(v_neighbor, neighbor_system, neighbor)

kernel = smoothing_kernel(system, distance, particle)
grad_kernel = smoothing_kernel_grad(system, pos_diff, distance,
particle)

# According to p. 29 below Eq. 9
R = 0.2
n = 4

# Eq. 7 in Sun et al. (2017).
# CFL * Ma can be rewritten as Δt * v_max / h (see p. 29, right above Eq. 9).
delta_r_ = -dt * v_max * 4 * h * (1 + R * (kernel / Wdx)^n) *
m_b / (rho_a + rho_b) * grad_kernel

# Write into the buffer
for i in eachindex(delta_r_)
@inbounds delta_r[i, particle] += delta_r_[i]
end
end
end
end
end
end

# Add δ_r from the buffer to the current coordinates
@threaded semi for particle in eachparticle(system)
for i in axes(delta_r, 1)
@inbounds u[i, particle] += delta_r[i, particle]
end
end

return u
end
4 changes: 2 additions & 2 deletions src/general/system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ end
@inline set_particle_pressure!(v, system, particle, pressure) = v

@inline function smoothing_kernel(system, distance, particle)
(; smoothing_kernel) = system
return kernel(smoothing_kernel, distance, smoothing_length(system, particle))
return kernel(system_smoothing_kernel(system), distance,
smoothing_length(system, particle))
end

@inline function smoothing_kernel_grad(system, pos_diff, distance, particle)
Expand Down
4 changes: 4 additions & 0 deletions src/schemes/boundary/open_boundary/system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ end

update_callback_used!(system::OpenBoundarySPHSystem) = system.update_callback_used[] = true

function system_smoothing_kernel(system::OpenBoundarySPHSystem)
return system.fluid_system.smoothing_kernel
end

function smoothing_length(system::OpenBoundarySPHSystem, particle)
return smoothing_length(system.fluid_system, particle)
end
Expand Down
Loading