Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cefc77b
Optimize kernels and kernel gradients
efaulhaber Mar 24, 2026
97ef7b0
Enable quartic spline kernel test on GPUs
efaulhaber Mar 25, 2026
f1cede8
Fix corrections
efaulhaber Mar 25, 2026
93f106a
Implement copilot suggestions
efaulhaber Mar 25, 2026
b662efd
Fix tests
efaulhaber Mar 25, 2026
52daa61
Fix docs tutorial
efaulhaber Mar 25, 2026
134de11
Merge branch 'main' into optimize-kernels
efaulhaber Mar 25, 2026
69b0cb1
Fix docs tutorial
efaulhaber Apr 1, 2026
2ba2d0d
Add 1D kernel tests
efaulhaber Apr 2, 2026
8ea6e52
Remove unused function
efaulhaber Apr 2, 2026
7900854
Merge branch 'main' into optimize-kernels
efaulhaber Apr 2, 2026
bd83177
Remove zero distance check for density diffusion
efaulhaber Apr 2, 2026
6faa918
Fix Laguerre kernel
efaulhaber Apr 2, 2026
ac3016e
Fix
efaulhaber Apr 7, 2026
b1bff6e
Merge branch 'main' into optimize-kernels
efaulhaber Apr 7, 2026
cf85299
Fix division by zero in density diffusion by adding checks in all int…
efaulhaber Apr 7, 2026
099b255
Fix tests
efaulhaber Apr 7, 2026
7eb5a4f
Reformat
efaulhaber Apr 7, 2026
0a7d190
Fix tests
efaulhaber Apr 7, 2026
183bdad
Fix comment
efaulhaber Apr 7, 2026
4d0a097
Fix GPU tests
efaulhaber Apr 7, 2026
015faf3
Add more comments
efaulhaber Apr 7, 2026
bcbf8c9
Fix
efaulhaber Apr 7, 2026
47c4007
Remove `@muladd` and dependency
efaulhaber Apr 9, 2026
8dfaa3e
Add docs
efaulhaber Apr 10, 2026
6bf3c57
Merge remote-tracking branch 'origin/main' into optimize-kernels
efaulhaber Apr 10, 2026
2ae1f15
Fix merge
efaulhaber Apr 10, 2026
26d0109
Merge branch 'main' into optimize-kernels
efaulhaber Apr 13, 2026
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
33 changes: 17 additions & 16 deletions docs/literate/src/tut_custom_kernel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,30 @@ struct MyGaussianKernel <: TrixiParticles.AbstractSmoothingKernel{2} end

# By looking at the implementation of existing kernels in TrixiParticles.jl,
# we can see that a kernel implementation requires three functions.
# `TrixiParticles.kernel`, which is the kernel function itself,
# `TrixiParticles.kernel_deriv`, which is the derivative of the kernel function,
# and `TrixiParticles.compact_support`, which defines the compact support of the
# kernel in relation to the smoothing length.
# `TrixiParticles.kernel_unsafe`, which is the kernel function itself,
# `TrixiParticles.kernel_deriv_div_r_unsafe`, which is the derivative of the
# kernel divided by ``r``, and `TrixiParticles.compact_support`, which defines
# the compact support of the kernel in relation to the smoothing length.
# The latter is relevant for determining the search radius of the neighborhood search.
function TrixiParticles.kernel(kernel::MyGaussianKernel, r, h)
#
# We implement `kernel_deriv_div_r_unsafe` instead of `kernel_deriv` directly since
# this avoids an extra division in the hot loop and is robust near ``r=0``.
# The public function `TrixiParticles.kernel_deriv` is defined automatically by
# TrixiParticles from this method (and multiplies by ``r`` again when needed).
# In the unsafe functions, we do not check the compact support; this is handled in the
# safe wrappers `TrixiParticles.kernel` and `TrixiParticles.kernel_deriv` based on the
# compact support defined in `TrixiParticles.compact_support`.
function TrixiParticles.kernel_unsafe(kernel::MyGaussianKernel, r::Real, h)
q = r / h

if q < 2
return 1 / (pi * h^2) * exp(-q^2)
end

return 0.0
return 1 / (pi * h^2) * exp(-q^2)
end

function TrixiParticles.kernel_deriv(kernel::MyGaussianKernel, r, h)
function TrixiParticles.kernel_deriv_div_r_unsafe(kernel::MyGaussianKernel, r::Real, h)
q = r / h

if q < 2
return 1 / (pi * h^2) * (-2 * q) * exp(-q^2) / h
end

return 0.0
kernel_deriv = 1 / (pi * h^2) * (-2 * q) * exp(-q^2) / h
return kernel_deriv / r
end

TrixiParticles.compact_support(::MyGaussianKernel, h) = 2 * h
Expand Down
2 changes: 1 addition & 1 deletion src/TrixiParticles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using Reexport: @reexport

using Accessors: @set
using Adapt: Adapt
using Base: @propagate_inbounds
using Base: @propagate_inbounds, FastMath.div_fast
using CSV: CSV
using Dates
using DataFrames: DataFrames, DataFrame
Expand Down
26 changes: 23 additions & 3 deletions src/general/abstract_system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,30 @@ end
return kernel(smoothing_kernel, distance, smoothing_length(system, particle))
end

@inline function skip_zero_distance(system, distance, almostzero)
return skip_zero_distance(system_correction(system), system, distance, almostzero)
end

# Robust/safe version of the function below. In performance-critical code, manually check
# the kernel support, call `skip_zero_distance` and then `smoothing_kernel_grad_unsafe`.
@inline function smoothing_kernel_grad(system, pos_diff, distance, particle)
return corrected_kernel_grad(system_smoothing_kernel(system), pos_diff,
distance, smoothing_length(system, particle),
system_correction(system), system, particle)
h = smoothing_length(system, particle)
compact_support_ = compact_support(system_smoothing_kernel(system), h)

# Note that `sqrt(eps(h^2)) != eps(h)`
if distance > compact_support_ || skip_zero_distance(system, distance, sqrt(eps(h^2)))
return zero(pos_diff)
end

return smoothing_kernel_grad_unsafe(system, pos_diff, distance, particle)
end

# Skip the zero distance and compact support checks for maximum performance.
# Only call this when you are sure that `0 < distance < compact_support`.
@inline function smoothing_kernel_grad_unsafe(system, pos_diff, distance, particle)
return corrected_kernel_grad_unsafe(system_smoothing_kernel(system), pos_diff,
distance, smoothing_length(system, particle),
system_correction(system), system, particle)
end

# System updates do nothing by default, but can be dispatched if needed
Expand Down
37 changes: 21 additions & 16 deletions src/general/corrections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,31 +337,36 @@ 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)
almostzero = sqrt(eps(compact_support(system, neighbor_system)^2))

foreach_point_neighbor(system, neighbor_system, coordinates, neighbor_coords,
semi) do particle, neighbor, pos_diff, distance
volume = hydrodynamic_mass(neighbor_system, neighbor) /
current_density(v_neighbor_system, neighbor_system, neighbor)
smoothing_length_ = smoothing_length(system, particle)

function compute_grad_kernel(correction, smoothing_kernel, pos_diff, distance,
smoothing_length_, system, particle)
return smoothing_kernel_grad(system, pos_diff, distance, particle)
function kernel_grad_local(correction, smoothing_kernel, pos_diff, distance,
smoothing_length_, system, particle)
return smoothing_kernel_grad_unsafe(system, pos_diff, distance, particle)
end

# Compute gradient of corrected kernel
function compute_grad_kernel(correction::MixedKernelGradientCorrection,
smoothing_kernel, pos_diff, distance,
smoothing_length_, system, particle)
return corrected_kernel_grad(smoothing_kernel, pos_diff, distance,
smoothing_length_, KernelCorrection(), system,
particle)
function kernel_grad_local(correction::MixedKernelGradientCorrection,
smoothing_kernel, pos_diff, distance,
smoothing_length_, system, particle)
return corrected_kernel_grad_unsafe(smoothing_kernel, pos_diff, distance,
smoothing_length_, KernelCorrection(),
system, particle)
end

grad_kernel = compute_grad_kernel(correction, smoothing_kernel, pos_diff,
distance, smoothing_length_, system, particle)
# Skip neighbors with the same position if the kernel gradient is zero.
# Note that `return` only exits the closure, i.e., skips the current neighbor.
skip_zero_distance(correction, system, distance, almostzero) && return

iszero(grad_kernel) && return
# Now that we know that `distance` is not zero, we can safely call the unsafe
# version of the kernel gradient to avoid redundant zero checks.
smoothing_length_ = smoothing_length(system, particle)
grad_kernel = kernel_grad_local(correction, smoothing_kernel, pos_diff,
distance, smoothing_length_, system, particle)

volume = hydrodynamic_mass(neighbor_system, neighbor) /
current_density(v_neighbor_system, neighbor_system, neighbor)

L = volume * grad_kernel * pos_diff'

Expand Down
Loading
Loading