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

Add interpolation functions #304

Merged
merged 75 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
e541ce8
add interpolation
svchb Nov 29, 2023
d09e779
basic working
svchb Nov 30, 2023
fd3c98b
support periodic
svchb Nov 30, 2023
118585b
allow to define different smoothing_length
svchb Nov 30, 2023
a4e306d
more precisely identify system regions
svchb Nov 30, 2023
d0d4e85
to improve accuracy calc shepard
svchb Dec 1, 2023
7f11ce6
add support for multiple points
svchb Dec 1, 2023
2d7334c
add line interpolation
svchb Dec 1, 2023
0a5a580
add doc
svchb Dec 1, 2023
2c10d6c
format
svchb Dec 1, 2023
69e8ddf
add test
svchb Dec 1, 2023
567e1fb
Merge branch 'main' into add_interpolation
svchb Dec 1, 2023
27065cc
small change to doc
svchb Dec 1, 2023
238671e
revert accidental change
svchb Dec 1, 2023
1512816
fix
svchb Dec 1, 2023
959e36e
another fix
svchb Dec 1, 2023
a0c9694
format
svchb Dec 1, 2023
b0a22e4
format
svchb Dec 1, 2023
9f3b68b
also interpolate pressure and velocity
svchb Dec 1, 2023
c83061e
lower tolerance
svchb Dec 1, 2023
f9b8bef
add example plot
svchb Dec 1, 2023
54ffa68
missing dependency
svchb Dec 1, 2023
9d2b15e
format
svchb Dec 1, 2023
b034713
comment out example
svchb Dec 1, 2023
1bf954b
remove pyplot again
svchb Dec 1, 2023
897add2
fix
svchb Dec 1, 2023
98cabcb
small update improving accuracy
svchb Dec 12, 2023
a49d45e
Merge branch 'main' into add_interpolation
svchb Dec 12, 2023
99938dc
fix tests
svchb Dec 12, 2023
69c8ece
Merge branch 'add_interpolation' of github.com:svchb/TrixiParticles.j…
svchb Dec 12, 2023
c5a9cb0
remove line
svchb Dec 12, 2023
ee8fbf3
fix
svchb Dec 13, 2023
e01cb04
format
svchb Dec 13, 2023
7f067a2
fix
svchb Dec 13, 2023
596dc21
merge
svchb Dec 13, 2023
2af76d4
Merge branch 'main' into add_interpolation
svchb Dec 13, 2023
f16ca92
Merge branch 'main' into add_interpolation
svchb Jan 4, 2024
8a47ef4
optimization
svchb Jan 4, 2024
3361096
fix result format
svchb Jan 4, 2024
095032d
Merge branch 'main' into add_interpolation
svchb Jan 4, 2024
fd222a9
update test
svchb Jan 4, 2024
ef2c7c2
fix
svchb Jan 5, 2024
c7be103
fix docs
svchb Jan 5, 2024
ab25212
rename to copy_neighborhood_search
svchb Jan 5, 2024
eb0c70c
review fixes
svchb Jan 5, 2024
11d1361
Merge branch 'main' into add_interpolation
svchb Jan 5, 2024
73473a7
format
svchb Jan 5, 2024
d358cb1
Merge branch 'main' into add_interpolation
svchb Jan 5, 2024
cc912b0
bs
svchb Jan 6, 2024
b46a1e1
tests
svchb Jan 9, 2024
715c703
more tests
svchb Jan 9, 2024
7e6d92b
fix all tests
svchb Jan 9, 2024
b8f9294
Merge branch 'main' into add_interpolation
svchb Jan 9, 2024
e029e3d
fix
svchb Jan 9, 2024
2182166
Merge branch 'add_interpolation' of github.com:svchb/TrixiParticles.j…
svchb Jan 9, 2024
e830efc
fix tests
svchb Jan 9, 2024
6dc6d5c
increase error since it passes locally but not on github
svchb Jan 9, 2024
fdefb39
fix
svchb Jan 10, 2024
3de97d5
fix
svchb Jan 10, 2024
ab4c2d2
review comments
svchb Jan 11, 2024
30ccff4
Merge branch 'main' into add_interpolation
svchb Jan 11, 2024
97f8b61
fix docs
svchb Jan 11, 2024
ca434c1
format
svchb Jan 11, 2024
61ea44f
add interpolation.jl to doc gen
svchb Jan 11, 2024
5ed40ce
review
svchb Jan 11, 2024
407f166
update
svchb Jan 11, 2024
d197fb7
add Plots version
svchb Jan 11, 2024
611c123
improve plot
svchb Jan 12, 2024
548d9fc
remove other dispatch
svchb Jan 12, 2024
5dd4ca8
fix
svchb Jan 12, 2024
f48effe
fix docs
svchb Jan 15, 2024
1994220
Merge branch 'main' into add_interpolation
svchb Jan 15, 2024
393e9e1
merge
svchb Jan 15, 2024
cf4aef3
remove background pressure
svchb Jan 16, 2024
274a31c
fix comment
svchb Jan 16, 2024
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
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ makedocs(sitename="TrixiParticles.jl",
"Semidiscretization" => joinpath("general", "semidiscretization.md"),
"Initial Condition and Setups" => joinpath("general",
"initial_condition.md"),
"Interpolation" => joinpath("general", "interpolation.md"),
"Density Calculators" => joinpath("general", "density_calculators.md"),
"Smoothing Kernels" => joinpath("general", "smoothing_kernels.md"),
"Neighborhood Search" => joinpath("general", "neighborhood_search.md"),
Expand Down
6 changes: 6 additions & 0 deletions docs/src/general/interpolation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Interpolation

```@autodocs
Modules = [TrixiParticles]
Pages = [joinpath("general", "interpolation.jl")]
```
61 changes: 61 additions & 0 deletions examples/postprocessing/interpolation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Example for using interpolation
#######################################################################################
using TrixiParticles

trixi_include(@__MODULE__, joinpath(examples_dir(), "fluid", "rectangular_tank_2d.jl"))

# `interpolate_point` can be used to interpolate the properties of the `fluid_system` with the original kernel and `smoothing_length`
println(interpolate_point([1.0, 0.01], semi, fluid_system, sol))
# Or with an increased `smoothing_length` smoothing the result
println(interpolate_point([1.0, 0.01], semi, fluid_system, sol,
smoothing_length=2.0 * smoothing_length))

# A point outside of the domain will result in properties with value 0
# On the boundary a result can still be obtained
println(interpolate_point([1.0, 0.0], semi, fluid_system, sol))
# Slightly outside of the fluid domain the result is 0
println(interpolate_point([1.0, -0.01], semi, fluid_system, sol))

# Multiple points can be interpolated by providing an array
println(interpolate_point([
[1.0, 0.01],
[1.0, 0.1],
[1.0, 0.0],
[1.0, -0.01],
[1.0, -0.05],
], semi, fluid_system, sol))

# It is also possible to interpolate along a line
result = interpolate_line([1.0, -0.05], [1.0, 1.0], 10, semi, fluid_system, sol)
result_endpoint = interpolate_line([1.0, -0.05], [1.0, 1.0], 10, semi, fluid_system, sol,
endpoint=false)

# Extracting wall distance for the standard and endpoint cases
walldistance = [coord[2] for coord in result.coord]
walldistance_endpoint = [coord[2] for coord in result_endpoint.coord]

# using PythonPlot

# figure()
# plot(walldistance, result.density, marker="o", linestyle="-", label="With Endpoint")
# plot(walldistance_endpoint, result_endpoint.density, marker="x", linestyle="--",
# label="Without Endpoint")

# xlabel("Wall distance")
# ylabel("Density")
# title("Density Interpolation Along a Line")
# legend()

# plotshow()

using Plots
svchb marked this conversation as resolved.
Show resolved Hide resolved

p = plot(walldistance, result.density, marker=:circle, color=:blue, markerstrokecolor=:blue,
linewidth=2, label="With Endpoint")

plot!(p, walldistance_endpoint, result_endpoint.density, marker=:xcross, linewidth=2,
linestyle=:dash, label="Without Endpoint", color=:orange)

plot!(p, framestyle=:box, legend=:best, xlabel="Wall distance",
ylabel="Density", title="Density Interpolation Along a Line", size=(800, 600),
dpi=300)
svchb marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions src/TrixiParticles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@ export VoxelSphere, RoundSphere, reset_wall!
export ShepardKernelCorrection, KernelCorrection, AkinciFreeSurfaceCorrection,
GradientCorrection, BlendedGradientCorrection, MixedKernelGradientCorrection
export nparticles
export interpolate_line, interpolate_point

end # module
6 changes: 3 additions & 3 deletions src/general/corrections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ function compute_shepard_coeff!(system, v, u, v_ode, u_ode, semi,
system_coords = current_coordinates(u, system)
neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system)

neighborhood_search = neighborhood_searches(system, neighbor_system, semi)
neighborhood_search = get_neighborhood_search(system, neighbor_system, semi)

# Loop over all pairs of particles and neighbors within the kernel cutoff
for_particle_neighbor(system, neighbor_system, system_coords,
Expand Down Expand Up @@ -259,7 +259,7 @@ function compute_correction_values!(system,
system_coords = current_coordinates(u, system)
neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system)

neighborhood_search = neighborhood_searches(system, neighbor_system, semi)
neighborhood_search = get_neighborhood_search(system, neighbor_system, semi)

# Loop over all pairs of particles and neighbors within the kernel cutoff
for_particle_neighbor(system, neighbor_system, system_coords,
Expand Down Expand Up @@ -402,7 +402,7 @@ function compute_gradient_correction_matrix!(corr_matrix::AbstractArray, system,
v_neighbor_system = wrap_v(v_ode, neighbor_system, semi)

neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system)
neighborhood_search = neighborhood_searches(system, neighbor_system, semi)
neighborhood_search = get_neighborhood_search(system, neighbor_system, semi)

for_particle_neighbor(system, neighbor_system, coordinates, neighbor_coords,
neighborhood_search;
Expand Down
2 changes: 1 addition & 1 deletion src/general/density_calculators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function summation_density!(system, semi, u, u_ode, density;
system_coords = current_coordinates(u, system)
neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system)

nhs = neighborhood_searches(system, neighbor_system, semi)
nhs = get_neighborhood_search(system, neighbor_system, semi)

# Loop over all pairs of particles and neighbors within the kernel cutoff.
for_particle_neighbor(system, neighbor_system, system_coords, neighbor_coords, nhs,
Expand Down
1 change: 1 addition & 0 deletions src/general/general.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ include("corrections.jl")
include("smoothing_kernels.jl")
include("initial_condition.jl")
include("system.jl")
include("interpolation.jl")
237 changes: 237 additions & 0 deletions src/general/interpolation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
@doc raw"""
interpolate_line(start, end_, no_points, semi, ref_system, sol; endpoint=true,
smoothing_length=ref_system.smoothing_length, cut_of_bnd=true)

Interpolates properties along a line in an TrixiParticles simulation.
The line interpolation is accomplished by generating a series of
evenly spaced points between `start` and `end_`.
If `endpoint` is `false`, the line is interpolated between the start and end points,
but does not include these points.

# Arguments
- `start`: The starting point of the line.
- `end_`: The ending point of the line.
- `n_points`: The number of points to interpolate along the line.
- `semi`: The semidiscretization used for the simulation.
- `ref_system`: The reference system for the interpolation.
- `sol`: The solution state from which the properties are interpolated.

# Keywords
- `cut_off_bnd`: `cut_off_bnd`: Boolean to indicate if quantities should be set to zero when a
point is "closer" to a boundary than to the fluid system
(see an explanation for "closer" below). Defaults to `true`.
- `endpoint`: A boolean to include (`true`) or exclude (`false`) the end point in the interpolation. Default is `true`.
- `smoothing_length`: The smoothing length used in the interpolation. Default is `ref_system.smoothing_length`.

# Returns
- A `NamedTuple` of arrays containing interpolated properties at each point along the line.

!!! note
- This function is particularly useful for analyzing gradients or creating visualizations
along a specified line in the SPH simulation domain.
- The interpolation accuracy is subject to the density of particles and the chosen smoothing length.
- With `cut_off_bnd` is used a density-based estimation of the surface is used which is not as
svchb marked this conversation as resolved.
Show resolved Hide resolved
accurate as a real surface reconstruction.

# Examples
```julia
# Interpolating along a line from [1.0, 0.0] to [1.0, 1.0] with 5 points
results = interpolate_line([1.0, 0.0], [1.0, 1.0], 5, semi, ref_system, sol)
```
"""
function interpolate_line(start, end_, n_points, semi, ref_system, sol; endpoint=true,
smoothing_length=ref_system.smoothing_length,
cut_off_bnd=true)
svchb marked this conversation as resolved.
Show resolved Hide resolved
start_svector = SVector{ndims(ref_system)}(start)
end_svector = SVector{ndims(ref_system)}(end_)
points_coords = range(start_svector, end_svector, length=n_points)

if !endpoint
points_coords = points_coords[2:(end - 1)]
end

return interpolate_point(points_coords, semi, ref_system, sol,
smoothing_length=smoothing_length,
cut_off_bnd=cut_off_bnd)
end

@doc raw"""
interpolate_point(points_coords::Array{Array{Float64,1},1}, semi, ref_system, sol;
smoothing_length=ref_system.smoothing_length, cut_of_bnd=true)

interpolate_point(point_coords, semi, ref_system, sol;
smoothing_length=ref_system.smoothing_length, cut_of_bnd=true)

Performs interpolation of properties at specified points or an array of points in a TrixiParticles simulation.

When given an array of points (`points_coords`), it iterates over each point and applies interpolation individually.
For a single point (`point_coords`), it performs the interpolation at that specific location.
The interpolation utilizes the same kernel function of the SPH simulation to weigh contributions from nearby particles.

# Arguments
- `points_coords`: An array of point coordinates, for which to interpolate properties.
- `point_coords`: The coordinates of a single point for interpolation.
- `semi`: The semidiscretization used in the SPH simulation.
- `ref_system`: The reference system defining the properties of the SPH particles.
- `sol`: The current solution state from which properties are interpolated.

# Keywords
- `cut_off_bnd`: Cut-off at the boundary.
- `smoothing_length`: The smoothing length used in the kernel function. Defaults to `ref_system.smoothing_length`.

# Returns:
- For multiple points: A `NamedTuple` of arrays containing interpolated properties at each point.
- For a single point: A `NamedTuple` of interpolated properties at the point.

# Examples:
```julia
# For a single point
result = interpolate_point([1.0, 0.5], semi, ref_system, sol)

# For multiple points
points = [[1.0, 0.5], [1.0, 0.6], [1.0, 0.7]]
results = interpolate_point(points, semi, ref_system, sol)
```
!!! note
- This function is particularly useful for analyzing gradients or creating visualizations
along a specified line in the SPH simulation domain.
- The interpolation accuracy is subject to the density of particles and the chosen smoothing length.
- With `cut_off_bnd` is used a density-based estimation of the surface is used which is not as
svchb marked this conversation as resolved.
Show resolved Hide resolved
accurate as a real surface reconstruction.
"""
function interpolate_point(points_coords::AbstractArray{<:AbstractArray}, semi, ref_system,
sol; smoothing_length=ref_system.smoothing_length,
cut_off_bnd=true)
num_points = length(points_coords)
coords = similar(points_coords)
velocities = similar(points_coords)
densities = Vector{Float64}(undef, num_points)
pressures = Vector{Float64}(undef, num_points)
neighbor_counts = Vector{Int}(undef, num_points)

neighborhood_searches = process_neighborhood_searches(semi, sol, ref_system,
smoothing_length)

for (i, point) in enumerate(points_coords)
result = interpolate_point(SVector{ndims(ref_system)}(point), semi, ref_system, sol,
neighborhood_searches, smoothing_length=smoothing_length,
cut_off_bnd=cut_off_bnd)
densities[i] = result.density
neighbor_counts[i] = result.neighbor_count
coords[i] = result.coord
velocities[i] = result.velocity
pressures[i] = result.pressure
end

return (density=densities, neighbor_count=neighbor_counts, coord=coords,
velocity=velocities, pressure=pressures)
end

function interpolate_point(point_coords, semi, ref_system, sol;
smoothing_length=ref_system.smoothing_length,
cut_off_bnd=true)
neighborhood_searches = process_neighborhood_searches(semi, sol, ref_system,
smoothing_length)

return interpolate_point(SVector{ndims(ref_system)}(point_coords), semi, ref_system,
sol, neighborhood_searches, smoothing_length=smoothing_length,
cut_off_bnd=cut_off_bnd)
end

function process_neighborhood_searches(semi, sol, ref_system, smoothing_length)
if isapprox(smoothing_length, ref_system.smoothing_length)
# Update existing NHS
update_nhs(sol.u[end].x[2], semi)
neighborhood_searches = semi.neighborhood_searches[system_indices(ref_system, semi)]
efaulhaber marked this conversation as resolved.
Show resolved Hide resolved
else
ref_smoothing_kernel = ref_system.smoothing_kernel
search_radius = compact_support(ref_smoothing_kernel, smoothing_length)
neighborhood_searches = map(semi.systems) do system
u = wrap_u(sol.u[end].x[2], system, semi)
system_coords = current_coordinates(u, system)
old_nhs = get_neighborhood_search(ref_system, system, semi)
nhs = copy_neighborhood_search(old_nhs, search_radius, system_coords)
return nhs
end
end

return neighborhood_searches
end

@inline function interpolate_point(point_coords, semi, ref_system, sol,
neighborhood_searches;
smoothing_length=ref_system.smoothing_length,
cut_off_bnd=true)
interpolated_density = 0.0
interpolated_velocity = zero(SVector{ndims(ref_system)})
interpolated_pressure = 0.0

shepard_coefficient = 0.0
ref_id = system_indices(ref_system, semi)
neighbor_count = 0
other_density = 0.0
ref_smoothing_kernel = ref_system.smoothing_kernel

if cut_off_bnd
systems = semi
else
# Don't loop over other systems
systems = (ref_system,)
svchb marked this conversation as resolved.
Show resolved Hide resolved
end

foreach_system(systems) do system
system_id = system_indices(system, semi)
nhs = neighborhood_searches[system_id]
(; search_radius, periodic_box) = nhs

v = wrap_v(sol.u[end].x[1], system, semi)
u = wrap_u(sol.u[end].x[2], system, semi)

system_coords = current_coordinates(u, system)

# This is basically `for_particle_neighbor` unrolled
for particle in eachneighbor(point_coords, nhs)
svchb marked this conversation as resolved.
Show resolved Hide resolved
coords = extract_svector(system_coords, Val(ndims(system)), particle)

pos_diff = point_coords - coords
distance2 = dot(pos_diff, pos_diff)
pos_diff, distance2 = compute_periodic_distance(pos_diff, distance2,
search_radius, periodic_box)
if distance2 > search_radius^2
continue
end

distance = sqrt(distance2)
mass = hydrodynamic_mass(system, particle)
kernel_value = kernel(ref_smoothing_kernel, distance, smoothing_length)
m_W = mass * kernel_value

if system_id == ref_id
interpolated_density += m_W

volume = mass / particle_density(v, system, particle)
particle_velocity = current_velocity(v, system, particle)
interpolated_velocity += particle_velocity * (volume * kernel_value)

pressure = particle_pressure(v, system, particle)
interpolated_pressure += pressure * (volume * kernel_value)
shepard_coefficient += volume * kernel_value
else
other_density += m_W
end

neighbor_count += 1
end
end

# Point is not within the ref_system
if other_density > interpolated_density || shepard_coefficient < eps()
return (density=0.0, neighbor_count=0, coord=point_coords,
velocity=zero(SVector{ndims(ref_system)}), pressure=0.0)
end

return (density=interpolated_density / shepard_coefficient,
neighbor_count=neighbor_count,
coord=point_coords, velocity=interpolated_velocity / shepard_coefficient,
pressure=interpolated_pressure / shepard_coefficient)
end
Loading